summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2005-10-24 21:04:19 +0000
committerjhb <jhb@FreeBSD.org>2005-10-24 21:04:19 +0000
commit679189182ba97332545877c8fd12c498bf999146 (patch)
tree04996df9019db70b3f1461e4764af227922a6b5f /sys/i386
parentb0356550ccf33cb4d4dac4a3541b70cf4a954071 (diff)
downloadFreeBSD-src-679189182ba97332545877c8fd12c498bf999146.zip
FreeBSD-src-679189182ba97332545877c8fd12c498bf999146.tar.gz
Rename the KDB_STOP_NMI kernel option to STOP_NMI and make it apply to all
IPI_STOP IPIs. - Change the i386 and amd64 MD IPI code to send an NMI if STOP_NMI is enabled if an attempt is made to send an IPI_STOP IPI. If the kernel option is enabled, there is also a sysctl to change the behavior at runtime (debug.stop_cpus_with_nmi which defaults to enabled). This includes removing stop_cpus_nmi() and making ipi_nmi_selected() a private function for i386 and amd64. - Fix ipi_all(), ipi_all_but_self(), and ipi_self() on i386 and amd64 to properly handle bitmapped IPIs as well as IPI_STOP IPIs when STOP_NMI is enabled. - Fix ipi_nmi_handler() to execute the restart function on the first CPU that is restarted making use of atomic_readandclear() rather than assuming that the BSP is always included in the set of restarted CPUs. Also, the NMI handler didn't clear the function pointer meaning that subsequent stop and restarts could execute the function again. - Define a new macro HAVE_STOPPEDPCBS on i386 and amd64 to control the use of stoppedpcbs[] and always enable it for i386 and amd64 instead of being dependent on KDB_STOP_NMI. It works fine in both the NMI and non-NMI cases.
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/conf/NOTES2
-rw-r--r--sys/i386/i386/mp_machdep.c53
-rw-r--r--sys/i386/i386/trap.c6
-rw-r--r--sys/i386/include/smp.h5
4 files changed, 50 insertions, 16 deletions
diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES
index 4a3a5b4..9cbbab5 100644
--- a/sys/i386/conf/NOTES
+++ b/sys/i386/conf/NOTES
@@ -56,7 +56,7 @@ options MP_WATCHDOG
# Debugging options.
#
-options KDB_STOP_NMI # Stop CPUS using NMI instead of IPI
+options STOP_NMI # Stop CPUS using NMI instead of IPI
diff --git a/sys/i386/i386/mp_machdep.c b/sys/i386/i386/mp_machdep.c
index 90ded0c..bfc3c5b 100644
--- a/sys/i386/i386/mp_machdep.c
+++ b/sys/i386/i386/mp_machdep.c
@@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$");
#include "opt_apic.h"
#include "opt_cpu.h"
-#include "opt_kdb.h"
#include "opt_kstack_pages.h"
#include "opt_mp_watchdog.h"
#include "opt_sched.h"
@@ -177,8 +176,10 @@ vm_offset_t smp_tlb_addr1;
vm_offset_t smp_tlb_addr2;
volatile int smp_tlb_wait;
-#ifdef KDB_STOP_NMI
+#ifdef STOP_NMI
volatile cpumask_t ipi_nmi_pending;
+
+static void ipi_nmi_selected(u_int32_t cpus);
#endif
#ifdef COUNT_IPIS
@@ -198,6 +199,20 @@ u_long *ipi_lazypmap_counts[MAXCPU];
* Local data and functions.
*/
+#ifdef STOP_NMI
+/*
+ * Provide an alternate method of stopping other CPUs. If another CPU has
+ * disabled interrupts the conventional STOP IPI will be blocked. This
+ * NMI-based stop should get through in that case.
+ */
+static int stop_cpus_with_nmi = 1;
+SYSCTL_INT(_debug, OID_AUTO, stop_cpus_with_nmi, CTLTYPE_INT | CTLFLAG_RW,
+ &stop_cpus_with_nmi, 0, "");
+TUNABLE_INT("debug.stop_cpus_with_nmi", &stop_cpus_with_nmi);
+#else
+#define stop_cpus_with_nmi 0
+#endif
+
static u_int logical_cpus;
/* used to hold the AP's until we are ready to release them */
@@ -1182,6 +1197,12 @@ ipi_selected(u_int32_t cpus, u_int ipi)
ipi = IPI_BITMAP_VECTOR;
}
+#ifdef STOP_NMI
+ if (ipi == IPI_STOP && stop_cpus_with_nmi) {
+ ipi_nmi_selected(cpus);
+ return;
+ }
+#endif
CTR3(KTR_SMP, "%s: cpus: %x ipi: %x", __func__, cpus, ipi);
while ((cpu = ffs(cpus)) != 0) {
cpu--;
@@ -1212,6 +1233,10 @@ void
ipi_all(u_int ipi)
{
+ if (IPI_IS_BITMAPED(ipi) || (ipi == IPI_STOP && stop_cpus_with_nmi)) {
+ ipi_selected(all_cpus, ipi);
+ return;
+ }
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
lapic_ipi_vectored(ipi, APIC_IPI_DEST_ALL);
}
@@ -1223,6 +1248,10 @@ void
ipi_all_but_self(u_int ipi)
{
+ if (IPI_IS_BITMAPED(ipi) || (ipi == IPI_STOP && stop_cpus_with_nmi)) {
+ ipi_selected(PCPU_GET(other_cpus), ipi);
+ return;
+ }
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS);
}
@@ -1234,11 +1263,15 @@ void
ipi_self(u_int ipi)
{
+ if (IPI_IS_BITMAPED(ipi) || (ipi == IPI_STOP && stop_cpus_with_nmi)) {
+ ipi_selected(PCPU_GET(cpumask), ipi);
+ return;
+ }
CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi);
lapic_ipi_vectored(ipi, APIC_IPI_DEST_SELF);
}
-#ifdef KDB_STOP_NMI
+#ifdef STOP_NMI
/*
* send NMI IPI to selected CPUs
*/
@@ -1273,14 +1306,14 @@ ipi_nmi_selected(u_int32_t cpus)
}
}
-
int
ipi_nmi_handler()
{
int cpu = PCPU_GET(cpuid);
int cpumask = PCPU_GET(cpumask);
+ void (*restartfunc)(void);
- if (!(atomic_load_acq_int(&ipi_nmi_pending) & cpumask))
+ if (!(ipi_nmi_pending & cpumask))
return 1;
atomic_clear_int(&ipi_nmi_pending, cpumask);
@@ -1291,19 +1324,21 @@ ipi_nmi_handler()
atomic_set_int(&stopped_cpus, cpumask);
/* Wait for restart */
- while (!(atomic_load_acq_int(&started_cpus) & cpumask))
+ while (!(started_cpus & cpumask))
ia32_pause();
atomic_clear_int(&started_cpus, cpumask);
atomic_clear_int(&stopped_cpus, cpumask);
- if (cpu == 0 && cpustop_restartfunc != NULL)
- cpustop_restartfunc();
+ restartfunc = (void (*)(void))atomic_readandclear_int(
+ (u_int *)&cpustop_restartfunc);
+ if (restartfunc != NULL)
+ restartfunc();
return 0;
}
-#endif /* KDB_STOP_NMI */
+#endif /* STOP_NMI */
/*
* This is called once the rest of the system is up and running and we're
diff --git a/sys/i386/i386/trap.c b/sys/i386/i386/trap.c
index 4703537..4c1df2a 100644
--- a/sys/i386/i386/trap.c
+++ b/sys/i386/i386/trap.c
@@ -185,13 +185,13 @@ trap(frame)
PCPU_LAZY_INC(cnt.v_trap);
type = frame.tf_trapno;
-#ifdef KDB_STOP_NMI
- /* Handler for NMI IPIs used for debugging */
+#ifdef STOP_NMI
+ /* Handler for NMI IPIs used for stopping CPUs. */
if (type == T_NMI) {
if (ipi_nmi_handler() == 0)
goto out;
}
-#endif /* KDB_STOP_NMI */
+#endif /* STOP_NMI */
#ifdef KDB
if (kdb_active) {
diff --git a/sys/i386/include/smp.h b/sys/i386/include/smp.h
index 4c9ae76..d2482fe 100644
--- a/sys/i386/include/smp.h
+++ b/sys/i386/include/smp.h
@@ -79,9 +79,8 @@ void smp_masked_invlpg_range(u_int mask, vm_offset_t startva,
void smp_invltlb(void);
void smp_masked_invltlb(u_int mask);
-#ifdef KDB_STOP_NMI
-int ipi_nmi_handler(void);
-void ipi_nmi_selected(u_int32_t cpus);
+#ifdef STOP_NMI
+int ipi_nmi_handler(void);
#endif
#endif /* !LOCORE */
OpenPOWER on IntegriCloud