* [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag. @ 2012-07-30 14:32 Chris Smith 2012-07-30 14:32 ` [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts Chris Smith 0 siblings, 1 reply; 4+ messages in thread From: Chris Smith @ 2012-07-30 14:32 UTC (permalink / raw) To: linux-kernel, linux-arm-kernel Cc: tglx, will.deacon, srinidhi.kasagar, Chris Smith Adds an accessor function, irq_is_per_cpu(), for the flag IRQ_PER_CPU. This is useful if you have an IRQ that is per-cpu in some hardware implementations, and not in others (example: ARM PMU Interrupts), and you want to handle both cases. Signed-off-by: Chris Smith <chris.smith@st.com> --- include/linux/irqdesc.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index f1e2527..771cb35 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -154,6 +154,14 @@ static inline int irq_balancing_disabled(unsigned int irq) return desc->status_use_accessors & IRQ_NO_BALANCING_MASK; } +static inline int irq_is_per_cpu(unsigned int irq) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + return desc->status_use_accessors & IRQ_PER_CPU; +} + static inline void irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class) { -- 1.7.6.5 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts. 2012-07-30 14:32 [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag Chris Smith @ 2012-07-30 14:32 ` Chris Smith 2012-07-30 16:37 ` Will Deacon 0 siblings, 1 reply; 4+ messages in thread From: Chris Smith @ 2012-07-30 14:32 UTC (permalink / raw) To: linux-kernel, linux-arm-kernel Cc: tglx, will.deacon, srinidhi.kasagar, Chris Smith We have systems where the PMU interrupts are PPIs, and so per-cpu. This patch adds support for per-cpu PMU interrupts to the perf event code. Note that because the dev_id passed to request_percpu_irq has to be percpu data, we now pass cpu_hw_events as the dev_id rather than armpmu. This only place the dev_id was used was in armpmu_platform_irq, which is fixed up accordingly. Signed-off-by: Chris Smith <chris.smith@st.com> --- arch/arm/kernel/perf_event.c | 91 +++++++++++++++++++++++++++++--------- arch/arm/kernel/perf_event_v6.c | 3 +- arch/arm/kernel/perf_event_v7.c | 3 +- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index b2abfa1..add9064 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -14,6 +14,7 @@ #include <linux/bitmap.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/perf_event.h> @@ -355,13 +356,27 @@ validate_group(struct perf_event *event) static irqreturn_t armpmu_platform_irq(int irq, void *dev) { - struct arm_pmu *armpmu = (struct arm_pmu *) dev; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; + struct arm_pmu *armpmu = to_arm_pmu((*(cpuc->events))->pmu); + struct platform_device *plat_device = armpmu->plat_device; struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); return plat->handle_irq(irq, dev, armpmu->handle_irq); } +/* Wrap enable_percpu_irq up as a smp_call_func_t */ +static void armpmu_enable_percpu_irq(void *irq) +{ + enable_percpu_irq((int)irq, IRQ_TYPE_NONE); +} + +/* Wrap disable_percpu_irq up as a smp_call_func_t */ +static void armpmu_disable_percpu_irq(void *irq) +{ + disable_percpu_irq((int)irq); +} + static void armpmu_release_hardware(struct arm_pmu *armpmu) { @@ -379,7 +394,14 @@ armpmu_release_hardware(struct arm_pmu *armpmu) if (irq >= 0) { if (plat && plat->disable_irq) plat->disable_irq(irq); - free_irq(irq, armpmu); + else if (irq_is_per_cpu(irq)) + on_each_cpu(armpmu_disable_percpu_irq, + (void *)irq, 1); + + if (irq_is_per_cpu(irq)) + free_percpu_irq(irq, &cpu_hw_events); + else + free_irq(irq, &per_cpu(cpu_hw_events, i)); } } @@ -421,28 +443,53 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) if (irq < 0) continue; - /* - * If we have a single PMU interrupt that we can't shift, - * assume that we're running on a uniprocessor machine and - * continue. Otherwise, continue without this interrupt. - */ - if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { - pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", - irq, i); - continue; + if (irq_is_per_cpu(irq)) { + /* + * We assume that if the PMU IRQ is per-cpu, then + * there is only one. + */ + WARN_ON(irqs > 1); + + err = request_percpu_irq(irq, handle_irq, + "arm-pmu", &cpu_hw_events); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) { + plat->enable_irq(irq); + } else { + on_each_cpu(armpmu_enable_percpu_irq, + (void *)irq, 1); + } + + } else { + /* + * If we have a single PMU interrupt that we can't + * shift, assume that we're running on a uniprocessor + * machine and continue. Otherwise, continue without + * this interrupt. + */ + if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, i); + continue; + } + + err = request_irq(irq, handle_irq, + IRQF_DISABLED | IRQF_NOBALANCING, + "arm-pmu", &per_cpu(cpu_hw_events, i)); + + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) + plat->enable_irq(irq); } - err = request_irq(irq, handle_irq, - IRQF_DISABLED | IRQF_NOBALANCING, - "arm-pmu", armpmu); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - armpmu_release_hardware(armpmu); - return err; - } else if (plat && plat->enable_irq) - plat->enable_irq(irq); - cpumask_set_cpu(i, &armpmu->active_irqs); } diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index b78af0c..6b348f5 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -473,7 +473,7 @@ armv6pmu_handle_irq(int irq_num, { unsigned long pmcr = armv6_pmcr_read(); struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -491,7 +491,6 @@ armv6pmu_handle_irq(int irq_num, perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4d7095a..56ddad7 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -933,7 +933,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) { u32 pmnc; struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -955,7 +955,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; -- 1.7.6.5 ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts. 2012-07-30 14:32 ` [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts Chris Smith @ 2012-07-30 16:37 ` Will Deacon 0 siblings, 0 replies; 4+ messages in thread From: Will Deacon @ 2012-07-30 16:37 UTC (permalink / raw) To: Chris Smith; +Cc: linux-kernel, linux-arm-kernel, tglx, srinidhi.kasagar Hi Chris, On Mon, Jul 30, 2012 at 03:32:12PM +0100, Chris Smith wrote: > We have systems where the PMU interrupts are PPIs, and so per-cpu. This > patch adds support for per-cpu PMU interrupts to the perf event code. > > Note that because the dev_id passed to request_percpu_irq has to be > percpu data, we now pass cpu_hw_events as the dev_id rather than armpmu. > This only place the dev_id was used was in armpmu_platform_irq, which is > fixed up accordingly. > > Signed-off-by: Chris Smith <chris.smith@st.com> > --- I'm actually in the process of moving request/free IRQ into an armpmu callback, so this patch would fit more neatly into that. I should have something available this week that you can take a look at. Will ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag. @ 2012-07-30 14:12 y 2012-07-30 14:12 ` [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts y 0 siblings, 1 reply; 4+ messages in thread From: y @ 2012-07-30 14:12 UTC (permalink / raw) To: linux-kernel, linux-arm-kernel Cc: tglx, will.deacon, srinidhi.kasagar, Chris Smith From: Chris Smith <chris.smith@st.com> Adds an accessor function, irq_is_per_cpu(), for the flag IRQ_PER_CPU. This is useful if you have an IRQ that is per-cpu in some hardware implementations, and not in others (example: ARM PMU Interrupts), and you want to handle both cases. Signed-off-by: Chris Smith <chris.smith@st.com> --- include/linux/irqdesc.h | 8 ++++++++ 1 files changed, 8 insertions(+), 0 deletions(-) diff --git a/include/linux/irqdesc.h b/include/linux/irqdesc.h index f1e2527..771cb35 100644 --- a/include/linux/irqdesc.h +++ b/include/linux/irqdesc.h @@ -154,6 +154,14 @@ static inline int irq_balancing_disabled(unsigned int irq) return desc->status_use_accessors & IRQ_NO_BALANCING_MASK; } +static inline int irq_is_per_cpu(unsigned int irq) +{ + struct irq_desc *desc; + + desc = irq_to_desc(irq); + return desc->status_use_accessors & IRQ_PER_CPU; +} + static inline void irq_set_lockdep_class(unsigned int irq, struct lock_class_key *class) { -- 1.7.6.5 ^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts. 2012-07-30 14:12 [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag y @ 2012-07-30 14:12 ` y 0 siblings, 0 replies; 4+ messages in thread From: y @ 2012-07-30 14:12 UTC (permalink / raw) To: linux-kernel, linux-arm-kernel Cc: tglx, will.deacon, srinidhi.kasagar, Chris Smith From: Chris Smith <chris.smith@st.com> We have systems where the PMU interrupts are PPIs, and so per-cpu. This patch adds support for per-cpu PMU interrupts to the perf event code. Note that because the dev_id passed to request_percpu_irq has to be percpu data, we now pass cpu_hw_events as the dev_id rather than armpmu. This only place the dev_id was used was in armpmu_platform_irq, which is fixed up accordingly. Signed-off-by: Chris Smith <chris.smith@st.com> --- arch/arm/kernel/perf_event.c | 91 +++++++++++++++++++++++++++++--------- arch/arm/kernel/perf_event_v6.c | 3 +- arch/arm/kernel/perf_event_v7.c | 3 +- 3 files changed, 71 insertions(+), 26 deletions(-) diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index b2abfa1..add9064 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c @@ -14,6 +14,7 @@ #include <linux/bitmap.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/perf_event.h> @@ -355,13 +356,27 @@ validate_group(struct perf_event *event) static irqreturn_t armpmu_platform_irq(int irq, void *dev) { - struct arm_pmu *armpmu = (struct arm_pmu *) dev; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; + struct arm_pmu *armpmu = to_arm_pmu((*(cpuc->events))->pmu); + struct platform_device *plat_device = armpmu->plat_device; struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); return plat->handle_irq(irq, dev, armpmu->handle_irq); } +/* Wrap enable_percpu_irq up as a smp_call_func_t */ +static void armpmu_enable_percpu_irq(void *irq) +{ + enable_percpu_irq((int)irq, IRQ_TYPE_NONE); +} + +/* Wrap disable_percpu_irq up as a smp_call_func_t */ +static void armpmu_disable_percpu_irq(void *irq) +{ + disable_percpu_irq((int)irq); +} + static void armpmu_release_hardware(struct arm_pmu *armpmu) { @@ -379,7 +394,14 @@ armpmu_release_hardware(struct arm_pmu *armpmu) if (irq >= 0) { if (plat && plat->disable_irq) plat->disable_irq(irq); - free_irq(irq, armpmu); + else if (irq_is_per_cpu(irq)) + on_each_cpu(armpmu_disable_percpu_irq, + (void *)irq, 1); + + if (irq_is_per_cpu(irq)) + free_percpu_irq(irq, &cpu_hw_events); + else + free_irq(irq, &per_cpu(cpu_hw_events, i)); } } @@ -421,28 +443,53 @@ armpmu_reserve_hardware(struct arm_pmu *armpmu) if (irq < 0) continue; - /* - * If we have a single PMU interrupt that we can't shift, - * assume that we're running on a uniprocessor machine and - * continue. Otherwise, continue without this interrupt. - */ - if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { - pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", - irq, i); - continue; + if (irq_is_per_cpu(irq)) { + /* + * We assume that if the PMU IRQ is per-cpu, then + * there is only one. + */ + WARN_ON(irqs > 1); + + err = request_percpu_irq(irq, handle_irq, + "arm-pmu", &cpu_hw_events); + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) { + plat->enable_irq(irq); + } else { + on_each_cpu(armpmu_enable_percpu_irq, + (void *)irq, 1); + } + + } else { + /* + * If we have a single PMU interrupt that we can't + * shift, assume that we're running on a uniprocessor + * machine and continue. Otherwise, continue without + * this interrupt. + */ + if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { + pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", + irq, i); + continue; + } + + err = request_irq(irq, handle_irq, + IRQF_DISABLED | IRQF_NOBALANCING, + "arm-pmu", &per_cpu(cpu_hw_events, i)); + + if (err) { + pr_err("unable to request IRQ%d for ARM PMU counters\n", + irq); + armpmu_release_hardware(armpmu); + return err; + } else if (plat && plat->enable_irq) + plat->enable_irq(irq); } - err = request_irq(irq, handle_irq, - IRQF_DISABLED | IRQF_NOBALANCING, - "arm-pmu", armpmu); - if (err) { - pr_err("unable to request IRQ%d for ARM PMU counters\n", - irq); - armpmu_release_hardware(armpmu); - return err; - } else if (plat && plat->enable_irq) - plat->enable_irq(irq); - cpumask_set_cpu(i, &armpmu->active_irqs); } diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c index b78af0c..6b348f5 100644 --- a/arch/arm/kernel/perf_event_v6.c +++ b/arch/arm/kernel/perf_event_v6.c @@ -473,7 +473,7 @@ armv6pmu_handle_irq(int irq_num, { unsigned long pmcr = armv6_pmcr_read(); struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -491,7 +491,6 @@ armv6pmu_handle_irq(int irq_num, perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c index 4d7095a..56ddad7 100644 --- a/arch/arm/kernel/perf_event_v7.c +++ b/arch/arm/kernel/perf_event_v7.c @@ -933,7 +933,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) { u32 pmnc; struct perf_sample_data data; - struct pmu_hw_events *cpuc; + struct pmu_hw_events *cpuc = (struct pmu_hw_events *)dev; struct pt_regs *regs; int idx; @@ -955,7 +955,6 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev) perf_sample_data_init(&data, 0); - cpuc = &__get_cpu_var(cpu_hw_events); for (idx = 0; idx < cpu_pmu->num_events; ++idx) { struct perf_event *event = cpuc->events[idx]; struct hw_perf_event *hwc; -- 1.7.6.5 ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2012-07-30 16:37 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-07-30 14:32 [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag Chris Smith 2012-07-30 14:32 ` [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts Chris Smith 2012-07-30 16:37 ` Will Deacon -- strict thread matches above, loose matches on Subject: below -- 2012-07-30 14:12 [PATCH 1/2] genirq: Provide an accessor for IRQ_PER_CPU flag y 2012-07-30 14:12 ` [PATCH 2/2] arm: pmu: add support for per-cpu PMU interrupts y
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®