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