diff options
Diffstat (limited to 'drivers/perf/arm_pmu_platform.c')
| -rw-r--r-- | drivers/perf/arm_pmu_platform.c | 129 |
1 files changed, 71 insertions, 58 deletions
diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c index 4eafa7a42e52..1c9e50a13201 100644 --- a/drivers/perf/arm_pmu_platform.c +++ b/drivers/perf/arm_pmu_platform.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * platform_device probing code for ARM performance counters. * @@ -5,6 +6,7 @@ * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com> */ #define pr_fmt(fmt) "hw perfevents: " fmt +#define dev_fmt pr_fmt #include <linux/bug.h> #include <linux/cpumask.h> @@ -14,7 +16,6 @@ #include <linux/irqdesc.h> #include <linux/kconfig.h> #include <linux/of.h> -#include <linux/of_device.h> #include <linux/percpu.h> #include <linux/perf/arm_pmu.h> #include <linux/platform_device.h> @@ -41,14 +42,13 @@ static int probe_current_pmu(struct arm_pmu *pmu, return ret; } -static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq) +static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq, + const struct cpumask *affinity) { - int cpu, ret; struct pmu_hw_events __percpu *hw_events = pmu->hw_events; + int cpu; - ret = irq_get_percpu_devid_partition(irq, &pmu->supported_cpus); - if (ret) - return ret; + cpumask_copy(&pmu->supported_cpus, affinity); for_each_cpu(cpu, &pmu->supported_cpus) per_cpu(hw_events->irq, cpu) = irq; @@ -58,10 +58,10 @@ static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq) static bool pmu_has_irq_affinity(struct device_node *node) { - return !!of_find_property(node, "interrupt-affinity", NULL); + return of_property_present(node, "interrupt-affinity"); } -static int pmu_parse_irq_affinity(struct device_node *node, int i) +static int pmu_parse_irq_affinity(struct device *dev, int i) { struct device_node *dn; int cpu; @@ -71,29 +71,19 @@ static int pmu_parse_irq_affinity(struct device_node *node, int i) * affinity matches our logical CPU order, as we used to assume. * This is fragile, so we'll warn in pmu_parse_irqs(). */ - if (!pmu_has_irq_affinity(node)) + if (!pmu_has_irq_affinity(dev->of_node)) return i; - dn = of_parse_phandle(node, "interrupt-affinity", i); + dn = of_parse_phandle(dev->of_node, "interrupt-affinity", i); if (!dn) { - pr_warn("failed to parse interrupt-affinity[%d] for %s\n", - i, node->name); + dev_warn(dev, "failed to parse interrupt-affinity[%d]\n", i); return -EINVAL; } - /* Now look up the logical CPU number */ - for_each_possible_cpu(cpu) { - struct device_node *cpu_dn; - - cpu_dn = of_cpu_device_node_get(cpu); - of_node_put(cpu_dn); - - if (dn == cpu_dn) - break; - } - - if (cpu >= nr_cpu_ids) { - pr_warn("failed to find logical CPU for %s\n", dn->name); + cpu = of_cpu_node_to_id(dn); + if (cpu < 0) { + dev_warn(dev, "failed to find logical CPU for %pOFn\n", dn); + cpu = nr_cpu_ids; } of_node_put(dn); @@ -106,41 +96,34 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) int i = 0, num_irqs; struct platform_device *pdev = pmu->plat_device; struct pmu_hw_events __percpu *hw_events = pmu->hw_events; + struct device *dev = &pdev->dev; num_irqs = platform_irq_count(pdev); - if (num_irqs < 0) { - pr_err("unable to count PMU IRQs\n"); - return num_irqs; - } + if (num_irqs < 0) + return dev_err_probe(dev, num_irqs, "unable to count PMU IRQs\n"); /* * In this case we have no idea which CPUs are covered by the PMU. * To match our prior behaviour, we assume all CPUs in this case. */ if (num_irqs == 0) { - pr_warn("no irqs for PMU, sampling events not supported\n"); + dev_warn(dev, "no irqs for PMU, sampling events not supported\n"); pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; cpumask_setall(&pmu->supported_cpus); return 0; } if (num_irqs == 1) { - int irq = platform_get_irq(pdev, 0); - if (irq && irq_is_percpu(irq)) - return pmu_parse_percpu_irq(pmu, irq); - } + const struct cpumask *affinity; + int irq; - if (!pmu_has_irq_affinity(pdev->dev.of_node)) { - pr_warn("no interrupt-affinity property for %pOF, guessing.\n", - pdev->dev.of_node); + irq = platform_get_irq_affinity(pdev, 0, &affinity); + if ((irq > 0) && irq_is_percpu_devid(irq)) + return pmu_parse_percpu_irq(pmu, irq, affinity); } - /* - * Some platforms have all PMU IRQs OR'd into a single IRQ, with a - * special platdata function that attempts to demux them. - */ - if (dev_get_platdata(&pdev->dev)) - cpumask_setall(&pmu->supported_cpus); + if (nr_cpu_ids != 1 && !pmu_has_irq_affinity(dev->of_node)) + dev_warn(dev, "no interrupt-affinity property, guessing.\n"); for (i = 0; i < num_irqs; i++) { int cpu, irq; @@ -149,19 +132,19 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) if (WARN_ON(irq <= 0)) continue; - if (irq_is_percpu(irq)) { - pr_warn("multiple PPIs or mismatched SPI/PPI detected\n"); + if (irq_is_percpu_devid(irq)) { + dev_warn(dev, "multiple PPIs or mismatched SPI/PPI detected\n"); return -EINVAL; } - cpu = pmu_parse_irq_affinity(pdev->dev.of_node, i); + cpu = pmu_parse_irq_affinity(dev, i); if (cpu < 0) return cpu; if (cpu >= nr_cpu_ids) continue; if (per_cpu(hw_events->irq, cpu)) { - pr_warn("multiple PMU IRQs for the same CPU detected\n"); + dev_warn(dev, "multiple PMU IRQs for the same CPU detected\n"); return -EINVAL; } @@ -172,13 +155,42 @@ static int pmu_parse_irqs(struct arm_pmu *pmu) return 0; } +static int armpmu_request_irqs(struct arm_pmu *armpmu) +{ + struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; + int cpu, err = 0; + + for_each_cpu(cpu, &armpmu->supported_cpus) { + int irq = per_cpu(hw_events->irq, cpu); + if (!irq) + continue; + + err = armpmu_request_irq(&hw_events->percpu_pmu, irq, cpu); + if (err) + break; + } + + return err; +} + +static void armpmu_free_irqs(struct arm_pmu *armpmu) +{ + int cpu; + struct pmu_hw_events __percpu *hw_events = armpmu->hw_events; + + for_each_cpu(cpu, &armpmu->supported_cpus) { + int irq = per_cpu(hw_events->irq, cpu); + + armpmu_free_irq(&hw_events->percpu_pmu, irq, cpu); + } +} + int arm_pmu_device_probe(struct platform_device *pdev, const struct of_device_id *of_table, const struct pmu_probe_info *probe_table) { - const struct of_device_id *of_id; armpmu_init_fn init_fn; - struct device_node *node = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct arm_pmu *pmu; int ret = -ENODEV; @@ -186,21 +198,21 @@ int arm_pmu_device_probe(struct platform_device *pdev, if (!pmu) return -ENOMEM; + pmu->pmu.parent = &pdev->dev; pmu->plat_device = pdev; ret = pmu_parse_irqs(pmu); if (ret) goto out_free; - if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { - init_fn = of_id->data; - - pmu->secure_access = of_property_read_bool(pdev->dev.of_node, + init_fn = of_device_get_match_data(dev); + if (init_fn) { + pmu->secure_access = of_property_read_bool(dev->of_node, "secure-reg-access"); /* arm64 systems boot only as non-secure */ if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) { - pr_warn("ignoring \"secure-reg-access\" property for arm64\n"); + dev_warn(dev, "ignoring \"secure-reg-access\" property for arm64\n"); pmu->secure_access = false; } @@ -211,7 +223,7 @@ int arm_pmu_device_probe(struct platform_device *pdev, } if (ret) { - pr_info("%pOF: failed to probe PMU!\n", node); + dev_err(dev, "failed to probe PMU!\n"); goto out_free; } @@ -220,15 +232,16 @@ int arm_pmu_device_probe(struct platform_device *pdev, goto out_free_irqs; ret = armpmu_register(pmu); - if (ret) - goto out_free; + if (ret) { + dev_err(dev, "failed to register PMU devices!\n"); + goto out_free_irqs; + } return 0; out_free_irqs: armpmu_free_irqs(pmu); out_free: - pr_info("%pOF: failed to register PMU devices!\n", node); armpmu_free(pmu); return ret; } |
