linux-arm-kernel.lists.infradead.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH 0/2] ARM: pmu: provide a registration mechanism for IRQs
@ 2010-03-10 14:58 Will Deacon
  2010-03-10 14:58 ` [RFC PATCH 1/2] ARM: pmu: register IRQs at runtime Will Deacon
  0 siblings, 1 reply; 3+ messages in thread
From: Will Deacon @ 2010-03-10 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

This RFC patch was prompted by a discussion with Russell about the PMU IRQs
for the new Versatile Express platform:

http://lists.infradead.org/pipermail/linux-arm-kernel/2010-March/010921.html

The set contains two patches, the second of which is intended purely as an
example to illustrate the usage of the new framework.

All comments welcome.

Cc: Russell King - ARM Linux <linux@arm.linux.org.uk>
Cc: Jamie Iles <jamie.iles@picochip.com>

Will Deacon (2):
  ARM: pmu: register IRQs at runtime
  ARM: Realview-PBX: register PMU IRQs during board initialisation

 arch/arm/include/asm/pmu.h            |   36 ++++++++---
 arch/arm/kernel/perf_event.c          |    6 +-
 arch/arm/kernel/pmu.c                 |  103 ++++++++++++++++++---------------
 arch/arm/mach-realview/realview_pbx.c |   15 +++++
 4 files changed, 101 insertions(+), 59 deletions(-)

^ permalink raw reply	[flat|nested] 3+ messages in thread

* [RFC PATCH 1/2] ARM: pmu: register IRQs at runtime
  2010-03-10 14:58 [RFC PATCH 0/2] ARM: pmu: provide a registration mechanism for IRQs Will Deacon
@ 2010-03-10 14:58 ` Will Deacon
  2010-03-10 14:58   ` [RFC PATCH 2/2] ARM: Realview-PBX: register PMU IRQs during board initialisation Will Deacon
  0 siblings, 1 reply; 3+ messages in thread
From: Will Deacon @ 2010-03-10 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

The current PMU infrastructure for ARM requires that the IRQs for the PMU
device are fixed at compile time and are selected based on the ARCH_ or MACH_
flags. This has the disadvantage of tying the Kernel down to a particular board
as far as profiling is concerned.

This patch replaces the compile-time IRQ registration with a runtime mechanism
which allows the IRQs to be passed in from the board initialisation files using
the pmu_device_register() function.

A further advantage of this change is that there is scope for registering
different types of performance counters in the future by adding a new field
to the arm_pmu_type enumeration.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/include/asm/pmu.h   |   36 +++++++++++----
 arch/arm/kernel/perf_event.c |    6 +-
 arch/arm/kernel/pmu.c        |  103 +++++++++++++++++++++++-------------------
 3 files changed, 86 insertions(+), 59 deletions(-)

diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 2829b9f..2ded693 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -12,22 +12,38 @@
 #ifndef __ARM_PMU_H__
 #define __ARM_PMU_H__
 
+enum arm_pmu_type {
+	ARM_PMU_DEVICE_CPU = 0,
+	ARM_NUM_PMU_DEVICES,
+};
+
 #ifdef CONFIG_CPU_HAS_PMU
 
 struct pmu_irqs {
-	const int   *irqs;
-	int	    num_irqs;
+	enum arm_pmu_type	device_type;
+	const int		*irqs;
+	int			num_irqs;
 };
 
 /**
+ * pmu_device_register() - register a new counter source with the kernel
+ *
+ * Register a new PMU device and its corresponding IRQs. Only one instance
+ * of each device type may be registered at once, but multiple IRQs can be
+ * specified in the corresponding struct pmu_irqs.
+ */
+void
+pmu_device_register(struct pmu_irqs *device);
+
+/**
  * reserve_pmu() - reserve the hardware performance counters
  *
  * Reserve the hardware performance counters in the system for exclusive use.
  * The 'struct pmu_irqs' for the system is returned on success, ERR_PTR()
  * encoded error on failure.
  */
-extern const struct pmu_irqs *
-reserve_pmu(void);
+extern struct pmu_irqs *
+reserve_pmu(enum arm_pmu_type device);
 
 /**
  * release_pmu() - Relinquish control of the performance counters
@@ -38,7 +54,7 @@ reserve_pmu(void);
  * a cookie.
  */
 extern int
-release_pmu(const struct pmu_irqs *irqs);
+release_pmu(struct pmu_irqs *irqs);
 
 /**
  * init_pmu() - Initialise the PMU.
@@ -48,24 +64,24 @@ release_pmu(const struct pmu_irqs *irqs);
  * the actual hardware initialisation.
  */
 extern int
-init_pmu(void);
+init_pmu(enum arm_pmu_type device);
 
 #else /* CONFIG_CPU_HAS_PMU */
 
-static inline const struct pmu_irqs *
-reserve_pmu(void)
+static inline struct pmu_irqs *
+reserve_pmu(enum arm_pmu_type device)
 {
 	return ERR_PTR(-ENODEV);
 }
 
 static inline int
-release_pmu(const struct pmu_irqs *irqs)
+release_pmu(struct pmu_irqs *irqs)
 {
 	return -ENODEV;
 }
 
 static inline int
-init_pmu(void)
+init_pmu(enum arm_pmu_type device)
 {
 	return -ENODEV;
 }
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index c45a155..752ada2 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -26,7 +26,7 @@
 #include <asm/pmu.h>
 #include <asm/stacktrace.h>
 
-static const struct pmu_irqs *pmu_irqs;
+static struct pmu_irqs *pmu_irqs;
 
 /*
  * Hardware lock to serialize accesses to PMU registers. Needed for the
@@ -317,13 +317,13 @@ armpmu_reserve_hardware(void)
 	int i;
 	int err;
 
-	pmu_irqs = reserve_pmu();
+	pmu_irqs = reserve_pmu(ARM_PMU_DEVICE_CPU);
 	if (IS_ERR(pmu_irqs)) {
 		pr_warning("unable to reserve pmu\n");
 		return PTR_ERR(pmu_irqs);
 	}
 
-	init_pmu();
+	init_pmu(ARM_PMU_DEVICE_CPU);
 
 	if (pmu_irqs->num_irqs < 1) {
 		pr_err("no irqs for PMUs defined\n");
diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c
index a124312..e58412f 100644
--- a/arch/arm/kernel/pmu.c
+++ b/arch/arm/kernel/pmu.c
@@ -2,6 +2,7 @@
  *  linux/arch/arm/kernel/pmu.c
  *
  *  Copyright (C) 2009 picoChip Designs Ltd, Jamie Iles
+ *  Copyright (C) 2010 ARM Ltd, Will Deacon
  *
  * 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
@@ -17,57 +18,48 @@
 
 #include <asm/pmu.h>
 
-/*
- * Define the IRQs for the system. We could use something like a platform
- * device but that seems fairly heavyweight for this. Also, the performance
- * counters can't be removed or hotplugged.
- *
- * Ordering is important: init_pmu() will use the ordering to set the affinity
- * to the corresponding core. e.g. the first interrupt will go to cpu 0, the
- * second goes to cpu 1 etc.
- */
-static const int irqs[] = {
-#if defined(CONFIG_ARCH_OMAP2)
-	3,
-#elif defined(CONFIG_ARCH_BCMRING)
-	IRQ_PMUIRQ,
-#elif defined(CONFIG_MACH_REALVIEW_EB)
-	IRQ_EB11MP_PMU_CPU0,
-	IRQ_EB11MP_PMU_CPU1,
-	IRQ_EB11MP_PMU_CPU2,
-	IRQ_EB11MP_PMU_CPU3,
-#elif defined(CONFIG_ARCH_OMAP3)
-	INT_34XX_BENCH_MPU_EMUL,
-#elif defined(CONFIG_ARCH_IOP32X)
-	IRQ_IOP32X_CORE_PMU,
-#elif defined(CONFIG_ARCH_IOP33X)
-	IRQ_IOP33X_CORE_PMU,
-#elif defined(CONFIG_ARCH_PXA)
-	IRQ_PMU,
-#endif
-};
-
-static const struct pmu_irqs pmu_irqs = {
-	.irqs	    = irqs,
-	.num_irqs   = ARRAY_SIZE(irqs),
-};
+static struct pmu_irqs *pmu_irqs[ARM_NUM_PMU_DEVICES];
 
 static volatile long pmu_lock;
 
-const struct pmu_irqs *
-reserve_pmu(void)
+void pmu_device_register(struct pmu_irqs *device)
 {
-	return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) :
-		&pmu_irqs;
+	int device_type = device->device_type;
+
+	if (pmu_irqs[device_type])
+		pr_warning("pmu: registering new device of type %d overwrites "
+				"previous definition!", device_type);
+	else
+		pr_info("pmu: registered new PMU device of type %d\n",
+				device_type);
+
+	pmu_irqs[device_type] = device;
+}
+
+struct pmu_irqs *
+reserve_pmu(enum arm_pmu_type device)
+{
+	struct pmu_irqs *irqs;
+
+	if (test_and_set_bit_lock(device, &pmu_lock)) {
+		irqs = ERR_PTR(-EBUSY);
+	} else if (pmu_irqs[device] == NULL) {
+		clear_bit_unlock(device, &pmu_lock);
+		irqs = ERR_PTR(-ENODEV);
+	} else {
+		irqs = pmu_irqs[device];
+	}
+
+	return irqs;
 }
 EXPORT_SYMBOL_GPL(reserve_pmu);
 
 int
-release_pmu(const struct pmu_irqs *irqs)
+release_pmu(struct pmu_irqs *irqs)
 {
-	if (WARN_ON(irqs != &pmu_irqs))
+	if (WARN_ON(irqs != pmu_irqs[irqs->device_type]))
 		return -EINVAL;
-	clear_bit_unlock(0, &pmu_lock);
+	clear_bit_unlock(irqs->device_type, &pmu_lock);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(release_pmu);
@@ -87,17 +79,36 @@ set_irq_affinity(int irq,
 #endif
 }
 
-int
-init_pmu(void)
+static int
+init_cpu_pmu(void)
 {
-	int i, err = 0;
+	int i, err = 0, num_irqs = pmu_irqs[ARM_PMU_DEVICE_CPU]->num_irqs;
+	const int *irqs = pmu_irqs[ARM_PMU_DEVICE_CPU]->irqs;
 
-	for (i = 0; i < pmu_irqs.num_irqs; ++i) {
-		err = set_irq_affinity(pmu_irqs.irqs[i], i);
+	for (i = 0; i < num_irqs; ++i) {
+		err = set_irq_affinity(irqs[i], i);
 		if (err)
 			break;
 	}
 
 	return err;
 }
+
+int
+init_pmu(enum arm_pmu_type device)
+{
+	int err = 0;
+
+	switch (device) {
+	case ARM_PMU_DEVICE_CPU:
+		err = init_cpu_pmu();
+		break;
+	default:
+		pr_warning("pmu: attempt to initialise unknown device %d\n",
+				device);
+		err = -EINVAL;
+	}
+
+	return err;
+}
 EXPORT_SYMBOL_GPL(init_pmu);
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [RFC PATCH 2/2] ARM: Realview-PBX: register PMU IRQs during board initialisation
  2010-03-10 14:58 ` [RFC PATCH 1/2] ARM: pmu: register IRQs at runtime Will Deacon
