I have a Shuttle NC02U "nano" PC that ends up with the the acpi0 kernel thread blocked on the "acpievt" wait channel. I tracked this down to an incorrect implementation of the Signal() and Wait() operations.
This changes the implementation to be a proper semaphore. It also releases the acpi interpreter lock. This is necessary because the acpivout(4) implementation directly executes AML code from the calling thread instead of using an acpi task. Maybe that should be fixed instead but it is non-trivial and the current code results in a hard hang during the initial mode setting stage. ok? Index: dev/acpi/dsdt.c =================================================================== RCS file: /cvs/src/sys/dev/acpi/dsdt.c,v retrieving revision 1.243 diff -u -p -r1.243 dsdt.c --- dev/acpi/dsdt.c 19 Aug 2018 08:23:47 -0000 1.243 +++ dev/acpi/dsdt.c 8 Jan 2019 16:25:12 -0000 @@ -2905,29 +2905,32 @@ int acpi_event_wait(struct aml_scope *scope, struct aml_value *evt, int timeout) { /* Wait for event to occur; do work in meantime */ - evt->v_evt.state = 0; - while (!evt->v_evt.state) { - if (!acpi_dotask(acpi_softc) && !cold) - tsleep(evt, PWAIT, "acpievt", 1); - else - delay(100); + while (evt->v_evt.state == 0 && timeout >= 0) { + if (!acpi_dotask(acpi_softc) && !cold) { + rw_exit_write(&acpi_softc->sc_lck); + if (tsleep(evt, PWAIT, "acpievt", 1) == EWOULDBLOCK) { + if (timeout < 0xffff) + timeout -= (1000 / hz); + } + rw_enter_write(&acpi_softc->sc_lck); + } else { + delay(1000); + if (timeout < 0xffff) + timeout--; + } } - if (evt->v_evt.state == 1) { - /* Object is signaled */ - return (0); - } else if (timeout == 0) { - /* Zero timeout */ + if (evt->v_evt.state == 0) return (-1); - } - /* Wait for timeout or signal */ + evt->v_evt.state--; return (0); } void acpi_event_signal(struct aml_scope *scope, struct aml_value *evt) { - evt->v_evt.state = 1; - /* Wakeup waiters */ + evt->v_evt.state++; + if (evt->v_evt.state > 0) + wakeup_one(evt); } void @@ -4215,7 +4218,7 @@ aml_parse(struct aml_scope *scope, int r case AMLOP_EVENT: /* Event: N */ rv = _aml_setvalue(opargs[0], AML_OBJTYPE_EVENT, 0, 0); - rv->v_integer = 0; + rv->v_evt.state = 0; break; case AMLOP_MUTEX: /* Mutex: Nw */