From ad814436a071b6401bfaf527a709138b9bf992e2 Mon Sep 17 00:00:00 2001 From: deraadt Date: Tue, 8 Feb 2022 17:25:10 +0000 Subject: [PATCH] The suspend/resume code is a sticky mess of MI, MD, and ACPI sequencing. This splits out the MI sequencing, backing it with per-architecture helper functions. Further steps will be neccesary because ACPI and MD are too tightly coupled, but soon we'll be able to use this code for more architectures (which depends on figuring out the lowest-level cpu sleeping method) ok kettenis --- sys/arch/amd64/amd64/acpi_machdep.c | 61 +++++- sys/arch/amd64/conf/GENERIC | 5 +- sys/arch/arm64/arm64/acpi_machdep.c | 4 +- sys/arch/i386/conf/GENERIC | 5 +- sys/arch/i386/i386/acpi_machdep.c | 62 +++++- sys/conf/files | 3 +- sys/dev/acpi/acpi.c | 294 ++++++++-------------------- sys/dev/acpi/acpibtn.c | 6 +- sys/dev/acpi/acpisony.c | 4 +- sys/dev/acpi/acpithinkpad.c | 6 +- sys/dev/acpi/acpitoshiba.c | 6 +- sys/dev/acpi/acpivar.h | 15 +- sys/kern/subr_suspend.c | 170 ++++++++++++++++ sys/sys/device.h | 17 +- 14 files changed, 414 insertions(+), 244 deletions(-) create mode 100644 sys/kern/subr_suspend.c diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index 0502a18a2a8..77678779e9e 100644 --- a/sys/arch/amd64/amd64/acpi_machdep.c +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.94 2021/03/15 22:44:57 patrick Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.95 2022/02/08 17:25:10 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -39,7 +39,10 @@ #include #include +#include + #include "isa.h" +#include "wsdisplay.h" #include "ioapic.h" #include "lapic.h" @@ -53,6 +56,8 @@ #include #endif +#include + extern u_char acpi_real_mode_resume[], acpi_resume_end[]; extern u_char acpi_tramp_data_start[], acpi_tramp_data_end[]; extern u_int32_t acpi_pdirpa; @@ -372,7 +377,7 @@ acpi_attach_machdep(struct acpi_softc *sc) #ifndef SMALL_KERNEL void -acpi_sleep_clocks(struct acpi_softc *sc, int state) +sleep_clocks(void *v) { rtcstop(); @@ -499,7 +504,7 @@ acpi_resume_cpu(struct acpi_softc *sc, int state) #ifdef MULTIPROCESSOR void -acpi_sleep_mp(void) +sleep_mp(void) { int i; @@ -522,7 +527,7 @@ acpi_sleep_mp(void) } void -acpi_resume_mp(void) +resume_mp(void) { void cpu_start_secondary(struct cpu_info *ci); struct cpu_info *ci; @@ -567,6 +572,54 @@ acpi_resume_mp(void) } #endif /* MULTIPROCESSOR */ +void +display_suspend(void *v) +{ +#if NWSDISPLAY > 0 + struct acpi_softc *sc = v; + + /* + * Temporarily release the lock to prevent the X server from + * blocking on setting the display brightness. + */ + rw_exit_write(&sc->sc_lck); + wsdisplay_suspend(); + rw_enter_write(&sc->sc_lck); +#endif /* NWSDISPLAY > 0 */ +} + +void +display_resume(void *v) +{ +#if NWSDISPLAY > 0 + struct acpi_softc *sc = v; + + rw_exit_write(&sc->sc_lck); + wsdisplay_resume(); + rw_enter_write(&sc->sc_lck); +#endif /* NWSDISPLAY > 0 */ +} + +void +suspend_finish(void *v) +{ + struct acpi_softc *sc = v; + extern int lid_action; + + acpi_record_event(sc, APM_NORMAL_RESUME); + acpi_indicator(sc, ACPI_SST_WORKING); + + /* If we woke up but all the lids are closed, go back to sleep */ + if (acpibtn_numopenlids() == 0 && lid_action != 0) + acpi_addtask(sc, acpi_sleep_task, sc, sc->sc_state); +} + +void +disable_lid_wakeups(void *v) +{ + acpibtn_disable_psw(); /* disable _LID for wakeup */ +} + #endif /* ! SMALL_KERNEL */ bus_dma_tag_t diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index af15c7f3ebf..e3e424ca8c8 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.510 2022/01/04 05:50:43 gnezdo Exp $ +# $OpenBSD: GENERIC,v 1.511 2022/02/08 17:25:11 deraadt Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -19,7 +19,8 @@ option APERTURE # in-kernel aperture driver for XFree86 option MTRR # CPU memory range attributes control option NTFS # NTFS support -option HIBERNATE # Hibernate support +option SUSPEND +option HIBERNATE config bsd swap generic diff --git a/sys/arch/arm64/arm64/acpi_machdep.c b/sys/arch/arm64/arm64/acpi_machdep.c index 9fb20a2376e..cc92da17c2a 100644 --- a/sys/arch/arm64/arm64/acpi_machdep.c +++ b/sys/arch/arm64/arm64/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.16 2021/10/24 17:52:28 mpi Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.17 2022/02/08 17:25:11 deraadt Exp $ */ /* * Copyright (c) 2018 Mark Kettenis * @@ -191,7 +191,7 @@ acpi_intr_disestablish(void *cookie) } void -acpi_sleep_clocks(struct acpi_softc *sc, int state) +sleep_clocks(void *) { } diff --git a/sys/arch/i386/conf/GENERIC b/sys/arch/i386/conf/GENERIC index 80f1807fcb5..0ae9592ef01 100644 --- a/sys/arch/i386/conf/GENERIC +++ b/sys/arch/i386/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.860 2022/01/02 23:14:27 jsg Exp $ +# $OpenBSD: GENERIC,v 1.861 2022/02/08 17:25:11 deraadt Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -19,7 +19,8 @@ option APERTURE # in-kernel aperture driver for XFree86 option MTRR # CPU memory range attributes control option NTFS # NTFS support -option HIBERNATE # Hibernate support +option SUSPEND +option HIBERNATE config bsd swap generic diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c index 4f011d47cbe..34166834b9d 100644 --- a/sys/arch/i386/i386/acpi_machdep.c +++ b/sys/arch/i386/i386/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.76 2021/03/15 22:44:57 patrick Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.77 2022/02/08 17:25:11 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -42,10 +42,14 @@ #include #include #include +#include #include #include +#include + #include "apm.h" +#include "wsdisplay.h" #include "isa.h" #include "ioapic.h" #include "lapic.h" @@ -60,6 +64,8 @@ #include #endif +#include + #if NAPM > 0 int haveacpibutusingapm; #endif @@ -329,7 +335,7 @@ int save_lapic_tpr; #endif void -acpi_sleep_clocks(struct acpi_softc *sc, int state) +sleep_clocks(void *v) { rtcstop(); @@ -457,7 +463,7 @@ acpi_resume_cpu(struct acpi_softc *sc, int state) #ifdef MULTIPROCESSOR void -acpi_sleep_mp(void) +sleep_mp(void) { int i; @@ -480,7 +486,7 @@ acpi_sleep_mp(void) } void -acpi_resume_mp(void) +resume_mp(void) { struct cpu_info *ci; struct proc *p; @@ -519,6 +525,54 @@ acpi_resume_mp(void) } #endif /* MULTIPROCESSOR */ +void +display_suspend(void *v) +{ +#if NWSDISPLAY > 0 + struct acpi_softc *sc = v; + + /* + * Temporarily release the lock to prevent the X server from + * blocking on setting the display brightness. + */ + rw_exit_write(&sc->sc_lck); + wsdisplay_suspend(); + rw_enter_write(&sc->sc_lck); +#endif /* NWSDISPLAY > 0 */ +} + +void +display_resume(void *v) +{ +#if NWSDISPLAY > 0 + struct acpi_softc *sc = v; + + rw_exit_write(&sc->sc_lck); + wsdisplay_resume(); + rw_enter_write(&sc->sc_lck); +#endif /* NWSDISPLAY > 0 */ +} + +void +suspend_finish(void *v) +{ + struct acpi_softc *sc = v; + extern int lid_action; + + acpi_record_event(sc, APM_NORMAL_RESUME); + acpi_indicator(sc, ACPI_SST_WORKING); + + /* If we woke up but all the lids are closed, go back to sleep */ + if (acpibtn_numopenlids() == 0 && lid_action != 0) + acpi_addtask(sc, acpi_sleep_task, sc, sc->sc_state); +} + +void +disable_lid_wakeups(void *v) +{ + acpibtn_disable_psw(); /* disable _LID for wakeup */ +} + #endif /* ! SMALL_KERNEL */ bus_dma_tag_t diff --git a/sys/conf/files b/sys/conf/files index 8996d9b9179..86d464c6477 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -1,4 +1,4 @@ -# $OpenBSD: files,v 1.708 2022/01/09 13:26:08 visa Exp $ +# $OpenBSD: files,v 1.709 2022/02/08 17:25:11 deraadt Exp $ # $NetBSD: files,v 1.87 1996/05/19 17:17:50 jonathan Exp $ # @(#)files.newconf 7.5 (Berkeley) 5/10/93 @@ -724,6 +724,7 @@ file kern/subr_autoconf.c file kern/subr_disk.c file kern/subr_evcount.c file kern/subr_extent.c +file kern/subr_suspend.c suspend file kern/subr_hibernate.c hibernate file kern/subr_kubsan.c kubsan file kern/subr_log.c diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 57885205ae2..ebcd047d397 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.409 2022/02/04 08:06:48 robert Exp $ */ +/* $OpenBSD: acpi.c,v 1.410 2022/02/08 17:25:12 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * Copyright (c) 2005 Jordan Hargrave @@ -113,8 +113,6 @@ void acpi_enable_onegpe(struct acpi_softc *, int); int acpi_gpe(struct acpi_softc *, int, void *); void acpi_enable_rungpes(struct acpi_softc *); -void acpi_enable_wakegpes(struct acpi_softc *, int); - int acpi_foundec(struct aml_node *, void *); int acpi_foundsony(struct aml_node *node, void *arg); @@ -126,8 +124,6 @@ void acpi_create_thread(void *); #ifndef SMALL_KERNEL -void acpi_indicator(struct acpi_softc *, int); - void acpi_init_pm(struct acpi_softc *); int acpi_founddock(struct aml_node *, void *); @@ -1961,8 +1957,9 @@ acpi_sleep_task(void *arg0, int sleepmode) { struct acpi_softc *sc = arg0; - /* System goes to sleep here.. */ - acpi_sleep_state(sc, sleepmode); +#ifdef SUSPEND + sleep_state(sc, sleepmode); +#endif /* Tell userland to recheck A/C and battery status */ acpi_record_event(sc, APM_POWER_CHANGE); } @@ -2043,7 +2040,7 @@ acpi_pbtn_task(void *arg0, int dummy) break; #ifndef SMALL_KERNEL case 2: - acpi_addtask(sc, acpi_sleep_task, sc, ACPI_SLEEP_SUSPEND); + acpi_addtask(sc, acpi_sleep_task, sc, SLEEP_SUSPEND); break; #endif } @@ -2549,203 +2546,6 @@ acpi_indicator(struct acpi_softc *sc, int led_state) } } - -int -acpi_sleep_state(struct acpi_softc *sc, int sleepmode) -{ - extern int perflevel; - extern int lid_action; - int error = ENXIO; - size_t rndbuflen = 0; - char *rndbuf = NULL; - int state, s; -#if NSOFTRAID > 0 - extern void sr_quiesce(void); -#endif - - switch (sleepmode) { - case ACPI_SLEEP_SUSPEND: - state = ACPI_STATE_S3; - break; - case ACPI_SLEEP_HIBERNATE: - state = ACPI_STATE_S4; - break; - default: - return (EOPNOTSUPP); - } - - if (sc->sc_sleeptype[state].slp_typa == -1 || - sc->sc_sleeptype[state].slp_typb == -1) { - printf("%s: state S%d unavailable\n", - sc->sc_dev.dv_xname, state); - return (EOPNOTSUPP); - } - - /* 1st suspend AML step: _TTS(tostate) */ - if (aml_node_setval(sc, sc->sc_tts, state) != 0) - goto fail_tts; - acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ - -#if NWSDISPLAY > 0 - /* - * Temporarily release the lock to prevent the X server from - * blocking on setting the display brightness. - */ - rw_exit_write(&sc->sc_lck); - wsdisplay_suspend(); - rw_enter_write(&sc->sc_lck); -#endif /* NWSDISPLAY > 0 */ - - stop_periodic_resettodr(); - -#ifdef HIBERNATE - if (sleepmode == ACPI_SLEEP_HIBERNATE) { - /* - * Discard useless memory to reduce fragmentation, - * and attempt to create a hibernate work area - */ - hibernate_suspend_bufcache(); - uvmpd_hibernate(); - if (hibernate_alloc()) { - printf("%s: failed to allocate hibernate memory\n", - sc->sc_dev.dv_xname); - goto fail_alloc; - } - } -#endif /* HIBERNATE */ - - sensor_quiesce(); - if (config_suspend_all(DVACT_QUIESCE)) - goto fail_quiesce; - - vfs_stall(curproc, 1); -#if NSOFTRAID > 0 - sr_quiesce(); -#endif - bufq_quiesce(); - -#ifdef MULTIPROCESSOR - acpi_sleep_mp(); -#endif - -#ifdef HIBERNATE - if (sleepmode == ACPI_SLEEP_HIBERNATE) { - /* - * We've just done various forms of syncing to disk - * churned lots of memory dirty. We don't need to - * save that dirty memory to hibernate, so release it. - */ - hibernate_suspend_bufcache(); - uvmpd_hibernate(); - } -#endif /* HIBERNATE */ - - resettodr(); - - s = splhigh(); - intr_disable(); /* PSL_I for resume; PIC/APIC broken until repair */ - cold = 2; /* Force other code to delay() instead of tsleep() */ - - if (config_suspend_all(DVACT_SUSPEND) != 0) - goto fail_suspend; - acpi_sleep_clocks(sc, state); - - suspend_randomness(); - - /* 2nd suspend AML step: _PTS(tostate) */ - if (aml_node_setval(sc, sc->sc_pts, state) != 0) - goto fail_pts; - - acpibtn_enable_psw(); /* enable _LID for wakeup */ - acpi_indicator(sc, ACPI_SST_SLEEPING); - - /* 3rd suspend AML step: _GTS(tostate) */ - aml_node_setval(sc, sc->sc_gts, state); - - /* Clear fixed event status */ - acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_ALL_STS); - - /* Enable wake GPEs */ - acpi_disable_allgpes(sc); - acpi_enable_wakegpes(sc, state); - - /* Sleep */ - sc->sc_state = state; - error = acpi_sleep_cpu(sc, state); - sc->sc_state = ACPI_STATE_S0; - /* Resume */ - -#ifdef HIBERNATE - if (sleepmode == ACPI_SLEEP_HIBERNATE) { - uvm_pmr_dirty_everything(); - hib_getentropy(&rndbuf, &rndbuflen); - } -#endif /* HIBERNATE */ - - acpi_resume_cpu(sc, state); - -fail_pts: - config_suspend_all(DVACT_RESUME); - -fail_suspend: - cold = 0; - intr_enable(); - splx(s); - - acpibtn_disable_psw(); /* disable _LID for wakeup */ - - inittodr(gettime()); - - /* 3rd resume AML step: _TTS(runstate) */ - aml_node_setval(sc, sc->sc_tts, sc->sc_state); - - /* force RNG upper level reseed */ - resume_randomness(rndbuf, rndbuflen); - -#ifdef MULTIPROCESSOR - acpi_resume_mp(); -#endif - - vfs_stall(curproc, 0); - bufq_restart(); - -fail_quiesce: - config_suspend_all(DVACT_WAKEUP); - sensor_restart(); - -#ifdef HIBERNATE - if (sleepmode == ACPI_SLEEP_HIBERNATE) { - hibernate_free(); -fail_alloc: - hibernate_resume_bufcache(); - } -#endif /* HIBERNATE */ - - start_periodic_resettodr(); - -#if NWSDISPLAY > 0 - rw_exit_write(&sc->sc_lck); - wsdisplay_resume(); - rw_enter_write(&sc->sc_lck); -#endif /* NWSDISPLAY > 0 */ - - sys_sync(curproc, NULL, NULL); - - /* Restore hw.setperf */ - if (cpu_setperf != NULL) - cpu_setperf(perflevel); - - acpi_record_event(sc, APM_NORMAL_RESUME); - acpi_indicator(sc, ACPI_SST_WORKING); - - /* If we woke up but all the lids are closed, go back to sleep */ - if (acpibtn_numopenlids() == 0 && lid_action != 0) - acpi_addtask(sc, acpi_sleep_task, sc, sleepmode); - -fail_tts: - return (error); -} - /* XXX * We are going to do AML execution but are not in the acpi thread. * We do not know if the acpi thread is sleeping on acpiec in some @@ -3528,7 +3328,7 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) error = EBADF; break; } - acpi_addtask(sc, acpi_sleep_task, sc, ACPI_SLEEP_SUSPEND); + acpi_addtask(sc, acpi_sleep_task, sc, SLEEP_SUSPEND); acpi_wakeup(sc); break; #ifdef HIBERNATE @@ -3543,7 +3343,7 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) error = EOPNOTSUPP; break; } - acpi_addtask(sc, acpi_sleep_task, sc, ACPI_SLEEP_HIBERNATE); + acpi_addtask(sc, acpi_sleep_task, sc, SLEEP_HIBERNATE); acpi_wakeup(sc); break; #endif @@ -3718,6 +3518,86 @@ acpikqfilter(dev_t dev, struct knote *kn) return (0); } +int +sleep_showstate(void *v, int sleepmode) +{ + struct acpi_softc *sc = v; + + switch (sleepmode) { + case SLEEP_SUSPEND: + sc->sc_state = ACPI_STATE_S3; + break; + case SLEEP_HIBERNATE: + sc->sc_state = ACPI_STATE_S4; + break; + default: + return (EOPNOTSUPP); + } + + if (sc->sc_sleeptype[sc->sc_state].slp_typa == -1 || + sc->sc_sleeptype[sc->sc_state].slp_typb == -1) { + printf("%s: state S%d unavailable\n", + sc->sc_dev.dv_xname, sc->sc_state); + return (EOPNOTSUPP); + } + + /* 1st suspend AML step: _TTS(tostate) */ + if (aml_node_setval(sc, sc->sc_tts, sc->sc_state) != 0) + return (EINVAL); + acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ + return 0; +} + +int +sleep_setstate(void *v) +{ + struct acpi_softc *sc = v; + + /* 2nd suspend AML step: _PTS(tostate) */ + if (aml_node_setval(sc, sc->sc_pts, sc->sc_state) != 0) + return (EINVAL); + acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ + return 0; +} + +void +gosleep(void *v) +{ + struct acpi_softc *sc = v; + + acpibtn_enable_psw(); /* enable _LID for wakeup */ + acpi_indicator(v, ACPI_SST_SLEEPING); + + /* 3rd suspend AML step: _GTS(tostate) */ + aml_node_setval(sc, sc->sc_gts, sc->sc_state); + + /* Clear fixed event status */ + acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_ALL_STS); + + /* Enable wake GPEs */ + acpi_disable_allgpes(sc); + acpi_enable_wakegpes(sc, sc->sc_state); + + /* Sleep */ + acpi_sleep_cpu(sc, sc->sc_state); + sc->sc_state = ACPI_STATE_S0; + /* Resume */ + + acpi_resume_cpu(sc, sc->sc_state); +} + +int +sleep_resume(void *v) +{ + struct acpi_softc *sc = v; + + /* 3rd resume AML step: _TTS(runstate) */ + if (aml_node_setval(sc, sc->sc_tts, sc->sc_state) != 0) + return (EINVAL); + acpi_indicator(sc, ACPI_SST_WAKING); /* blink */ + return 0; +} + #else /* SMALL_KERNEL */ int diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index da3b59ef084..1728f1c5fd3 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibtn.c,v 1.47 2019/01/20 02:45:44 tedu Exp $ */ +/* $OpenBSD: acpibtn.c,v 1.48 2022/02/08 17:25:12 deraadt Exp $ */ /* * Copyright (c) 2005 Marco Peereboom * @@ -245,7 +245,7 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) /* Request to go to sleep */ if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_HIBERNATE); + sc->sc_acpi, SLEEP_HIBERNATE); break; #endif default: @@ -264,7 +264,7 @@ sleep: /* Request to go to sleep */ if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_SUSPEND); + sc->sc_acpi, SLEEP_SUSPEND); break; } #endif /* SMALL_KERNEL */ diff --git a/sys/dev/acpi/acpisony.c b/sys/dev/acpi/acpisony.c index 4faf3ae8f1d..5ddda1dab44 100644 --- a/sys/dev/acpi/acpisony.c +++ b/sys/dev/acpi/acpisony.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpisony.c,v 1.8 2020/04/06 00:01:08 pirofti Exp $ */ +/* $OpenBSD: acpisony.c,v 1.9 2022/02/08 17:25:12 deraadt Exp $ */ /* * Copyright (c) 2010 Paul Irofti * @@ -198,7 +198,7 @@ acpisony_notify(struct aml_node *node, int notify, void *arg) #ifndef SMALL_KERNEL if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_SUSPEND); + sc->sc_acpi, SLEEP_SUSPEND); #endif break; case SONY_NOTIFY_SUSPEND_RELEASED: diff --git a/sys/dev/acpi/acpithinkpad.c b/sys/dev/acpi/acpithinkpad.c index 9c311dac5bf..8d4379234f7 100644 --- a/sys/dev/acpi/acpithinkpad.c +++ b/sys/dev/acpi/acpithinkpad.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpithinkpad.c,v 1.68 2019/12/31 01:38:33 jsg Exp $ */ +/* $OpenBSD: acpithinkpad.c,v 1.69 2022/02/08 17:25:12 deraadt Exp $ */ /* * Copyright (c) 2008 joshua stein * @@ -421,7 +421,7 @@ thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) #ifndef SMALL_KERNEL if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_SUSPEND); + sc->sc_acpi, SLEEP_SUSPEND); #endif break; case THINKPAD_BUTTON_VOLUME_MUTE: @@ -442,7 +442,7 @@ thinkpad_hotkey(struct aml_node *node, int notify_type, void *arg) #if defined(HIBERNATE) && !defined(SMALL_KERNEL) if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_HIBERNATE); + sc->sc_acpi, SLEEP_HIBERNATE); #endif break; case THINKPAD_BUTTON_THINKLIGHT: diff --git a/sys/dev/acpi/acpitoshiba.c b/sys/dev/acpi/acpitoshiba.c index 4ee4b085530..bdf643b9a54 100644 --- a/sys/dev/acpi/acpitoshiba.c +++ b/sys/dev/acpi/acpitoshiba.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpitoshiba.c,v 1.13 2020/03/16 08:51:48 jasper Exp $ */ +/* $OpenBSD: acpitoshiba.c,v 1.14 2022/02/08 17:25:12 deraadt Exp $ */ /*- * Copyright (c) 2003 Hiroyuki Aizu * All rights reserved. @@ -397,7 +397,7 @@ toshiba_hotkey(struct aml_node *node, int notify, void *arg) #ifndef SMALL_KERNEL if (acpi_record_event(sc->sc_acpi, APM_USER_SUSPEND_REQ)) { acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_SUSPEND); + sc->sc_acpi, SLEEP_SUSPEND); ret = HCI_SUCCESS; } #endif @@ -406,7 +406,7 @@ toshiba_hotkey(struct aml_node *node, int notify, void *arg) #if defined(HIBERNATE) && !defined(SMALL_KERNEL) if (acpi_record_event(sc->sc_acpi, APM_USER_HIBERNATE_REQ)) { acpi_addtask(sc->sc_acpi, acpi_sleep_task, - sc->sc_acpi, ACPI_SLEEP_HIBERNATE); + sc->sc_acpi, SLEEP_HIBERNATE); ret = HCI_SUCCESS; } #endif diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index 9058193e4b4..52b7526018c 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.117 2022/02/01 18:09:00 deraadt Exp $ */ +/* $OpenBSD: acpivar.h,v 1.118 2022/02/08 17:25:12 deraadt Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -334,21 +334,12 @@ int acpi_interrupt(void *); void acpi_powerdown(void); void acpi_reset(void); - -#define ACPI_SLEEP_SUSPEND 0x01 -#define ACPI_SLEEP_HIBERNATE 0x02 - -int acpi_sleep_state(struct acpi_softc *, int); -void acpi_sleep_clocks(struct acpi_softc *, int); int acpi_sleep_cpu(struct acpi_softc *, int); -void acpi_sleep_mp(void); void acpi_sleep_pm(struct acpi_softc *, int); void acpi_resume_pm(struct acpi_softc *, int); void acpi_resume_cpu(struct acpi_softc *, int); -void acpi_resume_mp(void); void acpi_sleep_walk(struct acpi_softc *, int); - #define ACPI_IOREAD 0 #define ACPI_IOWRITE 1 @@ -387,6 +378,10 @@ int64_t acpi_getsta(struct acpi_softc *sc, struct aml_node *); int acpi_getprop(struct aml_node *, const char *, void *, int); uint64_t acpi_getpropint(struct aml_node *, const char *, uint64_t); +void acpi_indicator(struct acpi_softc *, int); +void acpi_disable_allgpes(struct acpi_softc *); +void acpi_enable_wakegpes(struct acpi_softc *, int); + int acpi_record_event(struct acpi_softc *, u_int); void acpi_addtask(struct acpi_softc *, void (*)(void *, int), void *, int); diff --git a/sys/kern/subr_suspend.c b/sys/kern/subr_suspend.c new file mode 100644 index 00000000000..f92ee7d399c --- /dev/null +++ b/sys/kern/subr_suspend.c @@ -0,0 +1,170 @@ +/* $OpenBSD: subr_suspend.c,v 1.1 2022/02/08 17:25:12 deraadt Exp $ */ +/* + * Copyright (c) 2005 Thorsten Lockert + * Copyright (c) 2005 Jordan Hargrave + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HIBERNATE +#include +#endif + +#include "softraid.h" + +int +sleep_state(void *v, int sleepmode) +{ + int error = ENXIO; + extern int perflevel; + size_t rndbuflen = 0; + char *rndbuf = NULL; + int s; +#if NSOFTRAID > 0 + extern void sr_quiesce(void); +#endif + + if (sleep_showstate(v, sleepmode)) + return EOPNOTSUPP; + + display_suspend(v); + + stop_periodic_resettodr(); + +#ifdef HIBERNATE + if (sleepmode == SLEEP_HIBERNATE) { + /* + * Discard useless memory to reduce fragmentation, + * and attempt to create a hibernate work area + */ + hibernate_suspend_bufcache(); + uvmpd_hibernate(); + if (hibernate_alloc()) { + printf("failed to allocate hibernate memory\n"); + goto fail_alloc; + } + } +#endif /* HIBERNATE */ + + sensor_quiesce(); + if (config_suspend_all(DVACT_QUIESCE)) + goto fail_quiesce; + + vfs_stall(curproc, 1); +#if NSOFTRAID > 0 + sr_quiesce(); +#endif + bufq_quiesce(); + + +#ifdef MULTIPROCESSOR + sleep_mp(); +#endif + +#ifdef HIBERNATE + if (sleepmode == SLEEP_HIBERNATE) { + /* + * We've just done various forms of syncing to disk + * churned lots of memory dirty. We don't need to + * save that dirty memory to hibernate, so release it. + */ + hibernate_suspend_bufcache(); + uvmpd_hibernate(); + } +#endif /* HIBERNATE */ + + resettodr(); + + s = splhigh(); + intr_disable(); /* PSL_I for resume; PIC/APIC broken until repair */ + cold = 2; /* Force other code to delay() instead of tsleep() */ + + if (config_suspend_all(DVACT_SUSPEND) != 0) + goto fail_suspend; + sleep_clocks(v); + + suspend_randomness(); + + if (sleep_setstate(v)) + goto fail_pts; + + gosleep(v); + +#ifdef HIBERNATE + if (sleepmode == SLEEP_HIBERNATE) { + uvm_pmr_dirty_everything(); + hib_getentropy(&rndbuf, &rndbuflen); + } +#endif /* HIBERNATE */ + +fail_pts: + config_suspend_all(DVACT_RESUME); + +fail_suspend: + cold = 0; + intr_enable(); + splx(s); + + disable_lid_wakeups(v); + + inittodr(gettime()); + + sleep_resume(v); + + /* force RNG upper level reseed */ + resume_randomness(rndbuf, rndbuflen); + +#ifdef MULTIPROCESSOR + resume_mp(); +#endif + + vfs_stall(curproc, 0); + bufq_restart(); + +fail_quiesce: + config_suspend_all(DVACT_WAKEUP); + sensor_restart(); + +#ifdef HIBERNATE + if (sleepmode == SLEEP_HIBERNATE) { + hibernate_free(); +fail_alloc: + hibernate_resume_bufcache(); + } +#endif /* HIBERNATE */ + + start_periodic_resettodr(); + + display_resume(v); + + sys_sync(curproc, NULL, NULL); + + /* Restore hw.setperf */ + if (cpu_setperf != NULL) + cpu_setperf(perflevel); + + suspend_finish(v); + + return (error); +} diff --git a/sys/sys/device.h b/sys/sys/device.h index ec6c2649585..ec5e2b9e6b1 100644 --- a/sys/sys/device.h +++ b/sys/sys/device.h @@ -1,4 +1,4 @@ -/* $OpenBSD: device.h,v 1.56 2021/10/26 16:29:49 deraadt Exp $ */ +/* $OpenBSD: device.h,v 1.57 2022/02/08 17:25:12 deraadt Exp $ */ /* $NetBSD: device.h,v 1.15 1996/04/09 20:55:24 cgd Exp $ */ /* @@ -199,6 +199,21 @@ void config_pending_decr(void); void config_mountroot(struct device *, void (*)(struct device *)); void config_process_deferred_mountroot(void); +int sleep_state(void *, int); +#define SLEEP_SUSPEND 0x01 +#define SLEEP_HIBERNATE 0x02 +void sleep_clocks(void *); +void sleep_mp(void); +void resume_mp(void); +int sleep_showstate(void *v, int sleepmode); +int sleep_setstate(void *v); +int sleep_resume(void *v); +void gosleep(void *v); +void display_suspend(void *v); +void display_resume(void *v); +void suspend_finish(void *v); +void disable_lid_wakeups(void *v); + struct device *device_mainbus(void); struct device *device_mpath(void); struct device *device_lookup(struct cfdriver *, int unit); -- 2.20.1