drivers/perf/arm_pmuv3.c

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

File Facts

System
Linux kernel
Corpus path
drivers/perf/arm_pmuv3.c
Extension
.c
Size
52898 bytes
Lines
1667
Domain
Driver Families
Bucket
drivers/perf
Inferred role
Driver Families: exported/initcall integration point
Status
integration 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

device_initcall(armv8_pmu_driver_init)

void arch_perf_update_userpage(struct perf_event *event,
			       struct perf_event_mmap_page *userpg, u64 now)
{
	struct clock_read_data *rd;
	unsigned int seq;
	u64 ns;

	userpg->cap_user_time = 0;
	userpg->cap_user_time_zero = 0;
	userpg->cap_user_time_short = 0;
	userpg->cap_user_rdpmc = armv8pmu_event_has_user_read(event);

	if (userpg->cap_user_rdpmc) {
		if (event->hw.flags & ARMPMU_EVT_64BIT)
			userpg->pmc_width = 64;
		else
			userpg->pmc_width = 32;
	}

	do {
		rd = sched_clock_read_begin(&seq);

		if (rd->read_sched_clock != arch_timer_read_counter)
			return;

		userpg->time_mult = rd->mult;
		userpg->time_shift = rd->shift;
		userpg->time_zero = rd->epoch_ns;
		userpg->time_cycles = rd->epoch_cyc;
		userpg->time_mask = rd->sched_clock_mask;

		/*
		 * Subtract the cycle base, such that software that
		 * doesn't know about cap_user_time_short still 'works'
		 * assuming no wraps.
		 */
		ns = mul_u64_u32_shr(rd->epoch_cyc, rd->mult, rd->shift);
		userpg->time_zero -= ns;

	} while (sched_clock_read_retry(seq));

	userpg->time_offset = userpg->time_zero - now;

	/*
	 * time_shift is not expected to be greater than 31 due to
	 * the original published conversion algorithm shifting a
	 * 32-bit value (now specifies a 64-bit value) - refer
	 * perf_event_mmap_page documentation in perf_event.h.
	 */
	if (userpg->time_shift == 32) {
		userpg->time_shift = 31;
		userpg->time_mult >>= 1;
	}

	/*
	 * Internal timekeeping for enabled/running/stopped times
	 * is always computed with the sched_clock.
	 */
	userpg->cap_user_time = 1;
	userpg->cap_user_time_zero = 1;
	userpg->cap_user_time_short = 1;
}

Annotation

Implementation Notes