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