Index: sys/amd64/amd64/mp_machdep.c =================================================================== --- sys/amd64/amd64/mp_machdep.c +++ sys/amd64/amd64/mp_machdep.c @@ -613,10 +613,9 @@ * completion. */ static void -smp_targeted_tlb_shootdown(cpuset_t mask, pmap_t pmap, vm_offset_t addr1, +smp_targeted_tlb_shootdown(const cpuset_t *mask, pmap_t pmap, vm_offset_t addr1, vm_offset_t addr2, smp_invl_cb_t curcpu_cb, enum invl_op_codes op) { - cpuset_t other_cpus; uint32_t generation, *p_cpudone; int cpu; bool is_all; @@ -625,7 +624,7 @@ * It is not necessary to signal other CPUs while booting or * when in the debugger. */ - if (kdb_active || KERNEL_PANICKED() || !smp_started) + if (__predict_false(kdb_active || KERNEL_PANICKED() || !smp_started)) goto local_cb; KASSERT(curthread->td_pinned > 0, ("curthread not pinned")); @@ -633,9 +632,8 @@ /* * Check for other cpus. Return if none. */ - is_all = !CPU_CMP(&mask, &all_cpus); - CPU_CLR(PCPU_GET(cpuid), &mask); - if (CPU_EMPTY(&mask)) + is_all = CPU_CMP(mask, &all_cpus) == 0; + if (CPU_ISSET(curcpu, mask) && CPU_COUNT(mask) == 1) goto local_cb; /* @@ -660,10 +658,10 @@ /* Fence between filling smp_tlb fields and clearing scoreboard. */ atomic_thread_fence_rel(); - CPU_FOREACH_ISSET(cpu, &mask) { + CPU_FOREACH_ISSET(cpu, mask) { KASSERT(*invl_scoreboard_slot(cpu) != 0, ("IPI scoreboard is zero, initiator %d target %d", - PCPU_GET(cpuid), cpu)); + curcpu, cpu)); *invl_scoreboard_slot(cpu) = 0; } @@ -674,14 +672,12 @@ */ if (is_all) { ipi_all_but_self(IPI_INVLOP); - other_cpus = all_cpus; - CPU_CLR(PCPU_GET(cpuid), &other_cpus); } else { - other_cpus = mask; - ipi_selected(mask, IPI_INVLOP); + ipi_selected_but_self(mask, IPI_INVLOP); } curcpu_cb(pmap, addr1, addr2); - CPU_FOREACH_ISSET(cpu, &other_cpus) { + *invl_scoreboard_slot(curcpu) = generation; + CPU_FOREACH_ISSET(cpu, mask) { p_cpudone = invl_scoreboard_slot(cpu); while (atomic_load_int(p_cpudone) != generation) ia32_pause(); @@ -705,7 +701,7 @@ } void -smp_masked_invltlb(cpuset_t mask, pmap_t pmap, smp_invl_cb_t curcpu_cb) +smp_masked_invltlb(const cpuset_t *mask, pmap_t pmap, smp_invl_cb_t curcpu_cb) { smp_targeted_tlb_shootdown(mask, pmap, 0, 0, curcpu_cb, invl_op_tlb); #ifdef COUNT_XINVLTLB_HITS @@ -714,7 +710,7 @@ } void -smp_masked_invlpg(cpuset_t mask, vm_offset_t addr, pmap_t pmap, +smp_masked_invlpg(const cpuset_t *mask, vm_offset_t addr, pmap_t pmap, smp_invl_cb_t curcpu_cb) { smp_targeted_tlb_shootdown(mask, pmap, addr, 0, curcpu_cb, invl_op_pg); @@ -724,8 +720,8 @@ } void -smp_masked_invlpg_range(cpuset_t mask, vm_offset_t addr1, vm_offset_t addr2, - pmap_t pmap, smp_invl_cb_t curcpu_cb) +smp_masked_invlpg_range(const cpuset_t *mask, vm_offset_t addr1, + vm_offset_t addr2, pmap_t pmap, smp_invl_cb_t curcpu_cb) { smp_targeted_tlb_shootdown(mask, pmap, addr1, addr2, curcpu_cb, invl_op_pgrng); @@ -738,7 +734,7 @@ void smp_cache_flush(smp_invl_cb_t curcpu_cb) { - smp_targeted_tlb_shootdown(all_cpus, NULL, 0, 0, curcpu_cb, + smp_targeted_tlb_shootdown(&all_cpus, NULL, 0, 0, curcpu_cb, INVL_OP_CACHE); } Index: sys/amd64/amd64/pmap.c =================================================================== --- sys/amd64/amd64/pmap.c +++ sys/amd64/amd64/pmap.c @@ -2960,7 +2960,7 @@ * This will force the vcpu to exit and the cached EPT mappings * will be invalidated by the host before the next vmresume. */ -static __inline void +static __noinline void pmap_invalidate_ept(pmap_t pmap) { smr_seq_t goal; @@ -3010,10 +3010,15 @@ smr_wait(pmap->pm_eptsmr, goal); } -static cpuset_t +/* + * Returns a reference to a set of CPUs on which the pmap is currently active. + * Note that the set can be modified without any mutual exclusion, so a copy + * must be made if a stable snapshot is required. + */ +static volatile cpuset_t * pmap_invalidate_cpu_mask(pmap_t pmap) { - return (pmap == kernel_pmap ? all_cpus : pmap->pm_active); + return (pmap == kernel_pmap ? &all_cpus : &pmap->pm_active); } static inline void @@ -3138,6 +3143,8 @@ void pmap_invalidate_page(pmap_t pmap, vm_offset_t va) { + cpuset_t mask; + if (pmap_type_guest(pmap)) { pmap_invalidate_ept(pmap); return; @@ -3147,8 +3154,8 @@ ("pmap_invalidate_page: invalid type %d", pmap->pm_type)); pmap_invalidate_preipi(pmap); - smp_masked_invlpg(pmap_invalidate_cpu_mask(pmap), va, pmap, - pmap_invalidate_page_curcpu_cb); + mask = *pmap_invalidate_cpu_mask(pmap); + smp_masked_invlpg(&mask, va, pmap, pmap_invalidate_page_curcpu_cb); } /* 4k PTEs -- Chosen to exceed the total size of Broadwell L2 TLB */ @@ -3232,6 +3239,8 @@ void pmap_invalidate_range(pmap_t pmap, vm_offset_t sva, vm_offset_t eva) { + cpuset_t mask; + if (eva - sva >= PMAP_INVLPG_THRESHOLD) { pmap_invalidate_all(pmap); return; @@ -3246,7 +3255,8 @@ ("pmap_invalidate_range: invalid type %d", pmap->pm_type)); pmap_invalidate_preipi(pmap); - smp_masked_invlpg_range(pmap_invalidate_cpu_mask(pmap), sva, eva, pmap, + mask = *pmap_invalidate_cpu_mask(pmap); + smp_masked_invlpg_range(&mask, sva, eva, pmap, pmap_invalidate_range_curcpu_cb); } @@ -3323,6 +3333,8 @@ void pmap_invalidate_all(pmap_t pmap) { + cpuset_t mask; + if (pmap_type_guest(pmap)) { pmap_invalidate_ept(pmap); return; @@ -3332,8 +3344,8 @@ ("pmap_invalidate_all: invalid type %d", pmap->pm_type)); pmap_invalidate_preipi(pmap); - smp_masked_invltlb(pmap_invalidate_cpu_mask(pmap), pmap, - pmap_invalidate_all_curcpu_cb); + mask = *pmap_invalidate_cpu_mask(pmap); + smp_masked_invltlb(&mask, pmap, pmap_invalidate_all_curcpu_cb); } static void Index: sys/x86/include/x86_smp.h =================================================================== --- sys/x86/include/x86_smp.h +++ sys/x86/include/x86_smp.h @@ -105,16 +105,27 @@ int ipi_nmi_handler(void); void ipi_swi_handler(struct trapframe frame); void ipi_selected(cpuset_t cpus, u_int ipi); +void ipi_selected_but_self(const cpuset_t *cpus, u_int ipi); void ipi_self_from_nmi(u_int vector); void set_interrupt_apic_ids(void); +void mem_range_AP_init(void); +void topo_probe(void); + +/* functions in mp_machdep.c */ void smp_cache_flush(smp_invl_cb_t curcpu_cb); +#ifdef __i386__ void smp_masked_invlpg(cpuset_t mask, vm_offset_t addr, struct pmap *pmap, smp_invl_cb_t curcpu_cb); void smp_masked_invlpg_range(cpuset_t mask, vm_offset_t startva, vm_offset_t endva, struct pmap *pmap, smp_invl_cb_t curcpu_cb); void smp_masked_invltlb(cpuset_t mask, struct pmap *pmap, smp_invl_cb_t curcpu_cb); -void mem_range_AP_init(void); -void topo_probe(void); - +#else +void smp_masked_invlpg(const cpuset_t *mask, vm_offset_t addr, + struct pmap *pmap, smp_invl_cb_t curcpu_cb); +void smp_masked_invlpg_range(const cpuset_t *mask, vm_offset_t startva, + vm_offset_t endva, struct pmap *pmap, smp_invl_cb_t curcpu_cb); +void smp_masked_invltlb(const cpuset_t *mask, struct pmap *pmap, + smp_invl_cb_t curcpu_cb); +#endif #endif Index: sys/x86/x86/mp_x86.c =================================================================== --- sys/x86/x86/mp_x86.c +++ sys/x86/x86/mp_x86.c @@ -1352,6 +1352,33 @@ } } +void +ipi_selected_but_self(const cpuset_t *cpus, u_int ipi) +{ + cpuset_t other_cpus; + int cpu, skip; + + skip = curcpu; + + /* + * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit + * of help in order to understand what is the source. + * Set the mask of receiving CPUs for this purpose. + */ + if (__predict_false(ipi == IPI_STOP_HARD)) { + CPU_COPY(cpus, &other_cpus); + CPU_CLR(skip, &other_cpus); + CPU_OR_ATOMIC(&ipi_stop_nmi_pending, &other_cpus); + } + + CPU_FOREACH_ISSET(cpu, cpus) { + if (cpu == skip) + continue; + CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi); + ipi_send_cpu(cpu, ipi); + } +} + /* * send an IPI to a specific CPU. */