OSDN Git Service

ARM: perf: move CPU-specific PMU handling code into separate file
authorWill Deacon <will.deacon@arm.com>
Sun, 29 Jul 2012 12:09:14 +0000 (13:09 +0100)
committerWill Deacon <will.deacon@arm.com>
Thu, 23 Aug 2012 10:35:52 +0000 (11:35 +0100)
This patch moves the CPU-specific PMU handling code out of perf_event.c
and into perf_event_cpu.c.

Signed-off-by: Will Deacon <will.deacon@arm.com>
arch/arm/kernel/Makefile
arch/arm/kernel/perf_event.c
arch/arm/kernel/perf_event_cpu.c [new file with mode: 0644]

index cfbe3b4..1c43214 100644 (file)
@@ -69,7 +69,7 @@ obj-$(CONFIG_CPU_XSC3)                += xscale-cp0.o
 obj-$(CONFIG_CPU_MOHAWK)       += xscale-cp0.o
 obj-$(CONFIG_CPU_PJ4)          += pj4-cp0.o
 obj-$(CONFIG_IWMMXT)           += iwmmxt.o
-obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o
+obj-$(CONFIG_HW_PERF_EVENTS)   += perf_event.o perf_event_cpu.o
 AFLAGS_iwmmxt.o                        := -Wa,-mcpu=iwmmxt
 obj-$(CONFIG_ARM_CPU_TOPOLOGY)  += topology.o
 
index 9e3afd1..86fd399 100644 (file)
  */
 #define pr_fmt(fmt) "hw perfevents: " fmt
 
-#include <linux/bitmap.h>
-#include <linux/interrupt.h>
 #include <linux/kernel.h>
-#include <linux/export.h>
-#include <linux/of.h>
-#include <linux/perf_event.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/pm_runtime.h>
+#include <linux/uaccess.h>
 
-#include <asm/cputype.h>
-#include <asm/irq.h>
 #include <asm/irq_regs.h>
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
-/* Set at runtime when we know what CPU type we are. */
-static struct arm_pmu *cpu_pmu;
-
-static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
-static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
-static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
-
-/*
- * Despite the names, these two functions are CPU-specific and are used
- * by the OProfile/perf code.
- */
-const char *perf_pmu_name(void)
-{
-       if (!cpu_pmu)
-               return NULL;
-
-       return cpu_pmu->pmu.name;
-}
-EXPORT_SYMBOL_GPL(perf_pmu_name);
-
-int perf_num_counters(void)
-{
-       int max_events = 0;
-
-       if (cpu_pmu != NULL)
-               max_events = cpu_pmu->num_events;
-
-       return max_events;
-}
-EXPORT_SYMBOL_GPL(perf_num_counters);
-
 static int
 armpmu_map_cache_event(const unsigned (*cache_map)
                                      [PERF_COUNT_HW_CACHE_MAX]
@@ -608,176 +569,6 @@ int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
        return perf_pmu_register(&armpmu->pmu, name, type);
 }
 
