summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-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
4 files changed, 180 insertions, 62 deletions
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