ARM: perf: extend interrupt-affinity property for PPIs
[sfrench/cifs-2.6.git] / arch / arm / kernel / perf_event.c
index 7d5379c1c443b942fe0e711ddce4d0977b9eb91c..5a8f17bfcc6025043253233222e0c271039fa917 100644 (file)
@@ -790,32 +790,39 @@ static int probe_current_pmu(struct arm_pmu *pmu,
 
 static int of_pmu_irq_cfg(struct arm_pmu *pmu)
 {
-       int i, irq, *irqs;
+       int *irqs, i = 0;
+       bool using_spi = false;
        struct platform_device *pdev = pmu->plat_device;
 
-       /* Don't bother with PPIs; they're already affine */
-       irq = platform_get_irq(pdev, 0);
-       if (irq >= 0 && irq_is_percpu(irq)) {
-               cpumask_setall(&pmu->supported_cpus);
-               return 0;
-       }
-
        irqs = kcalloc(pdev->num_resources, sizeof(*irqs), GFP_KERNEL);
        if (!irqs)
                return -ENOMEM;
 
-       for (i = 0; i < pdev->num_resources; ++i) {
+       do {
                struct device_node *dn;
-               int cpu;
+               int cpu, irq;
 
-               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity",
-                                     i);
-               if (!dn) {
-                       pr_warn("Failed to parse %s/interrupt-affinity[%d]\n",
-                               of_node_full_name(pdev->dev.of_node), i);
+               /* See if we have an affinity entry */
+               dn = of_parse_phandle(pdev->dev.of_node, "interrupt-affinity", i);
+               if (!dn)
                        break;
+
+               /* Check the IRQ type and prohibit a mix of PPIs and SPIs */
+               irq = platform_get_irq(pdev, i);
+               if (irq >= 0) {
+                       bool spi = !irq_is_percpu(irq);
+
+                       if (i > 0 && spi != using_spi) {
+                               pr_err("PPI/SPI IRQ type mismatch for %s!\n",
+                                       dn->name);
+                               kfree(irqs);
+                               return -EINVAL;
+                       }
+
+                       using_spi = spi;
                }
 
+               /* Now look up the logical CPU number */
                for_each_possible_cpu(cpu)
                        if (arch_find_n_match_cpu_physical_id(dn, cpu, NULL))
                                break;
@@ -824,20 +831,36 @@ static int of_pmu_irq_cfg(struct arm_pmu *pmu)
                        pr_warn("Failed to find logical CPU for %s\n",
                                dn->name);
                        of_node_put(dn);
+                       cpumask_setall(&pmu->supported_cpus);
                        break;
                }
                of_node_put(dn);
 
-               irqs[i] = cpu;
+               /* For SPIs, we need to track the affinity per IRQ */
+               if (using_spi) {
+                       if (i >= pdev->num_resources) {
+                               of_node_put(dn);
+                               break;
+                       }
+
+                       irqs[i] = cpu;
+               }
+
+               /* Keep track of the CPUs containing this PMU type */
                cpumask_set_cpu(cpu, &pmu->supported_cpus);
-       }
+               of_node_put(dn);
+               i++;
+       } while (1);
 
-       if (i == pdev->num_resources) {
+       /* If we didn't manage to parse anything, claim to support all CPUs */
+       if (cpumask_weight(&pmu->supported_cpus) == 0)
+               cpumask_setall(&pmu->supported_cpus);
+
+       /* If we matched up the IRQ affinities, use them to route the SPIs */
+       if (using_spi && i == pdev->num_resources)
                pmu->irq_affinity = irqs;
-       } else {
+       else
                kfree(irqs);
-               cpumask_setall(&pmu->supported_cpus);
-       }
 
        return 0;
 }