From 99446a6d6053c09ce578b8707502aa059661f189 Mon Sep 17 00:00:00 2001 From: kettenis Date: Tue, 6 Aug 2024 17:38:56 +0000 Subject: [PATCH] Some laptops will generate an EC event shortly after we attempt to enter 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 | 19 ++++++++++++++++--- sys/dev/acpi/acpibtn.c | 4 ++-- sys/dev/acpi/acpidev.h | 7 ++++--- sys/dev/acpi/acpivar.h | 4 +++- sys/dev/acpi/dsdt.c | 20 ++++++++++++++------ 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/sys/dev/acpi/acpi_x86.c b/sys/dev/acpi/acpi_x86.c index 5b8ff4365e0..b0927ca7de0 100644 --- a/sys/dev/acpi/acpi_x86.c +++ b/sys/dev/acpi/acpi_x86.c @@ -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 * Copyright (c) 2005 Jordan Hargrave @@ -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); diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index bda94a9a4e1..ad1b8d1c856 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -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 * @@ -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 diff --git a/sys/dev/acpi/acpidev.h b/sys/dev/acpi/acpidev.h index 512d79b762b..6122c95016e 100644 --- a/sys/dev/acpi/acpidev.h +++ b/sys/dev/acpi/acpidev.h @@ -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 * Copyright (c) 2005 Thorsten Lockert @@ -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) diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index d1af26fa0b0..4ec231772ef 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -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 * @@ -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 *); diff --git a/sys/dev/acpi/dsdt.c b/sys/dev/acpi/dsdt.c index aeb114da395..d179cfdd136 100644 --- a/sys/dev/acpi/dsdt.c +++ b/sys/dev/acpi/dsdt.c @@ -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 * @@ -28,6 +28,7 @@ #include #endif +#include #include #include #include @@ -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); } -- 2.20.1