diff options
author | jhb <jhb@FreeBSD.org> | 2005-10-24 21:04:19 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2005-10-24 21:04:19 +0000 |
commit | 679189182ba97332545877c8fd12c498bf999146 (patch) | |
tree | 04996df9019db70b3f1461e4764af227922a6b5f /sys/i386 | |
parent | b0356550ccf33cb4d4dac4a3541b70cf4a954071 (diff) | |
download | FreeBSD-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/NOTES | 2 | ||||
-rw-r--r-- | sys/i386/i386/mp_machdep.c | 53 | ||||
-rw-r--r-- | sys/i386/i386/trap.c | 6 | ||||
-rw-r--r-- | sys/i386/include/smp.h | 5 |
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 */ |