Index: sys/kern/subr_smp.c =================================================================== --- sys/kern/subr_smp.c +++ sys/kern/subr_smp.c @@ -56,7 +56,8 @@ MALLOC_DEFINE(M_TOPO, "toponodes", "SMP topology data"); volatile cpuset_t stopped_cpus; -volatile cpuset_t started_cpus; +/* Align to attempt to keep started_cpus within a cache line for MWAIT. */ +volatile cpuset_t started_cpus __aligned(CACHE_LINE_SIZE); volatile cpuset_t suspended_cpus; cpuset_t hlt_cpus_mask; cpuset_t logical_cpus_mask; Index: sys/x86/x86/mp_x86.c =================================================================== --- sys/x86/x86/mp_x86.c +++ sys/x86/x86/mp_x86.c @@ -161,6 +161,10 @@ unsigned int boot_address; +static bool stop_mwait = false; +SYSCTL_BOOL(_machdep, OID_AUTO, stop_mwait, CTLFLAG_RWTUN, &stop_mwait, 0, + "Use MONITOR/MWAIT when stopping CPU"); + #define MiB(v) (v ## ULL << 20) void @@ -1389,6 +1393,17 @@ cpustop_handler_post(cpu); } +static bool +range_can_be_monitored(volatile void *start, size_t length) +{ + uint64_t addr, preceding; + + addr = (uintptr_t)start; + preceding = addr & (cpu_mon_min_size - 1); + + return (preceding + length <= cpu_mon_min_size); +} + /* * Handle an IPI_STOP by saving our current context and spinning until we * are resumed. @@ -1397,6 +1412,7 @@ cpustop_handler(void) { u_int cpu; + bool use_mwait; cpu = PCPU_GET(cpuid); @@ -1405,8 +1421,18 @@ /* Indicate that we are stopped */ CPU_SET_ATOMIC(cpu, &stopped_cpus); + use_mwait = (stop_mwait && (cpu_feature2 & CPUID2_MON) && + range_can_be_monitored(&started_cpus, sizeof(started_cpus))); + /* Wait for restart */ while (!CPU_ISSET(cpu, &started_cpus)) { + if (use_mwait) { + cpu_monitor(__DEVOLATILE(void *, &started_cpus), 0, 0); + if (!CPU_ISSET(cpu, &started_cpus)) + cpu_mwait(0, MWAIT_C1); + continue; + } + ia32_pause(); /*