static int smmu_pmu_probe()

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;
}