246 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * platform_device probing code for ARM performance counters.4 *5 * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles6 * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com>7 */8#define pr_fmt(fmt) "hw perfevents: " fmt9#define dev_fmt pr_fmt10 11#include <linux/bug.h>12#include <linux/cpumask.h>13#include <linux/device.h>14#include <linux/errno.h>15#include <linux/irq.h>16#include <linux/irqdesc.h>17#include <linux/kconfig.h>18#include <linux/of.h>19#include <linux/percpu.h>20#include <linux/perf/arm_pmu.h>21#include <linux/platform_device.h>22#include <linux/printk.h>23#include <linux/smp.h>24 25static int probe_current_pmu(struct arm_pmu *pmu,26 const struct pmu_probe_info *info)27{28 int cpu = get_cpu();29 unsigned int cpuid = read_cpuid_id();30 int ret = -ENODEV;31 32 pr_info("probing PMU on CPU %d\n", cpu);33 34 for (; info->init != NULL; info++) {35 if ((cpuid & info->mask) != info->cpuid)36 continue;37 ret = info->init(pmu);38 break;39 }40 41 put_cpu();42 return ret;43}44 45static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq)46{47 int cpu, ret;48 struct pmu_hw_events __percpu *hw_events = pmu->hw_events;49 50 ret = irq_get_percpu_devid_partition(irq, &pmu->supported_cpus);51 if (ret)52 return ret;53 54 for_each_cpu(cpu, &pmu->supported_cpus)55 per_cpu(hw_events->irq, cpu) = irq;56 57 return 0;58}59 60static bool pmu_has_irq_affinity(struct device_node *node)61{62 return of_property_present(node, "interrupt-affinity");63}64 65static int pmu_parse_irq_affinity(struct device *dev, int i)66{67 struct device_node *dn;68 int cpu;69 70 /*71 * If we don't have an interrupt-affinity property, we guess irq72 * affinity matches our logical CPU order, as we used to assume.73 * This is fragile, so we'll warn in pmu_parse_irqs().74 */75 if (!pmu_has_irq_affinity(dev->of_node))76 return i;77 78 dn = of_parse_phandle(dev->of_node, "interrupt-affinity", i);79 if (!dn) {80 dev_warn(dev, "failed to parse interrupt-affinity[%d]\n", i);81 return -EINVAL;82 }83 84 cpu = of_cpu_node_to_id(dn);85 if (cpu < 0) {86 dev_warn(dev, "failed to find logical CPU for %pOFn\n", dn);87 cpu = nr_cpu_ids;88 }89 90 of_node_put(dn);91 92 return cpu;93}94 95static int pmu_parse_irqs(struct arm_pmu *pmu)96{97 int i = 0, num_irqs;98 struct platform_device *pdev = pmu->plat_device;99 struct pmu_hw_events __percpu *hw_events = pmu->hw_events;100 struct device *dev = &pdev->dev;101 102 num_irqs = platform_irq_count(pdev);103 if (num_irqs < 0)104 return dev_err_probe(dev, num_irqs, "unable to count PMU IRQs\n");105 106 /*107 * In this case we have no idea which CPUs are covered by the PMU.108 * To match our prior behaviour, we assume all CPUs in this case.109 */110 if (num_irqs == 0) {111 dev_warn(dev, "no irqs for PMU, sampling events not supported\n");112 pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;113 cpumask_setall(&pmu->supported_cpus);114 return 0;115 }116 117 if (num_irqs == 1) {118 int irq = platform_get_irq(pdev, 0);119 if ((irq > 0) && irq_is_percpu_devid(irq))120 return pmu_parse_percpu_irq(pmu, irq);121 }122 123 if (nr_cpu_ids != 1 && !pmu_has_irq_affinity(dev->of_node))124 dev_warn(dev, "no interrupt-affinity property, guessing.\n");125 126 for (i = 0; i < num_irqs; i++) {127 int cpu, irq;128 129 irq = platform_get_irq(pdev, i);130 if (WARN_ON(irq <= 0))131 continue;132 133 if (irq_is_percpu_devid(irq)) {134 dev_warn(dev, "multiple PPIs or mismatched SPI/PPI detected\n");135 return -EINVAL;136 }137 138 cpu = pmu_parse_irq_affinity(dev, i);139 if (cpu < 0)140 return cpu;141 if (cpu >= nr_cpu_ids)142 continue;143 144 if (per_cpu(hw_events->irq, cpu)) {145 dev_warn(dev, "multiple PMU IRQs for the same CPU detected\n");146 return -EINVAL;147 }148 149 per_cpu(hw_events->irq, cpu) = irq;150 cpumask_set_cpu(cpu, &pmu->supported_cpus);151 }152 153 return 0;154}155 156static int armpmu_request_irqs(struct arm_pmu *armpmu)157{158 struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;159 int cpu, err = 0;160 161 for_each_cpu(cpu, &armpmu->supported_cpus) {162 int irq = per_cpu(hw_events->irq, cpu);163 if (!irq)164 continue;165 166 err = armpmu_request_irq(irq, cpu);167 if (err)168 break;169 }170 171 return err;172}173 174static void armpmu_free_irqs(struct arm_pmu *armpmu)175{176 int cpu;177 struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;178 179 for_each_cpu(cpu, &armpmu->supported_cpus) {180 int irq = per_cpu(hw_events->irq, cpu);181 182 armpmu_free_irq(irq, cpu);183 }184}185 186int arm_pmu_device_probe(struct platform_device *pdev,187 const struct of_device_id *of_table,188 const struct pmu_probe_info *probe_table)189{190 armpmu_init_fn init_fn;191 struct device *dev = &pdev->dev;192 struct arm_pmu *pmu;193 int ret = -ENODEV;194 195 pmu = armpmu_alloc();196 if (!pmu)197 return -ENOMEM;198 199 pmu->pmu.parent = &pdev->dev;200 pmu->plat_device = pdev;201 202 ret = pmu_parse_irqs(pmu);203 if (ret)204 goto out_free;205 206 init_fn = of_device_get_match_data(dev);207 if (init_fn) {208 pmu->secure_access = of_property_read_bool(dev->of_node,209 "secure-reg-access");210 211 /* arm64 systems boot only as non-secure */212 if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) {213 dev_warn(dev, "ignoring \"secure-reg-access\" property for arm64\n");214 pmu->secure_access = false;215 }216 217 ret = init_fn(pmu);218 } else if (probe_table) {219 cpumask_setall(&pmu->supported_cpus);220 ret = probe_current_pmu(pmu, probe_table);221 }222 223 if (ret) {224 dev_err(dev, "failed to probe PMU!\n");225 goto out_free;226 }227 228 ret = armpmu_request_irqs(pmu);229 if (ret)230 goto out_free_irqs;231 232 ret = armpmu_register(pmu);233 if (ret) {234 dev_err(dev, "failed to register PMU devices!\n");235 goto out_free_irqs;236 }237 238 return 0;239 240out_free_irqs:241 armpmu_free_irqs(pmu);242out_free:243 armpmu_free(pmu);244 return ret;245}246