Merge branch 'perf-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / drivers / perf / arm_pmu_acpi.c
index 705f1a3..0f19751 100644 (file)
@@ -11,6 +11,8 @@
 #include <linux/acpi.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
 #include <linux/percpu.h>
 #include <linux/perf/arm_pmu.h>
 
@@ -87,7 +89,13 @@ static int arm_pmu_acpi_parse_irqs(void)
                        pr_warn("No ACPI PMU IRQ for CPU%d\n", cpu);
                }
 
+               /*
+                * Log and request the IRQ so the core arm_pmu code can manage
+                * it. We'll have to sanity-check IRQs later when we associate
+                * them with their PMUs.
+                */
                per_cpu(pmu_irqs, cpu) = irq;
+               armpmu_request_irq(irq, cpu);
        }
 
        return 0;
@@ -127,7 +135,7 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
                return pmu;
        }
 
-       pmu = armpmu_alloc();
+       pmu = armpmu_alloc_atomic();
        if (!pmu) {
                pr_warn("Unable to allocate PMU for CPU%d\n",
                        smp_processor_id());
@@ -139,6 +147,35 @@ static struct arm_pmu *arm_pmu_acpi_find_alloc_pmu(void)
        return pmu;
 }
 
+/*
+ * Check whether the new IRQ is compatible with those already associated with
+ * the PMU (e.g. we don't have mismatched PPIs).
+ */
+static bool pmu_irq_matches(struct arm_pmu *pmu, int irq)
+{
+       struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
+       int cpu;
+
+       if (!irq)
+               return true;
+
+       for_each_cpu(cpu, &pmu->supported_cpus) {
+               int other_irq = per_cpu(hw_events->irq, cpu);
+               if (!other_irq)
+                       continue;
+
+               if (irq == other_irq)
+                       continue;
+               if (!irq_is_percpu_devid(irq) && !irq_is_percpu_devid(other_irq))
+                       continue;
+
+               pr_warn("mismatched PPIs detected\n");
+               return false;
+       }
+
+       return true;
+}
+
 /*
  * This must run before the common arm_pmu hotplug logic, so that we can
  * associate a CPU and its interrupt before the common code tries to manage the
@@ -164,19 +201,14 @@ static int arm_pmu_acpi_cpu_starting(unsigned int cpu)
        if (!pmu)
                return -ENOMEM;
 
-       cpumask_set_cpu(cpu, &pmu->supported_cpus);
-
        per_cpu(probed_pmus, cpu) = pmu;
 
-       /*
-        * Log and request the IRQ so the core arm_pmu code can manage it.  In
-        * some situations (e.g. mismatched PPIs), we may fail to request the
-        * IRQ. However, it may be too late for us to do anything about it.
-        * The common ARM PMU code will log a warning in this case.
-        */
-       hw_events = pmu->hw_events;
-       per_cpu(hw_events->irq, cpu) = irq;
-       armpmu_request_irq(pmu, cpu);
+       if (pmu_irq_matches(pmu, irq)) {
+               hw_events = pmu->hw_events;
+               per_cpu(hw_events->irq, cpu) = irq;
+       }
+
+       cpumask_set_cpu(cpu, &pmu->supported_cpus);
 
        /*
         * Ideally, we'd probe the PMU here when we find the first matching
@@ -247,11 +279,6 @@ static int arm_pmu_acpi_init(void)
        if (acpi_disabled)
                return 0;
 
-       /*
-        * We can't request IRQs yet, since we don't know the cookie value
-        * until we know which CPUs share the same logical PMU. We'll handle
-        * that in arm_pmu_acpi_cpu_starting().
-        */
        ret = arm_pmu_acpi_parse_irqs();
        if (ret)
                return ret;