x86/apic/x2apic: Allow CPU cluster_mask to be populated in parallel
[linux-2.6-block.git] / arch / x86 / kernel / apic / x2apic_cluster.c
index e696e22d0531976f7cba72ed17443592eac72c13..b2b2b7f3e03f69c716ff3555325390566b559692 100644 (file)
@@ -9,11 +9,7 @@
 
 #include "local.h"
 
-struct cluster_mask {
-       unsigned int    clusterid;
-       int             node;
-       struct cpumask  mask;
-};
+#define apic_cluster(apicid) ((apicid) >> 4)
 
 /*
  * __x2apic_send_IPI_mask() possibly needs to read
@@ -23,8 +19,7 @@ struct cluster_mask {
 static u32 *x86_cpu_to_logical_apicid __read_mostly;
 
 static DEFINE_PER_CPU(cpumask_var_t, ipi_mask);
-static DEFINE_PER_CPU_READ_MOSTLY(struct cluster_mask *, cluster_masks);
-static struct cluster_mask *cluster_hotplug_mask;
+static DEFINE_PER_CPU_READ_MOSTLY(struct cpumask *, cluster_masks);
 
 static int x2apic_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
@@ -60,10 +55,10 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
 
        /* Collapse cpus in a cluster so a single IPI per cluster is sent */
        for_each_cpu(cpu, tmpmsk) {
-               struct cluster_mask *cmsk = per_cpu(cluster_masks, cpu);
+               struct cpumask *cmsk = per_cpu(cluster_masks, cpu);
 
                dest = 0;
-               for_each_cpu_and(clustercpu, tmpmsk, &cmsk->mask)
+               for_each_cpu_and(clustercpu, tmpmsk, cmsk)
                        dest |= x86_cpu_to_logical_apicid[clustercpu];
 
                if (!dest)
@@ -71,7 +66,7 @@ __x2apic_send_IPI_mask(const struct cpumask *mask, int vector, int apic_dest)
 
                __x2apic_send_IPI_dest(dest, vector, APIC_DEST_LOGICAL);
                /* Remove cluster CPUs from tmpmask */
-               cpumask_andnot(tmpmsk, tmpmsk, &cmsk->mask);
+               cpumask_andnot(tmpmsk, tmpmsk, cmsk);
        }
 
        local_irq_restore(flags);
