in arm_spe_pmu.c [669:720]
static int arm_spe_pmu_event_init(struct perf_event *event)
{
u64 reg;
struct perf_event_attr *attr = &event->attr;
struct arm_spe_pmu *spe_pmu = to_spe_pmu(event->pmu);
/* This is, of course, deeply driver-specific */
if (attr->type != event->pmu->type)
return -ENOENT;
if (event->cpu >= 0 &&
!cpumask_test_cpu(event->cpu, &spe_pmu->supported_cpus))
return -ENOENT;
if (arm_spe_event_to_pmsevfr(event) & arm_spe_pmsevfr_res0(spe_pmu->pmsver))
return -EOPNOTSUPP;
if (attr->exclude_idle)
return -EOPNOTSUPP;
/*
* Feedback-directed frequency throttling doesn't work when we
* have a buffer of samples. We'd need to manually count the
* samples in the buffer when it fills up and adjust the event
* count to reflect that. Instead, just force the user to specify
* a sample period.
*/
if (attr->freq)
return -EINVAL;
reg = arm_spe_event_to_pmsfcr(event);
if ((reg & BIT(SYS_PMSFCR_EL1_FE_SHIFT)) &&
!(spe_pmu->features & SPE_PMU_FEAT_FILT_EVT))
return -EOPNOTSUPP;
if ((reg & BIT(SYS_PMSFCR_EL1_FT_SHIFT)) &&
!(spe_pmu->features & SPE_PMU_FEAT_FILT_TYP))
return -EOPNOTSUPP;
if ((reg & BIT(SYS_PMSFCR_EL1_FL_SHIFT)) &&
!(spe_pmu->features & SPE_PMU_FEAT_FILT_LAT))
return -EOPNOTSUPP;
reg = arm_spe_event_to_pmscr(event);
if (!perfmon_capable() &&
(reg & (BIT(SYS_PMSCR_EL1_PA_SHIFT) |
BIT(SYS_PMSCR_EL1_CX_SHIFT) |
BIT(SYS_PMSCR_EL1_PCT_SHIFT))))
return -EACCES;
return 0;
}