| From fdbef8c4e68ad423416aa6cc93d1616d6f8ac5b3 Mon Sep 17 00:00:00 2001 |
| From: Yang Jihong <yangjihong1@huawei.com> |
| Date: Fri, 30 Apr 2021 09:26:59 +0800 |
| Subject: arm_pmu: Fix write counter incorrect in ARMv7 big-endian mode |
| |
| From: Yang Jihong <yangjihong1@huawei.com> |
| |
| commit fdbef8c4e68ad423416aa6cc93d1616d6f8ac5b3 upstream. |
| |
| Commit 3a95200d3f89 ("arm_pmu: Change API to support 64bit counter values") |
| changes the input "value" type from 32-bit to 64-bit, which introduces the |
| following problem: ARMv7 PMU counters is 32-bit width, in big-endian mode, |
| write counter uses high 32-bit, which writes an incorrect value. |
| |
| Before: |
| |
| Performance counter stats for 'ls': |
| |
| 2.22 msec task-clock # 0.675 CPUs utilized |
| 0 context-switches # 0.000 K/sec |
| 0 cpu-migrations # 0.000 K/sec |
| 49 page-faults # 0.022 M/sec |
| 2150476593 cycles # 966.663 GHz |
| 2148588788 instructions # 1.00 insn per cycle |
| 2147745484 branches # 965435.074 M/sec |
| 2147508540 branch-misses # 99.99% of all branches |
| |
| None of the above hw event counters are correct. |
| |
| Solution: |
| |
| "value" forcibly converted to 32-bit type before being written to PMU register. |
| |
| After: |
| |
| Performance counter stats for 'ls': |
| |
| 2.09 msec task-clock # 0.681 CPUs utilized |
| 0 context-switches # 0.000 K/sec |
| 0 cpu-migrations # 0.000 K/sec |
| 46 page-faults # 0.022 M/sec |
| 2807301 cycles # 1.344 GHz |
| 1060159 instructions # 0.38 insn per cycle |
| 250496 branches # 119.914 M/sec |
| 23192 branch-misses # 9.26% of all branches |
| |
| Fixes: 3a95200d3f89 ("arm_pmu: Change API to support 64bit counter values") |
| Cc: <stable@vger.kernel.org> |
| Signed-off-by: Yang Jihong <yangjihong1@huawei.com> |
| Acked-by: Mark Rutland <mark.rutland@arm.com> |
| Link: https://lore.kernel.org/r/20210430012659.232110-1-yangjihong1@huawei.com |
| Signed-off-by: Will Deacon <will@kernel.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| arch/arm/kernel/perf_event_v7.c | 4 ++-- |
| 1 file changed, 2 insertions(+), 2 deletions(-) |
| |
| --- a/arch/arm/kernel/perf_event_v7.c |
| +++ b/arch/arm/kernel/perf_event_v7.c |
| @@ -773,10 +773,10 @@ static inline void armv7pmu_write_counte |
| pr_err("CPU%u writing wrong counter %d\n", |
| smp_processor_id(), idx); |
| } else if (idx == ARMV7_IDX_CYCLE_COUNTER) { |
| - asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value)); |
| + asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" ((u32)value)); |
| } else { |
| armv7_pmnc_select_counter(idx); |
| - asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value)); |
| + asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" ((u32)value)); |
| } |
| } |
| |