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
This commit is contained in:
Mitsuru IWASAKI 2012-06-01 15:26:32 +00:00
parent 3d1d73c22f
commit f0a101b7e2
5 changed files with 125 additions and 96 deletions

View File

@ -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 *

View File

@ -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);

View File

@ -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);

View File

@ -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",

View File

@ -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)
{