summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMarco Peereboom <marco@cvs.openbsd.org>2009-02-19 21:02:06 +0000
committerMarco Peereboom <marco@cvs.openbsd.org>2009-02-19 21:02:06 +0000
commit748c385494ee5d641b7e648df28568538e41467c (patch)
tree9b3648d5d080c29915d0f71b7a8d9c490046223d /sys
parent6fb68817a3957ab44390ea949e41e4b949d653a7 (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
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/amd64/amd64/acpi_machdep.c71
-rw-r--r--sys/arch/amd64/amd64/acpi_wakecode.S26
-rw-r--r--sys/arch/i386/i386/acpi_machdep.c78
-rw-r--r--sys/arch/i386/i386/acpi_wakecode.S19
-rw-r--r--sys/dev/acpi/acpi.c214
-rw-r--r--sys/dev/acpi/acpibtn.c5
-rw-r--r--sys/dev/acpi/acpireg.h11
-rw-r--r--sys/dev/acpi/acpivar.h12
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