@ 2010-03-10 14:58   ` Will Deacon
  0 siblings, 0 replies; 3+ messages in thread
From: Will Deacon @ 2010-03-10 14:58 UTC (permalink / raw)
  To: linux-arm-kernel

This patch updates the Realview-PBX initialisation routine to register
the PMU IRQs with the PMU framework in the Kernel.

Signed-off-by: Will Deacon <will.deacon@arm.com>
---
 arch/arm/mach-realview/realview_pbx.c |   15 +++++++++++++++
 1 files changed, 15 insertions(+), 0 deletions(-)

diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c
index d94857e..0d31486 100644
--- a/arch/arm/mach-realview/realview_pbx.c
+++ b/arch/arm/mach-realview/realview_pbx.c
@@ -29,6 +29,7 @@
 #include <asm/irq.h>
 #include <asm/leds.h>
 #include <asm/mach-types.h>
+#include <asm/pmu.h>
 #include <asm/smp_twd.h>
 #include <asm/hardware/gic.h>
 #include <asm/hardware/cache-l2x0.h>
@@ -270,6 +271,19 @@ static struct resource realview_pbx_isp1761_resources[] = {
 	},
 };
 
+static const int pmu_irqs[] = {
+	IRQ_PBX_PMU_CPU0,
+	IRQ_PBX_PMU_CPU1,
+	IRQ_PBX_PMU_CPU2,
+	IRQ_PBX_PMU_CPU3,
+};
+
+static struct pmu_irqs cpu_pmu_device = {
+	.device_type		= ARM_PMU_DEVICE_CPU,
+	.irqs			= pmu_irqs,
+	.num_irqs		= ARRAY_SIZE(pmu_irqs),
+};
+
 static void __init gic_init_irq(void)
 {
 	/* ARM PBX on-board GIC */
@@ -363,6 +377,7 @@ static void __init realview_pbx_init(void)
 	platform_device_register(&realview_i2c_device);
 	platform_device_register(&realview_cf_device);
 	realview_usb_register(realview_pbx_isp1761_resources);
+	pmu_device_register(&cpu_pmu_device);
 
 	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
 		struct amba_device *d = amba_devs[i];
-- 
1.6.3.3

^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2010-03-10 14:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-03-10 14:58 [RFC PATCH 0/2] ARM: pmu: provide a registration mechanism for IRQs Will Deacon
2010-03-10 14:58 ` [RFC PATCH 1/2] ARM: pmu: register IRQs at runtime Will Deacon
2010-03-10 14:58   ` [RFC PATCH 2/2] ARM: Realview-PBX: register PMU IRQs during board initialisation Will Deacon

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