diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2010-07-06 20:14:18 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2010-07-06 20:14:18 +0000 |
commit | 34742b972dd39d67dd2490891c0236fa4c793c6c (patch) | |
tree | 8a5c4ca588f678111198519b60d0e471b596a0b4 /sys | |
parent | 04ca5b42a1294c87014c29bb6dc82d41cb3ca3d2 (diff) |
Don't use a workq to do the suspend, because it races aginst the acpi
thread. Instead, just tell the acpi thread to do the suspend for us.
This makes apmd & zzz work correctly. While here, have acpithinkpad
attempt to post the event to apm before prompting the suspend itself.
ok kettenis marco mlarkin
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/acpi/acpi.c | 28 | ||||
-rw-r--r-- | sys/dev/acpi/acpibtn.c | 27 | ||||
-rw-r--r-- | sys/dev/acpi/acpithinkpad.c | 12 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 6 |
4 files changed, 51 insertions, 22 deletions
diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index e37c649e452..dffb5aa0d8c 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.170 2010/07/05 05:59:01 mlarkin Exp $ */ +/* $OpenBSD: acpi.c,v 1.171 2010/07/06 20:14:17 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -978,13 +978,8 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) switch (cmd) { case APM_IOC_SUSPEND: case APM_IOC_STANDBY: - /* - * Must use a workq to get out of this process's address - * space and into a kernel thread which has the kernel - * address space (with the ACPI trampoline way low). - */ - workq_add_task(NULL, 0, (workq_fn)acpi_sleep_state, - acpi_softc, (void *)ACPI_STATE_S3); + sc->sc_sleepmode = ACPI_STATE_S3; + acpi_wakeup(sc); break; case APM_IOC_GETPOWER: /* A/C */ @@ -2122,7 +2117,14 @@ fail: return (error); } +void +acpi_wakeup(void *arg) +{ + struct acpi_softc *sc = (struct acpi_softc *)arg; + sc->sc_wakeup = 0; + wakeup(sc); +} void acpi_powerdown(void) @@ -2216,6 +2218,16 @@ acpi_isr_thread(void *arg) sc->sc_poll = 0; acpi_poll_notify(); } + +#ifndef SMALL_KERNEL + if (sc->sc_sleepmode) { + int sleepmode = sc->sc_sleepmode; + + sc->sc_sleepmode = 0; + acpi_sleep_state(sc, sleepmode); + continue; + } +#endif /* SMALL_KERNEL */ } free(thread, M_DEVBUF); diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index 548dd3c800d..cba0cafed74 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibtn.c,v 1.26 2010/03/31 19:21:19 kettenis Exp $ */ +/* $OpenBSD: acpibtn.c,v 1.27 2010/07/06 20:14:17 deraadt Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -112,6 +112,9 @@ acpibtn_getsta(struct acpibtn_softc *sc) return (0); } +/* XXX tie this to a sysctl later */ +int acpi_lid_suspend = 0; + int acpibtn_notify(struct aml_node *node, int notify_type, void *arg) { @@ -125,24 +128,24 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) switch (sc->sc_btn_type) { case ACPIBTN_LID: +#ifndef SMALL_KERNEL /* * Notification of 0x80 for lid opens or closes. We * need to check the current status by calling the - * _LID method. Zero means the lid is closed and we + * _LID method. 0 means the lid is closed and we * should go to sleep. */ -#ifndef SMALL_KERNEL if (aml_evalinteger(sc->sc_acpi, sc->sc_devnode, "_LID", 0, NULL, &lid)) return (0); -#if 0 - if (lid == 0) { - if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) - acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3); + if (acpi_lid_suspend && lid == 0) { + if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) { + sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_wakeup(sc->sc_acpi); + } } -#endif - break; #endif /* SMALL_KERNEL */ + break; case ACPIBTN_SLEEP: #ifndef SMALL_KERNEL switch (notify_type) { @@ -151,8 +154,10 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) break; case 0x80: /* Request to go to sleep */ - if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) - acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3); + if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) { + sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_wakeup(sc->sc_acpi); + } break; } #endif /* SMALL_KERNEL */ diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c index b8f0ca6b54a..e91b0ac6514 100644 --- a/sys/dev/acpi/acpithinkpad.c +++ b/sys/dev/acpi/acpithinkpad.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpithinkpad.c,v 1.22 2009/11/25 18:57:02 deraadt Exp $ */ +/* $OpenBSD: acpithinkpad.c,v 1.23 2010/07/06 20:14:17 deraadt Exp $ */ /* * Copyright (c) 2008 joshua stein <jcs@openbsd.org> * @@ -17,6 +17,7 @@ #include <sys/param.h> #include <sys/systm.h> +#include <sys/proc.h> #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> @@ -24,6 +25,8 @@ #include <dev/acpi/amltypes.h> #include <dev/acpi/dsdt.h> +#include <machine/apmvar.h> + #define THINKPAD_HKEY_VERSION 0x0100 #define THINKPAD_CMOS_VOLUME_DOWN 0x00 @@ -279,8 +282,13 @@ thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) handled = 1; break; case THINKPAD_BUTTON_SUSPEND: +#ifndef SMALL_KERNEL + if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) { + sc->sc_acpi->sc_sleepmode = ACPI_STATE_S3; + acpi_wakeup(sc->sc_acpi); + } +#endif handled = 1; - acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3); break; case THINKPAD_BUTTON_HIBERNATE: case THINKPAD_BUTTON_FN_F1: diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index af31e3240cc..9016af5c36e 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.57 2010/04/07 06:33:06 kettenis Exp $ */ +/* $OpenBSD: acpivar.h,v 1.58 2010/07/06 20:14:17 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -207,6 +207,8 @@ struct acpi_softc { int sc_powerbtn; int sc_sleepbtn; + int sc_sleepmode; + struct { int slp_typa; int slp_typb; @@ -302,6 +304,8 @@ void acpi_sleep_walk(struct acpi_softc *, int); #define ACPI_IOWRITE 1 void acpi_delay(struct acpi_softc *, int64_t); +void acpi_wakeup(void *); + int acpi_gasio(struct acpi_softc *, int, int, uint64_t, int, int, void *); int acpi_set_gpehandler(struct acpi_softc *, int, |