* [RFC PATCH 0/6] ARM: pmu: provide a registration mechanism for IRQs [v2] @ 2010-03-12 17:29 Will Deacon 2010-03-12 17:29 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Will Deacon 0 siblings, 1 reply; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This is version 2 of the patch series originally posted here: http://lists.infradead.org/pipermail/linux-arm-kernel/2010-March/011162.html Changes from the original version include: - Removal of const keyword from IRQs to make it easier to select the IRQs to register at runtime. - Support for all the relevant Realview boards - Support for OMAP2, OMAP3, BCMRING, iop and PXA platforms The main reason for submitting this is to get some feedback on the registration code I've added to the board files because I'm not familiar with how the omap / bcmring / pxa / iop trees are structured. All feedback welcome [including the results of any testing for the platforms I've mentioned]. Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Cc: Jamie Iles <jamie.iles@picochip.com> Cc: Tony Lindgren <tony@atomide.com> Cc: Leo Chen <leochen@broadcom.com> Cc: Lennert Buytenhek <kernel@wantstofly.org> Cc: Eric Miao <eric.y.miao@gmail.com> Will Deacon (6): ARM: pmu: register IRQs at runtime ARM: Realview: register PMU IRQs during board initialisation ARM: OMAP: register PMU IRQs during board initialisation ARM: BCMRING: register PMU IRQ during board initialisation ARM: iop3xx: register PMU IRQs during board initialisation ARM: pxa: 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-bcmring/arch.c | 13 ++++ arch/arm/mach-omap2/devices.c | 30 +++++++++ arch/arm/mach-pxa/pxa25x.c | 14 ++++ arch/arm/mach-pxa/pxa27x.c | 13 ++++ arch/arm/mach-pxa/pxa3xx.c | 14 ++++ arch/arm/mach-realview/realview_eb.c | 15 ++++ arch/arm/mach-realview/realview_pb1176.c | 12 ++++ arch/arm/mach-realview/realview_pb11mp.c | 15 ++++ arch/arm/mach-realview/realview_pba8.c | 12 ++++ arch/arm/mach-realview/realview_pbx.c | 15 ++++ arch/arm/plat-iop/Makefile | 2 + arch/arm/plat-iop/pmu.c | 37 +++++++++++ 15 files changed, 278 insertions(+), 59 deletions(-) create mode 100644 arch/arm/plat-iop/pmu.c ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-12 17:29 [RFC PATCH 0/6] ARM: pmu: provide a registration mechanism for IRQs [v2] Will Deacon @ 2010-03-12 17:29 ` Will Deacon 2010-03-12 17:29 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon 2010-03-16 11:41 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 0 siblings, 2 replies; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 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. Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> Cc: Jamie Iles <jamie.iles@picochip.com> 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..133a86b 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; + 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..70e6f3f 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; + 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] 13+ messages in thread
* [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation 2010-03-12 17:29 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Will Deacon @ 2010-03-12 17:29 ` Will Deacon 2010-03-12 17:29 ` [RFC PATCH 3/6] ARM: OMAP: " Will Deacon 2010-03-16 11:41 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 1 sibling, 1 reply; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This patch updates the initialisation routines for the Realview boards so that they register their PMU IRQs with the PMU framework in the Kernel. Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mach-realview/realview_eb.c | 15 +++++++++++++++ arch/arm/mach-realview/realview_pb1176.c | 12 ++++++++++++ arch/arm/mach-realview/realview_pb11mp.c | 15 +++++++++++++++ arch/arm/mach-realview/realview_pba8.c | 12 ++++++++++++ arch/arm/mach-realview/realview_pbx.c | 15 +++++++++++++++ 5 files changed, 69 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 7d857d3..603a747 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -294,6 +295,19 @@ static struct resource realview_eb_isp1761_resources[] = { }, }; +static int pmu_irqs[] = { + IRQ_EB11MP_PMU_CPU0, + IRQ_EB11MP_PMU_CPU1, + IRQ_EB11MP_PMU_CPU2, + IRQ_EB11MP_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) { if (core_tile_eb11mp() || core_tile_a9mp()) { @@ -413,6 +427,7 @@ static void __init realview_eb_init(void) platform_device_register(&realview_i2c_device); eth_device_register(); realview_usb_register(realview_eb_isp1761_resources); + pmu_device_register(&cpu_pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 44392e5..e43fd53 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -263,6 +264,16 @@ static struct resource realview_pb1176_isp1761_resources[] = { }, }; +static int pmu_irqs[] = { + IRQ_DC1176_CORE_PMU, +}; + +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) { /* ARM1176 DevChip GIC, primary */ @@ -324,6 +335,7 @@ static void __init realview_pb1176_init(void) realview_eth_register(NULL, realview_pb1176_smsc911x_resources); platform_device_register(&realview_i2c_device); realview_usb_register(realview_pb1176_isp1761_resources); + pmu_device_register(&cpu_pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index 3e02731..00db50e 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -260,6 +261,19 @@ static struct resource realview_pb11mp_isp1761_resources[] = { }, }; +static int pmu_irqs[] = { + IRQ_TC11MP_PMU_CPU0, + IRQ_TC11MP_PMU_CPU1, + IRQ_TC11MP_PMU_CPU2, + IRQ_TC11MP_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) { unsigned int pldctrl; @@ -329,6 +343,7 @@ static void __init realview_pb11mp_init(void) platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); realview_usb_register(realview_pb11mp_isp1761_resources); + pmu_device_register(&cpu_pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index fe4e25c..9c787ac 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -30,6 +30,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> @@ -250,6 +251,16 @@ static struct resource realview_pba8_isp1761_resources[] = { }, }; +static int pmu_irqs[] = { + IRQ_PBA8_PMU, +}; + +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 PB-A8 on-board GIC */ @@ -296,6 +307,7 @@ static void __init realview_pba8_init(void) platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); realview_usb_register(realview_pba8_isp1761_resources); + pmu_device_register(&cpu_pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index d94857e..95b0a12 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 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] 13+ messages in thread
* [RFC PATCH 3/6] ARM: OMAP: register PMU IRQs during board initialisation 2010-03-12 17:29 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon @ 2010-03-12 17:29 ` Will Deacon 2010-03-12 17:29 ` [RFC PATCH 4/6] ARM: BCMRING: register PMU IRQ " Will Deacon 0 siblings, 1 reply; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This patch updates the initialisation routines for the OMAP2 and OMAP3 boards so that they register their PMU IRQs with the PMU framework in the Kernel. Cc: Tony Lindgren <tony@atomide.com> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mach-omap2/devices.c | 30 ++++++++++++++++++++++++++++++ 1 files changed, 30 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c index 18ad931..83d06d8 100644 --- a/arch/arm/mach-omap2/devices.c +++ b/arch/arm/mach-omap2/devices.c @@ -17,8 +17,10 @@ #include <linux/clk.h> #include <mach/hardware.h> +#include <mach/irqs.h> #include <asm/mach-types.h> #include <asm/mach/map.h> +#include <asm/pmu.h> #include <plat/control.h> #include <plat/tc.h> @@ -435,6 +437,33 @@ static void omap_init_mcspi(void) static inline void omap_init_mcspi(void) {} #endif +static int omap2_pmu_irqs[] = { + 3, +}; + +static int omap3_pmu_irqs[] = { + INT_34XX_BENCH_MPU_EMUL, +}; + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, +}; + +static void omap_init_pmu(void) +{ + if (cpu_is_omap24xx()) { + cpu_pmu_device.irqs = omap2_pmu_irqs;; + cpu_pmu_device.num_irqs = ARRAY_SIZE(omap2_pmu_irqs); + } else if (cpu_is_omap34xx()) { + cpu_pmu_device.irqs = omap3_pmu_irqs; + cpu_pmu_device.num_irqs = ARRAY_SIZE(omap3_pmu_irqs); + } else { + return; + } + + pmu_device_register(&cpu_pmu_device); +} + #ifdef CONFIG_OMAP_SHA1_MD5 static struct resource sha1_md5_resources[] = { { @@ -774,6 +803,7 @@ static int __init omap2_init_devices(void) omap_init_camera(); omap_init_mbox(); omap_init_mcspi(); + omap_init_pmu(); omap_hdq_init(); omap_init_sti(); omap_init_sha1_md5(); -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH 4/6] ARM: BCMRING: register PMU IRQ during board initialisation 2010-03-12 17:29 ` [RFC PATCH 3/6] ARM: OMAP: " Will Deacon @ 2010-03-12 17:29 ` Will Deacon 2010-03-12 17:29 ` [RFC PATCH 5/6] ARM: iop3xx: register PMU IRQs " Will Deacon 0 siblings, 1 reply; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This patch updates the initialisation routine for the BCMRING platform so that it registers its PMU IRQ with the PMU framework in the Kernel. Cc: Leo Chen <leochen@broadcom.com> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mach-bcmring/arch.c | 13 +++++++++++++ 1 files changed, 13 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-bcmring/arch.c b/arch/arm/mach-bcmring/arch.c index 53dd2a9..e9d952a 100644 --- a/arch/arm/mach-bcmring/arch.c +++ b/arch/arm/mach-bcmring/arch.c @@ -26,6 +26,7 @@ #include <linux/sysctl.h> #include <asm/irq.h> +#include <asm/pmu.h> #include <asm/setup.h> #include <asm/mach-types.h> #include <asm/mach/time.h> @@ -89,6 +90,16 @@ static struct platform_device *devices[] __initdata = { &nand_device, }; +static int pmu_irqs[] = { + IRQ_PMUIRQ, +}; + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, + .irqs = pmu_irqs, + .num_irqs = ARRAY_SIZE(pmu_irqs), +}; + /**************************************************************************** * * Called from the customize_machine function in arch/arm/kernel/setup.c @@ -108,6 +119,8 @@ static void __init bcmring_init_machine(void) platform_add_devices(devices, ARRAY_SIZE(devices)); + pmu_device_register(&cpu_pmu_device); + bcmring_amba_init(); dma_init(); -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH 5/6] ARM: iop3xx: register PMU IRQs during board initialisation 2010-03-12 17:29 ` [RFC PATCH 4/6] ARM: BCMRING: register PMU IRQ " Will Deacon @ 2010-03-12 17:29 ` Will Deacon 2010-03-12 17:29 ` [RFC PATCH 6/6] ARM: pxa: " Will Deacon 0 siblings, 1 reply; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This patch adds an initcall for the iop3xx platforms so that they register their PMU IRQS with the PMU framework in the Kernel. Cc: Lennert Buytenhek <kernel@wantstofly.org> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/plat-iop/Makefile | 2 ++ arch/arm/plat-iop/pmu.c | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 0 deletions(-) create mode 100644 arch/arm/plat-iop/pmu.c diff --git a/arch/arm/plat-iop/Makefile b/arch/arm/plat-iop/Makefile index 36bff03..69b09c1 100644 --- a/arch/arm/plat-iop/Makefile +++ b/arch/arm/plat-iop/Makefile @@ -13,6 +13,7 @@ obj-$(CONFIG_ARCH_IOP32X) += time.o obj-$(CONFIG_ARCH_IOP32X) += io.o obj-$(CONFIG_ARCH_IOP32X) += cp6.o obj-$(CONFIG_ARCH_IOP32X) += adma.o +obj-$(CONFIG_ARCH_IOP32X) += pmu.o # IOP33X obj-$(CONFIG_ARCH_IOP33X) += gpio.o @@ -23,6 +24,7 @@ obj-$(CONFIG_ARCH_IOP33X) += time.o obj-$(CONFIG_ARCH_IOP33X) += io.o obj-$(CONFIG_ARCH_IOP33X) += cp6.o obj-$(CONFIG_ARCH_IOP33X) += adma.o +obj-$(CONFIG_ARCH_IOP33X) += pmu.o # IOP13XX obj-$(CONFIG_ARCH_IOP13XX) += cp6.o diff --git a/arch/arm/plat-iop/pmu.c b/arch/arm/plat-iop/pmu.c new file mode 100644 index 0000000..582d72c --- /dev/null +++ b/arch/arm/plat-iop/pmu.c @@ -0,0 +1,37 @@ +/* + * PMU IRQ registration for the iop3xx xscale PMU families. + * Copyright (C) 2010 Will Deacon, ARM Ltd. + * + * 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 + * published by the Free Software Foundation. + * + */ + +#include <asm/pmu.h> +#include <mach/irqs.h> + +#ifdef CONFIG_ARCH_IOP32X +static int pmu_irqs[] = { + IRQ_IOP32X_CORE_PMU, +}; +#endif +#ifdef CONFIG_ARCH_IOP33X +static int pmu_irqs[] = { + IRQ_IOP33X_CORE_PMU, +}; +#endif + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, + .irqs = pmu_irqs, + .num_irqs = ARRAY_SIZE(pmu_irqs), +}; + +static int __init iop3xx_pmu_init(void) +{ + pmu_device_register(&cpu_pmu_device); + return 0; +} + +arch_initcall(iop3xx_pmu_init); -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH 6/6] ARM: pxa: register PMU IRQs during board initialisation 2010-03-12 17:29 ` [RFC PATCH 5/6] ARM: iop3xx: register PMU IRQs " Will Deacon @ 2010-03-12 17:29 ` Will Deacon 0 siblings, 0 replies; 13+ messages in thread From: Will Deacon @ 2010-03-12 17:29 UTC (permalink / raw) To: linux-arm-kernel This patch modifies the initialisation routines for the PXA25x, PXA27x and PXA3xx platforms so that they register their PMU IRQs with the PMU framework in the Kernel. Cc: Eric Miao <eric.y.miao@gmail.com> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mach-pxa/pxa25x.c | 14 ++++++++++++++ arch/arm/mach-pxa/pxa27x.c | 13 +++++++++++++ arch/arm/mach-pxa/pxa3xx.c | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c index 2c1b0b7..e2c30a2 100644 --- a/arch/arm/mach-pxa/pxa25x.c +++ b/arch/arm/mach-pxa/pxa25x.c @@ -23,6 +23,8 @@ #include <linux/suspend.h> #include <linux/sysdev.h> +#include <asm/pmu.h> + #include <mach/hardware.h> #include <mach/irqs.h> #include <mach/gpio.h> @@ -341,6 +343,16 @@ static struct sys_device pxa25x_sysdev[] = { }, }; +static int pmu_irqs[] = { + IRQ_PMU, +}; + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, + .irqs = pmu_irqs, + .num_irqs = ARRAY_SIZE(pmu_irqs), +}; + static int __init pxa25x_init(void) { int i, ret = 0; @@ -366,6 +378,8 @@ static int __init pxa25x_init(void) ARRAY_SIZE(pxa25x_devices)); if (ret) return ret; + + pmu_device_register(&cpu_pmu_device); } /* Only add HWUART for PXA255/26x; PXA210/250 do not have it. */ diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index 6a0b731..6e74cc0 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -18,6 +18,8 @@ #include <linux/platform_device.h> #include <linux/sysdev.h> +#include <asm/pmu.h> + #include <mach/hardware.h> #include <asm/irq.h> #include <mach/irqs.h> @@ -384,6 +386,16 @@ static struct sys_device pxa27x_sysdev[] = { }, }; +static int pmu_irqs[] = { + IRQ_PMU, +}; + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, + .irqs = pmu_irqs, + .num_irqs = ARRAY_SIZE(pmu_irqs), +}; + static int __init pxa27x_init(void) { int i, ret = 0; @@ -406,6 +418,7 @@ static int __init pxa27x_init(void) } ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + pmu_device_register(&cpu_pmu_device); } return ret; diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index fcb0721..b84681a 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -22,8 +22,11 @@ #include <linux/io.h> #include <linux/sysdev.h> +#include <asm/pmu.h> + #include <mach/hardware.h> #include <mach/gpio.h> +#include <mach/irqs.h> #include <mach/pxa3xx-regs.h> #include <mach/reset.h> #include <mach/ohci.h> @@ -618,6 +621,16 @@ static struct sys_device pxa3xx_sysdev[] = { }, }; +static int pmu_irqs[] = { + IRQ_PMU, +}; + +static struct pmu_irqs cpu_pmu_device = { + .device_type = ARM_PMU_DEVICE_CPU, + .irqs = pmu_irqs, + .num_irqs = ARRAY_SIZE(pmu_irqs), +}; + static int __init pxa3xx_init(void) { int i, ret = 0; @@ -648,6 +661,7 @@ static int __init pxa3xx_init(void) } ret = platform_add_devices(devices, ARRAY_SIZE(devices)); + pmu_device_register(&cpu_pmu_device); } return ret; -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-12 17:29 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Will Deacon 2010-03-12 17:29 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon @ 2010-03-16 11:41 ` Jamie Iles 2010-03-17 16:06 ` Will Deacon 2010-03-17 16:11 ` Will Deacon 1 sibling, 2 replies; 13+ messages in thread From: Jamie Iles @ 2010-03-16 11:41 UTC (permalink / raw) To: linux-arm-kernel On Fri, Mar 12, 2010 at 05:29:39PM +0000, Will Deacon wrote: > 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. > > Cc: Russell King - ARM Linux <linux@arm.linux.org.uk> > Cc: Jamie Iles <jamie.iles@picochip.com> > Signed-off-by: Will Deacon <will.deacon@arm.com> Hi Will, I much prefer this rather than the old static list that we had before. As an aside, do you know of any ARM PMU's that need memory resources in addition to the IRQ's? If so perhaps a platform_device might be an easy way of extending this. Anyway, Acked-by: Jamie Iles <jamie.iles@picochip.com> Jamie ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-16 11:41 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles @ 2010-03-17 16:06 ` Will Deacon 2010-03-17 16:11 ` Will Deacon 1 sibling, 0 replies; 13+ messages in thread From: Will Deacon @ 2010-03-17 16:06 UTC (permalink / raw) To: linux-arm-kernel Hi Jamie, > I much prefer this rather than the old static list that we had before. As an > aside, do you know of any ARM PMU's that need memory resources in addition to > the IRQ's? If so perhaps a platform_device might be an easy way of extending > this. Well, the ARM11MPCore SCU counters are memory mapped and I have a feeling that anything [counter-wise] outside the CPU core will likely be memory mapped in the future. I've had a go at using a platform_device instead of the struct pmu_irqs, I'll post the changes for you to take a look at. > Acked-by: Jamie Iles <jamie.iles@picochip.com> Thanks for that. Please take a look at the platform_device version and see what you reckon. Cheers, Will ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-16 11:41 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 2010-03-17 16:06 ` Will Deacon @ 2010-03-17 16:11 ` Will Deacon 2010-03-17 16:11 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon 2010-03-18 12:20 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 1 sibling, 2 replies; 13+ messages in thread From: Will Deacon @ 2010-03-17 16:11 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 registered with the framework as a platform_device. A further advantage of this change is that there is scope for registering different types of performance counters in the future by changing the id of the platform_device and attaching different resources to it. Cc: Linux ARM Kernel <linux-arm-kernel@lists.infradead.org> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/include/asm/pmu.h | 30 +++++----- arch/arm/kernel/perf_event.c | 36 +++++++------ arch/arm/kernel/pmu.c | 121 ++++++++++++++++++++++++++---------------- 3 files changed, 110 insertions(+), 77 deletions(-) diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 2829b9f..92866dc 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -12,33 +12,33 @@ #ifndef __ARM_PMU_H__ #define __ARM_PMU_H__ -#ifdef CONFIG_CPU_HAS_PMU - -struct pmu_irqs { - const int *irqs; - int num_irqs; +enum arm_pmu_type { + ARM_PMU_DEVICE_CPU = 0, + ARM_NUM_PMU_DEVICES, }; +#ifdef CONFIG_CPU_HAS_PMU + /** * 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() + * The platform_device for the system is returned on success, ERR_PTR() * encoded error on failure. */ -extern const struct pmu_irqs * -reserve_pmu(void); +extern struct platform_device * +reserve_pmu(enum arm_pmu_type device); /** * release_pmu() - Relinquish control of the performance counters * * Release the performance counters and allow someone else to use them. * Callers must have disabled the counters and released IRQs before calling - * this. The 'struct pmu_irqs' returned from reserve_pmu() must be passed as + * this. The platform_device returned from reserve_pmu() must be passed as * a cookie. */ extern int -release_pmu(const struct pmu_irqs *irqs); +release_pmu(struct platform_device *pdev); /** * init_pmu() - Initialise the PMU. @@ -48,24 +48,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 platform_device * +reserve_pmu(enum arm_pmu_type device) { return ERR_PTR(-ENODEV); } static inline int -release_pmu(const struct pmu_irqs *irqs) +release_pmu(struct platform_device *pdev) { 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..7b7e3ab 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -17,6 +17,7 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/perf_event.h> +#include <linux/platform_device.h> #include <linux/spinlock.h> #include <linux/uaccess.h> @@ -26,7 +27,7 @@ #include <asm/pmu.h> #include <asm/stacktrace.h> -static const struct pmu_irqs *pmu_irqs; +static struct platform_device *pmu_device; /* * Hardware lock to serialize accesses to PMU registers. Needed for the @@ -317,35 +318,36 @@ armpmu_reserve_hardware(void) int i; int err; - pmu_irqs = reserve_pmu(); - if (IS_ERR(pmu_irqs)) { + pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU); + if (IS_ERR(pmu_device)) { pr_warning("unable to reserve pmu\n"); - return PTR_ERR(pmu_irqs); + return PTR_ERR(pmu_device); } - init_pmu(); + init_pmu(ARM_PMU_DEVICE_CPU); - if (pmu_irqs->num_irqs < 1) { + if (pmu_device->num_resources < 1) { pr_err("no irqs for PMUs defined\n"); return -ENODEV; } - for (i = 0; i < pmu_irqs->num_irqs; ++i) { - err = request_irq(pmu_irqs->irqs[i], armpmu->handle_irq, + for (i = 0; i < pmu_device->num_resources; ++i) { + err = request_irq(platform_get_irq(pmu_device, i), + armpmu->handle_irq, IRQF_DISABLED | IRQF_NOBALANCING, "armpmu", NULL); if (err) { - pr_warning("unable to request IRQ%d for ARM " - "perf counters\n", pmu_irqs->irqs[i]); + pr_warning("unable to request IRQ%d for ARM perf " + "counters\n", platform_get_irq(pmu_device, i)); break; } } if (err) { for (i = i - 1; i >= 0; --i) - free_irq(pmu_irqs->irqs[i], NULL); - release_pmu(pmu_irqs); - pmu_irqs = NULL; + free_irq(platform_get_irq(pmu_device, i), NULL); + release_pmu(pmu_device); + pmu_device = NULL; } return err; @@ -356,12 +358,12 @@ armpmu_release_hardware(void) { int i; - for (i = pmu_irqs->num_irqs - 1; i >= 0; --i) - free_irq(pmu_irqs->irqs[i], NULL); + for (i = pmu_device->num_resources - 1; i >= 0; --i) + free_irq(platform_get_irq(pmu_device, i), NULL); armpmu->stop(); - release_pmu(pmu_irqs); - pmu_irqs = NULL; + release_pmu(pmu_device); + pmu_device = NULL; } static atomic_t active_events = ATOMIC_INIT(0); diff --git a/arch/arm/kernel/pmu.c b/arch/arm/kernel/pmu.c index a124312..a42fb60 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 @@ -14,60 +15,71 @@ #include <linux/interrupt.h> #include <linux/kernel.h> #include <linux/module.h> +#include <linux/platform_device.h> #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 volatile long pmu_lock; + +static struct platform_device *pmu_devices[ARM_NUM_PMU_DEVICES]; + +static int __devinit pmu_device_probe(struct platform_device *pdev) +{ + + if (pdev->id >= ARM_NUM_PMU_DEVICES) { + pr_warning("PMU: Received registration request for unknown " + "device %d\n", pdev->id); + return -EINVAL; + } + + if (pmu_devices[pdev->id]) + pr_warning("PMU: Registering new PMU device type %d overwrites " + "previous registration!\n", pdev->id); + else + pr_info("PMU: Registered new PMU device of type %d\n", + pdev->id); + + pmu_devices[pdev->id] = pdev; + return 0; +} -static const struct pmu_irqs pmu_irqs = { - .irqs = irqs, - .num_irqs = ARRAY_SIZE(irqs), +static struct platform_driver pmu_driver = { + .driver = { + .name = "arm-pmu", + }, + .probe = pmu_device_probe, }; -static volatile long pmu_lock; +static int __init register_pmu_driver(void) +{ + return platform_driver_register(&pmu_driver); +} +device_initcall(register_pmu_driver); -const struct pmu_irqs * -reserve_pmu(void) +struct platform_device * +reserve_pmu(enum arm_pmu_type device) { - return test_and_set_bit_lock(0, &pmu_lock) ? ERR_PTR(-EBUSY) : - &pmu_irqs; + struct platform_device *pdev; + + if (test_and_set_bit_lock(device, &pmu_lock)) { + pdev = ERR_PTR(-EBUSY); + } else if (pmu_devices[device] == NULL) { + clear_bit_unlock(device, &pmu_lock); + pdev = ERR_PTR(-ENODEV); + } else { + pdev = pmu_devices[device]; + } + + return pdev; } EXPORT_SYMBOL_GPL(reserve_pmu); int -release_pmu(const struct pmu_irqs *irqs) +release_pmu(struct platform_device *pdev) { - if (WARN_ON(irqs != &pmu_irqs)) + if (WARN_ON(pdev != pmu_devices[pdev->id])) return -EINVAL; - clear_bit_unlock(0, &pmu_lock); + clear_bit_unlock(pdev->id, &pmu_lock); return 0; } EXPORT_SYMBOL_GPL(release_pmu); @@ -79,7 +91,7 @@ set_irq_affinity(int irq, #ifdef CONFIG_SMP int err = irq_set_affinity(irq, cpumask_of(cpu)); if (err) - pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + pr_warning("PMU: Unable to set irq affinity (irq=%d, cpu=%u)\n", irq, cpu); return err; #else @@ -87,17 +99,36 @@ set_irq_affinity(int irq, #endif } -int -init_pmu(void) +static int +init_cpu_pmu(void) { int i, err = 0; + struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; - for (i = 0; i < pmu_irqs.num_irqs; ++i) { - err = set_irq_affinity(pmu_irqs.irqs[i], i); + for (i = 0; i < pdev->num_resources; ++i) { + err = set_irq_affinity(platform_get_irq(pdev, 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] 13+ messages in thread
* [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation 2010-03-17 16:11 ` Will Deacon @ 2010-03-17 16:11 ` Will Deacon 2010-03-18 12:20 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 1 sibling, 0 replies; 13+ messages in thread From: Will Deacon @ 2010-03-17 16:11 UTC (permalink / raw) To: linux-arm-kernel This patch updates the initialisation routines for the Realview boards so that they register their PMU IRQs with the PMU framework in the Kernel. Cc: Linux ARM Kernel <linux-arm-kernel@lists.infradead.org> Signed-off-by: Will Deacon <will.deacon@arm.com> --- arch/arm/mach-realview/realview_eb.c | 32 ++++++++++++++++++++++++++++++ arch/arm/mach-realview/realview_pb1176.c | 15 ++++++++++++++ arch/arm/mach-realview/realview_pb11mp.c | 32 ++++++++++++++++++++++++++++++ arch/arm/mach-realview/realview_pba8.c | 15 ++++++++++++++ arch/arm/mach-realview/realview_pbx.c | 32 ++++++++++++++++++++++++++++++ 5 files changed, 126 insertions(+), 0 deletions(-) diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index 7d857d3..a4a101a 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -294,6 +295,36 @@ static struct resource realview_eb_isp1761_resources[] = { }, }; +static struct resource pmu_resources[] = { + [0] = { + .start = IRQ_EB11MP_PMU_CPU0, + .end = IRQ_EB11MP_PMU_CPU0, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = IRQ_EB11MP_PMU_CPU1, + .end = IRQ_EB11MP_PMU_CPU1, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_EB11MP_PMU_CPU2, + .end = IRQ_EB11MP_PMU_CPU2, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = IRQ_EB11MP_PMU_CPU3, + .end = IRQ_EB11MP_PMU_CPU3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(pmu_resources), + .resource = pmu_resources, +}; + static void __init gic_init_irq(void) { if (core_tile_eb11mp() || core_tile_a9mp()) { @@ -407,6 +438,7 @@ static void __init realview_eb_init(void) * Bits: .... ...0 0111 1001 0000 .... .... .... */ l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff); #endif + platform_device_register(&pmu_device); } realview_flash_register(&realview_eb_flash_resource, 1); diff --git a/arch/arm/mach-realview/realview_pb1176.c b/arch/arm/mach-realview/realview_pb1176.c index 44392e5..85429cb 100644 --- a/arch/arm/mach-realview/realview_pb1176.c +++ b/arch/arm/mach-realview/realview_pb1176.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -263,6 +264,19 @@ static struct resource realview_pb1176_isp1761_resources[] = { }, }; +static struct resource pmu_resource = { + .start = IRQ_DC1176_PMU_CPU0, + .end = IRQ_DC1176_PMU_CPU0, + .flags = IORESOURCE_IRQ, +}; + +static struct platform_device pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = 1, + .resource = &pmu_resource, +}; + static void __init gic_init_irq(void) { /* ARM1176 DevChip GIC, primary */ @@ -324,6 +338,7 @@ static void __init realview_pb1176_init(void) realview_eth_register(NULL, realview_pb1176_smsc911x_resources); platform_device_register(&realview_i2c_device); realview_usb_register(realview_pb1176_isp1761_resources); + platform_device_register(&pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c index 3e02731..3ab4447 100644 --- a/arch/arm/mach-realview/realview_pb11mp.c +++ b/arch/arm/mach-realview/realview_pb11mp.c @@ -31,6 +31,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> #include <asm/hardware/cache-l2x0.h> @@ -260,6 +261,36 @@ static struct resource realview_pb11mp_isp1761_resources[] = { }, }; +static struct resource pmu_resources[] = { + [0] = { + .start = IRQ_TC11MP_PMU_CPU0, + .end = IRQ_TC11MP_PMU_CPU0, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = IRQ_TC11MP_PMU_CPU1, + .end = IRQ_TC11MP_PMU_CPU1, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_TC11MP_PMU_CPU2, + .end = IRQ_TC11MP_PMU_CPU2, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = IRQ_TC11MP_PMU_CPU3, + .end = IRQ_TC11MP_PMU_CPU3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(pmu_resources), + .resource = pmu_resources, +}; + static void __init gic_init_irq(void) { unsigned int pldctrl; @@ -329,6 +360,7 @@ static void __init realview_pb11mp_init(void) platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); realview_usb_register(realview_pb11mp_isp1761_resources); + platform_device_register(&pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pba8.c b/arch/arm/mach-realview/realview_pba8.c index fe4e25c..7b36ea9 100644 --- a/arch/arm/mach-realview/realview_pba8.c +++ b/arch/arm/mach-realview/realview_pba8.c @@ -30,6 +30,7 @@ #include <asm/irq.h> #include <asm/leds.h> #include <asm/mach-types.h> +#include <asm/pmu.h> #include <asm/hardware/gic.h> #include <asm/hardware/icst307.h> @@ -250,6 +251,19 @@ static struct resource realview_pba8_isp1761_resources[] = { }, }; +static struct resource pmu_resource = { + .start = IRQ_PBA8_PMU, + .end = IRQ_PBA8_PMU, + .flags = IORESOURCE_IRQ, +}; + +static struct platform_device pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = 1, + .resource = &pmu_resource, +}; + static void __init gic_init_irq(void) { /* ARM PB-A8 on-board GIC */ @@ -296,6 +310,7 @@ static void __init realview_pba8_init(void) platform_device_register(&realview_i2c_device); platform_device_register(&realview_cf_device); realview_usb_register(realview_pba8_isp1761_resources); + platform_device_register(&pmu_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { struct amba_device *d = amba_devs[i]; diff --git a/arch/arm/mach-realview/realview_pbx.c b/arch/arm/mach-realview/realview_pbx.c index d94857e..a235ba3 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,36 @@ static struct resource realview_pbx_isp1761_resources[] = { }, }; +static struct resource pmu_resources[] = { + [0] = { + .start = IRQ_PBX_PMU_CPU0, + .end = IRQ_PBX_PMU_CPU0, + .flags = IORESOURCE_IRQ, + }, + [1] = { + .start = IRQ_PBX_PMU_CPU1, + .end = IRQ_PBX_PMU_CPU1, + .flags = IORESOURCE_IRQ, + }, + [2] = { + .start = IRQ_PBX_PMU_CPU2, + .end = IRQ_PBX_PMU_CPU2, + .flags = IORESOURCE_IRQ, + }, + [3] = { + .start = IRQ_PBX_PMU_CPU3, + .end = IRQ_PBX_PMU_CPU3, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device pmu_device = { + .name = "arm-pmu", + .id = ARM_PMU_DEVICE_CPU, + .num_resources = ARRAY_SIZE(pmu_resources), + .resource = pmu_resources, +}; + static void __init gic_init_irq(void) { /* ARM PBX on-board GIC */ @@ -354,6 +385,7 @@ static void __init realview_pbx_init(void) /* 16KB way size, 8-way associativity, parity disabled * Bits: .. 0 0 0 0 1 00 1 0 1 001 0 000 0 .... .... .... */ l2x0_init(l2x0_base, 0x02520000, 0xc0000fff); + platform_device_register(&pmu_device); } #endif -- 1.6.3.3 ^ permalink raw reply related [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-17 16:11 ` Will Deacon 2010-03-17 16:11 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon @ 2010-03-18 12:20 ` Jamie Iles 2010-03-24 15:50 ` Will Deacon 1 sibling, 1 reply; 13+ messages in thread From: Jamie Iles @ 2010-03-18 12:20 UTC (permalink / raw) To: linux-arm-kernel On Wed, Mar 17, 2010 at 04:11:27PM +0000, Will Deacon wrote: > 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 registered with the framework as a platform_device. > > A further advantage of this change is that there is scope for registering > different types of performance counters in the future by changing the id of > the platform_device and attaching different resources to it. Hi Will, This seems like a nice approach to the problem. A couple of pedantic comments inline! Jamie > Cc: Linux ARM Kernel <linux-arm-kernel@lists.infradead.org> > Signed-off-by: Will Deacon <will.deacon@arm.com> > --- > arch/arm/include/asm/pmu.h | 30 +++++----- > arch/arm/kernel/perf_event.c | 36 +++++++------ > arch/arm/kernel/pmu.c | 121 ++++++++++++++++++++++++++---------------- > 3 files changed, 110 insertions(+), 77 deletions(-) [snip] > +static int __devinit pmu_device_probe(struct platform_device *pdev) > +{ > + > + if (pdev->id >= ARM_NUM_PMU_DEVICES) { > + pr_warning("PMU: Received registration request for unknown " > + "device %d\n", pdev->id); > + return -EINVAL; > + } > + > + if (pmu_devices[pdev->id]) > + pr_warning("PMU: Registering new PMU device type %d overwrites " > + "previous registration!\n", pdev->id); > + else > + pr_info("PMU: Registered new PMU device of type %d\n", > + pdev->id); > + > + pmu_devices[pdev->id] = pdev; struct pdev->id is a signed integer so we should check that it's not less than 0 so we don't overrun pmu_devices.. > @@ -79,7 +91,7 @@ set_irq_affinity(int irq, > #ifdef CONFIG_SMP > int err = irq_set_affinity(irq, cpumask_of(cpu)); > if (err) > - pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", > + pr_warning("PMU: Unable to set irq affinity (irq=%d, cpu=%u)\n", > irq, cpu); How about we stick a '#define pr_fmt(fmt) "PMU: " fmt' before the includes so we get consistent naming if we add more pr_*() statements? > return err; > #else > @@ -87,17 +99,36 @@ set_irq_affinity(int irq, > #endif > } > > -int > -init_pmu(void) > +static int > +init_cpu_pmu(void) > { > int i, err = 0; > + struct platform_device *pdev = pmu_devices[ARM_PMU_DEVICE_CPU]; Just to be safe: if (!pdev) return -ENODEV; > - for (i = 0; i < pmu_irqs.num_irqs; ++i) { > - err = set_irq_affinity(pmu_irqs.irqs[i], i); > + for (i = 0; i < pdev->num_resources; ++i) { > + err = set_irq_affinity(platform_get_irq(pdev, i), i); > if (err) > break; > } > > return err; > } ^ permalink raw reply [flat|nested] 13+ messages in thread
* [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime 2010-03-18 12:20 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles @ 2010-03-24 15:50 ` Will Deacon 0 siblings, 0 replies; 13+ messages in thread From: Will Deacon @ 2010-03-24 15:50 UTC (permalink / raw) To: linux-arm-kernel Hi Jamie, > This seems like a nice approach to the problem. A couple of pedantic comments > inline! Thanks for the feedback. I agree with all of the comments, so I'll submit an updated version in a bit. Cheers, Will ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2010-03-24 15:50 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2010-03-12 17:29 [RFC PATCH 0/6] ARM: pmu: provide a registration mechanism for IRQs [v2] Will Deacon 2010-03-12 17:29 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Will Deacon 2010-03-12 17:29 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon 2010-03-12 17:29 ` [RFC PATCH 3/6] ARM: OMAP: " Will Deacon 2010-03-12 17:29 ` [RFC PATCH 4/6] ARM: BCMRING: register PMU IRQ " Will Deacon 2010-03-12 17:29 ` [RFC PATCH 5/6] ARM: iop3xx: register PMU IRQs " Will Deacon 2010-03-12 17:29 ` [RFC PATCH 6/6] ARM: pxa: " Will Deacon 2010-03-16 11:41 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 2010-03-17 16:06 ` Will Deacon 2010-03-17 16:11 ` Will Deacon 2010-03-17 16:11 ` [RFC PATCH 2/6] ARM: Realview: register PMU IRQs during board initialisation Will Deacon 2010-03-18 12:20 ` [RFC PATCH 1/6] ARM: pmu: register IRQs at runtime Jamie Iles 2010-03-24 15:50 ` 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).