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 */

Reply via email to