* [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus
@ 2026-04-21 20:38 Besar Wicaksono
2026-04-22 10:32 ` James Clark
0 siblings, 1 reply; 4+ messages in thread
From: Besar Wicaksono @ 2026-04-21 20:38 UTC (permalink / raw)
To: will, mark.rutland, james.clark
Cc: linux-arm-kernel, linux-kernel, linux-tegra, treding, jonathanh,
vsethi, rwiley, sdonthineni, mochs, nirmoyd, skelley,
Besar Wicaksono
The PMCCNTR_EL0 in NVIDIA Olympus CPU may increment while
in WFI/WFE, which does not align with counting CPU_CYCLES
on a programmable counter. Add a MIDR range entry and
refuse PMCCNTR_EL0 for cycle events on affected parts so
perf does not mix the two behaviors.
Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
---
Changes from v1:
* add CONFIG_ARM64 check to fix build error found by kernel test robot
* add explicit include of <asm/cputype.h>
v1: https://lore.kernel.org/linux-arm-kernel/20260406232034.2566133-1-bwicaksono@nvidia.com/
---
drivers/perf/arm_pmuv3.c | 44 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
index 8014ff766cff..7c39d0804b9f 100644
--- a/drivers/perf/arm_pmuv3.c
+++ b/drivers/perf/arm_pmuv3.c
@@ -8,6 +8,7 @@
* This code is based heavily on the ARMv7 perf event code.
*/
+#include <asm/cputype.h>
#include <asm/irq_regs.h>
#include <asm/perf_event.h>
#include <asm/virt.h>
@@ -978,6 +979,41 @@ static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc,
return -EAGAIN;
}
+#ifdef CONFIG_ARM64
+/*
+ * List of CPUs that should avoid using PMCCNTR_EL0.
+ */
+static struct midr_range armv8pmu_avoid_pmccntr_cpus[] = {
+ /*
+ * The PMCCNTR_EL0 in Olympus CPU may still increment while in WFI/WFE state.
+ * This is an implementation specific behavior and not an erratum.
+ *
+ * From ARM DDI0487 D14.4:
+ * It is IMPLEMENTATION SPECIFIC whether CPU_CYCLES and PMCCNTR count
+ * when the PE is in WFI or WFE state, even if the clocks are not stopped.
+ *
+ * From ARM DDI0487 D24.5.2:
+ * All counters are subject to any changes in clock frequency, including
+ * clock stopping caused by the WFI and WFE instructions.
+ * This means that it is CONSTRAINED UNPREDICTABLE whether or not
+ * PMCCNTR_EL0 continues to increment when clocks are stopped by WFI and
+ * WFE instructions.
+ */
+ MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
+ {}
+};
+
+static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
+{
+ return is_midr_in_range_list(armv8pmu_avoid_pmccntr_cpus);
+}
+#else
+static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
+{
+ return false;
+}
+#endif
+
static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
struct perf_event *event)
{
@@ -1011,6 +1047,14 @@ static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
if (cpu_pmu->has_smt)
return false;
+ /*
+ * On some CPUs, PMCCNTR_EL0 does not match the behavior of CPU_CYCLES
+ * programmable counter, so avoid routing cycles through PMCCNTR_EL0 to
+ * prevent inconsistency in the results.
+ */
+ if (armv8pmu_is_in_avoid_pmccntr_cpus())
+ return false;
+
return true;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus
2026-04-21 20:38 [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus Besar Wicaksono
@ 2026-04-22 10:32 ` James Clark
2026-04-22 20:17 ` Besar Wicaksono
0 siblings, 1 reply; 4+ messages in thread
From: James Clark @ 2026-04-22 10:32 UTC (permalink / raw)
To: Besar Wicaksono, will, mark.rutland
Cc: linux-arm-kernel, linux-kernel, linux-tegra, treding, jonathanh,
vsethi, rwiley, sdonthineni, mochs, nirmoyd, skelley
On 21/04/2026 21:38, Besar Wicaksono wrote:
> The PMCCNTR_EL0 in NVIDIA Olympus CPU may increment while
> in WFI/WFE, which does not align with counting CPU_CYCLES
> on a programmable counter. Add a MIDR range entry and
> refuse PMCCNTR_EL0 for cycle events on affected parts so
> perf does not mix the two behaviors.
>
> Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
> ---
>
> Changes from v1:
> * add CONFIG_ARM64 check to fix build error found by kernel test robot
> * add explicit include of <asm/cputype.h>
> v1: https://lore.kernel.org/linux-arm-kernel/20260406232034.2566133-1-bwicaksono@nvidia.com/
>
> ---
> drivers/perf/arm_pmuv3.c | 44 ++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 44 insertions(+)
>
> diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
> index 8014ff766cff..7c39d0804b9f 100644
> --- a/drivers/perf/arm_pmuv3.c
> +++ b/drivers/perf/arm_pmuv3.c
> @@ -8,6 +8,7 @@
> * This code is based heavily on the ARMv7 perf event code.
> */
>
> +#include <asm/cputype.h>
> #include <asm/irq_regs.h>
> #include <asm/perf_event.h>
> #include <asm/virt.h>
> @@ -978,6 +979,41 @@ static int armv8pmu_get_chain_idx(struct pmu_hw_events *cpuc,
> return -EAGAIN;
> }
>
> +#ifdef CONFIG_ARM64
> +/*
> + * List of CPUs that should avoid using PMCCNTR_EL0.
> + */
> +static struct midr_range armv8pmu_avoid_pmccntr_cpus[] = {
> + /*
> + * The PMCCNTR_EL0 in Olympus CPU may still increment while in WFI/WFE state.
> + * This is an implementation specific behavior and not an erratum.
> + *
> + * From ARM DDI0487 D14.4:
> + * It is IMPLEMENTATION SPECIFIC whether CPU_CYCLES and PMCCNTR count
> + * when the PE is in WFI or WFE state, even if the clocks are not stopped.
> + *
> + * From ARM DDI0487 D24.5.2:
> + * All counters are subject to any changes in clock frequency, including
> + * clock stopping caused by the WFI and WFE instructions.
> + * This means that it is CONSTRAINED UNPREDICTABLE whether or not
> + * PMCCNTR_EL0 continues to increment when clocks are stopped by WFI and
> + * WFE instructions.
> + */
> + MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
> + {}
> +};
> +
> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
> +{
> + return is_midr_in_range_list(armv8pmu_avoid_pmccntr_cpus);
> +}
> +#else
> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
> +{
> + return false;
> +}
> +#endif
> +
> static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
> struct perf_event *event)
> {
> @@ -1011,6 +1047,14 @@ static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
> if (cpu_pmu->has_smt)
> return false;
>
> + /*
> + * On some CPUs, PMCCNTR_EL0 does not match the behavior of CPU_CYCLES
> + * programmable counter, so avoid routing cycles through PMCCNTR_EL0 to
> + * prevent inconsistency in the results.
> + */
> + if (armv8pmu_is_in_avoid_pmccntr_cpus())
> + return false;
> +
Hi Besar,
This is called from armpmu_event_init() before the event is scheduled on
the CPU so I don't think reading the MIDR at this point is safe.
When the PMU is probed you probably need to do an SMP call to get the
MIDR of CPUs in that PMU's mask and then cache the "avoid pmccntr"
result like has_smt. Or even rename has_smt to avoid_pmccntr and combine
the two results there.
I don't know what will happen if none of those CPUs are online when the
PMU is probed though...
James
> return true;
> }
>
^ permalink raw reply [flat|nested] 4+ messages in thread* RE: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus
2026-04-22 10:32 ` James Clark
@ 2026-04-22 20:17 ` Besar Wicaksono
2026-04-23 8:29 ` James Clark
0 siblings, 1 reply; 4+ messages in thread
From: Besar Wicaksono @ 2026-04-22 20:17 UTC (permalink / raw)
To: James Clark, will@kernel.org, mark.rutland@arm.com
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
Thierry Reding, Jon Hunter, Vikram Sethi, Rich Wiley,
Shanker Donthineni, Matt Ochs, Nirmoy Das, Sean Kelley
> -----Original Message-----
> From: James Clark <james.clark@linaro.org>
> Sent: Wednesday, April 22, 2026 5:33 AM
> To: Besar Wicaksono <bwicaksono@nvidia.com>; will@kernel.org;
> mark.rutland@arm.com
> Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-
> tegra@vger.kernel.org; Thierry Reding <treding@nvidia.com>; Jon Hunter
> <jonathanh@nvidia.com>; Vikram Sethi <vsethi@nvidia.com>; Rich Wiley
> <rwiley@nvidia.com>; Shanker Donthineni <sdonthineni@nvidia.com>; Matt
> Ochs <mochs@nvidia.com>; Nirmoy Das <nirmoyd@nvidia.com>; Sean Kelley
> <skelley@nvidia.com>
> Subject: Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA
> Olympus
>
> External email: Use caution opening links or attachments
>
>
> On 21/04/2026 21:38, Besar Wicaksono wrote:
> > The PMCCNTR_EL0 in NVIDIA Olympus CPU may increment while
> > in WFI/WFE, which does not align with counting CPU_CYCLES
> > on a programmable counter. Add a MIDR range entry and
> > refuse PMCCNTR_EL0 for cycle events on affected parts so
> > perf does not mix the two behaviors.
> >
> > Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
> > ---
> >
> > Changes from v1:
> > * add CONFIG_ARM64 check to fix build error found by kernel test robot
> > * add explicit include of <asm/cputype.h>
> > v1: https://lore.kernel.org/linux-arm-kernel/20260406232034.2566133-1-
> bwicaksono@nvidia.com/
> >
> > ---
> > drivers/perf/arm_pmuv3.c | 44
> ++++++++++++++++++++++++++++++++++++++++
> > 1 file changed, 44 insertions(+)
> >
> > diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
> > index 8014ff766cff..7c39d0804b9f 100644
> > --- a/drivers/perf/arm_pmuv3.c
> > +++ b/drivers/perf/arm_pmuv3.c
> > @@ -8,6 +8,7 @@
> > * This code is based heavily on the ARMv7 perf event code.
> > */
> >
> > +#include <asm/cputype.h>
> > #include <asm/irq_regs.h>
> > #include <asm/perf_event.h>
> > #include <asm/virt.h>
> > @@ -978,6 +979,41 @@ static int armv8pmu_get_chain_idx(struct
> pmu_hw_events *cpuc,
> > return -EAGAIN;
> > }
> >
> > +#ifdef CONFIG_ARM64
> > +/*
> > + * List of CPUs that should avoid using PMCCNTR_EL0.
> > + */
> > +static struct midr_range armv8pmu_avoid_pmccntr_cpus[] = {
> > + /*
> > + * The PMCCNTR_EL0 in Olympus CPU may still increment while in
> WFI/WFE state.
> > + * This is an implementation specific behavior and not an erratum.
> > + *
> > + * From ARM DDI0487 D14.4:
> > + * It is IMPLEMENTATION SPECIFIC whether CPU_CYCLES and PMCCNTR
> count
> > + * when the PE is in WFI or WFE state, even if the clocks are not stopped.
> > + *
> > + * From ARM DDI0487 D24.5.2:
> > + * All counters are subject to any changes in clock frequency, including
> > + * clock stopping caused by the WFI and WFE instructions.
> > + * This means that it is CONSTRAINED UNPREDICTABLE whether or not
> > + * PMCCNTR_EL0 continues to increment when clocks are stopped by
> WFI and
> > + * WFE instructions.
> > + */
> > + MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
> > + {}
> > +};
> > +
> > +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
> > +{
> > + return is_midr_in_range_list(armv8pmu_avoid_pmccntr_cpus);
> > +}
> > +#else
> > +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
> > +{
> > + return false;
> > +}
> > +#endif
> > +
> > static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
> > struct perf_event *event)
> > {
> > @@ -1011,6 +1047,14 @@ static bool armv8pmu_can_use_pmccntr(struct
> pmu_hw_events *cpuc,
> > if (cpu_pmu->has_smt)
> > return false;
> >
> > + /*
> > + * On some CPUs, PMCCNTR_EL0 does not match the behavior of
> CPU_CYCLES
> > + * programmable counter, so avoid routing cycles through PMCCNTR_EL0
> to
> > + * prevent inconsistency in the results.
> > + */
> > + if (armv8pmu_is_in_avoid_pmccntr_cpus())
> > + return false;
> > +
>
> Hi Besar,
>
> This is called from armpmu_event_init() before the event is scheduled on
> the CPU so I don't think reading the MIDR at this point is safe.
>
> When the PMU is probed you probably need to do an SMP call to get the
> MIDR of CPUs in that PMU's mask and then cache the "avoid pmccntr"
> result like has_smt. Or even rename has_smt to avoid_pmccntr and combine
> the two results there.
>
> I don't know what will happen if none of those CPUs are online when the
> PMU is probed though...
>
Hi James,
has_smt, iiuc, is common to all the supported CPUs of the PMU context.
It is configured based on the first CPU in supported cpu list.
pmu->has_smt = topology_core_has_smt(cpumask_first(&pmu->supported_cpus));
Is it okay to use same approach? Can we assume all CPUs in supported_cpus have same midr?
Thanks,
Besar
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus
2026-04-22 20:17 ` Besar Wicaksono
@ 2026-04-23 8:29 ` James Clark
0 siblings, 0 replies; 4+ messages in thread
From: James Clark @ 2026-04-23 8:29 UTC (permalink / raw)
To: Besar Wicaksono
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-tegra@vger.kernel.org,
Thierry Reding, Jon Hunter, Vikram Sethi, Rich Wiley,
Shanker Donthineni, Matt Ochs, Nirmoy Das, Sean Kelley,
will@kernel.org, mark.rutland@arm.com
On 22/04/2026 21:17, Besar Wicaksono wrote:
>
>
>> -----Original Message-----
>> From: James Clark <james.clark@linaro.org>
>> Sent: Wednesday, April 22, 2026 5:33 AM
>> To: Besar Wicaksono <bwicaksono@nvidia.com>; will@kernel.org;
>> mark.rutland@arm.com
>> Cc: linux-arm-kernel@lists.infradead.org; linux-kernel@vger.kernel.org; linux-
>> tegra@vger.kernel.org; Thierry Reding <treding@nvidia.com>; Jon Hunter
>> <jonathanh@nvidia.com>; Vikram Sethi <vsethi@nvidia.com>; Rich Wiley
>> <rwiley@nvidia.com>; Shanker Donthineni <sdonthineni@nvidia.com>; Matt
>> Ochs <mochs@nvidia.com>; Nirmoy Das <nirmoyd@nvidia.com>; Sean Kelley
>> <skelley@nvidia.com>
>> Subject: Re: [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA
>> Olympus
>>
>> External email: Use caution opening links or attachments
>>
>>
>> On 21/04/2026 21:38, Besar Wicaksono wrote:
>>> The PMCCNTR_EL0 in NVIDIA Olympus CPU may increment while
>>> in WFI/WFE, which does not align with counting CPU_CYCLES
>>> on a programmable counter. Add a MIDR range entry and
>>> refuse PMCCNTR_EL0 for cycle events on affected parts so
>>> perf does not mix the two behaviors.
>>>
>>> Signed-off-by: Besar Wicaksono <bwicaksono@nvidia.com>
>>> ---
>>>
>>> Changes from v1:
>>> * add CONFIG_ARM64 check to fix build error found by kernel test robot
>>> * add explicit include of <asm/cputype.h>
>>> v1: https://lore.kernel.org/linux-arm-kernel/20260406232034.2566133-1-
>> bwicaksono@nvidia.com/
>>>
>>> ---
>>> drivers/perf/arm_pmuv3.c | 44
>> ++++++++++++++++++++++++++++++++++++++++
>>> 1 file changed, 44 insertions(+)
>>>
>>> diff --git a/drivers/perf/arm_pmuv3.c b/drivers/perf/arm_pmuv3.c
>>> index 8014ff766cff..7c39d0804b9f 100644
>>> --- a/drivers/perf/arm_pmuv3.c
>>> +++ b/drivers/perf/arm_pmuv3.c
>>> @@ -8,6 +8,7 @@
>>> * This code is based heavily on the ARMv7 perf event code.
>>> */
>>>
>>> +#include <asm/cputype.h>
>>> #include <asm/irq_regs.h>
>>> #include <asm/perf_event.h>
>>> #include <asm/virt.h>
>>> @@ -978,6 +979,41 @@ static int armv8pmu_get_chain_idx(struct
>> pmu_hw_events *cpuc,
>>> return -EAGAIN;
>>> }
>>>
>>> +#ifdef CONFIG_ARM64
>>> +/*
>>> + * List of CPUs that should avoid using PMCCNTR_EL0.
>>> + */
>>> +static struct midr_range armv8pmu_avoid_pmccntr_cpus[] = {
>>> + /*
>>> + * The PMCCNTR_EL0 in Olympus CPU may still increment while in
>> WFI/WFE state.
>>> + * This is an implementation specific behavior and not an erratum.
>>> + *
>>> + * From ARM DDI0487 D14.4:
>>> + * It is IMPLEMENTATION SPECIFIC whether CPU_CYCLES and PMCCNTR
>> count
>>> + * when the PE is in WFI or WFE state, even if the clocks are not stopped.
>>> + *
>>> + * From ARM DDI0487 D24.5.2:
>>> + * All counters are subject to any changes in clock frequency, including
>>> + * clock stopping caused by the WFI and WFE instructions.
>>> + * This means that it is CONSTRAINED UNPREDICTABLE whether or not
>>> + * PMCCNTR_EL0 continues to increment when clocks are stopped by
>> WFI and
>>> + * WFE instructions.
>>> + */
>>> + MIDR_ALL_VERSIONS(MIDR_NVIDIA_OLYMPUS),
>>> + {}
>>> +};
>>> +
>>> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
>>> +{
>>> + return is_midr_in_range_list(armv8pmu_avoid_pmccntr_cpus);
>>> +}
>>> +#else
>>> +static bool armv8pmu_is_in_avoid_pmccntr_cpus(void)
>>> +{
>>> + return false;
>>> +}
>>> +#endif
>>> +
>>> static bool armv8pmu_can_use_pmccntr(struct pmu_hw_events *cpuc,
>>> struct perf_event *event)
>>> {
>>> @@ -1011,6 +1047,14 @@ static bool armv8pmu_can_use_pmccntr(struct
>> pmu_hw_events *cpuc,
>>> if (cpu_pmu->has_smt)
>>> return false;
>>>
>>> + /*
>>> + * On some CPUs, PMCCNTR_EL0 does not match the behavior of
>> CPU_CYCLES
>>> + * programmable counter, so avoid routing cycles through PMCCNTR_EL0
>> to
>>> + * prevent inconsistency in the results.
>>> + */
>>> + if (armv8pmu_is_in_avoid_pmccntr_cpus())
>>> + return false;
>>> +
>>
>> Hi Besar,
>>
>> This is called from armpmu_event_init() before the event is scheduled on
>> the CPU so I don't think reading the MIDR at this point is safe.
>>
>> When the PMU is probed you probably need to do an SMP call to get the
>> MIDR of CPUs in that PMU's mask and then cache the "avoid pmccntr"
>> result like has_smt. Or even rename has_smt to avoid_pmccntr and combine
>> the two results there.
>>
>> I don't know what will happen if none of those CPUs are online when the
>> PMU is probed though...
>>
>
> Hi James,
>
> has_smt, iiuc, is common to all the supported CPUs of the PMU context.
> It is configured based on the first CPU in supported cpu list.
>
> pmu->has_smt = topology_core_has_smt(cpumask_first(&pmu->supported_cpus));
>
> Is it okay to use same approach? Can we assume all CPUs in supported_cpus have same midr?
>
They should have the same MIDR otherwise it would be misconfigured, or
at least the PMUs should behave exactly the same way for all CPUs in the
mask. I think the whole point of separate PMUs is for heterogeneous systems.
As long as all CPUs in that mask behave the same way, then reading the
MIDR from any CPU in that mask should be ok. We do it that way for SPE
as well:
/* Make sure we probe the hardware on a relevant CPU */
ret = smp_call_function_any(mask, __arm_spe_pmu_dev_probe, spe_pmu, 1);
> Thanks,
> Besar
>
>
>
>
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-04-23 8:29 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-21 20:38 [PATCH v2] perf/arm_pmu: Skip PMCCNTR_EL0 on NVIDIA Olympus Besar Wicaksono
2026-04-22 10:32 ` James Clark
2026-04-22 20:17 ` Besar Wicaksono
2026-04-23 8:29 ` James Clark
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox