linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
From: will.deacon@arm.com (Will Deacon)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 6/9] ARM: perf: probe devicetree in preference to current CPU
Date: Fri, 10 Aug 2012 18:36:32 +0100	[thread overview]
Message-ID: <1344620195-22372-7-git-send-email-will.deacon@arm.com> (raw)
In-Reply-To: <1344620195-22372-1-git-send-email-will.deacon@arm.com>

The CPU PMU is probed using the current cpuid information as part of the
early_initcall initialising the architecture perf backend. For
architectures without NMI (such as ARM), this does not need to be
performed early and can be deferred to the driver probe callback. This
also allows us to probe the devicetree in preference to parsing the
current cpuid, which may be invalid on a big.LITTLE multi-cluster
system.

This patch defers the PMU probing and uses the devicetree information
when available.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/kernel/perf_event.c        |  175 ++++++++++++++++++-----------------
 arch/arm/kernel/perf_event_v6.c     |    8 +-
 arch/arm/kernel/perf_event_v7.c     |   22 ++--
 arch/arm/kernel/perf_event_xscale.c |    8 +-
 4 files changed, 110 insertions(+), 103 deletions(-)

diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 22ed512..7c29914 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -16,6 +16,7 @@
 #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>
@@ -610,9 +611,11 @@ static void __init armpmu_init(struct arm_pmu *armpmu)
 	};
 }
 
-int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
+int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 {
 	armpmu_init(armpmu);
+	pr_info("enabled with %s PMU driver, %d counters available\n",
+			armpmu->name, armpmu->num_events);
 	return perf_pmu_register(&armpmu->pmu, name, type);
 }
 
@@ -621,74 +624,12 @@ int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
 #include "perf_event_v6.c"
 #include "perf_event_v7.c"
 
-/*
- * Ensure the PMU has sane values out of reset.
- * This requires SMP to be available, so exists as a separate initcall.
- */
-static int __init
-cpu_pmu_reset(void)
-{
-	if (cpu_pmu && cpu_pmu->reset)
-		return on_each_cpu(cpu_pmu->reset, NULL, 1);
-	return 0;
-}
-arch_initcall(cpu_pmu_reset);
-
-/*
- * PMU platform driver and devicetree bindings.
- */
-static struct of_device_id armpmu_of_device_ids[] = {
-	{.compatible = "arm,cortex-a15-pmu"},
-	{.compatible = "arm,cortex-a9-pmu"},
-	{.compatible = "arm,cortex-a8-pmu"},
-	{.compatible = "arm,cortex-a7-pmu"},
-	{.compatible = "arm,cortex-a5-pmu"},
-	{.compatible = "arm,arm11mpcore-pmu"},
-	{.compatible = "arm,arm1176-pmu"},
-	{.compatible = "arm,arm1136-pmu"},
-	{},
-};
-
-static struct platform_device_id armpmu_plat_device_ids[] = {
-	{.name = "arm-pmu"},
-	{},
-};
-
-static int __devinit armpmu_device_probe(struct platform_device *pdev)
-{
-	if (!cpu_pmu)
-		return -ENODEV;
-
-	cpu_pmu->plat_device = pdev;
-	return 0;
-}
-
-static const struct dev_pm_ops armpmu_dev_pm_ops = {
-	SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
-};
-
-static struct platform_driver armpmu_driver = {
-	.driver		= {
-		.name	= "arm-pmu",
-		.pm	= &armpmu_dev_pm_ops,
-		.of_match_table = armpmu_of_device_ids,
-	},
-	.probe		= armpmu_device_probe,
-	.id_table	= armpmu_plat_device_ids,
-};
-
-static int __init register_pmu_driver(void)
-{
-	return platform_driver_register(&armpmu_driver);
-}
-device_initcall(register_pmu_driver);
-
 static struct pmu_hw_events *armpmu_get_cpu_events(void)
 {
 	return &__get_cpu_var(cpu_hw_events);
 }
 
-static void __init cpu_pmu_init(struct arm_pmu *armpmu)
+static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
 {
 	int cpu;
 	for_each_possible_cpu(cpu) {
@@ -697,7 +638,11 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu)
 		events->used_mask = per_cpu(used_mask, cpu);
 		raw_spin_lock_init(&events->pmu_lock);
 	}
