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))