@@ -105,55 +100,98 @@ static u32 x2apic_calc_apicid(unsigned int cpu)
 
 static void init_x2apic_ldr(void)
 {
-       struct cluster_mask *cmsk = this_cpu_read(cluster_masks);
-       u32 cluster, apicid = apic_read(APIC_LDR);
-       unsigned int cpu;
+       struct cpumask *cmsk = this_cpu_read(cluster_masks);
 
-       x86_cpu_to_logical_apicid[smp_processor_id()] = apicid;
+       BUG_ON(!cmsk);
 
-       if (cmsk)
-               goto update;
-
-       cluster = apicid >> 16;
-       for_each_online_cpu(cpu) {
-               cmsk = per_cpu(cluster_masks, cpu);
-               /* Matching cluster found. Link and update it. */
-               if (cmsk && cmsk->clusterid == cluster)
-                       goto update;
+       cpumask_set_cpu(smp_processor_id(), cmsk);
+}
+
+/*
+ * As an optimisation during boot, set the cluster_mask for all present
+ * CPUs at once, to prevent each of them having to iterate over the others
+ * to find the existing cluster_mask.
+ */
+static void prefill_clustermask(struct cpumask *cmsk, unsigned int cpu, u32 cluster)
+{
+       int cpu_i;
+
+       for_each_present_cpu(cpu_i) {
+               struct cpumask **cpu_cmsk = &per_cpu(cluster_masks, cpu_i);
+               u32 apicid = apic->cpu_present_to_apicid(cpu_i);
+
+               if (apicid == BAD_APICID || cpu_i == cpu || apic_cluster(apicid) != cluster)
+                       continue;
+
+               if (WARN_ON_ONCE(*cpu_cmsk == cmsk))
+                       continue;
+
+               BUG_ON(*cpu_cmsk);
+               *cpu_cmsk = cmsk;
        }
-       cmsk = cluster_hotplug_mask;
-       cmsk->clusterid = cluster;
-       cluster_hotplug_mask = NULL;
-update:
-       this_cpu_write(cluster_masks, cmsk);
-       cpumask_set_cpu(smp_processor_id(), &cmsk->mask);
 }
 
-static int alloc_clustermask(unsigned int cpu, int node)
+static int alloc_clustermask(unsigned int cpu, u32 cluster, int node)
 {
+       struct cpumask *cmsk = NULL;
+       unsigned int cpu_i;
+
+       /*
+        * At boot time, the CPU present mask is stable. The cluster mask is
+        * allocated for the first CPU in the cluster and propagated to all
+        * present siblings in the cluster. If the cluster mask is already set
+        * on entry to this function for a given CPU, there is nothing to do.
+        */
        if (per_cpu(cluster_masks, cpu))
                return 0;
+
+       if (system_state < SYSTEM_RUNNING)
+               goto alloc;
+
        /*
-        * If a hotplug spare mask exists, check whether it's on the right
-        * node. If not, free it and allocate a new one.
+        * On post boot hotplug for a CPU which was not present at boot time,
+        * iterate over all possible CPUs (even those which are not present
+        * any more) to find any existing cluster mask.
         */
-       if (cluster_hotplug_mask) {
-               if (cluster_hotplug_mask->node == node)
-                       return 0;
-               kfree(cluster_hotplug_mask);
+       for_each_possible_cpu(cpu_i) {
+               u32 apicid = apic->cpu_present_to_apicid(cpu_i);
+
+               if (apicid != BAD_APICID && apic_cluster(apicid) == cluster) {
+                       cmsk = per_cpu(cluster_masks, cpu_i);
+                       /*
+                        * If the cluster is already initialized, just store
+                        * the mask and return. There's no need to propagate.
+                        */
+                       if (cmsk) {
+                               per_cpu(cluster_masks, cpu) = cmsk;
+                               return 0;
+                       }
+               }
        }
-
-       cluster_hotplug_mask = kzalloc_node(sizeof(*cluster_hotplug_mask),
-                                           GFP_KERNEL, node);
-       if (!cluster_hotplug_mask)
+       /*
+        * No CPU in the cluster has ever been initialized, so fall through to
+        * the boot time code which will also populate the cluster mask for any
+        * other CPU in the cluster which is (now) present.
+        */
+alloc:
+       cmsk = kzalloc_node(sizeof(*cmsk), GFP_KERNEL, node);
+       if (!cmsk)
                return -ENOMEM;
-       cluster_hotplug_mask->node = node;
+       per_cpu(cluster_masks, cpu) = cmsk;
+       prefill_clustermask(cmsk, cpu, cluster);
+
        return 0;
 }
 
 static int x2apic_prepare_cpu(unsigned int cpu)
 {
-       if (alloc_clustermask(cpu, cpu_to_node(cpu)) < 0)
+       u32 phys_apicid = apic->cpu_present_to_apicid(cpu);
+       u32 cluster = apic_cluster(phys_apicid);
+       u32 logical_apicid = (cluster << 16) | (1 << (phys_apicid & 0xf));
+
+       x86_cpu_to_logical_apicid[cpu] = logical_apicid;
+
+       if (alloc_clustermask(cpu, cluster, cpu_to_node(cpu)) < 0)
                return -ENOMEM;
        if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL))
                return -ENOMEM;
@@ -162,10 +200,10 @@ static int x2apic_prepare_cpu(unsigned int cpu)
 
 static int x2apic_dead_cpu(unsigned int dead_cpu)
 {
-       struct cluster_mask *cmsk = per_cpu(cluster_masks, dead_cpu);
+       struct cpumask *cmsk = per_cpu(cluster_masks, dead_cpu);
 
        if (cmsk)
-               cpumask_clear_cpu(dead_cpu, &cmsk->mask);
+               cpumask_clear_cpu(dead_cpu, cmsk);
        free_cpumask_var(per_cpu(ipi_mask, dead_cpu));
        return 0;
 }