From f0a101b7e202b96da01094320a0ae95e13f3356f Mon Sep 17 00:00:00 2001 From: Mitsuru IWASAKI Date: Fri, 1 Jun 2012 15:26:32 +0000 Subject: [PATCH] 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 --- sys/amd64/acpica/acpi_wakeup.c | 85 ++++++++++++++----------- sys/dev/acpica/acpi.c | 16 +++-- sys/dev/acpica/acpivar.h | 2 + sys/i386/acpica/acpi_wakeup.c | 111 +++++++++++++++++---------------- sys/ia64/acpica/acpi_wakeup.c | 7 +++ 5 files changed, 125 insertions(+), 96 deletions(-) diff --git a/sys/amd64/acpica/acpi_wakeup.c b/sys/amd64/acpica/acpi_wakeup.c index a96f1bfc8b1f..0bf1359bfb5a 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); +#ifdef SMP + if (!CPU_EMPTY(&suspcpus)) + restart_cpus(suspcpus); +#endif + mca_resume(); + intr_resume(); + } else { + /* Wakeup MD procedures in interrupt enabled context */ + AcpiSetFirmwareWakingVector(0); - AcpiSetFirmwareWakingVector(0); + 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); + } - 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); - - return (ret); + return (sleep_result); } static void * diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 41cd9f1030fc..730a954e8a13 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 a1892ea4d3fd..a469588247de 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 06dfa24df9e7..21c3157bd3a9 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); +#ifdef SMP + if (!CPU_EMPTY(&suspcpus)) + restart_cpus(suspcpus); +#endif + mca_resume(); + intr_resume(); + } else { + /* Wakeup MD procedures in interrupt enabled context */ + AcpiSetFirmwareWakingVector(0); - AcpiSetFirmwareWakingVector(0); + 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); + } - 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); - - 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 c81c3b39f877..ae98ae0c87f5 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) {