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 : 207 : static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq)
46 : : {
47 : : int cpu, ret;
48 : 207 : struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
49 : :
50 : 207 : ret = irq_get_percpu_devid_partition(irq, &pmu->supported_cpus);
51 [ + - ]: 207 : if (ret)
52 : : return ret;
53 : :
54 [ + + ]: 1035 : for_each_cpu(cpu, &pmu->supported_cpus)
55 : 828 : 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 : 207 : static int pmu_parse_irqs(struct arm_pmu *pmu)
97 : : {
98 : : int i = 0, num_irqs;
99 : 207 : struct platform_device *pdev = pmu->plat_device;
100 : 207 : struct pmu_hw_events __percpu *hw_events = pmu->hw_events;
101 : :
102 : 207 : num_irqs = platform_irq_count(pdev);
103 [ - + ]: 207 : 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 [ - + ]: 207 : 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 [ + - ]: 207 : if (num_irqs == 1) {
120 : 207 : int irq = platform_get_irq(pdev, 0);
121 [ + - + - ]: 414 : if (irq && irq_is_percpu_devid(irq))
122 : 207 : 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 : 207 : static int armpmu_request_irqs(struct arm_pmu *armpmu)
161 : : {
162 : 207 : struct pmu_hw_events __percpu *hw_events = armpmu->hw_events;
163 : : int cpu, err = 0;
164 : :
165 [ + + ]: 1242 : for_each_cpu(cpu, &armpmu->supported_cpus) {
166 : 828 : int irq = per_cpu(hw_events->irq, cpu);
167 [ - + ]: 828 : if (!irq)
168 : 0 : continue;
169 : :
170 : 828 : err = armpmu_request_irq(irq, cpu);
171 [ + - ]: 828 : if (err)
172 : : break;
173 : : }
174 : :
175 : 207 : 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 : 207 : 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 : 207 : struct device_node *node = pdev->dev.of_node;
197 : : struct arm_pmu *pmu;
198 : : int ret = -ENODEV;
199 : :
200 : 207 : pmu = armpmu_alloc();
201 [ + - ]: 207 : if (!pmu)
202 : : return -ENOMEM;
203 : :
204 : 207 : pmu->plat_device = pdev;
205 : :
206 : 207 : ret = pmu_parse_irqs(pmu);
207 [ + - ]: 207 : if (ret)
208 : : goto out_free;
209 : :
210 [ + - + - ]: 207 : if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) {
211 : 207 : init_fn = of_id->data;
212 : :
213 : 414 : 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 : 207 : 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 [ - + ]: 207 : if (ret) {
229 : 0 : pr_info("%pOF: failed to probe PMU!\n", node);
230 : 0 : goto out_free;
231 : : }
232 : :
233 : 207 : ret = armpmu_request_irqs(pmu);
234 [ + - ]: 207 : if (ret)
235 : : goto out_free_irqs;
236 : :
237 : 207 : ret = armpmu_register(pmu);
238 [ - + ]: 207 : 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 : : }
|