1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * HiSilicon SoC HHA uncore Hardware event counters support |
4 | * |
5 | * Copyright (C) 2017 HiSilicon Limited |
6 | * Author: Shaokun Zhang <zhangshaokun@hisilicon.com> |
7 | * Anurup M <anurup.m@huawei.com> |
8 | * |
9 | * This code is based on the uncore PMUs like arm-cci and arm-ccn. |
10 | */ |
11 | #include <linux/acpi.h> |
12 | #include <linux/bug.h> |
13 | #include <linux/cpuhotplug.h> |
14 | #include <linux/interrupt.h> |
15 | #include <linux/irq.h> |
16 | #include <linux/list.h> |
17 | #include <linux/smp.h> |
18 | |
19 | #include "hisi_uncore_pmu.h" |
20 | |
21 | /* HHA register definition */ |
22 | #define HHA_INT_MASK 0x0804 |
23 | #define HHA_INT_STATUS 0x0808 |
24 | #define HHA_INT_CLEAR 0x080C |
25 | #define HHA_VERSION 0x1cf0 |
26 | #define HHA_PERF_CTRL 0x1E00 |
27 | #define HHA_EVENT_CTRL 0x1E04 |
28 | #define HHA_SRCID_CTRL 0x1E08 |
29 | #define HHA_DATSRC_CTRL 0x1BF0 |
30 | #define HHA_EVENT_TYPE0 0x1E80 |
31 | /* |
32 | * If the HW version only supports a 48-bit counter, then |
33 | * bits [63:48] are reserved, which are Read-As-Zero and |
34 | * Writes-Ignored. |
35 | */ |
36 | #define HHA_CNT0_LOWER 0x1F00 |
37 | |
38 | /* HHA PMU v1 has 16 counters and v2 only has 8 counters */ |
39 | #define HHA_V1_NR_COUNTERS 0x10 |
40 | #define HHA_V2_NR_COUNTERS 0x8 |
41 | |
42 | #define HHA_PERF_CTRL_EN 0x1 |
43 | #define HHA_TRACETAG_EN BIT(31) |
44 | #define HHA_SRCID_EN BIT(2) |
45 | #define HHA_SRCID_CMD_SHIFT 6 |
46 | #define HHA_SRCID_MSK_SHIFT 20 |
47 | #define HHA_SRCID_CMD GENMASK(16, 6) |
48 | #define HHA_SRCID_MSK GENMASK(30, 20) |
49 | #define HHA_DATSRC_SKT_EN BIT(23) |
50 | #define HHA_EVTYPE_NONE 0xff |
51 | #define HHA_V1_NR_EVENT 0x65 |
52 | #define HHA_V2_NR_EVENT 0xCE |
53 | |
54 | HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_cmd, config1, 10, 0); |
55 | HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_msk, config1, 21, 11); |
56 | HISI_PMU_EVENT_ATTR_EXTRACTOR(tracetag_en, config1, 22, 22); |
57 | HISI_PMU_EVENT_ATTR_EXTRACTOR(datasrc_skt, config1, 23, 23); |
58 | |
59 | static void hisi_hha_pmu_enable_tracetag(struct perf_event *event) |
60 | { |
61 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
62 | u32 tt_en = hisi_get_tracetag_en(event); |
63 | |
64 | if (tt_en) { |
65 | u32 val; |
66 | |
67 | val = readl(addr: hha_pmu->base + HHA_SRCID_CTRL); |
68 | val |= HHA_TRACETAG_EN; |
69 | writel(val, addr: hha_pmu->base + HHA_SRCID_CTRL); |
70 | } |
71 | } |
72 | |
73 | static void hisi_hha_pmu_clear_tracetag(struct perf_event *event) |
74 | { |
75 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
76 | u32 val; |
77 | |
78 | val = readl(addr: hha_pmu->base + HHA_SRCID_CTRL); |
79 | val &= ~HHA_TRACETAG_EN; |
80 | writel(val, addr: hha_pmu->base + HHA_SRCID_CTRL); |
81 | } |
82 | |
83 | static void hisi_hha_pmu_config_ds(struct perf_event *event) |
84 | { |
85 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
86 | u32 ds_skt = hisi_get_datasrc_skt(event); |
87 | |
88 | if (ds_skt) { |
89 | u32 val; |
90 | |
91 | val = readl(addr: hha_pmu->base + HHA_DATSRC_CTRL); |
92 | val |= HHA_DATSRC_SKT_EN; |
93 | writel(val, addr: hha_pmu->base + HHA_DATSRC_CTRL); |
94 | } |
95 | } |
96 | |
97 | static void hisi_hha_pmu_clear_ds(struct perf_event *event) |
98 | { |
99 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
100 | u32 ds_skt = hisi_get_datasrc_skt(event); |
101 | |
102 | if (ds_skt) { |
103 | u32 val; |
104 | |
105 | val = readl(addr: hha_pmu->base + HHA_DATSRC_CTRL); |
106 | val &= ~HHA_DATSRC_SKT_EN; |
107 | writel(val, addr: hha_pmu->base + HHA_DATSRC_CTRL); |
108 | } |
109 | } |
110 | |
111 | static void hisi_hha_pmu_config_srcid(struct perf_event *event) |
112 | { |
113 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
114 | u32 cmd = hisi_get_srcid_cmd(event); |
115 | |
116 | if (cmd) { |
117 | u32 val, msk; |
118 | |
119 | msk = hisi_get_srcid_msk(event); |
120 | val = readl(addr: hha_pmu->base + HHA_SRCID_CTRL); |
121 | val |= HHA_SRCID_EN | (cmd << HHA_SRCID_CMD_SHIFT) | |
122 | (msk << HHA_SRCID_MSK_SHIFT); |
123 | writel(val, addr: hha_pmu->base + HHA_SRCID_CTRL); |
124 | } |
125 | } |
126 | |
127 | static void hisi_hha_pmu_disable_srcid(struct perf_event *event) |
128 | { |
129 | struct hisi_pmu *hha_pmu = to_hisi_pmu(event->pmu); |
130 | u32 cmd = hisi_get_srcid_cmd(event); |
131 | |
132 | if (cmd) { |
133 | u32 val; |
134 | |
135 | val = readl(addr: hha_pmu->base + HHA_SRCID_CTRL); |
136 | val &= ~(HHA_SRCID_EN | HHA_SRCID_MSK | HHA_SRCID_CMD); |
137 | writel(val, addr: hha_pmu->base + HHA_SRCID_CTRL); |
138 | } |
139 | } |
140 | |
141 | static void hisi_hha_pmu_enable_filter(struct perf_event *event) |
142 | { |
143 | if (event->attr.config1 != 0x0) { |
144 | hisi_hha_pmu_enable_tracetag(event); |
145 | hisi_hha_pmu_config_ds(event); |
146 | hisi_hha_pmu_config_srcid(event); |
147 | } |
148 | } |
149 | |
150 | static void hisi_hha_pmu_disable_filter(struct perf_event *event) |
151 | { |
152 | if (event->attr.config1 != 0x0) { |
153 | hisi_hha_pmu_disable_srcid(event); |
154 | hisi_hha_pmu_clear_ds(event); |
155 | hisi_hha_pmu_clear_tracetag(event); |
156 | } |
157 | } |
158 | |
159 | /* |
160 | * Select the counter register offset using the counter index |
161 | * each counter is 48-bits. |
162 | */ |
163 | static u32 hisi_hha_pmu_get_counter_offset(int cntr_idx) |
164 | { |
165 | return (HHA_CNT0_LOWER + (cntr_idx * 8)); |
166 | } |
167 | |
168 | static u64 hisi_hha_pmu_read_counter(struct hisi_pmu *hha_pmu, |
169 | struct hw_perf_event *hwc) |
170 | { |
171 | /* Read 64 bits and like L3C, top 16 bits are RAZ */ |
172 | return readq(addr: hha_pmu->base + hisi_hha_pmu_get_counter_offset(cntr_idx: hwc->idx)); |
173 | } |
174 | |
175 | static void hisi_hha_pmu_write_counter(struct hisi_pmu *hha_pmu, |
176 | struct hw_perf_event *hwc, u64 val) |
177 | { |
178 | /* Write 64 bits and like L3C, top 16 bits are WI */ |
179 | writeq(val, addr: hha_pmu->base + hisi_hha_pmu_get_counter_offset(cntr_idx: hwc->idx)); |
180 | } |
181 | |
182 | static void hisi_hha_pmu_write_evtype(struct hisi_pmu *hha_pmu, int idx, |
183 | u32 type) |
184 | { |
185 | u32 reg, reg_idx, shift, val; |
186 | |
187 | /* |
188 | * Select the appropriate event select register(HHA_EVENT_TYPEx). |
189 | * There are 4 event select registers for the 16 hardware counters. |
190 | * Event code is 8-bits and for the first 4 hardware counters, |
191 | * HHA_EVENT_TYPE0 is chosen. For the next 4 hardware counters, |
192 | * HHA_EVENT_TYPE1 is chosen and so on. |
193 | */ |
194 | reg = HHA_EVENT_TYPE0 + 4 * (idx / 4); |
195 | reg_idx = idx % 4; |
196 | shift = 8 * reg_idx; |
197 | |
198 | /* Write event code to HHA_EVENT_TYPEx register */ |
199 | val = readl(addr: hha_pmu->base + reg); |
200 | val &= ~(HHA_EVTYPE_NONE << shift); |
201 | val |= (type << shift); |
202 | writel(val, addr: hha_pmu->base + reg); |
203 | } |
204 | |
205 | static void hisi_hha_pmu_start_counters(struct hisi_pmu *hha_pmu) |
206 | { |
207 | u32 val; |
208 | |
209 | /* |
210 | * Set perf_enable bit in HHA_PERF_CTRL to start event |
211 | * counting for all enabled counters. |
212 | */ |
213 | val = readl(addr: hha_pmu->base + HHA_PERF_CTRL); |
214 | val |= HHA_PERF_CTRL_EN; |
215 | writel(val, addr: hha_pmu->base + HHA_PERF_CTRL); |
216 | } |
217 | |
218 | static void hisi_hha_pmu_stop_counters(struct hisi_pmu *hha_pmu) |
219 | { |
220 | u32 val; |
221 | |
222 | /* |
223 | * Clear perf_enable bit in HHA_PERF_CTRL to stop event |
224 | * counting for all enabled counters. |
225 | */ |
226 | val = readl(addr: hha_pmu->base + HHA_PERF_CTRL); |
227 | val &= ~(HHA_PERF_CTRL_EN); |
228 | writel(val, addr: hha_pmu->base + HHA_PERF_CTRL); |
229 | } |
230 | |
231 | static void hisi_hha_pmu_enable_counter(struct hisi_pmu *hha_pmu, |
232 | struct hw_perf_event *hwc) |
233 | { |
234 | u32 val; |
235 | |
236 | /* Enable counter index in HHA_EVENT_CTRL register */ |
237 | val = readl(addr: hha_pmu->base + HHA_EVENT_CTRL); |
238 | val |= (1 << hwc->idx); |
239 | writel(val, addr: hha_pmu->base + HHA_EVENT_CTRL); |
240 | } |
241 | |
242 | static void hisi_hha_pmu_disable_counter(struct hisi_pmu *hha_pmu, |
243 | struct hw_perf_event *hwc) |
244 | { |
245 | u32 val; |
246 | |
247 | /* Clear counter index in HHA_EVENT_CTRL register */ |
248 | val = readl(addr: hha_pmu->base + HHA_EVENT_CTRL); |
249 | val &= ~(1 << hwc->idx); |
250 | writel(val, addr: hha_pmu->base + HHA_EVENT_CTRL); |
251 | } |
252 | |
253 | static void hisi_hha_pmu_enable_counter_int(struct hisi_pmu *hha_pmu, |
254 | struct hw_perf_event *hwc) |
255 | { |
256 | u32 val; |
257 | |
258 | /* Write 0 to enable interrupt */ |
259 | val = readl(addr: hha_pmu->base + HHA_INT_MASK); |
260 | val &= ~(1 << hwc->idx); |
261 | writel(val, addr: hha_pmu->base + HHA_INT_MASK); |
262 | } |
263 | |
264 | static void hisi_hha_pmu_disable_counter_int(struct hisi_pmu *hha_pmu, |
265 | struct hw_perf_event *hwc) |
266 | { |
267 | u32 val; |
268 | |
269 | /* Write 1 to mask interrupt */ |
270 | val = readl(addr: hha_pmu->base + HHA_INT_MASK); |
271 | val |= (1 << hwc->idx); |
272 | writel(val, addr: hha_pmu->base + HHA_INT_MASK); |
273 | } |
274 | |
275 | static u32 hisi_hha_pmu_get_int_status(struct hisi_pmu *hha_pmu) |
276 | { |
277 | return readl(addr: hha_pmu->base + HHA_INT_STATUS); |
278 | } |
279 | |
280 | static void hisi_hha_pmu_clear_int_status(struct hisi_pmu *hha_pmu, int idx) |
281 | { |
282 | writel(val: 1 << idx, addr: hha_pmu->base + HHA_INT_CLEAR); |
283 | } |
284 | |
285 | static const struct acpi_device_id hisi_hha_pmu_acpi_match[] = { |
286 | { "HISI0243" , }, |
287 | { "HISI0244" , }, |
288 | {} |
289 | }; |
290 | MODULE_DEVICE_TABLE(acpi, hisi_hha_pmu_acpi_match); |
291 | |
292 | static int hisi_hha_pmu_init_data(struct platform_device *pdev, |
293 | struct hisi_pmu *hha_pmu) |
294 | { |
295 | unsigned long long id; |
296 | acpi_status status; |
297 | |
298 | /* |
299 | * Use SCCL_ID and UID to identify the HHA PMU, while |
300 | * SCCL_ID is in MPIDR[aff2]. |
301 | */ |
302 | if (device_property_read_u32(dev: &pdev->dev, propname: "hisilicon,scl-id" , |
303 | val: &hha_pmu->sccl_id)) { |
304 | dev_err(&pdev->dev, "Can not read hha sccl-id!\n" ); |
305 | return -EINVAL; |
306 | } |
307 | |
308 | /* |
309 | * Early versions of BIOS support _UID by mistake, so we support |
310 | * both "hisilicon, idx-id" as preference, if available. |
311 | */ |
312 | if (device_property_read_u32(dev: &pdev->dev, propname: "hisilicon,idx-id" , |
313 | val: &hha_pmu->index_id)) { |
314 | status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev), |
315 | pathname: "_UID" , NULL, data: &id); |
316 | if (ACPI_FAILURE(status)) { |
317 | dev_err(&pdev->dev, "Cannot read idx-id!\n" ); |
318 | return -EINVAL; |
319 | } |
320 | |
321 | hha_pmu->index_id = id; |
322 | } |
323 | /* HHA PMUs only share the same SCCL */ |
324 | hha_pmu->ccl_id = -1; |
325 | |
326 | hha_pmu->base = devm_platform_ioremap_resource(pdev, index: 0); |
327 | if (IS_ERR(ptr: hha_pmu->base)) { |
328 | dev_err(&pdev->dev, "ioremap failed for hha_pmu resource\n" ); |
329 | return PTR_ERR(ptr: hha_pmu->base); |
330 | } |
331 | |
332 | hha_pmu->identifier = readl(addr: hha_pmu->base + HHA_VERSION); |
333 | |
334 | return 0; |
335 | } |
336 | |
337 | static struct attribute *hisi_hha_pmu_v1_format_attr[] = { |
338 | HISI_PMU_FORMAT_ATTR(event, "config:0-7" ), |
339 | NULL, |
340 | }; |
341 | |
342 | static const struct attribute_group hisi_hha_pmu_v1_format_group = { |
343 | .name = "format" , |
344 | .attrs = hisi_hha_pmu_v1_format_attr, |
345 | }; |
346 | |
347 | static struct attribute *hisi_hha_pmu_v2_format_attr[] = { |
348 | HISI_PMU_FORMAT_ATTR(event, "config:0-7" ), |
349 | HISI_PMU_FORMAT_ATTR(srcid_cmd, "config1:0-10" ), |
350 | HISI_PMU_FORMAT_ATTR(srcid_msk, "config1:11-21" ), |
351 | HISI_PMU_FORMAT_ATTR(tracetag_en, "config1:22" ), |
352 | HISI_PMU_FORMAT_ATTR(datasrc_skt, "config1:23" ), |
353 | NULL |
354 | }; |
355 | |
356 | static const struct attribute_group hisi_hha_pmu_v2_format_group = { |
357 | .name = "format" , |
358 | .attrs = hisi_hha_pmu_v2_format_attr, |
359 | }; |
360 | |
361 | static struct attribute *hisi_hha_pmu_v1_events_attr[] = { |
362 | HISI_PMU_EVENT_ATTR(rx_ops_num, 0x00), |
363 | HISI_PMU_EVENT_ATTR(rx_outer, 0x01), |
364 | HISI_PMU_EVENT_ATTR(rx_sccl, 0x02), |
365 | HISI_PMU_EVENT_ATTR(rx_ccix, 0x03), |
366 | HISI_PMU_EVENT_ATTR(rx_wbi, 0x04), |
367 | HISI_PMU_EVENT_ATTR(rx_wbip, 0x05), |
368 | HISI_PMU_EVENT_ATTR(rx_wtistash, 0x11), |
369 | HISI_PMU_EVENT_ATTR(rd_ddr_64b, 0x1c), |
370 | HISI_PMU_EVENT_ATTR(wr_ddr_64b, 0x1d), |
371 | HISI_PMU_EVENT_ATTR(rd_ddr_128b, 0x1e), |
372 | HISI_PMU_EVENT_ATTR(wr_ddr_128b, 0x1f), |
373 | HISI_PMU_EVENT_ATTR(spill_num, 0x20), |
374 | HISI_PMU_EVENT_ATTR(spill_success, 0x21), |
375 | HISI_PMU_EVENT_ATTR(bi_num, 0x23), |
376 | HISI_PMU_EVENT_ATTR(mediated_num, 0x32), |
377 | HISI_PMU_EVENT_ATTR(tx_snp_num, 0x33), |
378 | HISI_PMU_EVENT_ATTR(tx_snp_outer, 0x34), |
379 | HISI_PMU_EVENT_ATTR(tx_snp_ccix, 0x35), |
380 | HISI_PMU_EVENT_ATTR(rx_snprspdata, 0x38), |
381 | HISI_PMU_EVENT_ATTR(rx_snprsp_outer, 0x3c), |
382 | HISI_PMU_EVENT_ATTR(sdir-lookup, 0x40), |
383 | HISI_PMU_EVENT_ATTR(edir-lookup, 0x41), |
384 | HISI_PMU_EVENT_ATTR(sdir-hit, 0x42), |
385 | HISI_PMU_EVENT_ATTR(edir-hit, 0x43), |
386 | HISI_PMU_EVENT_ATTR(sdir-home-migrate, 0x4c), |
387 | HISI_PMU_EVENT_ATTR(edir-home-migrate, 0x4d), |
388 | NULL, |
389 | }; |
390 | |
391 | static const struct attribute_group hisi_hha_pmu_v1_events_group = { |
392 | .name = "events" , |
393 | .attrs = hisi_hha_pmu_v1_events_attr, |
394 | }; |
395 | |
396 | static struct attribute *hisi_hha_pmu_v2_events_attr[] = { |
397 | HISI_PMU_EVENT_ATTR(rx_ops_num, 0x00), |
398 | HISI_PMU_EVENT_ATTR(rx_outer, 0x01), |
399 | HISI_PMU_EVENT_ATTR(rx_sccl, 0x02), |
400 | HISI_PMU_EVENT_ATTR(hha_retry, 0x2e), |
401 | HISI_PMU_EVENT_ATTR(cycles, 0x55), |
402 | NULL |
403 | }; |
404 | |
405 | static const struct attribute_group hisi_hha_pmu_v2_events_group = { |
406 | .name = "events" , |
407 | .attrs = hisi_hha_pmu_v2_events_attr, |
408 | }; |
409 | |
410 | static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL); |
411 | |
412 | static struct attribute *hisi_hha_pmu_cpumask_attrs[] = { |
413 | &dev_attr_cpumask.attr, |
414 | NULL, |
415 | }; |
416 | |
417 | static const struct attribute_group hisi_hha_pmu_cpumask_attr_group = { |
418 | .attrs = hisi_hha_pmu_cpumask_attrs, |
419 | }; |
420 | |
421 | static struct device_attribute hisi_hha_pmu_identifier_attr = |
422 | __ATTR(identifier, 0444, hisi_uncore_pmu_identifier_attr_show, NULL); |
423 | |
424 | static struct attribute *hisi_hha_pmu_identifier_attrs[] = { |
425 | &hisi_hha_pmu_identifier_attr.attr, |
426 | NULL |
427 | }; |
428 | |
429 | static const struct attribute_group hisi_hha_pmu_identifier_group = { |
430 | .attrs = hisi_hha_pmu_identifier_attrs, |
431 | }; |
432 | |
433 | static const struct attribute_group *hisi_hha_pmu_v1_attr_groups[] = { |
434 | &hisi_hha_pmu_v1_format_group, |
435 | &hisi_hha_pmu_v1_events_group, |
436 | &hisi_hha_pmu_cpumask_attr_group, |
437 | &hisi_hha_pmu_identifier_group, |
438 | NULL, |
439 | }; |
440 | |
441 | static const struct attribute_group *hisi_hha_pmu_v2_attr_groups[] = { |
442 | &hisi_hha_pmu_v2_format_group, |
443 | &hisi_hha_pmu_v2_events_group, |
444 | &hisi_hha_pmu_cpumask_attr_group, |
445 | &hisi_hha_pmu_identifier_group, |
446 | NULL |
447 | }; |
448 | |
449 | static const struct hisi_uncore_ops hisi_uncore_hha_ops = { |
450 | .write_evtype = hisi_hha_pmu_write_evtype, |
451 | .get_event_idx = hisi_uncore_pmu_get_event_idx, |
452 | .start_counters = hisi_hha_pmu_start_counters, |
453 | .stop_counters = hisi_hha_pmu_stop_counters, |
454 | .enable_counter = hisi_hha_pmu_enable_counter, |
455 | .disable_counter = hisi_hha_pmu_disable_counter, |
456 | .enable_counter_int = hisi_hha_pmu_enable_counter_int, |
457 | .disable_counter_int = hisi_hha_pmu_disable_counter_int, |
458 | .write_counter = hisi_hha_pmu_write_counter, |
459 | .read_counter = hisi_hha_pmu_read_counter, |
460 | .get_int_status = hisi_hha_pmu_get_int_status, |
461 | .clear_int_status = hisi_hha_pmu_clear_int_status, |
462 | .enable_filter = hisi_hha_pmu_enable_filter, |
463 | .disable_filter = hisi_hha_pmu_disable_filter, |
464 | }; |
465 | |
466 | static int hisi_hha_pmu_dev_probe(struct platform_device *pdev, |
467 | struct hisi_pmu *hha_pmu) |
468 | { |
469 | int ret; |
470 | |
471 | ret = hisi_hha_pmu_init_data(pdev, hha_pmu); |
472 | if (ret) |
473 | return ret; |
474 | |
475 | ret = hisi_uncore_pmu_init_irq(hisi_pmu: hha_pmu, pdev); |
476 | if (ret) |
477 | return ret; |
478 | |
479 | if (hha_pmu->identifier >= HISI_PMU_V2) { |
480 | hha_pmu->counter_bits = 64; |
481 | hha_pmu->check_event = HHA_V2_NR_EVENT; |
482 | hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v2_attr_groups; |
483 | hha_pmu->num_counters = HHA_V2_NR_COUNTERS; |
484 | } else { |
485 | hha_pmu->counter_bits = 48; |
486 | hha_pmu->check_event = HHA_V1_NR_EVENT; |
487 | hha_pmu->pmu_events.attr_groups = hisi_hha_pmu_v1_attr_groups; |
488 | hha_pmu->num_counters = HHA_V1_NR_COUNTERS; |
489 | } |
490 | hha_pmu->ops = &hisi_uncore_hha_ops; |
491 | hha_pmu->dev = &pdev->dev; |
492 | hha_pmu->on_cpu = -1; |
493 | |
494 | return 0; |
495 | } |
496 | |
497 | static int hisi_hha_pmu_probe(struct platform_device *pdev) |
498 | { |
499 | struct hisi_pmu *hha_pmu; |
500 | char *name; |
501 | int ret; |
502 | |
503 | hha_pmu = devm_kzalloc(dev: &pdev->dev, size: sizeof(*hha_pmu), GFP_KERNEL); |
504 | if (!hha_pmu) |
505 | return -ENOMEM; |
506 | |
507 | platform_set_drvdata(pdev, data: hha_pmu); |
508 | |
509 | ret = hisi_hha_pmu_dev_probe(pdev, hha_pmu); |
510 | if (ret) |
511 | return ret; |
512 | |
513 | name = devm_kasprintf(dev: &pdev->dev, GFP_KERNEL, fmt: "hisi_sccl%u_hha%u" , |
514 | hha_pmu->sccl_id, hha_pmu->index_id); |
515 | if (!name) |
516 | return -ENOMEM; |
517 | |
518 | ret = cpuhp_state_add_instance(state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, |
519 | node: &hha_pmu->node); |
520 | if (ret) { |
521 | dev_err(&pdev->dev, "Error %d registering hotplug\n" , ret); |
522 | return ret; |
523 | } |
524 | |
525 | hisi_pmu_init(hisi_pmu: hha_pmu, THIS_MODULE); |
526 | |
527 | ret = perf_pmu_register(pmu: &hha_pmu->pmu, name, type: -1); |
528 | if (ret) { |
529 | dev_err(hha_pmu->dev, "HHA PMU register failed!\n" ); |
530 | cpuhp_state_remove_instance_nocalls( |
531 | state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, node: &hha_pmu->node); |
532 | } |
533 | |
534 | return ret; |
535 | } |
536 | |
537 | static int hisi_hha_pmu_remove(struct platform_device *pdev) |
538 | { |
539 | struct hisi_pmu *hha_pmu = platform_get_drvdata(pdev); |
540 | |
541 | perf_pmu_unregister(pmu: &hha_pmu->pmu); |
542 | cpuhp_state_remove_instance_nocalls(state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, |
543 | node: &hha_pmu->node); |
544 | return 0; |
545 | } |
546 | |
547 | static struct platform_driver hisi_hha_pmu_driver = { |
548 | .driver = { |
549 | .name = "hisi_hha_pmu" , |
550 | .acpi_match_table = ACPI_PTR(hisi_hha_pmu_acpi_match), |
551 | .suppress_bind_attrs = true, |
552 | }, |
553 | .probe = hisi_hha_pmu_probe, |
554 | .remove = hisi_hha_pmu_remove, |
555 | }; |
556 | |
557 | static int __init hisi_hha_pmu_module_init(void) |
558 | { |
559 | int ret; |
560 | |
561 | ret = cpuhp_setup_state_multi(state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE, |
562 | name: "AP_PERF_ARM_HISI_HHA_ONLINE" , |
563 | startup: hisi_uncore_pmu_online_cpu, |
564 | teardown: hisi_uncore_pmu_offline_cpu); |
565 | if (ret) { |
566 | pr_err("HHA PMU: Error setup hotplug, ret = %d;\n" , ret); |
567 | return ret; |
568 | } |
569 | |
570 | ret = platform_driver_register(&hisi_hha_pmu_driver); |
571 | if (ret) |
572 | cpuhp_remove_multi_state(state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE); |
573 | |
574 | return ret; |
575 | } |
576 | module_init(hisi_hha_pmu_module_init); |
577 | |
578 | static void __exit hisi_hha_pmu_module_exit(void) |
579 | { |
580 | platform_driver_unregister(&hisi_hha_pmu_driver); |
581 | cpuhp_remove_multi_state(state: CPUHP_AP_PERF_ARM_HISI_HHA_ONLINE); |
582 | } |
583 | module_exit(hisi_hha_pmu_module_exit); |
584 | |
585 | MODULE_DESCRIPTION("HiSilicon SoC HHA uncore PMU driver" ); |
586 | MODULE_LICENSE("GPL v2" ); |
587 | MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>" ); |
588 | MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>" ); |
589 | |