diff options
-rw-r--r-- | arch/arm/include/asm/pmu.h | 14 | ||||
-rw-r--r-- | arch/arm/kernel/perf_event.c | 17 | ||||
-rw-r--r-- | arch/arm/mach-ux500/cpu-db8500.c | 51 |
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 | |||
15 | enum arm_pmu_type { | 17 | enum 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 | */ | ||
29 | struct 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 | ||
380 | static 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 | |||
380 | static int | 387 | static int |
381 | armpmu_reserve_hardware(void) | 388 | armpmu_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 | ||
27 | static 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 */ |
32 | static struct map_desc u8500_uart_io_desc[] __initdata = { | 30 | static 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 | ||
90 | static 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 | */ | ||
102 | static 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 | |||
118 | static struct arm_pmu_platdata db8500_pmu_platdata = { | ||
119 | .handle_irq = db8500_pmu_handler, | ||
120 | }; | ||
121 | |||
122 | static 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 | |||
130 | static struct platform_device *platform_devs[] __initdata = { | ||
131 | &u8500_dma40_device, | ||
132 | &db8500_pmu_device, | ||
133 | }; | ||
134 | |||
92 | static resource_size_t __initdata db8500_gpio_base[] = { | 135 | static resource_size_t __initdata db8500_gpio_base[] = { |
93 | U8500_GPIOBANK0_BASE, | 136 | U8500_GPIOBANK0_BASE, |
94 | U8500_GPIOBANK1_BASE, | 137 | U8500_GPIOBANK1_BASE, |