drivers/perf/apple_m1_cpu_pmu.c

Source file repositories/reference/linux-study-clean/drivers/perf/apple_m1_cpu_pmu.c

File Facts

System
Linux kernel
Corpus path
drivers/perf/apple_m1_cpu_pmu.c
Extension
.c
Size
20502 bytes
Lines
706
Domain
Driver Families
Bucket
drivers/perf
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

// SPDX-License-Identifier: GPL-2.0
/*
 * CPU PMU driver for the Apple M1 and derivatives
 *
 * Copyright (C) 2021 Google LLC
 *
 * Author: Marc Zyngier <maz@kernel.org>
 *
 * Most of the information used in this driver was provided by the
 * Asahi Linux project. The rest was experimentally discovered.
 */

#include <linux/of.h>
#include <linux/perf/arm_pmu.h>
#include <linux/perf/arm_pmuv3.h>
#include <linux/platform_device.h>

#include <asm/apple_m1_pmu.h>
#include <asm/irq_regs.h>
#include <asm/perf_event.h>

#define M1_PMU_NR_COUNTERS		10

#define M1_PMU_CFG_EVENT		GENMASK(7, 0)

#define ANY_BUT_0_1			GENMASK(9, 2)
#define ONLY_2_TO_7			GENMASK(7, 2)
#define ONLY_2_4_6			(BIT(2) | BIT(4) | BIT(6))
#define ONLY_5_6_7			(BIT(5) | BIT(6) | BIT(7))

/*
 * Description of the events we actually know about, as well as those with
 * a specific counter affinity. Yes, this is a grand total of two known
 * counters, and the rest is anybody's guess.
 *
 * Not all counters can count all events. Counters #0 and #1 are wired to
 * count cycles and instructions respectively, and some events have
 * bizarre mappings (every other counter, or even *one* counter). These
 * restrictions equally apply to both P and E cores.
 *
 * It is worth noting that the PMUs attached to P and E cores are likely
 * to be different because the underlying uarches are different. At the
 * moment, we don't really need to distinguish between the two because we
 * know next to nothing about the events themselves, and we already have
 * per cpu-type PMU abstractions.
 *
 * If we eventually find out that the events are different across
 * implementations, we'll have to introduce per cpu-type tables.
 */
enum m1_pmu_events {
	M1_PMU_PERFCTR_RETIRE_UOP				= 0x1,
	M1_PMU_PERFCTR_CORE_ACTIVE_CYCLE			= 0x2,
	M1_PMU_PERFCTR_L1I_TLB_FILL				= 0x4,
	M1_PMU_PERFCTR_L1D_TLB_FILL				= 0x5,
	M1_PMU_PERFCTR_MMU_TABLE_WALK_INSTRUCTION		= 0x7,
	M1_PMU_PERFCTR_MMU_TABLE_WALK_DATA			= 0x8,
	M1_PMU_PERFCTR_L2_TLB_MISS_INSTRUCTION			= 0xa,
	M1_PMU_PERFCTR_L2_TLB_MISS_DATA				= 0xb,
	M1_PMU_PERFCTR_MMU_VIRTUAL_MEMORY_FAULT_NONSPEC		= 0xd,
	M1_PMU_PERFCTR_SCHEDULE_UOP				= 0x52,
	M1_PMU_PERFCTR_INTERRUPT_PENDING			= 0x6c,
	M1_PMU_PERFCTR_MAP_STALL_DISPATCH			= 0x70,
	M1_PMU_PERFCTR_MAP_REWIND				= 0x75,
	M1_PMU_PERFCTR_MAP_STALL				= 0x76,
	M1_PMU_PERFCTR_MAP_INT_UOP				= 0x7c,
	M1_PMU_PERFCTR_MAP_LDST_UOP				= 0x7d,
	M1_PMU_PERFCTR_MAP_SIMD_UOP				= 0x7e,
	M1_PMU_PERFCTR_FLUSH_RESTART_OTHER_NONSPEC		= 0x84,
	M1_PMU_PERFCTR_INST_ALL					= 0x8c,
	M1_PMU_PERFCTR_INST_BRANCH				= 0x8d,
	M1_PMU_PERFCTR_INST_BRANCH_CALL				= 0x8e,
	M1_PMU_PERFCTR_INST_BRANCH_RET				= 0x8f,
	M1_PMU_PERFCTR_INST_BRANCH_TAKEN			= 0x90,
	M1_PMU_PERFCTR_INST_BRANCH_INDIR			= 0x93,
	M1_PMU_PERFCTR_INST_BRANCH_COND				= 0x94,
	M1_PMU_PERFCTR_INST_INT_LD				= 0x95,
	M1_PMU_PERFCTR_INST_INT_ST				= 0x96,
	M1_PMU_PERFCTR_INST_INT_ALU				= 0x97,
	M1_PMU_PERFCTR_INST_SIMD_LD				= 0x98,
	M1_PMU_PERFCTR_INST_SIMD_ST				= 0x99,
	M1_PMU_PERFCTR_INST_SIMD_ALU				= 0x9a,
	M1_PMU_PERFCTR_INST_LDST				= 0x9b,
	M1_PMU_PERFCTR_INST_BARRIER				= 0x9c,
	M1_PMU_PERFCTR_UNKNOWN_9f				= 0x9f,
	M1_PMU_PERFCTR_L1D_TLB_ACCESS				= 0xa0,
	M1_PMU_PERFCTR_L1D_TLB_MISS				= 0xa1,
	M1_PMU_PERFCTR_L1D_CACHE_MISS_ST			= 0xa2,
	M1_PMU_PERFCTR_L1D_CACHE_MISS_LD			= 0xa3,
	M1_PMU_PERFCTR_LD_UNIT_UOP				= 0xa6,
	M1_PMU_PERFCTR_ST_UNIT_UOP				= 0xa7,

Annotation

Implementation Notes