summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoriwasaki <iwasaki@FreeBSD.org>2012-06-01 15:26:32 +0000
committeriwasaki <iwasaki@FreeBSD.org>2012-06-01 15:26:32 +0000
commit9cbcc3c49217bb72870e849e6d29f60a7f7523f4 (patch)
tree67744bb6bd77bbf3e84cf3f6921faa49fe802486
parentd642fa7a2f76eb02a58d652c2601150ccd82da42 (diff)
downloadFreeBSD-src-9cbcc3c49217bb72870e849e6d29f60a7f7523f4.zip
FreeBSD-src-9cbcc3c49217bb72870e849e6d29f60a7f7523f4.tar.gz
Call AcpiLeaveSleepStatePrep() in interrupt disabled context
(described in ACPICA source code). - Move intr_disable() and intr_restore() from acpi_wakeup.c to acpi.c and call AcpiLeaveSleepStatePrep() in interrupt disabled context. - Add acpi_wakeup_machdep() to execute wakeup MD procedures and call it twice in interrupt disabled/enabled context (ia64 version is just dummy). - Rename wakeup_cpus variable in acpi_sleep_machdep() to suspcpus in order to be shared by acpi_sleep_machdep() and acpi_wakeup_machdep(). - Move identity mapping related code to acpi_install_wakeup_handler() (i386 version) for preparation of x86/acpica/acpi_wakeup.c (MFC candidate). Reviewed by: jkim@ MFC after: 2 days
-rw-r--r--sys/amd64/acpica/acpi_wakeup.c85
-rw-r--r--sys/dev/acpica/acpi.c16
-rw-r--r--sys/dev/acpica/acpivar.h2
-rw-r--r--sys/i386/acpica/acpi_wakeup.c111
-rw-r--r--sys/ia64/acpica/acpi_wakeup.c7
5 files changed, 125 insertions, 96 deletions
diff --git a/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c
index a96f1bf..0bf1359 100644
--- a/sys/amd64/acpica/acpi_wakeup.c
+++ b/sys/amd64/acpica/acpi_wakeup.c
@@ -76,6 +76,10 @@ static struct pcb **susppcbs;
static void **suspfpusave;
#endif
+#ifdef SMP
+static cpuset_t suspcpus;
+#endif
+
int acpi_restorecpu(uint64_t, vm_offset_t);
static void *acpi_alloc_wakeup_handler(void);
@@ -220,21 +224,14 @@ acpi_wakeup_cpus(struct acpi_softc *sc, const cpuset_t *wakeup_cpus)
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
{
-#ifdef SMP
- cpuset_t wakeup_cpus;
-#endif
- register_t rf;
ACPI_STATUS status;
- int ret;
-
- ret = -1;
if (sc->acpi_wakeaddr == 0ul)
- return (ret);
+ return (-1); /* couldn't alloc wake memory */
#ifdef SMP
- wakeup_cpus = all_cpus;
- CPU_CLR(PCPU_GET(cpuid), &wakeup_cpus);
+ suspcpus = all_cpus;
+ CPU_CLR(PCPU_GET(cpuid), &suspcpus);
#endif
if (acpi_resume_beep != 0)
@@ -242,16 +239,15 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
AcpiSetFirmwareWakingVector(WAKECODE_PADDR(sc));
- rf = intr_disable();
intr_suspend();
if (savectx(susppcbs[0])) {
ctx_fpusave(suspfpusave[0]);
#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus) &&
- suspend_cpus(wakeup_cpus) == 0) {
+ if (!CPU_EMPTY(&suspcpus) &&
+ suspend_cpus(suspcpus) == 0) {
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
- goto out;
+ return (0); /* couldn't sleep */
}
#endif
@@ -276,41 +272,54 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
device_printf(sc->acpi_dev,
"AcpiEnterSleepState failed - %s\n",
AcpiFormatException(status));
- goto out;
+ return (0); /* couldn't sleep */
}
for (;;)
ia32_pause();
- } else {
- pmap_init_pat();
- load_cr3(susppcbs[0]->pcb_cr3);
- initializecpu();
- PCPU_SET(switchtime, 0);
- PCPU_SET(switchticks, ticks);
-#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus))
- acpi_wakeup_cpus(sc, &wakeup_cpus);
-#endif
- ret = 0;
}
-out:
+ return (1); /* wakeup successfully */
+}
+
+int
+acpi_wakeup_machdep(struct acpi_softc *sc, int state,
+ int sleep_result, int intr_enabled)
+{
+
+ if (sleep_result == -1)
+ return (sleep_result);
+
+ if (intr_enabled == 0) {
+ /* Wakeup MD procedures in interrupt disabled context */
+ if (sleep_result == 1) {
+ pmap_init_pat();
+ load_cr3(susppcbs[0]->pcb_cr3);
+ initializecpu();
+ PCPU_SET(switchtime, 0);
+ PCPU_SET(switchticks, ticks);
#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus))
- restart_cpus(wakeup_cpus);
+ if (!CPU_EMPTY(&suspcpus))
+ acpi_wakeup_cpus(sc, &suspcpus);
#endif
+ }
- mca_resume();
- intr_resume();
- intr_restore(rf);
-
- AcpiSetFirmwareWakingVector(0);
+#ifdef SMP
+ if (!CPU_EMPTY(&suspcpus))
+ restart_cpus(suspcpus);
+#endif
+ mca_resume();
+ intr_resume();
+ } else {
+ /* Wakeup MD procedures in interrupt enabled context */
+ AcpiSetFirmwareWakingVector(0);
- if (ret == 0 && mem_range_softc.mr_op != NULL &&
- mem_range_softc.mr_op->reinit != NULL)
- mem_range_softc.mr_op->reinit(&mem_range_softc);
+ if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
+ mem_range_softc.mr_op->reinit != NULL)
+ mem_range_softc.mr_op->reinit(&mem_range_softc);
+ }
- return (ret);
+ return (sleep_result);
}
static void *
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index 41cd9f1..730a954 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -2666,6 +2666,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
register_t intr;
ACPI_STATUS status;
enum acpi_sleep_state slp_state;
+ int sleep_result;
ACPI_FUNCTION_TRACE_U32((char *)(uintptr_t)__func__, state);
@@ -2746,7 +2747,16 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
DELAY(sc->acpi_sleep_delay * 1000000);
if (state != ACPI_STATE_S1) {
- if (acpi_sleep_machdep(sc, state))
+ intr = intr_disable();
+ sleep_result = acpi_sleep_machdep(sc, state);
+ acpi_wakeup_machdep(sc, state, sleep_result, 0);
+ AcpiLeaveSleepStatePrep(state, acpi_sleep_flags);
+ intr_restore(intr);
+
+ /* call acpi_wakeup_machdep() again with interrupt enabled */
+ acpi_wakeup_machdep(sc, state, sleep_result, 1);
+
+ if (sleep_result == -1)
goto backout;
/* Re-enable ACPI hardware on wakeup from sleep state 4. */
@@ -2775,10 +2785,8 @@ backout:
}
if (slp_state >= ACPI_SS_DEV_SUSPEND)
DEVICE_RESUME(root_bus);
- if (slp_state >= ACPI_SS_SLP_PREP) {
- AcpiLeaveSleepStatePrep(state, acpi_sleep_flags);
+ if (slp_state >= ACPI_SS_SLP_PREP)
AcpiLeaveSleepState(state);
- }
if (slp_state >= ACPI_SS_SLEPT) {
acpi_resync_clock(sc);
acpi_enable_fixed_events(sc);
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index a1892ea..a469588 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -439,6 +439,8 @@ int acpi_disabled(char *subsys);
int acpi_machdep_init(device_t dev);
void acpi_install_wakeup_handler(struct acpi_softc *sc);
int acpi_sleep_machdep(struct acpi_softc *sc, int state);
+int acpi_wakeup_machdep(struct acpi_softc *sc, int state,
+ int sleep_result, int intr_enabled);
int acpi_table_quirks(int *quirks);
int acpi_machdep_quirks(int *quirks);
diff --git a/sys/i386/acpica/acpi_wakeup.c b/sys/i386/acpica/acpi_wakeup.c
index 06dfa24..21c3157 100644
--- a/sys/i386/acpica/acpi_wakeup.c
+++ b/sys/i386/acpica/acpi_wakeup.c
@@ -74,6 +74,10 @@ extern struct pcb **susppcbs;
static struct pcb **susppcbs;
#endif
+#ifdef SMP
+static cpuset_t suspcpus;
+#endif
+
static void *acpi_alloc_wakeup_handler(void);
static void acpi_stop_beep(void *);
@@ -212,22 +216,14 @@ acpi_wakeup_cpus(struct acpi_softc *sc, const cpuset_t *wakeup_cpus)
int
acpi_sleep_machdep(struct acpi_softc *sc, int state)
{
-#ifdef SMP
- cpuset_t wakeup_cpus;
-#endif
- register_t cr3, rf;
ACPI_STATUS status;
- struct pmap *pm;
- int ret;
-
- ret = -1;
if (sc->acpi_wakeaddr == 0ul)
- return (ret);
+ return (-1); /* couldn't alloc wake memory */
#ifdef SMP
- wakeup_cpus = all_cpus;
- CPU_CLR(PCPU_GET(cpuid), &wakeup_cpus);
+ suspcpus = all_cpus;
+ CPU_CLR(PCPU_GET(cpuid), &suspcpus);
#endif
if (acpi_resume_beep != 0)
@@ -235,28 +231,14 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
AcpiSetFirmwareWakingVector(WAKECODE_PADDR(sc));
- rf = intr_disable();
intr_suspend();
- /*
- * Temporarily switch to the kernel pmap because it provides
- * an identity mapping (setup at boot) for the low physical
- * memory region containing the wakeup code.
- */
- pm = kernel_pmap;
- cr3 = rcr3();
-#ifdef PAE
- load_cr3(vtophys(pm->pm_pdpt));
-#else
- load_cr3(vtophys(pm->pm_pdir));
-#endif
-
if (suspendctx(susppcbs[0])) {
#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus) &&
- suspend_cpus(wakeup_cpus) == 0) {
+ if (!CPU_EMPTY(&suspcpus) &&
+ suspend_cpus(suspcpus) == 0) {
device_printf(sc->acpi_dev, "Failed to suspend APs\n");
- goto out;
+ return (0); /* couldn't sleep */
}
#endif
@@ -264,8 +246,6 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
WAKECODE_FIXUP(reset_video, uint8_t, (acpi_reset_video != 0));
WAKECODE_FIXUP(wakeup_cr4, register_t, susppcbs[0]->pcb_cr4);
- WAKECODE_FIXUP(wakeup_cr3, register_t, susppcbs[0]->pcb_cr3);
-
WAKECODE_FIXUP(wakeup_pcb, struct pcb *, susppcbs[0]);
/* Call ACPICA to enter the desired sleep state */
@@ -278,41 +258,54 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
device_printf(sc->acpi_dev,
"AcpiEnterSleepState failed - %s\n",
AcpiFormatException(status));
- goto out;
+ return (0); /* couldn't sleep */
}
for (;;)
ia32_pause();
- } else {
- pmap_init_pat();
- initializecpu();
- PCPU_SET(switchtime, 0);
- PCPU_SET(switchticks, ticks);
-#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus))
- acpi_wakeup_cpus(sc, &wakeup_cpus);
-#endif
- ret = 0;
}
-out:
+ return (1); /* wakeup successfully */
+}
+
+int
+acpi_wakeup_machdep(struct acpi_softc *sc, int state,
+ int sleep_result, int intr_enabled)
+{
+
+ if (sleep_result == -1)
+ return (sleep_result);
+
+ if (intr_enabled == 0) {
+ /* Wakeup MD procedures in interrupt disabled context */
+ if (sleep_result == 1) {
+ pmap_init_pat();
+ load_cr3(susppcbs[0]->pcb_cr3);
+ initializecpu();
+ PCPU_SET(switchtime, 0);
+ PCPU_SET(switchticks, ticks);
#ifdef SMP
- if (!CPU_EMPTY(&wakeup_cpus))
- restart_cpus(wakeup_cpus);
+ if (!CPU_EMPTY(&suspcpus))
+ acpi_wakeup_cpus(sc, &suspcpus);
#endif
+ }
- load_cr3(cr3);
- mca_resume();
- intr_resume();
- intr_restore(rf);
-
- AcpiSetFirmwareWakingVector(0);
+#ifdef SMP
+ if (!CPU_EMPTY(&suspcpus))
+ restart_cpus(suspcpus);
+#endif
+ mca_resume();
+ intr_resume();
+ } else {
+ /* Wakeup MD procedures in interrupt enabled context */
+ AcpiSetFirmwareWakingVector(0);
- if (ret == 0 && mem_range_softc.mr_op != NULL &&
- mem_range_softc.mr_op->reinit != NULL)
- mem_range_softc.mr_op->reinit(&mem_range_softc);
+ if (sleep_result == 1 && mem_range_softc.mr_op != NULL &&
+ mem_range_softc.mr_op->reinit != NULL)
+ mem_range_softc.mr_op->reinit(&mem_range_softc);
+ }
- return (ret);
+ return (sleep_result);
}
static void *
@@ -373,6 +366,16 @@ acpi_install_wakeup_handler(struct acpi_softc *sc)
/* Save pointers to some global data. */
WAKECODE_FIXUP(wakeup_ret, void *, resumectx);
+ /*
+ * Temporarily switch to the kernel pmap because it provides
+ * an identity mapping (setup at boot) for the low physical
+ * memory region containing the wakeup code.
+ */
+#ifdef PAE
+ WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdpt));
+#else
+ WAKECODE_FIXUP(wakeup_cr3, register_t, vtophys(kernel_pmap->pm_pdir));
+#endif
if (bootverbose)
device_printf(sc->acpi_dev, "wakeup code va %#x pa %#jx\n",
diff --git a/sys/ia64/acpica/acpi_wakeup.c b/sys/ia64/acpica/acpi_wakeup.c
index c81c3b3..ae98ae0 100644
--- a/sys/ia64/acpica/acpi_wakeup.c
+++ b/sys/ia64/acpica/acpi_wakeup.c
@@ -39,6 +39,13 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
return (0);
}
+int
+acpi_wakeup_machdep(struct acpi_softc *sc, int state,
+ int sleep_result, int intr_enabled)
+{
+ return (0);
+}
+
void
acpi_install_wakeup_handler(struct acpi_softc *sc)
{
OpenPOWER on IntegriCloud