Index: sys/amd64/amd64/mp_machdep.c =================================================================== --- sys/amd64/amd64/mp_machdep.c (revision 259179) +++ sys/amd64/amd64/mp_machdep.c (working copy) @@ -1082,25 +1082,40 @@ ipi_startup(int apic_id, int vector) /* * Send an IPI to specified CPU handling the bitmap logic. */ -static void -ipi_send_cpu(int cpu, u_int ipi) +static int +ipi_send_cpu(cpuset_t mask, u_int ipi) { u_int bitmap, old_pending, new_pending; + cpuset_t mask2; + int cpu, sendit; - KASSERT(cpu_apic_ids[cpu] != -1, ("IPI to non-existent CPU %d", cpu)); - if (IPI_IS_BITMAPED(ipi)) { + sendit = 0; bitmap = 1 << ipi; ipi = IPI_BITMAP_VECTOR; - do { - old_pending = cpu_ipi_pending[cpu]; - new_pending = old_pending | bitmap; - } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu], - old_pending, new_pending)); - if (old_pending) - return; + mask2 = mask; + while ((cpu = cpusetobj_ffs(&mask2)) != 0) { + cpu--; + CPU_CLR(cpu, &mask2); + do { + old_pending = cpu_ipi_pending[cpu]; + new_pending = old_pending | bitmap; + } while (!atomic_cmpset_int(&cpu_ipi_pending[cpu], + old_pending, new_pending)); + + if (old_pending) + CPU_CLR(cpu, &mask); + else + sendit = 1; + } + } else { + sendit = 1; } - lapic_ipi_vectored(ipi, cpu_apic_ids[cpu]); + + if (sendit) + return (lapic_ipi_vectored(ipi, APIC_IPI_DEST_MASK, &mask)); + else + return (0); } /* @@ -1129,7 +1144,7 @@ smp_tlb_shootdown(u_int vector, vm_offset_t addr1, static void smp_targeted_tlb_shootdown(cpuset_t mask, u_int vector, vm_offset_t addr1, vm_offset_t addr2) { - int cpu, ncpu, othercpus; + int ncpu, othercpus; othercpus = mp_ncpus - 1; if (CPU_ISFULLSET(&mask)) { @@ -1150,15 +1165,7 @@ smp_targeted_tlb_shootdown(cpuset_t mask, u_int ve ncpu = othercpus; ipi_all_but_self(vector); } else { - ncpu = 0; - while ((cpu = cpusetobj_ffs(&mask)) != 0) { - cpu--; - CPU_CLR(cpu, &mask); - CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, - cpu, vector); - ipi_send_cpu(cpu, vector); - ncpu++; - } + ncpu = ipi_send_cpu(mask, vector); } while (smp_tlb_wait < ncpu) ia32_pause(); @@ -1290,7 +1297,6 @@ ipi_bitmap_handler(struct trapframe frame) void ipi_selected(cpuset_t cpus, u_int ipi) { - int cpu; /* * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit @@ -1300,12 +1306,7 @@ ipi_selected(cpuset_t cpus, u_int ipi) if (ipi == IPI_STOP_HARD) CPU_OR_ATOMIC(&ipi_nmi_pending, &cpus); - while ((cpu = cpusetobj_ffs(&cpus)) != 0) { - cpu--; - CPU_CLR(cpu, &cpus); - CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi); - ipi_send_cpu(cpu, ipi); - } + ipi_send_cpu(cpus, ipi); } /* @@ -1314,6 +1315,7 @@ ipi_selected(cpuset_t cpus, u_int ipi) void ipi_cpu(int cpu, u_int ipi) { + cpuset_t cpumask; /* * IPI_STOP_HARD maps to a NMI and the trap handler needs a bit @@ -1324,7 +1326,8 @@ ipi_cpu(int cpu, u_int ipi) CPU_SET_ATOMIC(cpu, &ipi_nmi_pending); CTR3(KTR_SMP, "%s: cpu: %d ipi: %x", __func__, cpu, ipi); - ipi_send_cpu(cpu, ipi); + CPU_SETOF(cpu, &cpumask); + ipi_send_cpu(cpumask, ipi); } /* @@ -1352,7 +1355,7 @@ ipi_all_but_self(u_int ipi) CPU_OR_ATOMIC(&ipi_nmi_pending, &other_cpus); CTR2(KTR_SMP, "%s: ipi: %x", __func__, ipi); - lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS); + lapic_ipi_vectored(ipi, APIC_IPI_DEST_OTHERS, NULL); } int Index: sys/amd64/include/apicvar.h =================================================================== --- sys/amd64/include/apicvar.h (revision 259179) +++ sys/amd64/include/apicvar.h (working copy) @@ -150,6 +150,7 @@ #define APIC_IPI_DEST_SELF -1 #define APIC_IPI_DEST_ALL -2 #define APIC_IPI_DEST_OTHERS -3 +#define APIC_IPI_DEST_MASK -4 #define APIC_BUS_UNKNOWN -1 #define APIC_BUS_ISA 0 @@ -212,7 +213,7 @@ void lapic_init(vm_paddr_t addr); void lapic_init_ap(void); int lapic_intr_pending(u_int vector); void lapic_ipi_raw(register_t icrlo, u_int dest); -void lapic_ipi_vectored(u_int vector, int dest); +int lapic_ipi_vectored(u_int vector, int dest, const cpuset_t *dmask); int lapic_ipi_wait(int delay); void lapic_handle_cmc(void); void lapic_handle_error(void); Index: sys/x86/x86/local_apic.c =================================================================== --- sys/x86/x86/local_apic.c (revision 259179) +++ sys/x86/x86/local_apic.c (working copy) @@ -1856,8 +1856,6 @@ lapic_ipi_raw(register_t icrlo, u_int dest) /* XXX: Need more sanity checking of icrlo? */ KASSERT(!lapic_missing(), ("%s called too early", __func__)); - KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, - ("%s: invalid dest field", __func__)); KASSERT((icrlo & APIC_ICRLO_RESV_MASK) == 0, ("%s: reserved bits set in ICR LO register", __func__)); @@ -1887,10 +1885,19 @@ lapic_ipi_raw(register_t icrlo, u_int dest) #define AFTER_SPIN 1000 #endif -void -lapic_ipi_vectored(u_int vector, int dest) +/* + * Each x2APIC cluster can address 16 APIC IDs. Therefore the range of + * x2APIC IDs that can be addressed is: [0, MAX_CLUSTER_ID * 16 + 15] + */ +#define MAX_CLUSTER_ID 1 + +int +lapic_ipi_vectored(u_int vector, int dest, const cpuset_t *cpumask) { register_t icrlo, destfield; + int num_cpus, i, apic_id, cluster_id; + uint16_t logmask[MAX_CLUSTER_ID + 1]; + cpuset_t dmask; KASSERT((vector & ~APIC_VECTOR_MASK) == 0, ("%s: invalid vector %d", __func__, vector)); @@ -1909,30 +1916,74 @@ lapic_ipi_raw(register_t icrlo, u_int dest) destfield = 0; switch (dest) { case APIC_IPI_DEST_SELF: + num_cpus = 1; icrlo |= APIC_DEST_SELF; break; case APIC_IPI_DEST_ALL: + num_cpus = mp_ncpus; icrlo |= APIC_DEST_ALLISELF; break; case APIC_IPI_DEST_OTHERS: + num_cpus = mp_ncpus - 1; icrlo |= APIC_DEST_ALLESELF; break; + case APIC_IPI_DEST_MASK: + break; default: - KASSERT((dest & ~(APIC_ID_MASK >> APIC_ID_SHIFT)) == 0, - ("%s: invalid destination 0x%x", __func__, dest)); - destfield = dest; + panic("lapic_ipi_vectored: unknown dest field %#x", dest); } /* Wait for an earlier IPI to finish. */ if (!lapic_ipi_wait(BEFORE_SPIN)) { if (panicstr != NULL) - return; + return (0); else panic("APIC: Previous IPI is stuck"); } - lapic_ipi_raw(icrlo, destfield); + if ((icrlo & APIC_DEST_MASK) == APIC_DEST_DESTFLD) { + if (x2apic) { + for (i = 0; i <= MAX_CLUSTER_ID; i++) + logmask[i] = 0; + } + num_cpus = 0; + dmask = *cpumask; + while ((cpu = cpusetobj_ffs(&dmask)) != 0) { + cpu--; + CPU_CLR(cpu, &dmask); + num_cpus++; + apic_id = cpu_apic_ids[cpu]; + KASSERT(apic_id != -1, ("CPU %d does not exist", cpu)); + if (x2apic) { + cluster_id = apic_id >> 4; + KASSERT(cluster_id >= 0 && + cluster_id <= MAX_CLUSTER_ID, + ("invalid cluster_id %#x", cluster_id)); + logmask[cluster_id] |= 1 << (apic_id & 0xf); + } else { + lapic_ipi_raw(icrlo, apic_id); + } + } + if (x2apic) { + if (num_cpus == 1) { + lapic_ipi_raw(icrlo, apic_id); + } else { + icrlo &= ~APIC_DESTMODE_PHY; + icrlo |= APIC_DESTMODE_LOG; + for (i = 0; i <= MAX_CLUSTER_ID; i++) { + destfield = logmask[i]; + if (destfield != 0) { + destfield |= i << 16; + lapic_ipi_raw(icrlo, destfield); + } + } + } + } + } else { + lapic_ipi_raw(icrlo, destfield); + } + #ifdef DETECT_DEADLOCK /* Wait for IPI to be delivered. */ if (!lapic_ipi_wait(AFTER_SPIN)) { @@ -1960,5 +2011,7 @@ lapic_ipi_raw(register_t icrlo, u_int dest) #endif /* needsattention */ } #endif /* DETECT_DEADLOCK */ + + return (num_cpus); } #endif /* SMP */