-/* Include the PMU-specific implementations. */
-#include "perf_event_xscale.c"
-#include "perf_event_v6.c"
-#include "perf_event_v7.c"
-
-static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
-{
-       return &__get_cpu_var(cpu_hw_events);
-}
-
-static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
-{
-       int cpu;
-       for_each_possible_cpu(cpu) {
-               struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
-               events->events = per_cpu(hw_events, cpu);
-               events->used_mask = per_cpu(used_mask, cpu);
-               raw_spin_lock_init(&events->pmu_lock);
-       }
-       cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events;
-
-       /* Ensure the PMU has sane values out of reset. */
-       if (cpu_pmu && cpu_pmu->reset)
-               on_each_cpu(cpu_pmu->reset, NULL, 1);
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
-                                   unsigned long action, void *hcpu)
-{
-       if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
-               return NOTIFY_DONE;
-
-       if (cpu_pmu && cpu_pmu->reset)
-               cpu_pmu->reset(NULL);
-
-       return NOTIFY_OK;
-}
-
-static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
-       .notifier_call = cpu_pmu_notify,
-};
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
-       {.compatible = "arm,cortex-a15-pmu",    .data = armv7_a15_pmu_init},
-       {.compatible = "arm,cortex-a9-pmu",     .data = armv7_a9_pmu_init},
-       {.compatible = "arm,cortex-a8-pmu",     .data = armv7_a8_pmu_init},
-       {.compatible = "arm,cortex-a7-pmu",     .data = armv7_a7_pmu_init},
-       {.compatible = "arm,cortex-a5-pmu",     .data = armv7_a5_pmu_init},
-       {.compatible = "arm,arm11mpcore-pmu",   .data = armv6mpcore_pmu_init},
-       {.compatible = "arm,arm1176-pmu",       .data = armv6pmu_init},
-       {.compatible = "arm,arm1136-pmu",       .data = armv6pmu_init},
-       {},
-};
-
-static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
-       {.name = "arm-pmu"},
-       {},
-};
-
-/*
- * CPU PMU identification and probing.
- */
-static struct arm_pmu *__devinit probe_current_pmu(void)
-{
-       struct arm_pmu *pmu = NULL;
-       int cpu = get_cpu();
-       unsigned long cpuid = read_cpuid_id();
-       unsigned long implementor = (cpuid & 0xFF000000) >> 24;
-       unsigned long part_number = (cpuid & 0xFFF0);
-
-       pr_info("probing PMU on CPU %d\n", cpu);
-
-       /* ARM Ltd CPUs. */
-       if (0x41 == implementor) {
-               switch (part_number) {
-               case 0xB360:    /* ARM1136 */
-               case 0xB560:    /* ARM1156 */
-               case 0xB760:    /* ARM1176 */
-                       pmu = armv6pmu_init();
-                       break;
-               case 0xB020:    /* ARM11mpcore */
-                       pmu = armv6mpcore_pmu_init();
-                       break;
-               case 0xC080:    /* Cortex-A8 */
-                       pmu = armv7_a8_pmu_init();
-                       break;
-               case 0xC090:    /* Cortex-A9 */
-                       pmu = armv7_a9_pmu_init();
-                       break;
-               case 0xC050:    /* Cortex-A5 */
-                       pmu = armv7_a5_pmu_init();
-                       break;
-               case 0xC0F0:    /* Cortex-A15 */
-                       pmu = armv7_a15_pmu_init();
-                       break;
-               case 0xC070:    /* Cortex-A7 */
-                       pmu = armv7_a7_pmu_init();
-                       break;
-               }
-       /* Intel CPUs [xscale]. */
-       } else if (0x69 == implementor) {
-               part_number = (cpuid >> 13) & 0x7;
-               switch (part_number) {
-               case 1:
-                       pmu = xscale1pmu_init();
-                       break;
-               case 2:
-                       pmu = xscale2pmu_init();
-                       break;
-               }
-       }
-
-       put_cpu();
-       return pmu;
-}
-
-static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
-{
-       const struct of_device_id *of_id;
-       struct arm_pmu *(*init_fn)(void);
-       struct device_node *node = pdev->dev.of_node;
-
-       if (cpu_pmu) {
-               pr_info("attempt to register multiple PMU devices!");
-               return -ENOSPC;
-       }
-
-       if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
-               init_fn = of_id->data;
-               cpu_pmu = init_fn();
-       } else {
-               cpu_pmu = probe_current_pmu();
-       }
-
-       if (!cpu_pmu)
-               return -ENODEV;
-
-       cpu_pmu->plat_device = pdev;
-       cpu_pmu_init(cpu_pmu);
-       register_cpu_notifier(&cpu_pmu_hotplug_notifier);
-       armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
-
-       return 0;
-}
-
-static struct platform_driver cpu_pmu_driver = {
-       .driver         = {
-               .name   = "arm-pmu",
-               .pm     = &armpmu_dev_pm_ops,
-               .of_match_table = cpu_pmu_of_device_ids,
-       },
-       .probe          = cpu_pmu_device_probe,
-       .id_table       = cpu_pmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
-       return platform_driver_register(&cpu_pmu_driver);
-}
-device_initcall(register_pmu_driver);
-
 /*
  * Callchain handling code.
  */
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
new file mode 100644 (file)
index 0000000..56ddc98
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+#define pr_fmt(fmt) "CPU PMU: " fmt
+
+#include <linux/bitmap.h>
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <asm/cputype.h>
+#include <asm/irq_regs.h>
+#include <asm/pmu.h>
+
+/* Set at runtime when we know what CPU type we are. */
+static struct arm_pmu *cpu_pmu;
+
+static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
+static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
+static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
+
+/*
+ * Despite the names, these two functions are CPU-specific and are used
+ * by the OProfile/perf code.
+ */
+const char *perf_pmu_name(void)
+{
+       if (!cpu_pmu)
+               return NULL;
+
+       return cpu_pmu->pmu.name;
+}
+EXPORT_SYMBOL_GPL(perf_pmu_name);
+
+int perf_num_counters(void)
+{
+       int max_events = 0;
+
+       if (cpu_pmu != NULL)
+               max_events = cpu_pmu->num_events;
+
+       return max_events;
+}
+EXPORT_SYMBOL_GPL(perf_num_counters);
+
+/* Include the PMU-specific implementations. */
+#include "perf_event_xscale.c"
+#include "perf_event_v6.c"
+#include "perf_event_v7.c"
+
+static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
+{
+       return &__get_cpu_var(cpu_hw_events);
+}
+
+static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
+{
+       int cpu;
+       for_each_possible_cpu(cpu) {
+               struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
+               events->events = per_cpu(hw_events, cpu);
+               events->used_mask = per_cpu(used_mask, cpu);
+               raw_spin_lock_init(&events->pmu_lock);
+       }
+       cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events;
+
+       /* Ensure the PMU has sane values out of reset. */
+       if (cpu_pmu && cpu_pmu->reset)
+               on_each_cpu(cpu_pmu->reset, NULL, 1);
+}
+
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int __cpuinit cpu_pmu_notify(struct notifier_block *b,
+                                   unsigned long action, void *hcpu)
+{
+       if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+               return NOTIFY_DONE;
+
+       if (cpu_pmu && cpu_pmu->reset)
+               cpu_pmu->reset(NULL);
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata cpu_pmu_hotplug_notifier = {
+       .notifier_call = cpu_pmu_notify,
+};
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
+       {.compatible = "arm,cortex-a15-pmu",    .data = armv7_a15_pmu_init},
+       {.compatible = "arm,cortex-a9-pmu",     .data = armv7_a9_pmu_init},
+       {.compatible = "arm,cortex-a8-pmu",     .data = armv7_a8_pmu_init},
+       {.compatible = "arm,cortex-a7-pmu",     .data = armv7_a7_pmu_init},
+       {.compatible = "arm,cortex-a5-pmu",     .data = armv7_a5_pmu_init},
+       {.compatible = "arm,arm11mpcore-pmu",   .data = armv6mpcore_pmu_init},
+       {.compatible = "arm,arm1176-pmu",       .data = armv6pmu_init},
+       {.compatible = "arm,arm1136-pmu",       .data = armv6pmu_init},
+       {},
+};
+
+static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
+       {.name = "arm-pmu"},
+       {},
+};
+
+/*
+ * CPU PMU identification and probing.
+ */
+static struct arm_pmu *__devinit probe_current_pmu(void)
+{
+       struct arm_pmu *pmu = NULL;
+       int cpu = get_cpu();
+       unsigned long cpuid = read_cpuid_id();
+       unsigned long implementor = (cpuid & 0xFF000000) >> 24;
+       unsigned long part_number = (cpuid & 0xFFF0);
+
+       pr_info("probing PMU on CPU %d\n", cpu);
+
+       /* ARM Ltd CPUs. */
+       if (0x41 == implementor) {
+               switch (part_number) {
+               case 0xB360:    /* ARM1136 */
+               case 0xB560:    /* ARM1156 */
+               case 0xB760:    /* ARM1176 */
+                       pmu = armv6pmu_init();
+                       break;
+               case 0xB020:    /* ARM11mpcore */
+                       pmu = armv6mpcore_pmu_init();
+                       break;
+               case 0xC080:    /* Cortex-A8 */
+                       pmu = armv7_a8_pmu_init();
+                       break;
+               case 0xC090:    /* Cortex-A9 */
+                       pmu = armv7_a9_pmu_init();
+                       break;
+               case 0xC050:    /* Cortex-A5 */
+                       pmu = armv7_a5_pmu_init();
+                       break;
+               case 0xC0F0:    /* Cortex-A15 */
+                       pmu = armv7_a15_pmu_init();
+                       break;
+               case 0xC070:    /* Cortex-A7 */
+                       pmu = armv7_a7_pmu_init();
+                       break;
+               }
+       /* Intel CPUs [xscale]. */
+       } else if (0x69 == implementor) {
+               part_number = (cpuid >> 13) & 0x7;
+               switch (part_number) {
+               case 1:
+                       pmu = xscale1pmu_init();
+                       break;
+               case 2:
+                       pmu = xscale2pmu_init();
+                       break;
+               }
+       }
+
+       put_cpu();
+       return pmu;
+}
+
+static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id;
+       struct arm_pmu *(*init_fn)(void);
+       struct device_node *node = pdev->dev.of_node;
+
+       if (cpu_pmu) {
+               pr_info("attempt to register multiple PMU devices!");
+               return -ENOSPC;
+       }
+
+       if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
+               init_fn = of_id->data;
+               cpu_pmu = init_fn();
+       } else {
+               cpu_pmu = probe_current_pmu();
+       }
+
+       if (!cpu_pmu)
+               return -ENODEV;
+
+       cpu_pmu->plat_device = pdev;
+       cpu_pmu_init(cpu_pmu);
+       register_cpu_notifier(&cpu_pmu_hotplug_notifier);
+       armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+
+       return 0;
+}
+
+static struct platform_driver cpu_pmu_driver = {
+       .driver         = {
+               .name   = "arm-pmu",
+               .pm     = &armpmu_dev_pm_ops,
+               .of_match_table = cpu_pmu_of_device_ids,
+       },
+       .probe          = cpu_pmu_device_probe,
+       .id_table       = cpu_pmu_plat_device_ids,
+};
+
+static int __init register_pmu_driver(void)
+{
+       return platform_driver_register(&cpu_pmu_driver);
+}
+device_initcall(register_pmu_driver);