Perf: Add DT support for L1 and L2 PMU
Add device tree bindings for L1 and L2 performance
monitoring units.
CRs-Fixed: 430010
Change-Id: Ia10e21a445e9daa6b2e4a3f1dba4881e3e7b2ccb
Signed-off-by: Ashwin Chaugule <ashwinc@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/arm/msm/pmu.txt b/Documentation/devicetree/bindings/arm/msm/pmu.txt
new file mode 100644
index 0000000..0bd5e58
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/msm/pmu.txt
@@ -0,0 +1,40 @@
+* Qcom Performance Monitor Units
+Qcom cores have several PMUs for counting CPU side, L2 and bus side events.
+
+For the L1CC PMU:
+In most cases the L1 cache controller PMU is a per cpu unit. The irq-is-percpu
+flag becomes a requirement if this is the case.
+
+Required Properties:
+
+- compatible : Should be "qcom,krait-pmu"
+- interrupts : 1 combined interrupt or 1 per core. See the devicetree/bindings/gic.txt for more details on this format.
+
+Optional:
+
+- qcom,irq-is-percpu: Define this if the IRQ of the PMU is a PPI. This will tell perf to use
+ the per_cpu IRQ API for request and free.
+
+Example:
+
+ arm-pmu {
+ compatible = "qcom,krait-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+For the L2CC PMU:
+If the L2 cache controller PMU is available, its DT bindings should be defined as
+follows.
+
+Required Properties:
+
+- compatible: Should be "qcom,l2-pmu"
+- interrupts : 1 combined interrupt.
+
+Example:
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
diff --git a/arch/arm/boot/dts/msm8974.dtsi b/arch/arm/boot/dts/msm8974.dtsi
index 1922591..0ef6791 100644
--- a/arch/arm/boot/dts/msm8974.dtsi
+++ b/arch/arm/boot/dts/msm8974.dtsi
@@ -1320,6 +1320,17 @@
reg = <0xfa00000 0x200000>;
status = "disable";
};
+
+ cpu-pmu {
+ compatible = "qcom,krait-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0xf00>;
+ };
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
};
&gdsc_venus {
diff --git a/arch/arm/boot/dts/msm9625.dtsi b/arch/arm/boot/dts/msm9625.dtsi
index e1501ac..eb216e2 100644
--- a/arch/arm/boot/dts/msm9625.dtsi
+++ b/arch/arm/boot/dts/msm9625.dtsi
@@ -731,6 +731,17 @@
status = "disable";
};
+ cpu-pmu {
+ compatible = "arm,cortex-a5-pmu";
+ qcom,irq-is-percpu;
+ interrupts = <1 7 0x00>;
+ };
+
+ l2-pmu {
+ compatible = "qcom,l2-pmu";
+ interrupts = <0 1 0>;
+ };
+
};
/include/ "msm-pm8019-rpm-regulator.dtsi"
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index d1a3e61..e1fc42f 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -52,6 +52,10 @@
void (*disable_irq)(int irq);
};
+extern int multicore_request_irq(int irq, irq_handler_t *handle_irq);
+extern void multicore_free_irq(int irq);
+extern struct arm_pmu_platdata multicore_data;
+
#ifdef CONFIG_CPU_HAS_PMU
/**
@@ -151,9 +155,6 @@
struct hw_perf_event *hwc,
int idx);
-extern void enable_irq_callback(void *);
-extern void disable_irq_callback(void *);
-
#endif /* CONFIG_HW_PERF_EVENTS */
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 5311d74..cef66ec 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -21,6 +21,7 @@
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/irq.h>
+#include <linux/of.h>
#include <asm/cputype.h>
#include <asm/irq.h>
@@ -51,6 +52,8 @@
/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *cpu_pmu;
+static int per_cpu_irq;
+
enum arm_perf_pmu_ids
armpmu_get_pmu_id(void)
{
@@ -381,6 +384,58 @@
return plat->handle_irq(irq, dev, armpmu->handle_irq);
}
+static DEFINE_PER_CPU(u32, pmu_irq_cookie);
+
+void enable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
+}
+
+void disable_irq_callback(void *info)
+{
+ int irq = *(unsigned int *)info;
+ disable_percpu_irq(irq);
+}
+
+int
+multicore_request_irq(int irq, irq_handler_t *handle_irq)
+{
+ int err = 0;
+ int cpu;
+
+ err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
+ &pmu_irq_cookie);
+
+ if (!err) {
+ for_each_cpu(cpu, cpu_online_mask) {
+ smp_call_function_single(cpu,
+ enable_irq_callback, &irq, 1);
+ }
+ }
+
+ return err;
+}
+
+void
+multicore_free_irq(int irq)
+{
+ int cpu;
+
+ if (irq >= 0) {
+ for_each_cpu(cpu, cpu_online_mask) {
+ smp_call_function_single(cpu,
+ disable_irq_callback, &irq, 1);
+ }
+ free_percpu_irq(irq, &pmu_irq_cookie);
+ }
+}
+
+struct arm_pmu_platdata multicore_data = {
+ .request_pmu_irq = multicore_request_irq,
+ .free_pmu_irq = multicore_free_irq,
+};
+
int
armpmu_generic_request_irq(int irq, irq_handler_t *handle_irq)
{
@@ -689,11 +744,12 @@
{.compatible = "arm,cortex-a8-pmu"},
{.compatible = "arm,arm1136-pmu"},
{.compatible = "arm,arm1176-pmu"},
+ {.compatible = "qcom,krait-pmu"},
{},
};
static struct platform_device_id armpmu_plat_device_ids[] = {
- {.name = "cpu-arm-pmu"},
+ {.name = "cpu-pmu"},
{},
};
@@ -703,12 +759,16 @@
return -ENODEV;
cpu_pmu->plat_device = pdev;
+
+ if (per_cpu_irq == 1)
+ cpu_pmu->plat_device->dev.platform_data = &multicore_data;
+
return 0;
}
static struct platform_driver armpmu_driver = {
.driver = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.of_match_table = armpmu_of_device_ids,
},
.probe = armpmu_device_probe,
@@ -756,18 +816,6 @@
return 0;
}
-void enable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING);
-}
-
-void disable_irq_callback(void *info)
-{
- int irq = *(unsigned int *)info;
- disable_percpu_irq(irq);
-}
-
/*
* PMU hardware loses all context when a CPU goes offline.
* When a CPU is hotplugged back in, since some hardware registers are
@@ -881,6 +929,24 @@
.notifier_call = perf_cpu_pm_notifier,
};
+#ifdef CONFIG_OF
+static inline int get_dt_irq_prop(void)
+{
+ struct device_node *np = NULL;
+ int err = -1;
+
+ np = of_find_matching_node(NULL, armpmu_of_device_ids);
+ if (np)
+ err = of_property_read_bool(np, "qcom,irq-is-percpu");
+ else
+ pr_err("Perf: can't find DT node.\n");
+
+ return err;
+}
+#else
+static inline int get_dt_irq_prop(void) {return 0; }
+#endif
+
/*
* CPU PMU identification and registration.
*/
@@ -956,6 +1022,8 @@
register_cpu_notifier(&pmu_cpu_notifier);
armpmu_register(cpu_pmu, "cpu", PERF_TYPE_RAW);
cpu_pm_register_notifier(&perf_cpu_pm_notifier_block);
+ per_cpu_irq = get_dt_irq_prop();
+
} else {
pr_info("no hardware support available\n");
}
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index cb5e712..ea3c60a 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -29,15 +29,17 @@
obj-$(CONFIG_DEBUG_FS) += acpuclock-krait-debug.o
endif
obj-$(CONFIG_ARCH_MSM7X27) += acpuclock-7627.o acpuclock-8625q.o clock-pll.o
-obj-$(CONFIG_ARCH_MSM_SCORPION) += pmu.o
obj-$(CONFIG_ARCH_MSM_SCORPIONMP) += perf_event_msm_l2.o
-obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o pmu.o perf_event_msm_krait_l2.o
+ifndef CONFIG_OF
+obj-$(CONFIG_HW_PERF_EVENTS) += pmu.o
+endif
+obj-$(CONFIG_ARCH_MSM_KRAIT) += msm-krait-l2-accessors.o perf_event_msm_krait_l2.o
obj-$(CONFIG_ARCH_MSM_KRAIT) += krait-scm.o
ifdef CONFIG_HW_PERF_EVENTS
-obj-$(CONFIG_ARCH_MSM7X27A) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM8625) += pmu.o perf_event_msm_pl310.o
-obj-$(CONFIG_ARCH_MSM9615) += pmu.o perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM7X27A) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM8625) += perf_event_msm_pl310.o
+obj-$(CONFIG_ARCH_MSM9615) += perf_event_msm_pl310.o
obj-$(CONFIG_DEBUG_FS) += perf_debug.o
endif
diff --git a/arch/arm/mach-msm/perf_debug.c b/arch/arm/mach-msm/perf_debug.c
index 0579145..7f2f528 100644
--- a/arch/arm/mach-msm/perf_debug.c
+++ b/arch/arm/mach-msm/perf_debug.c
@@ -27,6 +27,7 @@
"2 Perf: Toggle PMU IRQ when CPU's are hotplugged\n"
"3 Perf: Correct irq for CPU hotplug detection\n"
"4 Perf: Check perf activity on correct CPU\n"
+ "5 Perf: Add DT support for L1 and L2 PMU\n"
;
static ssize_t desc_read(struct file *fp, char __user *buf,
diff --git a/arch/arm/mach-msm/perf_event_msm_krait_l2.c b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
index 34b9426..ad34457 100644
--- a/arch/arm/mach-msm/perf_event_msm_krait_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_krait_l2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -564,6 +564,14 @@
.pmu.attr_groups = msm_l2_pmu_attr_grps,
};
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+ {.compatible = "qcom,l2-pmu"},
+ {},
+};
+
static int __devinit krait_l2_pmu_device_probe(struct platform_device *pdev)
{
krait_l2_pmu.plat_device = pdev;
@@ -576,7 +584,8 @@
static struct platform_driver krait_l2_pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
+ .of_match_table = l2pmu_of_device_ids,
},
.probe = krait_l2_pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/perf_event_msm_l2.c b/arch/arm/mach-msm/perf_event_msm_l2.c
index f78487a..efd5e21 100644
--- a/arch/arm/mach-msm/perf_event_msm_l2.c
+++ b/arch/arm/mach-msm/perf_event_msm_l2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011, 2012 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2011-2013 The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -917,7 +917,7 @@
static struct platform_driver scorpion_l2_pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
},
.probe = scorpion_l2_pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/perf_event_msm_pl310.c b/arch/arm/mach-msm/perf_event_msm_pl310.c
index e2a580f..a0d96bf 100644
--- a/arch/arm/mach-msm/perf_event_msm_pl310.c
+++ b/arch/arm/mach-msm/perf_event_msm_pl310.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007 ARM Limited
- * Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -415,9 +415,18 @@
return 0;
}
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static struct of_device_id l2pmu_of_device_ids[] = {
+ {.compatible = "qcom,l2-pmu"},
+ {},
+};
+
static struct platform_driver l2x0pmu_driver = {
.driver = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
+ .of_match_table = l2pmu_of_device_ids,
},
.probe = l2x0pmu_device_probe,
};
diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c
index febeb19..57378c7 100644
--- a/arch/arm/mach-msm/pmu.c
+++ b/arch/arm/mach-msm/pmu.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2010-2012, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2010-2013, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -15,62 +15,6 @@
#include <mach/irqs.h>
#include <mach/socinfo.h>
-/*
- * If a GIC is present, then all IRQ's < 32 are PPI's and can only be
- * requested and free'd using the percpu IRQ API.
- * If a VIC is present, then only the traditional request, free API works.
- *
- * All MPCore's have GIC's. The Cortex A5 however may or may not be MPcore, but
- * it still has a GIC. Except, the 7x27a, which is an A5 and yet has a VIC.
- * So if the chip is A5 but does not have a GIC, default to the traditional
- * IRQ {request, free}_irq API.
- */
-
-#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
- || defined(CONFIG_ARCH_MSM8625) || \
- (defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))
-
-static DEFINE_PER_CPU(u32, pmu_irq_cookie);
-
-static int
-multicore_request_irq(int irq, irq_handler_t *handle_irq)
-{
- int err = 0;
- int cpu;
-
- err = request_percpu_irq(irq, *handle_irq, "l1-armpmu",
- &pmu_irq_cookie);
-
- if (!err) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- enable_irq_callback, &irq, 1);
- }
- }
-
- return err;
-}
-
-static void
-multicore_free_irq(int irq)
-{
- int cpu;
-
- if (irq >= 0) {
- for_each_cpu(cpu, cpu_online_mask) {
- smp_call_function_single(cpu,
- disable_irq_callback, &irq, 1);
- }
- free_percpu_irq(irq, &pmu_irq_cookie);
- }
-}
-
-static struct arm_pmu_platdata multicore_data = {
- .request_pmu_irq = multicore_request_irq,
- .free_pmu_irq = multicore_free_irq,
-};
-#endif
-
static struct resource cpu_pmu_resource[] = {
{
.start = INT_ARMQC_PERFMON,
@@ -89,7 +33,7 @@
};
static struct platform_device l2_pmu_device = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
.id = ARM_PMU_DEVICE_L2CC,
.resource = l2_pmu_resource,
.num_resources = ARRAY_SIZE(l2_pmu_resource),
@@ -98,7 +42,7 @@
#endif
static struct platform_device cpu_pmu_device = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.id = ARM_PMU_DEVICE_CPU,
.resource = cpu_pmu_resource,
.num_resources = ARRAY_SIZE(cpu_pmu_resource),
@@ -120,7 +64,7 @@
};
static struct platform_device msm8625_cpu_pmu_device = {
- .name = "cpu-arm-pmu",
+ .name = "cpu-pmu",
.id = ARM_PMU_DEVICE_CPU,
.resource = msm8625_cpu_pmu_resource,
.num_resources = ARRAY_SIZE(msm8625_cpu_pmu_resource),
@@ -135,7 +79,7 @@
};
static struct platform_device msm8625_l2_pmu_device = {
- .name = "l2-arm-pmu",
+ .name = "l2-pmu",
.id = ARM_PMU_DEVICE_L2CC,
.resource = msm8625_l2_pmu_resource,
.num_resources = ARRAY_SIZE(msm8625_l2_pmu_resource),
@@ -156,7 +100,6 @@
* handlers to call the percpu API.
* Defaults to unicore API {request,free}_irq().
* See arch/arm/kernel/perf_event.c
- * See Comment above on the A5 and MSM_VIC.
*/
#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) \
|| (defined(CONFIG_ARCH_MSM_CORTEX_A5) && !defined(CONFIG_MSM_VIC))