call suspend_cpus() under smp_ipi_mtx
Andriy Gapon
avg at FreeBSD.org
Fri Feb 8 07:37:23 UTC 2013
Could you please review and/or test the following patch?
The idea is exactly the same as for cpu_stop() invocation in the shutdown path.
Please note that I've kept intr_disable() just because potentially mtx_lock_spin
could be implemented in such a way that it wouldn't block all interrupts via CPU
flags, but would use LAPIC TPR, for example.
I've also decided to add smp_ipi_mtx assertions to suspend_cpus and stop_cpus.
diff --git a/sys/dev/acpica/acpi.c b/sys/dev/acpica/acpi.c
index f0c750f..9750d46 100644
--- a/sys/dev/acpica/acpi.c
+++ b/sys/dev/acpica/acpi.c
@@ -2741,6 +2741,15 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
if (sc->acpi_sleep_delay > 0)
DELAY(sc->acpi_sleep_delay * 1000000);
+#ifdef SMP
+ /*
+ * Prevent inter-CPU deadlock possibility between suspend_cpus()
+ * and other inter-CPU synchronous calls like smp_rendezvous and
+ * TLB shootdowns.
+ */
+ if (state != ACPI_STATE_S1)
+ mtx_lock_spin(&smp_ipi_mtx);
+#endif
intr = intr_disable();
if (state != ACPI_STATE_S1) {
sleep_result = acpi_sleep_machdep(sc, state);
@@ -2784,6 +2793,9 @@ acpi_EnterSleepState(struct acpi_softc *sc, int state)
}
intr_restore(intr);
+#ifdef SMP
+ mtx_unlock_spin(&smp_ipi_mtx);
+#endif
/* call acpi_wakeup_machdep() again with interrupt enabled */
acpi_wakeup_machdep(sc, state, sleep_result, 1);
diff --git a/sys/kern/subr_smp.c b/sys/kern/subr_smp.c
index 3614798..edf16db 100644
--- a/sys/kern/subr_smp.c
+++ b/sys/kern/subr_smp.c
@@ -260,6 +260,7 @@ int
stop_cpus(cpuset_t map)
{
+ mtx_assert(&smp_ipi_mtx, MA_OWNED);
return (generic_stop_cpus(map, IPI_STOP));
}
@@ -275,6 +276,7 @@ int
suspend_cpus(cpuset_t map)
{
+ mtx_assert(&smp_ipi_mtx, MA_OWNED);
return (generic_stop_cpus(map, IPI_SUSPEND));
}
#endif
--
Andriy Gapon
More information about the freebsd-current
mailing list