in arm_smmuv3_pmu.c [364:423]
static int smmu_pmu_event_init(struct perf_event *event)
{
struct hw_perf_event *hwc = &event->hw;
struct smmu_pmu *smmu_pmu = to_smmu_pmu(event->pmu);
struct device *dev = smmu_pmu->dev;
struct perf_event *sibling;
int group_num_events = 1;
u16 event_id;
if (event->attr.type != event->pmu->type)
return -ENOENT;
if (hwc->sample_period) {
dev_dbg(dev, "Sampling not supported\n");
return -EOPNOTSUPP;
}
if (event->cpu < 0) {
dev_dbg(dev, "Per-task mode not supported\n");
return -EOPNOTSUPP;
}
/* Verify specified event is supported on this PMU */
event_id = get_event(event);
if (event_id < SMMU_PMCG_ARCH_MAX_EVENTS &&
(!test_bit(event_id, smmu_pmu->supported_events))) {
dev_dbg(dev, "Invalid event %d for this PMU\n", event_id);
return -EINVAL;
}
/* Don't allow groups with mixed PMUs, except for s/w events */
if (!is_software_event(event->group_leader)) {
if (!smmu_pmu_events_compatible(event->group_leader, event))
return -EINVAL;
if (++group_num_events > smmu_pmu->num_counters)
return -EINVAL;
}
for_each_sibling_event(sibling, event->group_leader) {
if (is_software_event(sibling))
continue;
if (!smmu_pmu_events_compatible(sibling, event))
return -EINVAL;
if (++group_num_events > smmu_pmu->num_counters)
return -EINVAL;
}
hwc->idx = -1;
/*
* Ensure all events are on the same cpu so all events are in the
* same cpu context, to avoid races on pmu_enable etc.
*/
event->cpu = smmu_pmu->on_cpu;
return 0;
}