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