diff options
author | Marco Peereboom <marco@cvs.openbsd.org> | 2009-02-19 21:02:06 +0000 |
---|---|---|
committer | Marco Peereboom <marco@cvs.openbsd.org> | 2009-02-19 21:02:06 +0000 |
commit | 748c385494ee5d641b7e648df28568538e41467c (patch) | |
tree | 9b3648d5d080c29915d0f71b7a8d9c490046223d | |
parent | 6fb68817a3957ab44390ea949e41e4b949d653a7 (diff) |
suspend/resume bits so that we can develop this in tree. This is disabled.
code from mlarkin and me
help from art,toby,jordan and several others
ok jordan, go for it deraadt
-rw-r--r-- | sys/arch/amd64/amd64/acpi_machdep.c | 71 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/acpi_wakecode.S | 26 | ||||
-rw-r--r-- | sys/arch/i386/i386/acpi_machdep.c | 78 | ||||
-rw-r--r-- | sys/arch/i386/i386/acpi_wakecode.S | 19 | ||||
-rw-r--r-- | sys/dev/acpi/acpi.c | 214 | ||||
-rw-r--r-- | sys/dev/acpi/acpibtn.c | 5 | ||||
-rw-r--r-- | sys/dev/acpi/acpireg.h | 11 | ||||
-rw-r--r-- | sys/dev/acpi/acpivar.h | 12 |
8 files changed, 338 insertions, 98 deletions
diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index 24cdfc7b58b..f6a5f98e30f 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.15 2009/02/15 02:03:40 marco Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.16 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -30,6 +30,7 @@ #include <dev/isa/isareg.h> #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> #include "ioapic.h" @@ -171,4 +172,72 @@ acpi_attach_machdep(struct acpi_softc *sc) #endif /* ACPI_SLEEP_ENABLED */ } + +void +acpi_cpu_flush(struct acpi_softc *sc, int state) +{ + /* + * Flush write back caches since we'll lose them. + */ + if (state > ACPI_STATE_S1) + wbinvd(); +} +int +acpi_sleep_machdep(struct acpi_softc *sc, int state) +{ +#ifdef ACPI_SLEEP_ENABLED + + if (sc->sc_facs == NULL) { + printf("%s: acpi_sleep_machdep: no FACS\n", DEVNAME(sc)); + return (ENXIO); + } + + if (rcr3() != pmap_kernel()->pm_pdirpa) { + printf("%s: acpi_sleep_machdep: only kernel may sleep\n", + DEVNAME(sc)); + return (ENXIO); + } + + /* + * + * ACPI defines two wakeup vectors. One is used for ACPI 1.0 + * implementations - it's in the FACS table as wakeup_vector and + * indicates a 32-bit physical address containing real-mode wakeup + * code. + * + * The second wakeup vector is in the FACS table as + * x_wakeup_vector and indicates a 64-bit physical address + * containing protected-mode wakeup code. + * + */ + + sc->sc_facs->wakeup_vector = (u_int32_t)ACPI_TRAMPOLINE; + if (sc->sc_facs->version == 1) + sc->sc_facs->x_wakeup_vector = 0; + + disable_intr(); + + /* Copy the current cpu registers into a safe place for resume. */ + if (acpi_savecpu()) { + wbinvd(); + acpi_enter_sleep_state(sc, state); + panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc)); + } + + /* + * On resume, the execution path will actually occur here. + * This is because we previously saved the stack location + * in acpi_savecpu, and issued a far jmp to the restore + * routine in the wakeup code. This means we are + * returning to the location immediately following the + * last call instruction - after the call to acpi_savecpu. + */ + + initrtclock(); + enable_intr(); +#endif /* ACPI_SLEEP_ENABLED */ + return 0; + } + + #endif /* ! SMALL_KERNEL */ diff --git a/sys/arch/amd64/amd64/acpi_wakecode.S b/sys/arch/amd64/amd64/acpi_wakecode.S index 777a9a13809..7da9a0a4b8a 100644 --- a/sys/arch/amd64/amd64/acpi_wakecode.S +++ b/sys/arch/amd64/amd64/acpi_wakecode.S @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_wakecode.S,v 1.2 2009/02/15 02:06:09 marco Exp $ */ +/* $OpenBSD: acpi_wakecode.S,v 1.3 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> @@ -128,6 +128,7 @@ _C_LABEL(acpi_real_mode_resume): * laptops), we might not restore the proper VGA mode * on resume. Caveat emptor. */ + jmp nobiosreset /* XXX make this a tunable */ lcall $0xc000,$3 /* @@ -137,6 +138,7 @@ _C_LABEL(acpi_real_mode_resume): movw %cs,%ax movw %ax,%ds movw %ax,%ss +nobiosreset: /* * Set up esi to point to start of current routine's CS. @@ -152,7 +154,6 @@ _C_LABEL(acpi_real_mode_resume): 1: jmp 1f 1: - /* * We're about to enter protected mode, so we need a GDT for that. * Set up a temporary GDT describing 2 segments, one for code @@ -180,11 +181,10 @@ _C_LABEL(acpi_real_mode_resume): */ ljmpl $0x8, $acpi_protected_mode_trampoline -_ACPI_TRMP_LABEL(acpi_protected_mode_trampoline) -_C_LABEL(acpi_protected_mode_resume): .code32 .align 16 - +_ACPI_TRMP_LABEL(acpi_protected_mode_trampoline) +_C_LABEL(acpi_protected_mode_resume): nop /* @@ -257,13 +257,10 @@ _C_LABEL(acpi_protected_mode_resume): /* Enter long mode by making another intersegment jump */ ljmp $0x8, $acpi_long_mode_trampoline -_ACPI_TRMP_LABEL(acpi_long_mode_trampoline) -_C_LABEL(acpi_long_mode_resume): .code64 .align 16 - - - +_ACPI_TRMP_LABEL(acpi_long_mode_trampoline) +_C_LABEL(acpi_long_mode_resume): /* Restore the stashed copy of EFER we set aside earlier */ movl %ebx, %eax movl $MSR_EFER, %ecx @@ -353,8 +350,6 @@ _C_LABEL(acpi_long_mode_resume): xorq %rax, %rax jmp *acpi_saved_ret - - .align 8 _ACPI_TRMP_OFFSET(tmp_gdt) .word tmp_gdt_end - tmp_gdtable @@ -398,7 +393,6 @@ _ACPI_TRMP_LABEL(tmp_gdtable) */ .word 0xffff, 0 .byte 0, 0x93, 0xcf, 0 - _ACPI_TRMP_LABEL(tmp_gdt_end) .align 8 @@ -411,7 +405,6 @@ _ACPI_TRMP_LABEL(tmp_gdtable64) .quad 0x0000000000000000 .quad 0x00af9a000000ffff .quad 0x00cf92000000ffff - _ACPI_TRMP_LABEL(tmp_gdt64_end) .align 8 @@ -447,7 +440,6 @@ _ACPI_TRMP_LABEL(acpi_saved_r14) .quad 0 _ACPI_TRMP_LABEL(acpi_saved_r15) .quad 0 - _ACPI_TRMP_LABEL(acpi_saved_fl) .quad 0 _ACPI_TRMP_LABEL(acpi_saved_cr0) @@ -460,7 +452,6 @@ _ACPI_TRMP_LABEL(acpi_saved_cr4) .quad 0 _ACPI_TRMP_LABEL(acpi_saved_cr8) .quad 0 - _ACPI_TRMP_LABEL(acpi_saved_ret) .quad 0 @@ -563,7 +554,6 @@ NENTRY(acpi_savecpu) popq %rdx popq %rcx - sgdt acpi_saved_gdt sidt acpi_saved_idt sldt acpi_saved_ldt @@ -571,7 +561,5 @@ NENTRY(acpi_savecpu) movl $1, %eax ret - - #endif /* SMALL_KERNEL */ #endif /* NACPI > 0 */ diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c index 8f5f7b36b87..bac6d1f8757 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.16 2009/01/20 20:21:03 mlarkin Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.17 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -34,6 +34,7 @@ #include <dev/isa/isareg.h> #include <dev/acpi/acpireg.h> #include <dev/acpi/acpivar.h> +#include <dev/acpi/acpidev.h> #include "apm.h" @@ -44,6 +45,8 @@ int haveacpibutusingapm; extern u_char acpi_real_mode_resume[], acpi_resume_end[]; int acpi_savecpu(void); +void intr_calculatemasks(void); +void acpi_cpu_flush(struct acpi_softc *, int); #define ACPI_BIOS_RSDP_WINDOW_BASE 0xe0000 #define ACPI_BIOS_RSDP_WINDOW_SIZE 0x20000 @@ -174,15 +177,84 @@ acpi_attach_machdep(struct acpi_softc *sc) cpuresetfn = acpi_reset; #ifdef ACPI_SLEEP_ENABLED - /* * Sanity check before setting up trampoline. * Ensure the trampoline size is < PAGE_SIZE */ KASSERT(acpi_resume_end - acpi_real_mode_resume < PAGE_SIZE); - bcopy(acpi_real_mode_resume, (caddr_t)ACPI_TRAMPOLINE, acpi_resume_end - acpi_real_mode_resume); #endif /* ACPI_SLEEP_ENABLED */ +} + +void +acpi_cpu_flush(struct acpi_softc *sc, int state) +{ + /* flush write back caches since we'll lose them */ + if (state > ACPI_STATE_S1) + wbinvd(); +} + +int +acpi_sleep_machdep(struct acpi_softc *sc, int state) +{ +#ifdef ACPI_SLEEP_ENABLED + u_long ef; + + if (sc->sc_facs == NULL) { + printf("%s: acpi_sleep_machdep: no FACS\n", DEVNAME(sc)); + return (ENXIO); + } + + if (rcr3() != pmap_kernel()->pm_pdirpa) { + printf("%s: acpi_sleep_machdep: only kernel may sleep\n", + DEVNAME(sc)); + return (ENXIO); + } + + /* + * + * ACPI defines two wakeup vectors. One is used for ACPI 1.0 + * implementations - it's in the FACS table as wakeup_vector and + * indicates a 32-bit physical address containing real-mode wakeup + * code. + * + * The second wakeup vector is in the FACS table as + * x_wakeup_vector and indicates a 64-bit physical address + * containing protected-mode wakeup code. + * + */ + sc->sc_facs->wakeup_vector = (u_int32_t)ACPI_TRAMPOLINE; + if (sc->sc_facs->version == 1) + sc->sc_facs->x_wakeup_vector = 0; + + ef = read_eflags(); + + /* Copy the current cpu registers into a safe place for resume. */ + if (acpi_savecpu()) { + wbinvd(); + acpi_enter_sleep_state(sc, state); + panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc)); + } + /* + * On resume, the execution path will actually occur here. + * This is because we previously saved the stack location + * in acpi_savecpu, and issued a far jmp to the restore + * routine in the wakeup code. This means we are + * returning to the location immediately following the + * last call instruction - after the call to acpi_savecpu. + */ + + npxinit(&cpu_info_primary); + isa_defaultirq(); + intr_calculatemasks(); +#if NIOAPIC > 0 + ioapic_enable(); +#endif + initrtclock(); + enable_intr(); + write_eflags(ef); +#endif /* ACPI_SLEEP_ENABLED */ + return (0); } #endif /* ! SMALL_KERNEL */ diff --git a/sys/arch/i386/i386/acpi_wakecode.S b/sys/arch/i386/i386/acpi_wakecode.S index daedfdf7a07..5ec361465b7 100644 --- a/sys/arch/i386/i386/acpi_wakecode.S +++ b/sys/arch/i386/i386/acpi_wakecode.S @@ -90,7 +90,7 @@ _C_LABEL(acpi_real_mode_resume): /* * Set up segment registers for real mode. * We'll only be in real mode for a moment, and we don't have - * ant real dependencies on data or stack, so we'll just use + * want real dependencies on data or stack, so we'll just use * the code segment for data and stack (eg, a 64k memory space). */ movw %cs,%ax @@ -124,6 +124,7 @@ _C_LABEL(acpi_real_mode_resume): * laptops), we might not restore the proper VGA mode * on resume. Caveat emptor. */ + jmp nobiosreset /* XXX make this a tunable */ lcall $0xc000,$3 /* @@ -133,6 +134,7 @@ _C_LABEL(acpi_real_mode_resume): movw %cs,%ax movw %ax,%ds movw %ax,%ss +nobiosreset: /* * Set up esi to point to start of current routine's CS. @@ -148,7 +150,6 @@ _C_LABEL(acpi_real_mode_resume): 1: jmp 1f 1: - /* * We're about to enter protected mode, so we need a GDT for that. * Set up a temporary GDT describing 2 segments, one for code @@ -176,11 +177,10 @@ _C_LABEL(acpi_real_mode_resume): */ ljmpl $0x8, $acpi_protected_mode_trampoline -_ACPI_TRMP_LABEL(acpi_protected_mode_trampoline) -_C_LABEL(acpi_protected_mode_resume): .code32 .align 16 - +_ACPI_TRMP_LABEL(acpi_protected_mode_trampoline) +_C_LABEL(acpi_protected_mode_resume): nop /* @@ -322,9 +322,7 @@ _C_LABEL(acpi_protected_mode_resume): * before we went to sleep. */ xorl %eax, %eax - jmp *acpi_saved_ret - - + jmp *acpi_saved_ret .align 8 _ACPI_TRMP_OFFSET(tmp_gdt) @@ -369,7 +367,6 @@ _ACPI_TRMP_LABEL(tmp_gdtable) */ .word 0xffff, 0 .byte 0, 0x93, 0xcf, 0 - _ACPI_TRMP_LABEL(tmp_gdt_end) .align 4 @@ -387,7 +384,6 @@ _ACPI_TRMP_LABEL(acpi_saved_edi) .long 0 _ACPI_TRMP_LABEL(acpi_saved_esp) .long 0 - _ACPI_TRMP_LABEL(acpi_saved_fl) .long 0 _ACPI_TRMP_LABEL(acpi_saved_cr0) @@ -398,7 +394,6 @@ _ACPI_TRMP_LABEL(acpi_saved_cr3) .long 0 _ACPI_TRMP_LABEL(acpi_saved_cr4) .long 0 - _ACPI_TRMP_LABEL(acpi_saved_ret) .long 0 @@ -476,7 +471,5 @@ NENTRY(acpi_savecpu) movl $1, %eax ret - - #endif /* SMALL_KERNEL */ #endif /* NACPI > 0 */ diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index 42aab210cab..b34d35e1a18 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.129 2009/02/10 02:13:19 jordan Exp $ */ +/* $OpenBSD: acpi.c,v 1.130 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org> @@ -26,6 +26,7 @@ #include <sys/signalvar.h> #include <sys/proc.h> #include <sys/kthread.h> +#include <sys/workq.h> #include <machine/conf.h> #include <machine/cpufunc.h> @@ -81,6 +82,10 @@ void acpi_init_states(struct acpi_softc *); void acpi_init_gpes(struct acpi_softc *); void acpi_init_pm(struct acpi_softc *); +#ifdef ACPI_SLEEP_ENABLED +void acpi_sleep_walk(struct acpi_softc *, int); +#endif /* ACPI_SLEEP_ENABLED */ + #ifndef SMALL_KERNEL int acpi_add_device(struct aml_node *node, void *arg); #endif /* SMALL_KERNEL */ @@ -841,6 +846,13 @@ acpiioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) ACPI_LOCK(sc); /* fake APM */ switch (cmd) { +#ifdef ACPI_SLEEP_ENABLED + case APM_IOC_SUSPEND: + case APM_IOC_STANDBY: + workq_add_task(NULL, 0, (workq_fn)acpi_sleep_state, + acpi_softc, (void *)ACPI_STATE_S3); + break; +#endif /* ACPI_SLEEP_ENABLED */ case APM_IOC_GETPOWER: /* A/C */ pi->ac_state = APM_AC_UNKNOWN; @@ -1651,65 +1663,78 @@ acpi_init_pm(struct acpi_softc *sc) sc->sc_gts = aml_searchname(&aml_root, "_GTS"); } +#ifndef SMALL_KERNEL void -acpi_enter_sleep_state(struct acpi_softc *sc, int state) +acpi_sleep_walk(struct acpi_softc *sc, int state) { - struct aml_value env; - u_int16_t rega, regb; - int retries; + struct acpi_wakeq *wentry; + int idx; - if (sc == NULL || state == ACPI_STATE_S0) - return; - 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; + /* Clear GPE status */ + for (idx = 0; idx < sc->sc_lastgpe; idx += 8) { + acpi_write_pmreg(sc, ACPIREG_GPE_EN, idx>>3, 0); + acpi_write_pmreg(sc, ACPIREG_GPE_STS, idx>>3, -1); } - memset(&env, 0, sizeof(env)); - env.type = AML_OBJTYPE_INTEGER; - env.v_integer = state; - /* _TTS(state) */ - if (sc->sc_tts) { - if (aml_evalnode(sc, sc->sc_tts, 1, &env, NULL) != 0) { - dnprintf(10, "%s evaluating method _TTS failed.\n", - DEVNAME(sc)); - return; - } + SIMPLEQ_FOREACH(wentry, &sc->sc_wakedevs, q_next) { + dnprintf(10, "%.4s(S%d) gpe %.2x\n", wentry->q_node->name, + wentry->q_state, + wentry->q_gpe); + + if (state <= wentry->q_state) + acpi_enable_onegpe(sc, wentry->q_gpe, 1); } +} +#endif /* ! SMALL_KERNEL */ + +int +acpi_sleep_state(struct acpi_softc *sc, int state) +{ + int ret; + switch (state) { + case ACPI_STATE_S0: + return (0); + case ACPI_STATE_S4: + return (EOPNOTSUPP); + case ACPI_STATE_S5: + break; case ACPI_STATE_S1: case ACPI_STATE_S2: - resettodr(); - dopowerhooks(PWR_SUSPEND); - break; case ACPI_STATE_S3: - resettodr(); - dopowerhooks(PWR_STANDBY); - break; - } - /* _PTS(state) */ - if (sc->sc_pts) { - if (aml_evalnode(sc, sc->sc_pts, 1, &env, NULL) != 0) { - dnprintf(10, "%s evaluating method _PTS failed.\n", - DEVNAME(sc)); - return; - } - } - sc->sc_state = state; - /* _GTS(state) */ - if (sc->sc_gts) { - if (aml_evalnode(sc, sc->sc_gts, 1, &env, NULL) != 0) { - dnprintf(10, "%s evaluating method _GTS failed.\n", - DEVNAME(sc)); - return; - } + if (sc->sc_sleeptype[state].slp_typa == -1 || + sc->sc_sleeptype[state].slp_typb == -1) + return (EOPNOTSUPP); } - disable_intr(); + + acpi_sleep_walk(sc, state); + + if ((ret = acpi_prepare_sleep_state(sc, state)) != 0) + return (ret); + + if (state != ACPI_STATE_S1) + ret = acpi_sleep_machdep(sc, state); + else + ret = acpi_enter_sleep_state(sc, state); + +#ifndef SMALL_KERNEL + acpi_resume(sc); + Debugger(); +#endif /* ! SMALL_KERNEL */ + return (ret); +} + +int +acpi_enter_sleep_state(struct acpi_softc *sc, int state) +{ + uint16_t rega, regb; + int retries; /* Clear WAK_STS bit */ - acpi_write_pmreg(sc, ACPIREG_PM1_STS, 0, ACPI_PM1_WAK_STS); + acpi_write_pmreg(sc, ACPIREG_PM1_STS, 1, ACPI_PM1_WAK_STS); + + /* Disable BM arbitration */ + acpi_write_pmreg(sc, ACPIREG_PM2_CNT, 1, ACPI_PM2_ARB_DIS); /* Write SLP_TYPx values */ rega = acpi_read_pmreg(sc, ACPIREG_PM1A_CNT, 0); @@ -1724,9 +1749,15 @@ acpi_enter_sleep_state(struct acpi_softc *sc, int state) /* Set SLP_EN bit */ rega |= ACPI_PM1_SLP_EN; regb |= ACPI_PM1_SLP_EN; + + /* + * Let the machdep code flush caches and do any other necessary + * tasks before going away. + */ + acpi_cpu_flush(sc, state); + acpi_write_pmreg(sc, ACPIREG_PM1A_CNT, 0, rega); acpi_write_pmreg(sc, ACPIREG_PM1B_CNT, 0, regb); - /* Loop on WAK_STS */ for (retries = 1000; retries > 0; retries--) { rega = acpi_read_pmreg(sc, ACPIREG_PM1A_STS, 0); @@ -1737,10 +1768,10 @@ acpi_enter_sleep_state(struct acpi_softc *sc, int state) DELAY(10); } - enable_intr(); + return (-1); } -#if 0 +#ifndef SMALL_KERNEL void acpi_resume(struct acpi_softc *sc) { @@ -1750,20 +1781,21 @@ acpi_resume(struct acpi_softc *sc) env.type = AML_OBJTYPE_INTEGER; env.v_integer = sc->sc_state; - if (sc->sc_bfs) { + if (sc->sc_bfs) if (aml_evalnode(sc, sc->sc_pts, 1, &env, NULL) != 0) { dnprintf(10, "%s evaluating method _BFS failed.\n", DEVNAME(sc)); } - } + dopowerhooks(PWR_RESUME); inittodr(0); - if (sc->sc_wak) { + + if (sc->sc_wak) if (aml_evalnode(sc, sc->sc_wak, 1, &env, NULL) != 0) { dnprintf(10, "%s evaluating method _WAK failed.\n", DEVNAME(sc)); } - } + sc->sc_state = ACPI_STATE_S0; if (sc->sc_tts) { env.v_integer = sc->sc_state; @@ -1773,14 +1805,84 @@ acpi_resume(struct acpi_softc *sc) } } } -#endif +#endif /* ! SMALL_KERNEL */ + +int +acpi_prepare_sleep_state(struct acpi_softc *sc, int state) +{ + struct aml_value env; + + if (sc == NULL || state == ACPI_STATE_S0) + return(0); + + 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 (ENXIO); + } + + memset(&env, 0, sizeof(env)); + env.type = AML_OBJTYPE_INTEGER; + env.v_integer = state; + /* _TTS(state) */ + if (sc->sc_tts) + if (aml_evalnode(sc, sc->sc_tts, 1, &env, NULL) != 0) { + dnprintf(10, "%s evaluating method _TTS failed.\n", + DEVNAME(sc)); + return (ENXIO); + } + + switch (state) { + case ACPI_STATE_S1: + case ACPI_STATE_S2: + resettodr(); + dopowerhooks(PWR_SUSPEND); + break; + case ACPI_STATE_S3: + resettodr(); + dopowerhooks(PWR_STANDBY); + break; + } + + /* _PTS(state) */ + if (sc->sc_pts) + if (aml_evalnode(sc, sc->sc_pts, 1, &env, NULL) != 0) { + dnprintf(10, "%s evaluating method _PTS failed.\n", + DEVNAME(sc)); + return (ENXIO); + } + + sc->sc_state = state; + /* _GTS(state) */ + if (sc->sc_gts) + if (aml_evalnode(sc, sc->sc_gts, 1, &env, NULL) != 0) { + dnprintf(10, "%s evaluating method _GTS failed.\n", + DEVNAME(sc)); + return (ENXIO); + } + + disable_intr(); + aml_evalname(sc, &aml_root, "\\_SST", 1, &env, NULL); + sc->sc_state = state; + + return (0); +} + + void acpi_powerdown(void) { - acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); + /* + * In case acpi_prepare_sleep fails, we shouldn't try to enter + * the sleep state. It might cost us the battery. + */ + if (acpi_prepare_sleep_state(acpi_softc, ACPI_STATE_S5) == 0) + acpi_enter_sleep_state(acpi_softc, ACPI_STATE_S5); } + extern int aml_busy; void diff --git a/sys/dev/acpi/acpibtn.c b/sys/dev/acpi/acpibtn.c index 65de567b39a..9c25a575026 100644 --- a/sys/dev/acpi/acpibtn.c +++ b/sys/dev/acpi/acpibtn.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpibtn.c,v 1.20 2008/11/06 23:41:28 marco Exp $ */ +/* $OpenBSD: acpibtn.c,v 1.21 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> * @@ -122,6 +122,9 @@ acpibtn_notify(struct aml_node *node, int notify_type, void *arg) switch (sc->sc_btn_type) { case ACPIBTN_LID: case ACPIBTN_SLEEP: +#ifdef ACPI_SLEEP_ENABLED + acpi_sleep_state(sc->sc_acpi, ACPI_STATE_S3); +#endif /* ACPI_SLEEP_ENABLED */ break; case ACPIBTN_POWER: if (notify_type == 0x80) diff --git a/sys/dev/acpi/acpireg.h b/sys/dev/acpi/acpireg.h index 3a32b89d121..1193c4428f2 100644 --- a/sys/dev/acpi/acpireg.h +++ b/sys/dev/acpi/acpireg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpireg.h,v 1.15 2008/06/24 08:24:57 sobrado Exp $ */ +/* $OpenBSD: acpireg.h,v 1.16 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * Copyright (c) 2005 Marco Peereboom <marco@openbsd.org> @@ -391,7 +391,7 @@ struct acpi_facs { #define FACS_LOCK_OWNED 0x00000002 u_int32_t flags; #define FACS_S4BIOS_F 0x00000001 /* S4BIOS_REQ supported */ - struct acpi_gas x_wakeup_vector; + uint64_t x_wakeup_vector; u_int8_t version; u_int8_t reserved[31]; } __packed; @@ -443,6 +443,13 @@ struct acpi_facs { #define ACPI_PM1_SLP_EN 0x2000 /* + * PM2 Control Registers + */ +#define ACPI_PM2_CONTROL 0x06 +#define ACPI_PM2_ARB_DIS 0x0001 + + +/* * Sleeping States */ #define ACPI_STATE_S0 0 diff --git a/sys/dev/acpi/acpivar.h b/sys/dev/acpi/acpivar.h index 4399525b340..981a154eae3 100644 --- a/sys/dev/acpi/acpivar.h +++ b/sys/dev/acpi/acpivar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: acpivar.h,v 1.45 2009/01/20 20:21:03 mlarkin Exp $ */ +/* $OpenBSD: acpivar.h,v 1.46 2009/02/19 21:02:05 marco Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com> * @@ -249,10 +249,16 @@ int acpi_probe(struct device *, struct cfdata *, struct bios_attach_args *); u_int acpi_checksum(const void *, size_t); void acpi_attach_machdep(struct acpi_softc *); int acpi_interrupt(void *); -void acpi_enter_sleep_state(struct acpi_softc *, int); void acpi_powerdown(void); -void acpi_resume(struct acpi_softc *); void acpi_reset(void); +void acpi_cpu_flush(struct acpi_softc *, int); +int acpi_sleep_state(struct acpi_softc *, int); +void acpi_resume(struct acpi_softc *); +int acpi_prepare_sleep_state(struct acpi_softc *, int); +int acpi_enter_sleep_state(struct acpi_softc *, int); +int acpi_sleep_machdep(struct acpi_softc *, int); +void acpi_sleep_walk(struct acpi_softc *, int); + #define ACPI_IOREAD 0 #define ACPI_IOWRITE 1 |