diff --git a/sys/dev/acpica/Osd/OsdInterrupt.c b/sys/dev/acpica/Osd/OsdInterrupt.c index 3fb1e70685d..8233eca812b 100644 --- a/sys/dev/acpica/Osd/OsdInterrupt.c +++ b/sys/dev/acpica/Osd/OsdInterrupt.c @@ -218,3 +218,9 @@ acpi_OverrideInterruptLevel(UINT32 InterruptNumber) InterruptOverride = InterruptNumber; return_ACPI_STATUS (AE_OK); } + +UINT32 +acpi_GetSciInterrupt(void) +{ + return InterruptOverride ?: AcpiGbl_FADT.SciInterrupt; +} diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c index 1be783c132f..09b956a0abe 100644 --- a/sys/dev/acpica/acpi.c +++ b/sys/dev/acpica/acpi.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD$"); #endif #include #include +#include #include #include #include @@ -3050,20 +3051,12 @@ __do_sleep(struct acpi_softc *sc, int state) static void __do_s0ix(struct acpi_softc *sc) { - int *state; + intr_suspend(); + intr_enable_src(acpi_GetSciInterrupt()); - critical_enter(); + acpi_cpu_idle_mwait(0); - state = (int *)PCPU_PTR(monitorbuf); - atomic_store_int(state, 1); - - cpu_monitor(state, 0, 0); - if (atomic_load_int(state) == 1) - cpu_mwait(0, 0); - - atomic_store_int(state, 0); - - critical_exit(); + intr_resume(false); } /* @@ -3141,11 +3134,13 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) } slp_state = ACPI_SS_DEV_SUSPEND; - status = AcpiEnterSleepStatePrep(state); - if (ACPI_FAILURE(status)) { - device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", - AcpiFormatException(status)); - goto backout; + if (!prefer_s0ix(sc, state)) { + status = AcpiEnterSleepStatePrep(state); + if (ACPI_FAILURE(status)) { + device_printf(sc->acpi_dev, "AcpiEnterSleepStatePrep failed - %s\n", + AcpiFormatException(status)); + goto backout; + } } slp_state = ACPI_SS_SLP_PREP; @@ -3196,7 +3191,7 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state) } if (slp_state >= ACPI_SS_DEV_SUSPEND) DEVICE_RESUME(root_bus); - if (slp_state >= ACPI_SS_SLP_PREP) + if (!prefer_s0ix(sc, state)&& (slp_state >= ACPI_SS_SLP_PREP)) AcpiLeaveSleepState(state); sc->acpi_next_sstate = 0; diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h index faf6c75424b..1c39e4bd830 100644 --- a/sys/dev/acpica/acpivar.h +++ b/sys/dev/acpica/acpivar.h @@ -367,6 +367,7 @@ ACPI_STATUS acpi_EvaluateOSC(ACPI_HANDLE handle, uint8_t *uuid, int revision, int count, uint32_t *caps_in, uint32_t *caps_out, bool query); ACPI_STATUS acpi_OverrideInterruptLevel(UINT32 InterruptNumber); +UINT32 acpi_GetSciInterrupt(void); ACPI_STATUS acpi_SetIntrModel(int model); int acpi_ReqSleepState(struct acpi_softc *sc, int state); int acpi_AckSleepState(struct apm_clone_data *clone, int error); diff --git a/sys/x86/include/intr_machdep.h b/sys/x86/include/intr_machdep.h index d9e7f881ffd..f4c5e3b19b5 100644 --- a/sys/x86/include/intr_machdep.h +++ b/sys/x86/include/intr_machdep.h @@ -162,6 +162,7 @@ int intr_register_source(struct intsrc *isrc); int intr_remove_handler(void *cookie); void intr_resume(bool suspend_cancelled); void intr_suspend(void); +void intr_enable_src(u_int irq); void intr_reprogram(void); void intrcnt_add(const char *name, u_long **countp); void nexus_add_irq(u_long irq); diff --git a/sys/x86/x86/intr_machdep.c b/sys/x86/x86/intr_machdep.c index 9f93ec96f83..0a64156678f 100644 --- a/sys/x86/x86/intr_machdep.c +++ b/sys/x86/x86/intr_machdep.c @@ -396,6 +396,17 @@ intr_suspend(void) mtx_unlock(&intrpic_lock); } +void +intr_enable_src(u_int irq) +{ + struct intsrc *is; + + sx_slock(&intrsrc_lock); + is = interrupt_sources[irq]; + is->is_pic->pic_enable_source(is); + sx_sunlock(&intrsrc_lock); +} + static int intr_assign_cpu(void *arg, int cpu) {