From: me@cyberex.cc Subject: acpiec(4): fall back to namespace EC device when ECDT namepath is bogus To: tech@openbsd.org Cc: me@cyberex.cc Date: Wed, 28 Oct 2026 07:49:19 +0000 Hi, On a Lenovo IdeaPad L3 15ITL6 (82HL, Tiger Lake) the battery is not detected on OpenBSD 8.0/amd64 ( GENERIC.MP#84, acpiec.c rev 1.67): acpiec at acpi0 not configured acpibat0 at acpi0: BAT0 not present There are no hw.sensors.acpibat0.* sensors at all, apm(8) always reports "absent", and hw.sensors.acpiac0.indicator0 stays Off even with the AC adapter connected. The firmware provides an ECDT whose namepath refers to an object that does not exist in the namespace: ECDT: UID 1, GPE 0x6E, IO 0x62/0x66 Namepath: "\_SB.PC00.LPCB.H_EC" The embedded controller described by the DSDT is called EC0: Device (EC0) { Name (_HID, EisaId ("PNP0C09")) Name (_UID, One) ... } acpiec attaches from the ECDT (aa->aaa_node == NULL) and acpiec_getcrs() does: sc->sc_devnode = aml_searchname(sc->sc_acpi->sc_root, ecdt->ec_id); which returns NULL for this namepath, and there is no fallback. As a result acpiec_reg() never evaluates _REG on the real EC node. This particular DSDT gates every battery/AC method on ECAV, which is only ever set by EC0._REG: Method (_REG, 2) { If (Arg0 == 0x03) { ECAV = Arg1 } ... } so ECAV stays 0, BAT0._STA() returns 0x0F ("not present") forever and _BIF()/_BST() return static defaults. The "acpiec at acpi0 not configured" line comes from acpi_foundecdt() finding the namespace EC0 later: sc_ec is already set (and its sc_devnode is NULL, so the equality check does not shortcut the attach). The diff below makes acpiec_getcrs() fall back to the first PNP0C09 device found in the namespace when the ECDT namepath does not resolve. It is modelled after acpi_foundecdt() in acpi.c. Note that simply ignoring the ECDT and taking the regular _CRS/_GPE path would not work here: EC0._GPE() reads EC fields (ESPI/SRSP), which cannot be evaluated before the EC is attached. Tested on the machine above, with the diff battery, AC status and charging state all work: acpiec0 at acpi0 acpibat0 at acpi0: BAT0 model "L18D3PF1" serial 49284 type LiP oem "Sunwoda" hw.sensors.acpibat0.watthour3=26.97 Wh (remaining capacity), OK hw.sensors.acpibat0.raw0=2 (battery charging) hw.sensors.acpiac0.indicator0=On (power supply) The "acpiec ... not configured" message is gone as well. Full dmesg (before and after) and an acpidump of this machine are available on request. Comments? In particular, should the fallback also match _UID, or would it be preferable to retry the attach from the namespace device instead of binding the ECDT one? Sergey Index: sys/dev/acpi/acpiec.c --- sys/dev/acpi/acpiec.c +++ sys/dev/acpi/acpiec.c @@ -49,6 +49,7 @@ int acpiec_getcrs(struct acpiec_softc *, struct acpi_attach_args *); int acpiec_parse_resources(int, union acpi_resource *, void *); +int acpiec_foundecdt(struct aml_node *, void *); void acpiec_wait(struct acpiec_softc *, uint8_t, uint8_t); void acpiec_sci_event(struct acpiec_softc *); @@ -435,6 +436,38 @@ } int +acpiec_foundecdt(struct aml_node *node, void *arg) +{ + struct acpiec_softc *sc = arg; + struct aml_value res; + const char *dev; + + if (aml_evalnode(sc->sc_acpi, node, 0, NULL, &res) != 0) + return (0); + + switch (res.type) { + case AML_OBJTYPE_STRING: + dev = res.v_string; + break; + case AML_OBJTYPE_INTEGER: + dev = aml_eisaid(aml_val2int(&res)); + break; + default: + aml_freevalue(&res); + return (0); + } + + if (strcmp(dev, ACPI_DEV_ECD) == 0) { + sc->sc_devnode = node->parent; + aml_freevalue(&res); + return (1); + } + + aml_freevalue(&res); + return (0); +} + +int acpiec_getcrs(struct acpiec_softc *sc, struct acpi_attach_args *aa) { struct aml_value res; @@ -463,6 +496,19 @@ sc->sc_devnode = aml_searchname(sc->sc_acpi->sc_root, ecdt->ec_id); + /* + * Some BIOSes contain an ECDT whose namepath refers to an + * object that does not exist in the namespace (seen on a + * Lenovo IdeaPad L3 15ITL6 whose ECDT refers to + * \_SB.PC00.LPCB.H_EC while the namespace EC device is + * called EC0). Fall back to the Embedded Controller device + * found in the namespace such that _REG is evaluated on the + * right node and EC operation regions become available. + */ + if (sc->sc_devnode == NULL) + aml_find_node(sc->sc_acpi->sc_root, "_HID", + acpiec_foundecdt, sc); + goto ecdtdone; }