From 0e53dc32b02f516072b5b7fa511cdccf64b8c6c5 Mon Sep 17 00:00:00 2001 From: Ashwin Chaugule Date: Mon, 29 Oct 2012 16:30:05 -0400 Subject: [PATCH] Perf: Let platforms decide IRQ request methods. This is in preparation for adding support for the unicore A5 and dualcore A5, both of which have the same MIDR value. Instead of adding extra parsing to the ARM generic perf_event file, this patch moves it to the 'mach' directory where targets types can be detected in an implementation specific manner. The default behavior is maintained for all other ARM targets. Change-Id: I041937273dbbd0fa4c602cf89a2e0fee7f73342b Signed-off-by: Ashwin Chaugule --- arch/arm/include/asm/pmu.h | 10 +++- arch/arm/kernel/perf_event.c | 10 ++++ arch/arm/kernel/perf_event_msm_krait.c | 49 ------------------- arch/arm/mach-msm/pmu.c | 67 ++++++++++++++++++++++++++ 4 files changed, 85 insertions(+), 51 deletions(-) diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h index 0d0103a4aec..02b199d3b28 100644 --- a/arch/arm/include/asm/pmu.h +++ b/arch/arm/include/asm/pmu.h @@ -32,6 +32,10 @@ enum arm_pmu_type { * interrupt and passed the address of the low level handler, * and can be used to implement any platform specific handling * before or after calling it. + * @request_pmu_irq: an optional handler in case the platform wants + * to use a percpu IRQ API call. e.g. request_percpu_irq + * @free_pmu_irq: an optional handler in case the platform wants + * to use a percpu IRQ API call. e.g. free_percpu_irq * @enable_irq: an optional handler which will be called after * request_irq and be used to handle some platform specific * irq enablement @@ -42,6 +46,8 @@ enum arm_pmu_type { struct arm_pmu_platdata { irqreturn_t (*handle_irq)(int irq, void *dev, irq_handler_t pmu_handler); + int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); + void (*free_pmu_irq)(int irq); void (*enable_irq)(int irq); void (*disable_irq)(int irq); }; @@ -115,8 +121,8 @@ struct arm_pmu { struct platform_device *plat_device; u32 from_idle; irqreturn_t (*handle_irq)(int irq_num, void *dev); - int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); - void (*free_pmu_irq)(int irq); + int (*request_pmu_irq)(int irq, irq_handler_t *irq_h); + void (*free_pmu_irq)(int irq); void (*enable)(struct hw_perf_event *evt, int idx, int cpu); void (*disable)(struct hw_perf_event *evt, int idx); int (*get_event_idx)(struct pmu_hw_events *hw_events, diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index e97aef2b4ca..86c63e44314 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -436,6 +436,16 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) else handle_irq = armpmu->handle_irq; + if (plat && plat->request_pmu_irq) + armpmu->request_pmu_irq = plat->request_pmu_irq; + else + armpmu->request_pmu_irq = armpmu_generic_request_irq; + + if (plat && plat->free_pmu_irq) + armpmu->free_pmu_irq = plat->free_pmu_irq; + else + armpmu->free_pmu_irq = armpmu_generic_free_irq; + irqs = min(pmu_device->num_resources, num_possible_cpus()); if (irqs < 1) { pr_err("no irqs for PMUs defined\n"); diff --git a/arch/arm/kernel/perf_event_msm_krait.c b/arch/arm/kernel/perf_event_msm_krait.c index 8b5d2066266..5708d7465ee 100644 --- a/arch/arm/kernel/perf_event_msm_krait.c +++ b/arch/arm/kernel/perf_event_msm_krait.c @@ -520,53 +520,6 @@ static void krait_pmu_reset(void *info) armv7_pmnc_write(ARMV7_PMNC_P | ARMV7_PMNC_C); } -static void enable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - - enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); -} - -static void disable_irq_callback(void *info) -{ - int irq = *(unsigned int *)info; - - disable_percpu_irq(irq); -} - -static int -msm_request_irq(int irq, irq_handler_t *handle_irq) -{ - int err = 0; - int cpu; - - err = request_percpu_irq(irq, *handle_irq, "l1-armpmu", - &cpu_hw_events); - - if (!err) { - for_each_cpu(cpu, cpu_online_mask) { - smp_call_function_single(cpu, - enable_irq_callback, &irq, 1); - } - } - - return err; -} - -static void -msm_free_irq(int irq) -{ - int cpu; - - if (irq >= 0) { - for_each_cpu(cpu, cpu_online_mask) { - smp_call_function_single(cpu, - disable_irq_callback, &irq, 1); - } - free_percpu_irq(irq, &cpu_hw_events); - } -} - /* * We check for column exclusion constraints here. * Two events cant have same reg and same group. @@ -621,8 +574,6 @@ static int msm_clear_ev_constraint(struct perf_event *event) static struct arm_pmu krait_pmu = { .handle_irq = armv7pmu_handle_irq, - .request_pmu_irq = msm_request_irq, - .free_pmu_irq = msm_free_irq, .enable = krait_pmu_enable_event, .disable = krait_pmu_disable_event, .read_counter = armv7pmu_read_counter, diff --git a/arch/arm/mach-msm/pmu.c b/arch/arm/mach-msm/pmu.c index ed3a651e8c5..5e87bc01202 100644 --- a/arch/arm/mach-msm/pmu.c +++ b/arch/arm/mach-msm/pmu.c @@ -11,8 +11,64 @@ */ #include +#include #include #include +#include + +#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) +static DEFINE_PER_CPU(u32, pmu_irq_cookie); + +static void enable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + enable_percpu_irq(irq, IRQ_TYPE_EDGE_RISING); +} + +static void disable_irq_callback(void *info) +{ + int irq = *(unsigned int *)info; + disable_percpu_irq(irq); +} + +static int +multicore_request_irq(int irq, irq_handler_t *handle_irq) +{ + int err = 0; + int cpu; + + err = request_percpu_irq(irq, *handle_irq, "l1-armpmu", + &pmu_irq_cookie); + + if (!err) { + for_each_cpu(cpu, cpu_online_mask) { + smp_call_function_single(cpu, + enable_irq_callback, &irq, 1); + } + } + + return err; +} + +static void +multicore_free_irq(int irq) +{ + int cpu; + + if (irq >= 0) { + for_each_cpu(cpu, cpu_online_mask) { + smp_call_function_single(cpu, + disable_irq_callback, &irq, 1); + } + free_percpu_irq(irq, &pmu_irq_cookie); + } +} + +static struct arm_pmu_platdata multicore_data = { + .request_pmu_irq = multicore_request_irq, + .free_pmu_irq = multicore_free_irq, +}; +#endif static struct resource cpu_pmu_resource[] = { { @@ -47,6 +103,7 @@ static struct platform_device cpu_pmu_device = { .num_resources = ARRAY_SIZE(cpu_pmu_resource), }; + static struct platform_device *pmu_devices[] = { &cpu_pmu_device, #ifdef CONFIG_CPU_HAS_L2_PMU @@ -56,6 +113,16 @@ static struct platform_device *pmu_devices[] = { static int __init msm_pmu_init(void) { + /* + * For the targets we know are multicore's set the request/free IRQ + * handlers to call the percpu API. + * Defaults to unicore API {request,free}_irq(). + * See arch/arm/kernel/perf_event.c + */ +#if defined(CONFIG_ARCH_MSM_KRAITMP) || defined(CONFIG_ARCH_MSM_SCORPIONMP) + cpu_pmu_device.dev.platform_data = &multicore_data; +#endif + return platform_add_devices(pmu_devices, ARRAY_SIZE(pmu_devices)); }