-	armpmu->get_hw_events = armpmu_get_cpu_events;
+	cpu_pmu->get_hw_events = armpmu_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);
 }
 
 /*
@@ -722,41 +667,68 @@ static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
 	.notifier_call = pmu_cpu_notify,
 };
 
+static const struct dev_pm_ops armpmu_dev_pm_ops = {
+	SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
+};
+
+/*
+ * 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 registration.
+ * CPU PMU identification and probing.
  */
-static int __init
-init_hw_perf_events(void)
+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 */
-			cpu_pmu = armv6pmu_init();
+			pmu = armv6pmu_init();
 			break;
 		case 0xB020:	/* ARM11mpcore */
-			cpu_pmu = armv6mpcore_pmu_init();
+			pmu = armv6mpcore_pmu_init();
 			break;
 		case 0xC080:	/* Cortex-A8 */
-			cpu_pmu = armv7_a8_pmu_init();
+			pmu = armv7_a8_pmu_init();
 			break;
 		case 0xC090:	/* Cortex-A9 */
-			cpu_pmu = armv7_a9_pmu_init();
+			pmu = armv7_a9_pmu_init();
 			break;
 		case 0xC050:	/* Cortex-A5 */
-			cpu_pmu = armv7_a5_pmu_init();
+			pmu = armv7_a5_pmu_init();
 			break;
 		case 0xC0F0:	/* Cortex-A15 */
-			cpu_pmu = armv7_a15_pmu_init();
+			pmu = armv7_a15_pmu_init();
 			break;
 		case 0xC070:	/* Cortex-A7 */
-			cpu_pmu = armv7_a7_pmu_init();
+			pmu = armv7_a7_pmu_init();
 			break;
 		}
 	/* Intel CPUs [xscale]. */
@@ -764,27 +736,62 @@ init_hw_perf_events(void)
 		part_number = (cpuid >> 13) & 0x7;
 		switch (part_number) {
 		case 1:
-			cpu_pmu = xscale1pmu_init();
+			pmu = xscale1pmu_init();
 			break;
 		case 2:
-			cpu_pmu = xscale2pmu_init();
+			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("enabled with %s PMU driver, %d counters available\n",
-			cpu_pmu->name, cpu_pmu->num_events);
-		cpu_pmu_init(cpu_pmu);
-		register_cpu_notifier(&pmu_cpu_notifier);
-		armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+		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 {
-		pr_info("no hardware support available\n");
+		cpu_pmu = probe_current_pmu();
 	}
 
+	if (!cpu_pmu)
+		return -ENODEV;
+
+	cpu_pmu->plat_device = pdev;
+	cpu_pmu_init(cpu_pmu);
+	register_cpu_notifier(&pmu_cpu_notifier);
+	armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
+
 	return 0;
 }
-early_initcall(init_hw_perf_events);
+
+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_v6.c b/arch/arm/kernel/perf_event_v6.c
index c90fcb2..a4328b1 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -664,7 +664,7 @@ static struct arm_pmu armv6pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return &armv6pmu;
 }
@@ -698,17 +698,17 @@ static struct arm_pmu armv6mpcore_pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return &armv6mpcore_pmu;
 }
 #else
-static struct arm_pmu *__init armv6pmu_init(void)
+static struct arm_pmu *__devinit armv6pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv6mpcore_pmu_init(void)
+static struct arm_pmu *__devinit armv6mpcore_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index f04070b..d65a1b8 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -1245,7 +1245,7 @@ static struct arm_pmu armv7pmu = {
 	.max_period		= (1LLU << 32) - 1,
 };
 
-static u32 __init armv7_read_num_pmnc_events(void)
+static u32 __devinit armv7_read_num_pmnc_events(void)
 {
 	u32 nb_cnt;
 
@@ -1256,7 +1256,7 @@ static u32 __init armv7_read_num_pmnc_events(void)
 	return nb_cnt + 1;
 }
 
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A8";
 	armv7pmu.map_event	= armv7_a8_map_event;
@@ -1264,7 +1264,7 @@ static struct arm_pmu *__init armv7_a8_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A9";
 	armv7pmu.map_event	= armv7_a9_map_event;
@@ -1272,7 +1272,7 @@ static struct arm_pmu *__init armv7_a9_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A5";
 	armv7pmu.map_event	= armv7_a5_map_event;
