On Wed, Nov 29, 2017 at 04:30:01AM +0100, Mark Kettenis wrote: > Diff below revises the OperationRegion support to allow chvgpio(4) to > register its own OEM defined regions. This prevents a panic on a > Lenovo 2-in-1 that mlarkin@ carried all the way to Elk Lakes cabin. > It even makes the lid switch work somewhat. > > This will also make it easier to add CMOS support and other > OEM-specific regions in the future. > > ok? >
Looks ok, no objections here. -ml > Index: dev/acpi/chvgpio.c > =================================================================== > RCS file: /cvs/src/sys/dev/acpi/chvgpio.c,v > retrieving revision 1.6 > diff -u -p -r1.6 chvgpio.c > --- dev/acpi/chvgpio.c 25 Oct 2016 06:48:58 -0000 1.6 > +++ dev/acpi/chvgpio.c 29 Nov 2017 03:18:06 -0000 > @@ -43,6 +43,9 @@ > #define CHVGPIO_PAD_CFG1_INVRXTX_MASK 0x000000f0 > #define CHVGPIO_PAD_CFG1_INVRXTX_RXDATA 0x00000040 > > +/* OEM defined RegionSpace. */ > +#define CHVGPIO_REGIONSPACE_BASE 0x90 > + > struct chvgpio_intrhand { > int (*ih_func)(void *); > void *ih_arg; > @@ -149,6 +152,7 @@ int chvgpio_read_pin(void *, int); > void chvgpio_write_pin(void *, int, int); > void chvgpio_intr_establish(void *, int, int, int (*)(), void *); > int chvgpio_intr(void *); > +int chvgpio_opreg_handler(void *, int, uint64_t, int, uint64_t *); > > int > chvgpio_match(struct device *parent, void *match, void *aux) > @@ -247,7 +251,7 @@ chvgpio_attach(struct device *parent, st > > printf(", %d pins\n", sc->sc_npins); > > - /* Register address space. */ > + /* Register GeneralPurposeIO address space. */ > memset(&arg, 0, sizeof(arg)); > arg[0].type = AML_OBJTYPE_INTEGER; > arg[0].v_integer = ACPI_OPREG_GPIO; > @@ -257,6 +261,9 @@ chvgpio_attach(struct device *parent, st > if (node && aml_evalnode(sc->sc_acpi, node, 2, arg, NULL)) > printf("%s: _REG failed\n", sc->sc_dev.dv_xname); > > + /* Register OEM defined address space. */ > + aml_register_regionspace(sc->sc_node, CHVGPIO_REGIONSPACE_BASE + uid, > + sc, chvgpio_opreg_handler); > return; > > unmap: > @@ -398,4 +405,22 @@ chvgpio_intr(void *arg) > } > > return rc; > +} > + > +int > +chvgpio_opreg_handler(void *cookie, int iodir, uint64_t address, int size, > + uint64_t *value) > +{ > + struct chvgpio_softc *sc = cookie; > + > + /* Only allow 32-bit access. */ > + if (size != 4 || address > sc->sc_size - size) > + return -1; > + > + if (iodir == ACPI_IOREAD) > + *value = bus_space_read_4(sc->sc_memt, sc->sc_memh, address); > + else > + bus_space_write_4(sc->sc_memt, sc->sc_memh, address, *value); > + > + return 0; > } > Index: dev/acpi/dsdt.c > =================================================================== > RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v > retrieving revision 1.235 > diff -u -p -r1.235 dsdt.c > --- dev/acpi/dsdt.c 12 Oct 2017 07:24:46 -0000 1.235 > +++ dev/acpi/dsdt.c 29 Nov 2017 03:08:06 -0000 > @@ -2208,8 +2208,6 @@ void aml_createfield(struct aml_value *, > void aml_parsefieldlist(struct aml_scope *, int, int, > struct aml_value *, struct aml_value *, int); > > -#define GAS_PCI_CFG_SPACE_UNEVAL 0xCC > - > int > aml_evalhid(struct aml_node *node, struct aml_value *val) > { > @@ -2222,7 +2220,73 @@ aml_evalhid(struct aml_node *node, struc > return (0); > } > > -void aml_rwgas(struct aml_value *, int, int, struct aml_value *, int, int); > +int > +aml_opreg_sysmem_handler(void *cookie, int iodir, uint64_t address, int size, > + uint64_t *value) > +{ > + return acpi_gasio(acpi_softc, iodir, GAS_SYSTEM_MEMORY, > + address, size, size, value); > +} > + > +int > +aml_opreg_sysio_handler(void *cookie, int iodir, uint64_t address, int size, > + uint64_t *value) > +{ > + return acpi_gasio(acpi_softc, iodir, GAS_SYSTEM_IOSPACE, > + address, size, size, value); > +} > + > +int > +aml_opreg_pcicfg_handler(void *cookie, int iodir, uint64_t address, int size, > + uint64_t *value) > +{ > + return acpi_gasio(acpi_softc, iodir, GAS_PCI_CFG_SPACE, > + address, size, size, value); > +} > + > +int > +aml_opreg_ec_handler(void *cookie, int iodir, uint64_t address, int size, > + uint64_t *value) > +{ > + return acpi_gasio(acpi_softc, iodir, GAS_EMBEDDED, > + address, size, size, value); > +} > + > +struct aml_regionspace { > + void *cookie; > + int (*handler)(void *, int, uint64_t, int, uint64_t *); > +}; > + > +struct aml_regionspace aml_regionspace[256] = { > + [ACPI_OPREG_SYSMEM] = { NULL, aml_opreg_sysmem_handler }, > + [ACPI_OPREG_SYSIO] = { NULL, aml_opreg_sysio_handler }, > + [ACPI_OPREG_PCICFG] = { NULL, aml_opreg_pcicfg_handler }, > + [ACPI_OPREG_EC] = { NULL, aml_opreg_ec_handler }, > +}; > + > +void > +aml_register_regionspace(struct aml_node *node, int iospace, void *cookie, > + int (*handler)(void *, int, uint64_t, int, uint64_t *)) > +{ > + struct aml_value arg[2]; > + > + KASSERT(iospace >= 0 && iospace < 256); > + > + aml_regionspace[iospace].cookie = cookie; > + aml_regionspace[iospace].handler = handler; > + > + /* Register address space. */ > + memset(&arg, 0, sizeof(arg)); > + arg[0].type = AML_OBJTYPE_INTEGER; > + arg[0].v_integer = iospace; > + arg[1].type = AML_OBJTYPE_INTEGER; > + arg[1].v_integer = 1; > + node = aml_searchname(node, "_REG"); > + if (node) > + aml_evalnode(acpi_softc, node, 2, arg, NULL); > +} > + > +void aml_rwgen(struct aml_value *, int, int, struct aml_value *, int, int); > void aml_rwgpio(struct aml_value *, int, int, struct aml_value *, int, int); > void aml_rwindexfield(struct aml_value *, struct aml_value *val, int); > void aml_rwfield(struct aml_value *, int, int, struct aml_value *, int); > @@ -2250,9 +2314,73 @@ aml_rdpciaddr(struct aml_node *pcidev, u > return (0); > } > > +int > +acpi_genio(struct acpi_softc *sc, int iodir, int iospace, uint64_t address, > + int access_size, int len, void *buffer) > +{ > + struct aml_regionspace *region = &aml_regionspace[iospace]; > + u_int8_t *pb; > + int reg; > + > + dnprintf(50, "genio: %.2x 0x%.8llx %s\n", > + iospace, address, (iodir == ACPI_IOWRITE) ? "write" : "read"); > + > + KASSERT((len % access_size) == 0); > + > + pb = (u_int8_t *)buffer; > + for (reg = 0; reg < len; reg += access_size) { > + uint64_t value; > + int err; > + > + if (iodir == ACPI_IOREAD) { > + err = region->handler(region->cookie, iodir, > + address + reg, access_size, &value); > + if (err) > + return err; > + switch (access_size) { > + case 1: > + *(uint8_t *)(pb + reg) = value; > + break; > + case 2: > + *(uint16_t *)(pb + reg) = value; > + break; > + case 4: > + *(uint32_t *)(pb + reg) = value; > + break; > + default: > + printf("%s: invalid access size %d on read\n", > + __func__, access_size); > + return -1; > + } > + } else { > + switch (access_size) { > + case 1: > + value = *(uint8_t *)(pb + reg); > + break; > + case 2: > + value = *(uint16_t *)(pb + reg); > + break; > + case 4: > + value = *(uint32_t *)(pb + reg); > + break; > + default: > + printf("%s: invalid access size %d on write\n", > + __func__, access_size); > + return -1; > + } > + err = region->handler(region->cookie, iodir, > + address + reg, access_size, &value); > + if (err) > + return err; > + } > + } > + > + return 0; > +} > + > /* Read/Write from opregion object */ > void > -aml_rwgas(struct aml_value *rgn, int bpos, int blen, struct aml_value *val, > +aml_rwgen(struct aml_value *rgn, int bpos, int blen, struct aml_value *val, > int mode, int flag) > { > struct aml_value tmp; > @@ -2287,7 +2415,7 @@ aml_rwgas(struct aml_value *rgn, int bpo > bpos += ((rgn->v_opregion.iobase & (sz - 1)) << 3); > bpos &= ((sz << 3) - 1); > > - if (rgn->v_opregion.iospace == GAS_PCI_CFG_SPACE) { > + if (rgn->v_opregion.iospace == ACPI_OPREG_PCICFG) { > /* Get PCI Root Address for this opregion */ > aml_rdpciaddr(rgn->node->parent, &pi); > } > @@ -2297,6 +2425,9 @@ aml_rwgas(struct aml_value *rgn, int bpo > tlen = roundup(bpos + blen, sz << 3); > type = rgn->v_opregion.iospace; > > + if (aml_regionspace[type].handler == NULL) > + panic("%s: unregistered RegionSpace 0x%x\n", __func__, type); > + > /* Allocate temporary storage */ > if (tlen > aml_intlen) { > _aml_setvalue(&tmp, AML_OBJTYPE_BUFFER, tlen >> 3, 0); > @@ -2327,21 +2458,21 @@ aml_rwgas(struct aml_value *rgn, int bpo > > if (mode == ACPI_IOREAD) { > /* Read bits from opregion */ > - acpi_gasio(acpi_softc, ACPI_IOREAD, type, pi.addr, > + acpi_genio(acpi_softc, ACPI_IOREAD, type, pi.addr, > sz, tlen >> 3, tbit); > aml_bufcpy(vbit, 0, tbit, bpos, blen); > } else { > /* Write bits to opregion */ > if (AML_FIELD_UPDATE(flag) == AML_FIELD_PRESERVE && > (bpos != 0 || blen != tlen)) { > - acpi_gasio(acpi_softc, ACPI_IOREAD, type, pi.addr, > + acpi_genio(acpi_softc, ACPI_IOREAD, type, pi.addr, > sz, tlen >> 3, tbit); > } else if (AML_FIELD_UPDATE(flag) == AML_FIELD_WRITEASONES) { > memset(tbit, 0xff, tmp.length); > } > /* Copy target bits, then write to region */ > aml_bufcpy(tbit, bpos, vbit, 0, blen); > - acpi_gasio(acpi_softc, ACPI_IOWRITE, type, pi.addr, > + acpi_genio(acpi_softc, ACPI_IOWRITE, type, pi.addr, > sz, tlen >> 3, tbit); > > aml_delref(&val, "fld.write"); > @@ -2473,7 +2604,7 @@ aml_rwfield(struct aml_value *fld, int b > } else if (fld->v_field.type == AMLOP_BANKFIELD) { > _aml_setvalue(&tmp, AML_OBJTYPE_INTEGER, fld->v_field.ref3, 0); > aml_rwfield(ref2, 0, aml_intlen, &tmp, ACPI_IOWRITE); > - aml_rwgas(ref1, fld->v_field.bitpos, fld->v_field.bitlen, > + aml_rwgen(ref1, fld->v_field.bitpos, fld->v_field.bitlen, > val, mode, fld->v_field.flags); > } else if (fld->v_field.type == AMLOP_FIELD) { > switch (ref1->v_opregion.iospace) { > @@ -2481,16 +2612,9 @@ aml_rwfield(struct aml_value *fld, int b > aml_rwgpio(ref2, bpos, blen, val, mode, > fld->v_field.flags); > break; > - case ACPI_OPREG_SYSMEM: > - case ACPI_OPREG_SYSIO: > - case ACPI_OPREG_PCICFG: > - case ACPI_OPREG_EC: > - aml_rwgas(ref1, fld->v_field.bitpos + bpos, blen, > - val, mode, fld->v_field.flags); > - break; > default: > - aml_die("Unsupported RegionSpace 0x%x", > - ref1->v_opregion.iospace); > + aml_rwgen(ref1, fld->v_field.bitpos + bpos, blen, > + val, mode, fld->v_field.flags); > break; > } > } else if (mode == ACPI_IOREAD) { > Index: dev/acpi/dsdt.h > =================================================================== > RCS file: /cvs/src/sys/dev/acpi/dsdt.h,v > retrieving revision 1.73 > diff -u -p -r1.73 dsdt.h > --- dev/acpi/dsdt.h 25 Oct 2016 06:48:58 -0000 1.73 > +++ dev/acpi/dsdt.h 29 Nov 2017 01:28:07 -0000 > @@ -60,6 +60,8 @@ int acpi_parse_aml(struct acpi_softc * > void aml_register_notify(struct aml_node *, const char *, > int (*)(struct aml_node *, int, void *), void *, > int); > +void aml_register_regionspace(struct aml_node *, int, void *, > + int (*)(void *, int, uint64_t, int, uint64_t *)); > > int aml_evalnode(struct acpi_softc *, struct aml_node *, > int, struct aml_value *, struct aml_value *); >