aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/arm/include/asm/pmu.h14
-rw-r--r--arch/arm/kernel/perf_event.c17
-rw-r--r--arch/arm/mach-ux500/cpu-db8500.c51
3 files changed, 77 insertions, 5 deletions
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 8ccea012722c..7544ce6b481a 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -12,11 +12,25 @@
12#ifndef __ARM_PMU_H__ 12#ifndef __ARM_PMU_H__
13#define __ARM_PMU_H__ 13#define __ARM_PMU_H__
14 14
15#include <linux/interrupt.h>
16
15enum arm_pmu_type { 17enum arm_pmu_type {
16 ARM_PMU_DEVICE_CPU = 0, 18 ARM_PMU_DEVICE_CPU = 0,
17 ARM_NUM_PMU_DEVICES, 19 ARM_NUM_PMU_DEVICES,
18}; 20};
19 21
22/*
23 * struct arm_pmu_platdata - ARM PMU platform data
24 *
25 * @handle_irq: an optional handler which will be called from the interrupt and
26 * passed the address of the low level handler, and can be used to implement
27 * any platform specific handling before or after calling it.
28 */
29struct arm_pmu_platdata {
30 irqreturn_t (*handle_irq)(int irq, void *dev,
31 irq_handler_t pmu_handler);
32};
33
20#ifdef CONFIG_CPU_HAS_PMU 34#ifdef CONFIG_CPU_HAS_PMU
21 35
22/** 36/**
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index d150ad1ccb5d..22e194eb8536 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -377,9 +377,18 @@ validate_group(struct perf_event *event)
377 return 0; 377 return 0;
378} 378}
379 379
380static irqreturn_t armpmu_platform_irq(int irq, void *dev)
381{
382 struct arm_pmu_platdata *plat = dev_get_platdata(&pmu_device->dev);
383
384 return plat->handle_irq(irq, dev, armpmu->handle_irq);
385}
386
380static int 387static int
381armpmu_reserve_hardware(void) 388armpmu_reserve_hardware(void)
382{ 389{
390 struct arm_pmu_platdata *plat;
391 irq_handler_t handle_irq;
383 int i, err = -ENODEV, irq; 392 int i, err = -ENODEV, irq;
384 393
385 pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU); 394 pmu_device = reserve_pmu(ARM_PMU_DEVICE_CPU);
@@ -390,6 +399,12 @@ armpmu_reserve_hardware(void)
390 399
391 init_pmu(ARM_PMU_DEVICE_CPU); 400 init_pmu(ARM_PMU_DEVICE_CPU);
392 401
402 plat = dev_get_platdata(&pmu_device->dev);
403 if (plat && plat->handle_irq)
404 handle_irq = armpmu_platform_irq;
405 else
406 handle_irq = armpmu->handle_irq;
407
393 if (pmu_device->num_resources < 1) { 408 if (pmu_device->num_resources < 1) {
394 pr_err("no irqs for PMUs defined\n"); 409 pr_err("no irqs for PMUs defined\n");
395 return -ENODEV; 410 return -ENODEV;
@@ -400,7 +415,7 @@ armpmu_reserve_hardware(void)
400 if (irq < 0) 415 if (irq < 0)
401 continue; 416 continue;
402 417
403 err = request_irq(irq, armpmu->handle_irq, 418 err = request_irq(irq, handle_irq,
404 IRQF_DISABLED | IRQF_NOBALANCING, 419 IRQF_DISABLED | IRQF_NOBALANCING,
405 "armpmu", NULL); 420 "armpmu", NULL);
406 if (err) { 421 if (err) {
diff --git a/arch/arm/mach-ux500/cpu-db8500.c b/arch/arm/mach-ux500/cpu-db8500.c
index 1748fbc58530..5c0fabf5fa01 100644
--- a/arch/arm/mach-ux500/cpu-db8500.c
+++ b/arch/arm/mach-ux500/cpu-db8500.c
@@ -12,22 +12,20 @@
12#include <linux/init.h> 12#include <linux/init.h>
13#include <linux/device.h> 13#include <linux/device.h>
14#include <linux/amba/bus.h> 14#include <linux/amba/bus.h>
15#include <linux/interrupt.h>
15#include <linux/irq.h> 16#include <linux/irq.h>
16#include <linux/gpio.h> 17#include <linux/gpio.h>
17#include <linux/platform_device.h> 18#include <linux/platform_device.h>
18#include <linux/io.h> 19#include <linux/io.h>
19 20
20#include <asm/mach/map.h> 21#include <asm/mach/map.h>
22#include <asm/pmu.h>
21#include <mach/hardware.h> 23#include <mach/hardware.h>
22#include <mach/setup.h> 24#include <mach/setup.h>
23#include <mach/devices.h> 25#include <mach/devices.h>
24 26
25#include "devices-db8500.h" 27#include "devices-db8500.h"
26 28
27static struct platform_device *platform_devs[] __initdata = {
28 &u8500_dma40_device,
29};
30
31/* minimum static i/o mapping required to boot U8500 platforms */ 29/* minimum static i/o mapping required to boot U8500 platforms */
32static struct map_desc u8500_uart_io_desc[] __initdata = { 30static struct map_desc u8500_uart_io_desc[] __initdata = {
33 __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K), 31 __IO_DEV_DESC(U8500_UART0_BASE, SZ_4K),
@@ -89,6 +87,51 @@ void __init u8500_map_io(void)
89 iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc)); 87 iotable_init(u8500_v2_io_desc, ARRAY_SIZE(u8500_v2_io_desc));
90} 88}
91 89
90static struct resource db8500_pmu_resources[] = {
91 [0] = {
92 .start = IRQ_DB8500_PMU,
93 .end = IRQ_DB8500_PMU,
94 .flags = IORESOURCE_IRQ,
95 },
96};
97
98/*
99 * The PMU IRQ lines of two cores are wired together into a single interrupt.
100 * Bounce the interrupt to the other core if it's not ours.
101 */
102static irqreturn_t db8500_pmu_handler(int irq, void *dev, irq_handler_t handler)
103{
104 irqreturn_t ret = handler(irq, dev);
105 int other = !smp_processor_id();
106
107 if (ret == IRQ_NONE && cpu_online(other))
108 irq_set_affinity(irq, cpumask_of(other));
109
110 /*
111 * We should be able to get away with the amount of IRQ_NONEs we give,
112 * while still having the spurious IRQ detection code kick in if the
113 * interrupt really starts hitting spuriously.
114 */
115 return ret;
116}
117
118static struct arm_pmu_platdata db8500_pmu_platdata = {
119 .handle_irq = db8500_pmu_handler,
120};
121
122static struct platform_device db8500_pmu_device = {
123 .name = "arm-pmu",
124 .id = ARM_PMU_DEVICE_CPU,
125 .num_resources = ARRAY_SIZE(db8500_pmu_resources),
126 .resource = db8500_pmu_resources,
127 .dev.platform_data = &db8500_pmu_platdata,
128};
129
130static struct platform_device *platform_devs[] __initdata = {
131 &u8500_dma40_device,
132 &db8500_pmu_device,
133};
134
92static resource_size_t __initdata db8500_gpio_base[] = { 135static resource_size_t __initdata db8500_gpio_base[] = {
93 U8500_GPIOBANK0_BASE, 136 U8500_GPIOBANK0_BASE,
94 U8500_GPIOBANK1_BASE, 137 U8500_GPIOBANK1_BASE,