[PATCH v2 4/4] perf/arm_cspmu: Decouple APMT dependency

Ilkka Koskinen ilkka at os.amperecomputing.com
Mon Jun 5 13:29:40 PDT 2023


On Mon, 5 Jun 2023, Robin Murphy wrote:
> The functional paths of the driver need not care about ACPI, so abstract
> the property of atomic doubleword access as its own flag (repacking the
> structure for a better fit). We also do not need to go poking directly
> at the APMT for standard resources which the ACPI layer has already
> dealt with, so deal with the optional MMIO page and interrupt in the
> normal firmware-agnostic manner. The few remaining portions of probing
> that *are* APMT-specific can still easily retrieve the APMT pointer as
> needed without us having to carry a duplicate copy around everywhere.
>
> Reviewed-by: Suzuki K Poulose <suzuki.poulose at arm.com>
> Signed-off-by: Robin Murphy <robin.murphy at arm.com>

Reviewed-and-tested-by: Ilkka Koskinen <ilkka at os.amperecomputing.com>

Cheers, Ilkka

>
> ---
> v2: Fix platdata dereferences, clean up now-unused acpi.h include too.
> ---
> drivers/perf/arm_cspmu/arm_cspmu.c | 54 ++++++++++--------------------
> drivers/perf/arm_cspmu/arm_cspmu.h |  5 ++-
> 2 files changed, 19 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/perf/arm_cspmu/arm_cspmu.c b/drivers/perf/arm_cspmu/arm_cspmu.c
> index 3b91115c376d..38e1170af347 100644
> --- a/drivers/perf/arm_cspmu/arm_cspmu.c
> +++ b/drivers/perf/arm_cspmu/arm_cspmu.c
> @@ -100,10 +100,6 @@
> #define ARM_CSPMU_ACTIVE_CPU_MASK		0x0
> #define ARM_CSPMU_ASSOCIATED_CPU_MASK		0x1
>
> -/* Check if field f in flags is set with value v */
> -#define CHECK_APMT_FLAG(flags, f, v) \
> -	((flags & (ACPI_APMT_FLAGS_ ## f)) == (ACPI_APMT_FLAGS_ ## f ## _ ## v))
> -
> /* Check and use default if implementer doesn't provide attribute callback */
> #define CHECK_DEFAULT_IMPL_OPS(ops, callback)			\
> 	do {							\
> @@ -121,6 +117,11 @@
>
> static unsigned long arm_cspmu_cpuhp_state;
>
> +static struct acpi_apmt_node *arm_cspmu_apmt_node(struct device *dev)
> +{
> +	return *(struct acpi_apmt_node **)dev_get_platdata(dev);
> +}
> +
> /*
>  * In CoreSight PMU architecture, all of the MMIO registers are 32-bit except
>  * counter register. The counter register can be implemented as 32-bit or 64-bit
> @@ -155,12 +156,6 @@ static u64 read_reg64_hilohi(const void __iomem *addr, u32 max_poll_count)
> 	return val;
> }
>
> -/* Check if PMU supports 64-bit single copy atomic. */
> -static inline bool supports_64bit_atomics(const struct arm_cspmu *cspmu)
> -{
> -	return CHECK_APMT_FLAG(cspmu->apmt_node->flags, ATOMIC, SUPP);
> -}
> -
> /* Check if cycle counter is supported. */
> static inline bool supports_cycle_counter(const struct arm_cspmu *cspmu)
> {
> @@ -319,7 +314,7 @@ static const char *arm_cspmu_get_name(const struct arm_cspmu *cspmu)
> 	static atomic_t pmu_idx[ACPI_APMT_NODE_TYPE_COUNT] = { 0 };
>
> 	dev = cspmu->dev;
> -	apmt_node = cspmu->apmt_node;
> +	apmt_node = arm_cspmu_apmt_node(dev);
> 	pmu_type = apmt_node->type;
>
> 	if (pmu_type >= ACPI_APMT_NODE_TYPE_COUNT) {
> @@ -396,8 +391,8 @@ static const struct impl_match impl_match[] = {
> static int arm_cspmu_init_impl_ops(struct arm_cspmu *cspmu)
> {
> 	int ret;
> -	struct acpi_apmt_node *apmt_node = cspmu->apmt_node;
> 	struct arm_cspmu_impl_ops *impl_ops = &cspmu->impl.ops;
> +	struct acpi_apmt_node *apmt_node = arm_cspmu_apmt_node(cspmu->dev);
> 	const struct impl_match *match = impl_match;
>
> 	/*
> @@ -719,7 +714,7 @@ static u64 arm_cspmu_read_counter(struct perf_event *event)
> 		offset = counter_offset(sizeof(u64), event->hw.idx);
> 		counter_addr = cspmu->base1 + offset;
>
> -		return supports_64bit_atomics(cspmu) ?
> +		return cspmu->has_atomic_dword ?
> 			       readq(counter_addr) :
> 			       read_reg64_hilohi(counter_addr, HILOHI_MAX_POLL);
> 	}
> @@ -910,24 +905,18 @@ static struct arm_cspmu *arm_cspmu_alloc(struct platform_device *pdev)
> {
> 	struct acpi_apmt_node *apmt_node;
> 	struct arm_cspmu *cspmu;
> -	struct device *dev;
> -
> -	dev = &pdev->dev;
> -	apmt_node = *(struct acpi_apmt_node **)dev_get_platdata(dev);
> -	if (!apmt_node) {
> -		dev_err(dev, "failed to get APMT node\n");
> -		return NULL;
> -	}
> +	struct device *dev = &pdev->dev;
>
> 	cspmu = devm_kzalloc(dev, sizeof(*cspmu), GFP_KERNEL);
> 	if (!cspmu)
> 		return NULL;
>
> 	cspmu->dev = dev;
> -	cspmu->apmt_node = apmt_node;
> -
> 	platform_set_drvdata(pdev, cspmu);
>
> +	apmt_node = arm_cspmu_apmt_node(dev);
> +	cspmu->has_atomic_dword = apmt_node->flags & ACPI_APMT_FLAGS_ATOMIC;
> +
> 	return cspmu;
> }
>
> @@ -935,11 +924,9 @@ static int arm_cspmu_init_mmio(struct arm_cspmu *cspmu)
> {
> 	struct device *dev;
> 	struct platform_device *pdev;
> -	struct acpi_apmt_node *apmt_node;
>
> 	dev = cspmu->dev;
> 	pdev = to_platform_device(dev);
> -	apmt_node = cspmu->apmt_node;
>
> 	/* Base address for page 0. */
> 	cspmu->base0 = devm_platform_ioremap_resource(pdev, 0);
> @@ -950,7 +937,7 @@ static int arm_cspmu_init_mmio(struct arm_cspmu *cspmu)
>
> 	/* Base address for page 1 if supported. Otherwise point to page 0. */
> 	cspmu->base1 = cspmu->base0;
> -	if (CHECK_APMT_FLAG(apmt_node->flags, DUAL_PAGE, SUPP)) {
> +	if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
> 		cspmu->base1 = devm_platform_ioremap_resource(pdev, 1);
> 		if (IS_ERR(cspmu->base1)) {
> 			dev_err(dev, "ioremap failed for page-1 resource\n");
> @@ -1047,19 +1034,14 @@ static int arm_cspmu_request_irq(struct arm_cspmu *cspmu)
> 	int irq, ret;
> 	struct device *dev;
> 	struct platform_device *pdev;
> -	struct acpi_apmt_node *apmt_node;
>
> 	dev = cspmu->dev;
> 	pdev = to_platform_device(dev);
> -	apmt_node = cspmu->apmt_node;
>
> 	/* Skip IRQ request if the PMU does not support overflow interrupt. */
> -	if (apmt_node->ovflw_irq == 0)
> -		return 0;
> -
> -	irq = platform_get_irq(pdev, 0);
> +	irq = platform_get_irq_optional(pdev, 0);
> 	if (irq < 0)
> -		return irq;
> +		return irq == -ENXIO ? 0 : irq;
>
> 	ret = devm_request_irq(dev, irq, arm_cspmu_handle_irq,
> 			       IRQF_NOBALANCING | IRQF_NO_THREAD, dev_name(dev),
> @@ -1103,13 +1085,11 @@ static inline int arm_cspmu_find_cpu_container(int cpu, u32 container_uid)
>
> static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu)
> {
> -	struct device *dev;
> 	struct acpi_apmt_node *apmt_node;
> 	int affinity_flag;
> 	int cpu;
>
> -	dev = cspmu->pmu.dev;
> -	apmt_node = cspmu->apmt_node;
> +	apmt_node = arm_cspmu_apmt_node(cspmu->dev);
> 	affinity_flag = apmt_node->flags & ACPI_APMT_FLAGS_AFFINITY;
>
> 	if (affinity_flag == ACPI_APMT_FLAGS_AFFINITY_PROC) {
> @@ -1131,7 +1111,7 @@ static int arm_cspmu_acpi_get_cpus(struct arm_cspmu *cspmu)
> 	}
>
> 	if (cpumask_empty(&cspmu->associated_cpus)) {
> -		dev_dbg(dev, "No cpu associated with the PMU\n");
> +		dev_dbg(cspmu->dev, "No cpu associated with the PMU\n");
> 		return -ENODEV;
> 	}
>
> diff --git a/drivers/perf/arm_cspmu/arm_cspmu.h b/drivers/perf/arm_cspmu/arm_cspmu.h
> index 51323b175a4a..83df53d1c132 100644
> --- a/drivers/perf/arm_cspmu/arm_cspmu.h
> +++ b/drivers/perf/arm_cspmu/arm_cspmu.h
> @@ -8,7 +8,6 @@
> #ifndef __ARM_CSPMU_H__
> #define __ARM_CSPMU_H__
>
> -#include <linux/acpi.h>
> #include <linux/bitfield.h>
> #include <linux/cpumask.h>
> #include <linux/device.h>
> @@ -118,16 +117,16 @@ struct arm_cspmu_impl {
> struct arm_cspmu {
> 	struct pmu pmu;
> 	struct device *dev;
> -	struct acpi_apmt_node *apmt_node;
> 	const char *name;
> 	const char *identifier;
> 	void __iomem *base0;
> 	void __iomem *base1;
> -	int irq;
> 	cpumask_t associated_cpus;
> 	cpumask_t active_cpu;
> 	struct hlist_node cpuhp_node;
> +	int irq;
>
> +	bool has_atomic_dword;
> 	u32 pmcfgr;
> 	u32 num_logical_ctrs;
> 	u32 num_set_clr_reg;
> -- 
> 2.39.2.101.g768bb238c484.dirty
>
>



More information about the linux-arm-kernel mailing list