Skip to content

Commit 8be3593

Browse files
Marc Zyngierwilldeacon
authored andcommitted
drivers/perf: apple_m1: Force 63bit counters for M2 CPUs
Sidharth reports that on M2, the PMU never generates any interrupt when using 'perf record', which is a annoying as you get no sample. I'm temped to say "no sample, no problem", but others may have a different opinion. Upon investigation, it appears that the counters on M2 are significantly different from the ones on M1, as they count on 64 bits instead of 48. Which of course, in the fine M1 tradition, means that we can only use 63 bits, as the top bit is used to signal the interrupt... This results in having to introduce yet another flag to indicate yet another odd counter width. Who knows what the next crazy implementation will do... With this, perf can work out the correct offset, and 'perf record' works as intended. Tested on M2 and M2-Pro CPUs. Cc: Janne Grunau <[email protected]> Cc: Hector Martin <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Will Deacon <[email protected]> Fixes: 7d0bfb7 ("drivers/perf: apple_m1: Add Apple M2 support") Reported-by: Sidharth Kshatriya <[email protected]> Tested-by: Sidharth Kshatriya <[email protected]> Signed-off-by: Marc Zyngier <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 71746c9 commit 8be3593

File tree

3 files changed

+28
-6
lines changed

3 files changed

+28
-6
lines changed

drivers/perf/apple_m1_cpu_pmu.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,17 @@ static int m1_pmu_map_event(struct perf_event *event)
493493
return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
494494
}
495495

496+
static int m2_pmu_map_event(struct perf_event *event)
497+
{
498+
/*
499+
* Same deal as the above, except that M2 has 64bit counters.
500+
* Which, as far as we're concerned, actually means 63 bits.
501+
* Yes, this is getting awkward.
502+
*/
503+
event->hw.flags |= ARMPMU_EVT_63BIT;
504+
return armpmu_map_event(event, &m1_pmu_perf_map, NULL, M1_PMU_CFG_EVENT);
505+
}
506+
496507
static void m1_pmu_reset(void *info)
497508
{
498509
int i;
@@ -525,7 +536,7 @@ static int m1_pmu_set_event_filter(struct hw_perf_event *event,
525536
return 0;
526537
}
527538

528-
static int m1_pmu_init(struct arm_pmu *cpu_pmu)
539+
static int m1_pmu_init(struct arm_pmu *cpu_pmu, u32 flags)
529540
{
530541
cpu_pmu->handle_irq = m1_pmu_handle_irq;
531542
cpu_pmu->enable = m1_pmu_enable_event;
@@ -536,7 +547,14 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu)
536547
cpu_pmu->clear_event_idx = m1_pmu_clear_event_idx;
537548
cpu_pmu->start = m1_pmu_start;
538549
cpu_pmu->stop = m1_pmu_stop;
539-
cpu_pmu->map_event = m1_pmu_map_event;
550+
551+
if (flags & ARMPMU_EVT_47BIT)
552+
cpu_pmu->map_event = m1_pmu_map_event;
553+
else if (flags & ARMPMU_EVT_63BIT)
554+
cpu_pmu->map_event = m2_pmu_map_event;
555+
else
556+
return WARN_ON(-EINVAL);
557+
540558
cpu_pmu->reset = m1_pmu_reset;
541559
cpu_pmu->set_event_filter = m1_pmu_set_event_filter;
542560

@@ -550,25 +568,25 @@ static int m1_pmu_init(struct arm_pmu *cpu_pmu)
550568
static int m1_pmu_ice_init(struct arm_pmu *cpu_pmu)
551569
{
552570
cpu_pmu->name = "apple_icestorm_pmu";
553-
return m1_pmu_init(cpu_pmu);
571+
return m1_pmu_init(cpu_pmu, ARMPMU_EVT_47BIT);
554572
}
555573

556574
static int m1_pmu_fire_init(struct arm_pmu *cpu_pmu)
557575
{
558576
cpu_pmu->name = "apple_firestorm_pmu";
559-
return m1_pmu_init(cpu_pmu);
577+
return m1_pmu_init(cpu_pmu, ARMPMU_EVT_47BIT);
560578
}
561579

562580
static int m2_pmu_avalanche_init(struct arm_pmu *cpu_pmu)
563581
{
564582
cpu_pmu->name = "apple_avalanche_pmu";
565-
return m1_pmu_init(cpu_pmu);
583+
return m1_pmu_init(cpu_pmu, ARMPMU_EVT_63BIT);
566584
}
567585

568586
static int m2_pmu_blizzard_init(struct arm_pmu *cpu_pmu)
569587
{
570588
cpu_pmu->name = "apple_blizzard_pmu";
571-
return m1_pmu_init(cpu_pmu);
589+
return m1_pmu_init(cpu_pmu, ARMPMU_EVT_63BIT);
572590
}
573591

574592
static const struct of_device_id m1_pmu_of_device_ids[] = {

drivers/perf/arm_pmu.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,8 @@ static inline u64 arm_pmu_event_max_period(struct perf_event *event)
109109
{
110110
if (event->hw.flags & ARMPMU_EVT_64BIT)
111111
return GENMASK_ULL(63, 0);
112+
else if (event->hw.flags & ARMPMU_EVT_63BIT)
113+
return GENMASK_ULL(62, 0);
112114
else if (event->hw.flags & ARMPMU_EVT_47BIT)
113115
return GENMASK_ULL(46, 0);
114116
else

include/linux/perf/arm_pmu.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,11 @@
2626
*/
2727
#define ARMPMU_EVT_64BIT 0x00001 /* Event uses a 64bit counter */
2828
#define ARMPMU_EVT_47BIT 0x00002 /* Event uses a 47bit counter */
29+
#define ARMPMU_EVT_63BIT 0x00004 /* Event uses a 63bit counter */
2930

3031
static_assert((PERF_EVENT_FLAG_ARCH & ARMPMU_EVT_64BIT) == ARMPMU_EVT_64BIT);
3132
static_assert((PERF_EVENT_FLAG_ARCH & ARMPMU_EVT_47BIT) == ARMPMU_EVT_47BIT);
33+
static_assert((PERF_EVENT_FLAG_ARCH & ARMPMU_EVT_63BIT) == ARMPMU_EVT_63BIT);
3234

3335
#define HW_OP_UNSUPPORTED 0xFFFF
3436
#define C(_x) PERF_COUNT_HW_CACHE_##_x

0 commit comments

Comments
 (0)