diff options
Diffstat (limited to 'arch/arm64/kernel/perf_event.c')
| -rw-r--r-- | arch/arm64/kernel/perf_event.c | 89 | 
1 files changed, 70 insertions, 19 deletions
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c index 4d7879484cec..462f9a9cc44b 100644 --- a/arch/arm64/kernel/perf_event.c +++ b/arch/arm64/kernel/perf_event.c @@ -13,12 +13,15 @@  #include <asm/sysreg.h>  #include <asm/virt.h> +#include <clocksource/arm_arch_timer.h> +  #include <linux/acpi.h>  #include <linux/clocksource.h>  #include <linux/kvm_host.h>  #include <linux/of.h>  #include <linux/perf/arm_pmu.h>  #include <linux/platform_device.h> +#include <linux/sched_clock.h>  #include <linux/smp.h>  /* ARMv8 Cortex-A53 specific event types. */ @@ -155,7 +158,7 @@ armv8pmu_events_sysfs_show(struct device *dev,  	pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); -	return sprintf(page, "event=0x%03llx\n", pmu_attr->id); +	return sprintf(page, "event=0x%04llx\n", pmu_attr->id);  }  #define ARMV8_EVENT_ATTR(name, config)						\ @@ -222,10 +225,29 @@ static struct attribute *armv8_pmuv3_event_attrs[] = {  	ARMV8_EVENT_ATTR(ll_cache_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_RD),  	ARMV8_EVENT_ATTR(ll_cache_miss_rd, ARMV8_PMUV3_PERFCTR_LL_CACHE_MISS_RD),  	ARMV8_EVENT_ATTR(remote_access_rd, ARMV8_PMUV3_PERFCTR_REMOTE_ACCESS_RD), +	ARMV8_EVENT_ATTR(l1d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L1D_CACHE_LMISS_RD), +	ARMV8_EVENT_ATTR(op_retired, ARMV8_PMUV3_PERFCTR_OP_RETIRED), +	ARMV8_EVENT_ATTR(op_spec, ARMV8_PMUV3_PERFCTR_OP_SPEC), +	ARMV8_EVENT_ATTR(stall, ARMV8_PMUV3_PERFCTR_STALL), +	ARMV8_EVENT_ATTR(stall_slot_backend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_BACKEND), +	ARMV8_EVENT_ATTR(stall_slot_frontend, ARMV8_PMUV3_PERFCTR_STALL_SLOT_FRONTEND), +	ARMV8_EVENT_ATTR(stall_slot, ARMV8_PMUV3_PERFCTR_STALL_SLOT),  	ARMV8_EVENT_ATTR(sample_pop, ARMV8_SPE_PERFCTR_SAMPLE_POP),  	ARMV8_EVENT_ATTR(sample_feed, ARMV8_SPE_PERFCTR_SAMPLE_FEED),  	ARMV8_EVENT_ATTR(sample_filtrate, ARMV8_SPE_PERFCTR_SAMPLE_FILTRATE),  	ARMV8_EVENT_ATTR(sample_collision, ARMV8_SPE_PERFCTR_SAMPLE_COLLISION), +	ARMV8_EVENT_ATTR(cnt_cycles, ARMV8_AMU_PERFCTR_CNT_CYCLES), +	ARMV8_EVENT_ATTR(stall_backend_mem, ARMV8_AMU_PERFCTR_STALL_BACKEND_MEM), +	ARMV8_EVENT_ATTR(l1i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L1I_CACHE_LMISS), +	ARMV8_EVENT_ATTR(l2d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L2D_CACHE_LMISS_RD), +	ARMV8_EVENT_ATTR(l2i_cache_lmiss, ARMV8_PMUV3_PERFCTR_L2I_CACHE_LMISS), +	ARMV8_EVENT_ATTR(l3d_cache_lmiss_rd, ARMV8_PMUV3_PERFCTR_L3D_CACHE_LMISS_RD), +	ARMV8_EVENT_ATTR(ldst_align_lat, ARMV8_PMUV3_PERFCTR_LDST_ALIGN_LAT), +	ARMV8_EVENT_ATTR(ld_align_lat, ARMV8_PMUV3_PERFCTR_LD_ALIGN_LAT), +	ARMV8_EVENT_ATTR(st_align_lat, ARMV8_PMUV3_PERFCTR_ST_ALIGN_LAT), +	ARMV8_EVENT_ATTR(mem_access_checked, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED), +	ARMV8_EVENT_ATTR(mem_access_checked_rd, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_RD), +	ARMV8_EVENT_ATTR(mem_access_checked_wr, ARMV8_MTE_PERFCTR_MEM_ACCESS_CHECKED_WR),  	NULL,  }; @@ -244,10 +266,13 @@ armv8pmu_event_attr_is_visible(struct kobject *kobj,  	    test_bit(pmu_attr->id, cpu_pmu->pmceid_bitmap))  		return attr->mode; -	pmu_attr->id -= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE; -	if (pmu_attr->id < ARMV8_PMUV3_MAX_COMMON_EVENTS && -	    test_bit(pmu_attr->id, cpu_pmu->pmceid_ext_bitmap)) -		return attr->mode; +	if (pmu_attr->id >= ARMV8_PMUV3_EXT_COMMON_EVENT_BASE) { +		u64 id = pmu_attr->id - ARMV8_PMUV3_EXT_COMMON_EVENT_BASE; + +		if (id < ARMV8_PMUV3_MAX_COMMON_EVENTS && +		    test_bit(id, cpu_pmu->pmceid_ext_bitmap)) +			return attr->mode; +	}  	return 0;  } @@ -1165,28 +1190,54 @@ device_initcall(armv8_pmu_driver_init)  void arch_perf_update_userpage(struct perf_event *event,  			       struct perf_event_mmap_page *userpg, u64 now)  { -	u32 freq; -	u32 shift; +	struct clock_read_data *rd; +	unsigned int seq; +	u64 ns; -	/* -	 * Internal timekeeping for enabled/running/stopped times -	 * is always computed with the sched_clock. -	 */ -	freq = arch_timer_get_rate(); -	userpg->cap_user_time = 1; +	userpg->cap_user_time = 0; +	userpg->cap_user_time_zero = 0; +	userpg->cap_user_time_short = 0; + +	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; -	clocks_calc_mult_shift(&userpg->time_mult, &shift, freq, -			NSEC_PER_SEC, 0);  	/*  	 * 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 (shift == 32) { -		shift = 31; +	if (userpg->time_shift == 32) { +		userpg->time_shift = 31;  		userpg->time_mult >>= 1;  	} -	userpg->time_shift = (u16)shift; -	userpg->time_offset = -now; + +	/* +	 * 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;  }  |