@@ -1280,7 +1280,7 @@ static struct arm_pmu *__init armv7_a5_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A15";
 	armv7pmu.map_event	= armv7_a15_map_event;
@@ -1289,7 +1289,7 @@ static struct arm_pmu *__init armv7_a15_pmu_init(void)
 	return &armv7pmu;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	armv7pmu.name		= "ARMv7 Cortex-A7";
 	armv7pmu.map_event	= armv7_a7_map_event;
@@ -1298,27 +1298,27 @@ static struct arm_pmu *__init armv7_a7_pmu_init(void)
 	return &armv7pmu;
 }
 #else
-static struct arm_pmu *__init armv7_a8_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a8_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a9_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a9_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a5_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a5_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a15_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a15_pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init armv7_a7_pmu_init(void)
+static struct arm_pmu *__devinit armv7_a7_pmu_init(void)
 {
 	return NULL;
 }
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index f759fe0..dcc478c 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -449,7 +449,7 @@ static struct arm_pmu xscale1pmu = {
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return &xscale1pmu;
 }
@@ -816,17 +816,17 @@ static struct arm_pmu xscale2pmu = {
 	.max_period	= (1LLU << 32) - 1,
 };
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return &xscale2pmu;
 }
 #else
-static struct arm_pmu *__init xscale1pmu_init(void)
+static struct arm_pmu *__devinit xscale1pmu_init(void)
 {
 	return NULL;
 }
 
-static struct arm_pmu *__init xscale2pmu_init(void)
+static struct arm_pmu *__devinit xscale2pmu_init(void)
 {
 	return NULL;
 }
-- 
1.7.4.1

  parent reply	other threads:[~2012-08-10 17:36 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-08-10 17:36 [PATCH 0/9] ARM perf updates for 3.7 Will Deacon
2012-08-10 17:36 ` [PATCH 1/9] ARM: PMU: Add runtime PM Support Will Deacon
2012-08-11 15:09   ` Ming Lei
2012-08-13 10:40     ` Will Deacon
2012-08-16 13:56       ` Jon Hunter
2012-08-10 17:36 ` [PATCH 2/9] ARM: perf: add devicetree bindings for 11MPcore, A5, A7 and A15 PMUs Will Deacon
2012-08-10 18:42   ` Rob Herring
2012-08-10 17:36 ` [PATCH 3/9] ARM: pmu: remove unused reservation mechanism Will Deacon
2012-08-10 17:36 ` [PATCH 4/9] ARM: pmu: remove arm_pmu_type enumeration Will Deacon
2012-08-13 14:17   ` Linus Walleij
2012-08-13 21:57   ` Jiandong Zheng
2012-08-14  8:43     ` Sudeep KarkadaNagesha
2012-08-14 16:53       ` Jiandong Zheng
2012-08-16 13:59   ` Jon Hunter
2012-08-17 14:08   ` Jon Hunter
2012-08-20  9:01     ` Will Deacon
2012-08-20 13:05       ` Jon Hunter
2012-08-23  5:45   ` Kukjin Kim
2012-08-10 17:36 ` [PATCH 5/9] ARM: perf: remove mysterious compiler barrier Will Deacon
2012-08-10 17:36 ` Will Deacon [this message]
2012-08-10 17:36 ` [PATCH 7/9] ARM: perf: prepare for moving CPU PMU code into separate file Will Deacon
2012-08-10 17:36 ` [PATCH 8/9] ARM: perf: move CPU-specific PMU handling " Will Deacon
2012-08-10 17:36 ` [PATCH 9/9] ARM: perf: move irq registration into pmu implementation Will Deacon
2012-08-13  9:11 ` [PATCH 0/9] ARM perf updates for 3.7 Hui Wang
2012-08-13  9:32   ` Will Deacon
2012-08-14  1:46     ` Hui Wang
2013-02-28  6:54       ` i.MX6Quad PMU irq handling (was: Re: [PATCH 0/9] ARM perf updates for 3.7) Dirk Behme
2013-02-28  7:27         ` Shawn Guo
2013-02-28  7:38         ` i.MX6Quad PMU irq handling Hui Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1344620195-22372-7-git-send-email-will.deacon@arm.com \
    --to=will.deacon@arm.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).