From: kettenis Date: Wed, 29 Nov 2017 15:22:22 +0000 (+0000) Subject: Revise OperatingRegion code to make it extensible and have chvgpio(4) X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=4c89a905f3554a6ea4e9c071640c9a820da70fc7;p=openbsd Revise OperatingRegion code to make it extensible and have chvgpio(4) provide the OEM defined regions that are used by the AML on some Cherryview-based machines. ok mlarkin@ --- diff --git a/sys/dev/acpi/chvgpio.c b/sys/dev/acpi/chvgpio.c index c3352dcbe81..a82e6c53fbb 100644 --- a/sys/dev/acpi/chvgpio.c +++ b/sys/dev/acpi/chvgpio.c @@ -1,4 +1,4 @@ -/* $OpenBSD: chvgpio.c,v 1.6 2016/10/25 06:48:58 pirofti Exp $ */ +/* $OpenBSD: chvgpio.c,v 1.7 2017/11/29 15:22:22 kettenis Exp $ */ /* * Copyright (c) 2016 Mark Kettenis * @@ -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, struct device *self, void *aux) 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, struct device *self, void *aux) 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: @@ -399,3 +406,21 @@ 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; +} diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index 544c9cf7358..1c38be3bbfa 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.c,v 1.235 2017/10/12 07:24:46 anton Exp $ */ +/* $OpenBSD: dsdt.c,v 1.236 2017/11/29 15:22:22 kettenis Exp $ */ /* * Copyright (c) 2005 Jordan Hargrave * @@ -2208,8 +2208,6 @@ void aml_createfield(struct aml_value *, int, struct aml_value *, int, int, 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, struct aml_value *val) 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, union amlpci_t *addr) 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 bpos, int blen, struct aml_value *val, 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 bpos, int blen, struct aml_value *val, 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 bpos, int blen, struct aml_value *val, 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 bpos, int blen, struct aml_value *val, } 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 bpos, int blen, struct aml_value *val, 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) { diff --git a/sys/dev/acpi/dsdt.h b/sys/dev/acpi/dsdt.h index a3b871a5ecd..66e1ba73c99 100644 --- a/sys/dev/acpi/dsdt.h +++ b/sys/dev/acpi/dsdt.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dsdt.h,v 1.73 2016/10/25 06:48:58 pirofti Exp $ */ +/* $OpenBSD: dsdt.h,v 1.74 2017/11/29 15:22:22 kettenis Exp $ */ /* * Copyright (c) 2005 Marco Peereboom * @@ -60,6 +60,8 @@ int acpi_parse_aml(struct acpi_softc *, u_int8_t *, 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 *);