summaryrefslogtreecommitdiff
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
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
-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