in arm_smmuv3_pmu.c [808:920]
static int smmu_pmu_probe(struct platform_device *pdev)
{
struct smmu_pmu *smmu_pmu;
struct resource *res_0;
u32 cfgr, reg_size;
u64 ceid_64[2];
int irq, err;
char *name;
struct device *dev = &pdev->dev;
smmu_pmu = devm_kzalloc(dev, sizeof(*smmu_pmu), GFP_KERNEL);
if (!smmu_pmu)
return -ENOMEM;
smmu_pmu->dev = dev;
platform_set_drvdata(pdev, smmu_pmu);
smmu_pmu->pmu = (struct pmu) {
.module = THIS_MODULE,
.task_ctx_nr = perf_invalid_context,
.pmu_enable = smmu_pmu_enable,
.pmu_disable = smmu_pmu_disable,
.event_init = smmu_pmu_event_init,
.add = smmu_pmu_event_add,
.del = smmu_pmu_event_del,
.start = smmu_pmu_event_start,
.stop = smmu_pmu_event_stop,
.read = smmu_pmu_event_read,
.attr_groups = smmu_pmu_attr_grps,
.capabilities = PERF_PMU_CAP_NO_EXCLUDE,
};
smmu_pmu->reg_base = devm_platform_get_and_ioremap_resource(pdev, 0, &res_0);
if (IS_ERR(smmu_pmu->reg_base))
return PTR_ERR(smmu_pmu->reg_base);
cfgr = readl_relaxed(smmu_pmu->reg_base + SMMU_PMCG_CFGR);
/* Determine if page 1 is present */
if (cfgr & SMMU_PMCG_CFGR_RELOC_CTRS) {
smmu_pmu->reloc_base = devm_platform_ioremap_resource(pdev, 1);
if (IS_ERR(smmu_pmu->reloc_base))
return PTR_ERR(smmu_pmu->reloc_base);
} else {
smmu_pmu->reloc_base = smmu_pmu->reg_base;
}
irq = platform_get_irq_optional(pdev, 0);
if (irq > 0)
smmu_pmu->irq = irq;
ceid_64[0] = readq_relaxed(smmu_pmu->reg_base + SMMU_PMCG_CEID0);
ceid_64[1] = readq_relaxed(smmu_pmu->reg_base + SMMU_PMCG_CEID1);
bitmap_from_arr32(smmu_pmu->supported_events, (u32 *)ceid_64,
SMMU_PMCG_ARCH_MAX_EVENTS);
smmu_pmu->num_counters = FIELD_GET(SMMU_PMCG_CFGR_NCTR, cfgr) + 1;
smmu_pmu->global_filter = !!(cfgr & SMMU_PMCG_CFGR_SID_FILTER_TYPE);
reg_size = FIELD_GET(SMMU_PMCG_CFGR_SIZE, cfgr);
smmu_pmu->counter_mask = GENMASK_ULL(reg_size, 0);
smmu_pmu_reset(smmu_pmu);
err = smmu_pmu_setup_irq(smmu_pmu);
if (err) {
dev_err(dev, "Setup irq failed, PMU @%pa\n", &res_0->start);
return err;
}
smmu_pmu_get_iidr(smmu_pmu);
name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "smmuv3_pmcg_%llx",
(res_0->start) >> SMMU_PMCG_PA_SHIFT);
if (!name) {
dev_err(dev, "Create name failed, PMU @%pa\n", &res_0->start);
return -EINVAL;
}
if (!dev->of_node)
smmu_pmu_get_acpi_options(smmu_pmu);
/* Pick one CPU to be the preferred one to use */
smmu_pmu->on_cpu = raw_smp_processor_id();
WARN_ON(irq_set_affinity(smmu_pmu->irq, cpumask_of(smmu_pmu->on_cpu)));
err = cpuhp_state_add_instance_nocalls(cpuhp_state_num,
&smmu_pmu->node);
if (err) {
dev_err(dev, "Error %d registering hotplug, PMU @%pa\n",
err, &res_0->start);
return err;
}
err = perf_pmu_register(&smmu_pmu->pmu, name, -1);
if (err) {
dev_err(dev, "Error %d registering PMU @%pa\n",
err, &res_0->start);
goto out_unregister;
}
dev_info(dev, "Registered PMU @ %pa using %d counters with %s filter settings\n",
&res_0->start, smmu_pmu->num_counters,
smmu_pmu->global_filter ? "Global(Counter0)" :
"Individual");
return 0;
out_unregister:
cpuhp_state_remove_instance_nocalls(cpuhp_state_num, &smmu_pmu->node);
return err;
}