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