Message ID | 1563351432-55652-10-git-send-email-julien.thierry@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm_pmu: Use NMI for perf interrupt | expand |
On Wed, Jul 17, 2019 at 09:17:12AM +0100, Julien Thierry wrote: > Add required PMU interrupt operations for NMIs. Request interrupt lines as > NMIs when possible, otherwise fall back to normal interrupts. > > Signed-off-by: Julien Thierry <julien.thierry@arm.com> > Tested-by: Shijith Thotton <sthotton@marvell.com> > Cc: Will Deacon <will.deacon@arm.com> > Cc: Mark Rutland <mark.rutland@arm.com> This has no effect on 32-bit ARM?
Hi Russell, On 30/07/2019 10:11, Russell King - ARM Linux admin wrote: > On Wed, Jul 17, 2019 at 09:17:12AM +0100, Julien Thierry wrote: >> Add required PMU interrupt operations for NMIs. Request interrupt lines as >> NMIs when possible, otherwise fall back to normal interrupts. >> >> Signed-off-by: Julien Thierry <julien.thierry@arm.com> >> Tested-by: Shijith Thotton <sthotton@marvell.com> >> Cc: Will Deacon <will.deacon@arm.com> >> Cc: Mark Rutland <mark.rutland@arm.com> > > This has no effect on 32-bit ARM? > It shouldn't. request_nmi()/request_percpu_nmi() should fail on a platform that doesn't have the NMI (through IRQ framework) support . Currently, only arm64 with GICv3 provides that support. So the pmu driver should fallback to request_irq()/request_percpu_irq() for a 32-bit ARM kernel platforms and work as before. I can clarify that in the commit message if there is a respin (or if maintainers agree to amend). Thanks,
On Tue, Jul 30, 2019 at 10:18:16AM +0100, Julien Thierry wrote: > Hi Russell, > > On 30/07/2019 10:11, Russell King - ARM Linux admin wrote: > > On Wed, Jul 17, 2019 at 09:17:12AM +0100, Julien Thierry wrote: > >> Add required PMU interrupt operations for NMIs. Request interrupt lines as > >> NMIs when possible, otherwise fall back to normal interrupts. > >> > >> Signed-off-by: Julien Thierry <julien.thierry@arm.com> > >> Tested-by: Shijith Thotton <sthotton@marvell.com> > >> Cc: Will Deacon <will.deacon@arm.com> > >> Cc: Mark Rutland <mark.rutland@arm.com> > > > > This has no effect on 32-bit ARM? > > > > It shouldn't. request_nmi()/request_percpu_nmi() should fail on a > platform that doesn't have the NMI (through IRQ framework) support . > Currently, only arm64 with GICv3 provides that support. > > So the pmu driver should fallback to request_irq()/request_percpu_irq() > for a 32-bit ARM kernel platforms and work as before. I can clarify that > in the commit message if there is a respin (or if maintainers agree to > amend). Has it been tested with a 32-bit guest kernel running on ARM64?
On 30/07/2019 10:28, Russell King - ARM Linux admin wrote: > On Tue, Jul 30, 2019 at 10:18:16AM +0100, Julien Thierry wrote: >> Hi Russell, >> >> On 30/07/2019 10:11, Russell King - ARM Linux admin wrote: >>> On Wed, Jul 17, 2019 at 09:17:12AM +0100, Julien Thierry wrote: >>>> Add required PMU interrupt operations for NMIs. Request interrupt lines as >>>> NMIs when possible, otherwise fall back to normal interrupts. >>>> >>>> Signed-off-by: Julien Thierry <julien.thierry@arm.com> >>>> Tested-by: Shijith Thotton <sthotton@marvell.com> >>>> Cc: Will Deacon <will.deacon@arm.com> >>>> Cc: Mark Rutland <mark.rutland@arm.com> >>> >>> This has no effect on 32-bit ARM? >>> >> >> It shouldn't. request_nmi()/request_percpu_nmi() should fail on a >> platform that doesn't have the NMI (through IRQ framework) support . >> Currently, only arm64 with GICv3 provides that support. >> >> So the pmu driver should fallback to request_irq()/request_percpu_irq() >> for a 32-bit ARM kernel platforms and work as before. I can clarify that >> in the commit message if there is a respin (or if maintainers agree to >> amend). > > Has it been tested with a 32-bit guest kernel running on ARM64? In theory, this shouldn't change anything. Even if the host has a PMU as NMI, interrupts are presented to the guest the same way as before, not in an host NMI context. And as long as the guest handles it's interrupts the same way (i.e. doesn't use priorities and sticks to PSTATE/CPSR I bit to block interrupts) things should behave like before. I still gave this a try, just in case there would be other surprises. Running (and profiling) a 32bit kvm guest from a host that is using Pseudo-NMIs for the PMU interrupt works and using the virtual PMU from within the guest also works. Thanks,
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index 9ac072a..a9c00cd 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c @@ -45,6 +45,17 @@ static void armpmu_free_pmuirq(unsigned int irq, int cpu, void __percpu *devid) .free_pmuirq = armpmu_free_pmuirq }; +static void armpmu_free_pmunmi(unsigned int irq, int cpu, void __percpu *devid) +{ + free_nmi(irq, per_cpu_ptr(devid, cpu)); +} + +static const struct pmu_irq_ops pmunmi_ops = { + .enable_pmuirq = enable_nmi, + .disable_pmuirq = disable_nmi_nosync, + .free_pmuirq = armpmu_free_pmunmi +}; + static void armpmu_enable_percpu_pmuirq(unsigned int irq) { enable_percpu_irq(irq, IRQ_TYPE_NONE); @@ -63,6 +74,31 @@ static void armpmu_free_percpu_pmuirq(unsigned int irq, int cpu, .free_pmuirq = armpmu_free_percpu_pmuirq }; +static void armpmu_enable_percpu_pmunmi(unsigned int irq) +{ + if (!prepare_percpu_nmi(irq)) + enable_percpu_nmi(irq, IRQ_TYPE_NONE); +} + +static void armpmu_disable_percpu_pmunmi(unsigned int irq) +{ + disable_percpu_nmi(irq); + teardown_percpu_nmi(irq); +} + +static void armpmu_free_percpu_pmunmi(unsigned int irq, int cpu, + void __percpu *devid) +{ + if (armpmu_count_irq_users(irq) == 1) + free_percpu_nmi(irq, devid); +} + +static const struct pmu_irq_ops percpu_pmunmi_ops = { + .enable_pmuirq = armpmu_enable_percpu_pmunmi, + .disable_pmuirq = armpmu_disable_percpu_pmunmi, + .free_pmuirq = armpmu_free_percpu_pmunmi +}; + static DEFINE_PER_CPU(struct arm_pmu *, cpu_armpmu); static DEFINE_PER_CPU(int, cpu_irq); static DEFINE_PER_CPU(const struct pmu_irq_ops *, cpu_irq_ops); @@ -633,15 +669,29 @@ int armpmu_request_irq(int irq, int cpu) IRQF_NO_THREAD; irq_set_status_flags(irq, IRQ_NOAUTOEN); - err = request_irq(irq, handler, irq_flags, "arm-pmu", + + err = request_nmi(irq, handler, irq_flags, "arm-pmu", per_cpu_ptr(&cpu_armpmu, cpu)); - irq_ops = &pmuirq_ops; + /* If cannot get an NMI, get a normal interrupt */ + if (err) { + err = request_irq(irq, handler, irq_flags, "arm-pmu", + per_cpu_ptr(&cpu_armpmu, cpu)); + irq_ops = &pmuirq_ops; + } else { + irq_ops = &pmunmi_ops; + } } else if (armpmu_count_irq_users(irq) == 0) { - err = request_percpu_irq(irq, handler, "arm-pmu", - &cpu_armpmu); - - irq_ops = &percpu_pmuirq_ops; + err = request_percpu_nmi(irq, handler, "arm-pmu", &cpu_armpmu); + + /* If cannot get an NMI, get a normal interrupt */ + if (err) { + err = request_percpu_irq(irq, handler, "arm-pmu", + &cpu_armpmu); + irq_ops = &percpu_pmuirq_ops; + } else { + irq_ops = &percpu_pmunmi_ops; + } } else { /* Per cpudevid irq was already requested by another CPU */ irq_ops = armpmu_find_irq_ops(irq);