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 /sys/dev/acpi | |
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
Diffstat (limited to 'sys/dev/acpi')
-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 |
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 |