Some laptops will generate an EC event shortly after we attempt to enter
authorkettenis <kettenis@openbsd.org>
Tue, 6 Aug 2024 17:38:56 +0000 (17:38 +0000)
committerkettenis <kettenis@openbsd.org>
Tue, 6 Aug 2024 17:38:56 +0000 (17:38 +0000)
a low power S0 idle state.  Since we register the EC GPE as a wakeup GPE
this means we'll wake up immediately.  Unfortunately we have to register
that GPE as a wakeup GPE otherwise many laptops won't wake up when the
user opens the lid (and some laptops won't wake up at all).  So add some
code to handle EC events while suspended and introduce the concept of
wakeup AML notify handlers.  Register the acpibtn(4) notify handlers as
wakeup notify handlers such that we wake up.  We'll go back to sleep
immediately if we wake up for any other EC event.

ok mlarkin@, deraadt@

sys/dev/acpi/acpi_x86.c
sys/dev/acpi/acpibtn.c
sys/dev/acpi/acpidev.h
sys/dev/acpi/acpivar.h
sys/dev/acpi/dsdt.c

index 5b8ff43..b0927ca 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_x86.c,v 1.23 2024/08/04 11:05:18 kettenis Exp $ */
+/* $OpenBSD: acpi_x86.c,v 1.24 2024/08/06 17:38:56 kettenis Exp $ */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
@@ -107,8 +107,17 @@ gosleep(void *v)
        if (sc->sc_pmc_suspend)
                sc->sc_pmc_suspend(sc->sc_pmc_cookie);
 
-       ret = acpi_sleep_cpu(sc, sc->sc_state);
-       acpi_resume_cpu(sc, sc->sc_state);
+       sc->sc_wakeup = 0;
+       while (!sc->sc_wakeup) {
+               ret = acpi_sleep_cpu(sc, sc->sc_state);
+               acpi_resume_cpu(sc, sc->sc_state);
+
+               if (sc->sc_ec && sc->sc_wakegpe == sc->sc_ec->sc_gpe) {
+                       sc->sc_wakeup = 0;
+                       acpiec_gpehandler(sc, sc->sc_wakegpe, sc->sc_ec);
+               } else
+                       sc->sc_wakeup = 1;
+       }
 
        if (sc->sc_pmc_resume)
                sc->sc_pmc_resume(sc->sc_pmc_cookie);
@@ -155,6 +164,9 @@ suspend_finish(void *v)
 
        printf("wakeup event: ");
        switch (sc->sc_wakegpe) {
+       case 0:
+               printf("unknown\n");
+               break;
        case -1:
                printf("PWRBTN\n");
                break;
@@ -165,6 +177,7 @@ suspend_finish(void *v)
                printf("GPE 0x%x\n", sc->sc_wakegpe);
                break;
        }
+       sc->sc_wakegpe = 0;
 
        acpi_record_event(sc, APM_NORMAL_RESUME);
        acpi_indicator(sc, ACPI_SST_WORKING);
index bda94a9..ad1b8d1 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpibtn.c,v 1.52 2024/05/13 19:56:37 kettenis Exp $ */
+/* $OpenBSD: acpibtn.c,v 1.53 2024/08/06 17:38:56 kettenis Exp $ */
 /*
  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
  *
@@ -213,7 +213,7 @@ acpibtn_attach(struct device *parent, struct device *self, void *aux)
 
        printf("\n");
        aml_register_notify(sc->sc_devnode, aa->aaa_dev, acpibtn_notify,
-           sc, ACPIDEV_NOPOLL);
+           sc, ACPIDEV_NOPOLL | ACPIDEV_WAKEUP);
 }
 
 int
index 512d79b..6122c95 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpidev.h,v 1.44 2018/06/29 17:39:18 kettenis Exp $ */
+/* $OpenBSD: acpidev.h,v 1.45 2024/08/06 17:38:56 kettenis Exp $ */
 /*
  * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org>
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
@@ -26,8 +26,9 @@
 
 #define DEVNAME(s)  ((s)->sc_dev.dv_xname)
 
-#define ACPIDEV_NOPOLL         0
-#define ACPIDEV_POLL           1
+#define ACPIDEV_NOPOLL         0x0000
+#define ACPIDEV_POLL           0x0001
+#define ACPIDEV_WAKEUP         0x0002
 
 /*
  * _BIF (Battery InFormation)
index d1af26f..4ec2317 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: acpivar.h,v 1.132 2024/08/04 11:05:18 kettenis Exp $  */
+/*     $OpenBSD: acpivar.h,v 1.133 2024/08/06 17:38:56 kettenis Exp $  */
 /*
  * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
  *
@@ -264,6 +264,7 @@ struct acpi_softc {
        struct aml_node         *sc_sst;
        struct aml_node         *sc_wak;
        int                     sc_state;
+       int                     sc_wakeup;
        time_t                  sc_resume_time;
        struct acpiec_softc     *sc_ec;         /* XXX assume single EC */
 
@@ -341,6 +342,7 @@ int acpi_set_gpehandler(struct acpi_softc *, int,
 
 void   acpiec_read(struct acpiec_softc *, uint8_t, int, uint8_t *);
 void   acpiec_write(struct acpiec_softc *, uint8_t, int, uint8_t *);
+int    acpiec_gpehandler(struct acpi_softc *, int, void *);
 
 #if NACPIPWRRES > 0
 int    acpipwrres_ref_incr(struct acpipwrres_softc *, struct aml_node *);
index aeb114d..d179cfd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: dsdt.c,v 1.269 2024/06/26 01:40:49 jsg Exp $ */
+/* $OpenBSD: dsdt.c,v 1.270 2024/08/06 17:38:56 kettenis Exp $ */
 /*
  * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
  *
@@ -28,6 +28,7 @@
 #include <machine/db_machdep.h>
 #endif
 
+#include <dev/acpi/acpidev.h>
 #include <dev/acpi/acpireg.h>
 #include <dev/acpi/acpivar.h>
 #include <dev/acpi/amltypes.h>
@@ -364,7 +365,7 @@ struct aml_notify_data {
        char                    pnpid[20];
        void                    *cbarg;
        int                     (*cbproc)(struct aml_node *, int, void *);
-       int                     poll;
+       int                     flags;
 
        SLIST_ENTRY(aml_notify_data) link;
 };
@@ -536,7 +537,7 @@ aml_notify_task(void *node, int notify_value)
 
 void
 aml_register_notify(struct aml_node *node, const char *pnpid,
-    int (*proc)(struct aml_node *, int, void *), void *arg, int poll)
+    int (*proc)(struct aml_node *, int, void *), void *arg, int flags)
 {
        struct aml_notify_data  *pdata;
        extern int acpi_poll_enabled;
@@ -548,23 +549,30 @@ aml_register_notify(struct aml_node *node, const char *pnpid,
        pdata->node = node;
        pdata->cbarg = arg;
        pdata->cbproc = proc;
-       pdata->poll = poll;
+       pdata->flags = flags;
 
        if (pnpid)
                strlcpy(pdata->pnpid, pnpid, sizeof(pdata->pnpid));
 
        SLIST_INSERT_HEAD(&aml_notify_list, pdata, link);
 
-       if (poll && !acpi_poll_enabled)
+       if ((flags & ACPIDEV_POLL) && !acpi_poll_enabled)
                timeout_add_sec(&acpi_softc->sc_dev_timeout, 10);
 }
 
 void
 aml_notify(struct aml_node *node, int notify_value)
 {
+       struct aml_notify_data *pdata;
+
        if (node == NULL)
                return;
 
+       SLIST_FOREACH(pdata, &aml_notify_list, link) {
+               if (pdata->node == node && (pdata->flags & ACPIDEV_WAKEUP))
+                       acpi_softc->sc_wakeup = 1;
+       }
+
        dnprintf(10,"queue notify: %s %x\n", aml_nodename(node), notify_value);
        acpi_addtask(acpi_softc, aml_notify_task, node, notify_value);
 }
@@ -588,7 +596,7 @@ acpi_poll_notify_task(void *arg0, int arg1)
        struct aml_notify_data  *pdata = NULL;
 
        SLIST_FOREACH(pdata, &aml_notify_list, link)
-               if (pdata->cbproc && pdata->poll)
+               if (pdata->cbproc && (pdata->flags & ACPIDEV_POLL))
                        pdata->cbproc(pdata->node, 0, pdata->cbarg);
 }