1 // SPDX-License-Identifier: GPL-2.0-only
3 * HiSilicon SoC UC (unified cache) uncore Hardware event counters support
5 * Copyright (C) 2023 HiSilicon Limited
7 * This code is based on the uncore PMUs like hisi_uncore_l3c_pmu.
9 #include <linux/cpuhotplug.h>
10 #include <linux/interrupt.h>
11 #include <linux/irq.h>
12 #include <linux/list.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/property.h>
16 #include "hisi_uncore_pmu.h"
18 /* Dynamic CPU hotplug state used by UC PMU */
19 static enum cpuhp_state hisi_uc_pmu_online
;
21 /* UC register definition */
22 #define HISI_UC_INT_MASK_REG 0x0800
23 #define HISI_UC_INT_STS_REG 0x0808
24 #define HISI_UC_INT_CLEAR_REG 0x080c
25 #define HISI_UC_TRACETAG_CTRL_REG 0x1b2c
26 #define HISI_UC_TRACETAG_REQ_MSK GENMASK(9, 7)
27 #define HISI_UC_TRACETAG_MARK_EN BIT(0)
28 #define HISI_UC_TRACETAG_REQ_EN (HISI_UC_TRACETAG_MARK_EN | BIT(2))
29 #define HISI_UC_TRACETAG_SRCID_EN BIT(3)
30 #define HISI_UC_SRCID_CTRL_REG 0x1b40
31 #define HISI_UC_SRCID_MSK GENMASK(14, 1)
32 #define HISI_UC_EVENT_CTRL_REG 0x1c00
33 #define HISI_UC_EVENT_TRACETAG_EN BIT(29)
34 #define HISI_UC_EVENT_URING_MSK GENMASK(28, 27)
35 #define HISI_UC_EVENT_GLB_EN BIT(26)
36 #define HISI_UC_VERSION_REG 0x1cf0
37 #define HISI_UC_EVTYPE_REGn(n) (0x1d00 + (n) * 4)
38 #define HISI_UC_EVTYPE_MASK GENMASK(7, 0)
39 #define HISI_UC_CNTR_REGn(n) (0x1e00 + (n) * 8)
41 #define HISI_UC_NR_COUNTERS 0x8
42 #define HISI_UC_V2_NR_EVENTS 0xFF
43 #define HISI_UC_CNTR_REG_BITS 64
45 #define HISI_UC_RD_REQ_TRACETAG 0x4
46 #define HISI_UC_URING_EVENT_MIN 0x47
47 #define HISI_UC_URING_EVENT_MAX 0x59
49 HISI_PMU_EVENT_ATTR_EXTRACTOR(rd_req_en
, config1
, 0, 0);
50 HISI_PMU_EVENT_ATTR_EXTRACTOR(uring_channel
, config1
, 5, 4);
51 HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid
, config1
, 19, 6);
52 HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_en
, config1
, 20, 20);
54 static int hisi_uc_pmu_check_filter(struct perf_event
*event
)
56 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
58 if (hisi_get_srcid_en(event
) && !hisi_get_rd_req_en(event
)) {
60 "rcid_en depends on rd_req_en being enabled!\n");
64 if (!hisi_get_uring_channel(event
))
67 if ((HISI_GET_EVENTID(event
) < HISI_UC_URING_EVENT_MIN
) ||
68 (HISI_GET_EVENTID(event
) > HISI_UC_URING_EVENT_MAX
))
70 "Only events: [%#x ~ %#x] support channel filtering!",
71 HISI_UC_URING_EVENT_MIN
, HISI_UC_URING_EVENT_MAX
);
76 static void hisi_uc_pmu_config_req_tracetag(struct perf_event
*event
)
78 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
81 if (!hisi_get_rd_req_en(event
))
84 val
= readl(uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
86 /* The request-type has been configured */
87 if (FIELD_GET(HISI_UC_TRACETAG_REQ_MSK
, val
) == HISI_UC_RD_REQ_TRACETAG
)
90 /* Set request-type for tracetag, only read request is supported! */
91 val
&= ~HISI_UC_TRACETAG_REQ_MSK
;
92 val
|= FIELD_PREP(HISI_UC_TRACETAG_REQ_MSK
, HISI_UC_RD_REQ_TRACETAG
);
93 val
|= HISI_UC_TRACETAG_REQ_EN
;
94 writel(val
, uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
97 static void hisi_uc_pmu_clear_req_tracetag(struct perf_event
*event
)
99 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
102 if (!hisi_get_rd_req_en(event
))
105 val
= readl(uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
107 /* Do nothing, the request-type tracetag has been cleaned up */
108 if (FIELD_GET(HISI_UC_TRACETAG_REQ_MSK
, val
) == 0)
111 /* Clear request-type */
112 val
&= ~HISI_UC_TRACETAG_REQ_MSK
;
113 val
&= ~HISI_UC_TRACETAG_REQ_EN
;
114 writel(val
, uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
117 static void hisi_uc_pmu_config_srcid_tracetag(struct perf_event
*event
)
119 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
122 if (!hisi_get_srcid_en(event
))
125 val
= readl(uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
127 /* Do nothing, the source id has been configured */
128 if (FIELD_GET(HISI_UC_TRACETAG_SRCID_EN
, val
))
131 /* Enable source id tracetag */
132 val
|= HISI_UC_TRACETAG_SRCID_EN
;
133 writel(val
, uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
135 val
= readl(uc_pmu
->base
+ HISI_UC_SRCID_CTRL_REG
);
136 val
&= ~HISI_UC_SRCID_MSK
;
137 val
|= FIELD_PREP(HISI_UC_SRCID_MSK
, hisi_get_srcid(event
));
138 writel(val
, uc_pmu
->base
+ HISI_UC_SRCID_CTRL_REG
);
140 /* Depend on request-type tracetag enabled */
141 hisi_uc_pmu_config_req_tracetag(event
);
144 static void hisi_uc_pmu_clear_srcid_tracetag(struct perf_event
*event
)
146 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
149 if (!hisi_get_srcid_en(event
))
152 val
= readl(uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
154 /* Do nothing, the source id has been cleaned up */
155 if (FIELD_GET(HISI_UC_TRACETAG_SRCID_EN
, val
) == 0)
158 hisi_uc_pmu_clear_req_tracetag(event
);
160 /* Disable source id tracetag */
161 val
&= ~HISI_UC_TRACETAG_SRCID_EN
;
162 writel(val
, uc_pmu
->base
+ HISI_UC_TRACETAG_CTRL_REG
);
164 val
= readl(uc_pmu
->base
+ HISI_UC_SRCID_CTRL_REG
);
165 val
&= ~HISI_UC_SRCID_MSK
;
166 writel(val
, uc_pmu
->base
+ HISI_UC_SRCID_CTRL_REG
);
169 static void hisi_uc_pmu_config_uring_channel(struct perf_event
*event
)
171 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
172 u32 uring_channel
= hisi_get_uring_channel(event
);
175 /* Do nothing if not being set or is set explicitly to zero (default) */
176 if (uring_channel
== 0)
179 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
181 /* Do nothing, the uring_channel has been configured */
182 if (uring_channel
== FIELD_GET(HISI_UC_EVENT_URING_MSK
, val
))
185 val
&= ~HISI_UC_EVENT_URING_MSK
;
186 val
|= FIELD_PREP(HISI_UC_EVENT_URING_MSK
, uring_channel
);
187 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
190 static void hisi_uc_pmu_clear_uring_channel(struct perf_event
*event
)
192 struct hisi_pmu
*uc_pmu
= to_hisi_pmu(event
->pmu
);
195 /* Do nothing if not being set or is set explicitly to zero (default) */
196 if (hisi_get_uring_channel(event
) == 0)
199 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
201 /* Do nothing, the uring_channel has been cleaned up */
202 if (FIELD_GET(HISI_UC_EVENT_URING_MSK
, val
) == 0)
205 val
&= ~HISI_UC_EVENT_URING_MSK
;
206 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
209 static void hisi_uc_pmu_enable_filter(struct perf_event
*event
)
211 if (event
->attr
.config1
== 0)
214 hisi_uc_pmu_config_uring_channel(event
);
215 hisi_uc_pmu_config_req_tracetag(event
);
216 hisi_uc_pmu_config_srcid_tracetag(event
);
219 static void hisi_uc_pmu_disable_filter(struct perf_event
*event
)
221 if (event
->attr
.config1
== 0)
224 hisi_uc_pmu_clear_srcid_tracetag(event
);
225 hisi_uc_pmu_clear_req_tracetag(event
);
226 hisi_uc_pmu_clear_uring_channel(event
);
229 static void hisi_uc_pmu_write_evtype(struct hisi_pmu
*uc_pmu
, int idx
, u32 type
)
234 * Select the appropriate event select register.
235 * There are 2 32-bit event select registers for the
236 * 8 hardware counters, each event code is 8-bit wide.
238 val
= readl(uc_pmu
->base
+ HISI_UC_EVTYPE_REGn(idx
/ 4));
239 val
&= ~(HISI_UC_EVTYPE_MASK
<< HISI_PMU_EVTYPE_SHIFT(idx
));
240 val
|= (type
<< HISI_PMU_EVTYPE_SHIFT(idx
));
241 writel(val
, uc_pmu
->base
+ HISI_UC_EVTYPE_REGn(idx
/ 4));
244 static void hisi_uc_pmu_start_counters(struct hisi_pmu
*uc_pmu
)
248 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
249 val
|= HISI_UC_EVENT_GLB_EN
;
250 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
253 static void hisi_uc_pmu_stop_counters(struct hisi_pmu
*uc_pmu
)
257 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
258 val
&= ~HISI_UC_EVENT_GLB_EN
;
259 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
262 static void hisi_uc_pmu_enable_counter(struct hisi_pmu
*uc_pmu
,
263 struct hw_perf_event
*hwc
)
267 /* Enable counter index */
268 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
269 val
|= (1 << hwc
->idx
);
270 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
273 static void hisi_uc_pmu_disable_counter(struct hisi_pmu
*uc_pmu
,
274 struct hw_perf_event
*hwc
)
278 /* Clear counter index */
279 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
280 val
&= ~(1 << hwc
->idx
);
281 writel(val
, uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
284 static u64
hisi_uc_pmu_read_counter(struct hisi_pmu
*uc_pmu
,
285 struct hw_perf_event
*hwc
)
287 return readq(uc_pmu
->base
+ HISI_UC_CNTR_REGn(hwc
->idx
));
290 static bool hisi_uc_pmu_get_glb_en_state(struct hisi_pmu
*uc_pmu
)
294 val
= readl(uc_pmu
->base
+ HISI_UC_EVENT_CTRL_REG
);
295 return !!FIELD_GET(HISI_UC_EVENT_GLB_EN
, val
);
298 static void hisi_uc_pmu_write_counter_normal(struct hisi_pmu
*uc_pmu
,
299 struct hw_perf_event
*hwc
, u64 val
)
301 writeq(val
, uc_pmu
->base
+ HISI_UC_CNTR_REGn(hwc
->idx
));
304 static void hisi_uc_pmu_write_counter_quirk_v2(struct hisi_pmu
*uc_pmu
,
305 struct hw_perf_event
*hwc
, u64 val
)
307 hisi_uc_pmu_start_counters(uc_pmu
);
308 hisi_uc_pmu_write_counter_normal(uc_pmu
, hwc
, val
);
309 hisi_uc_pmu_stop_counters(uc_pmu
);
312 static void hisi_uc_pmu_write_counter(struct hisi_pmu
*uc_pmu
,
313 struct hw_perf_event
*hwc
, u64 val
)
315 bool enable
= hisi_uc_pmu_get_glb_en_state(uc_pmu
);
316 bool erratum
= uc_pmu
->identifier
== HISI_PMU_V2
;
319 * HiSilicon UC PMU v2 suffers the erratum 162700402 that the
320 * PMU counter cannot be set due to the lack of clock under power
321 * saving mode. This will lead to error or inaccurate counts.
322 * The clock can be enabled by the PMU global enabling control.
323 * The irq handler and pmu_start() will call the function to set
324 * period. If the function under irq context, the PMU has been
325 * enabled therefore we set counter directly. Other situations
326 * the PMU is disabled, we need to enable it to turn on the
327 * counter clock to set period, and then restore PMU enable
328 * status, the counter can hold its value without a clock.
330 if (enable
|| !erratum
)
331 hisi_uc_pmu_write_counter_normal(uc_pmu
, hwc
, val
);
333 hisi_uc_pmu_write_counter_quirk_v2(uc_pmu
, hwc
, val
);
336 static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu
*uc_pmu
,
337 struct hw_perf_event
*hwc
)
341 val
= readl(uc_pmu
->base
+ HISI_UC_INT_MASK_REG
);
342 val
&= ~(1 << hwc
->idx
);
343 writel(val
, uc_pmu
->base
+ HISI_UC_INT_MASK_REG
);
346 static void hisi_uc_pmu_disable_counter_int(struct hisi_pmu
*uc_pmu
,
347 struct hw_perf_event
*hwc
)
351 val
= readl(uc_pmu
->base
+ HISI_UC_INT_MASK_REG
);
352 val
|= (1 << hwc
->idx
);
353 writel(val
, uc_pmu
->base
+ HISI_UC_INT_MASK_REG
);
356 static u32
hisi_uc_pmu_get_int_status(struct hisi_pmu
*uc_pmu
)
358 return readl(uc_pmu
->base
+ HISI_UC_INT_STS_REG
);
361 static void hisi_uc_pmu_clear_int_status(struct hisi_pmu
*uc_pmu
, int idx
)
363 writel(1 << idx
, uc_pmu
->base
+ HISI_UC_INT_CLEAR_REG
);
366 static int hisi_uc_pmu_init_data(struct platform_device
*pdev
,
367 struct hisi_pmu
*uc_pmu
)
370 * Use SCCL (Super CPU Cluster) ID and CCL (CPU Cluster) ID to
371 * identify the topology information of UC PMU devices in the chip.
372 * They have some CCLs per SCCL and then 4 UC PMU per CCL.
374 if (device_property_read_u32(&pdev
->dev
, "hisilicon,scl-id",
376 dev_err(&pdev
->dev
, "Can not read uc sccl-id!\n");
380 if (device_property_read_u32(&pdev
->dev
, "hisilicon,ccl-id",
382 dev_err(&pdev
->dev
, "Can not read uc ccl-id!\n");
386 if (device_property_read_u32(&pdev
->dev
, "hisilicon,sub-id",
388 dev_err(&pdev
->dev
, "Can not read sub-id!\n");
392 uc_pmu
->base
= devm_platform_ioremap_resource(pdev
, 0);
393 if (IS_ERR(uc_pmu
->base
)) {
394 dev_err(&pdev
->dev
, "ioremap failed for uc_pmu resource\n");
395 return PTR_ERR(uc_pmu
->base
);
398 uc_pmu
->identifier
= readl(uc_pmu
->base
+ HISI_UC_VERSION_REG
);
403 static struct attribute
*hisi_uc_pmu_format_attr
[] = {
404 HISI_PMU_FORMAT_ATTR(event
, "config:0-7"),
405 HISI_PMU_FORMAT_ATTR(rd_req_en
, "config1:0-0"),
406 HISI_PMU_FORMAT_ATTR(uring_channel
, "config1:4-5"),
407 HISI_PMU_FORMAT_ATTR(srcid
, "config1:6-19"),
408 HISI_PMU_FORMAT_ATTR(srcid_en
, "config1:20-20"),
412 static const struct attribute_group hisi_uc_pmu_format_group
= {
414 .attrs
= hisi_uc_pmu_format_attr
,
417 static struct attribute
*hisi_uc_pmu_events_attr
[] = {
418 HISI_PMU_EVENT_ATTR(sq_time
, 0x00),
419 HISI_PMU_EVENT_ATTR(pq_time
, 0x01),
420 HISI_PMU_EVENT_ATTR(hbm_time
, 0x02),
421 HISI_PMU_EVENT_ATTR(iq_comp_time_cring
, 0x03),
422 HISI_PMU_EVENT_ATTR(iq_comp_time_uring
, 0x05),
423 HISI_PMU_EVENT_ATTR(cpu_rd
, 0x10),
424 HISI_PMU_EVENT_ATTR(cpu_rd64
, 0x17),
425 HISI_PMU_EVENT_ATTR(cpu_rs64
, 0x19),
426 HISI_PMU_EVENT_ATTR(cpu_mru
, 0x1c),
427 HISI_PMU_EVENT_ATTR(cycles
, 0x95),
428 HISI_PMU_EVENT_ATTR(spipe_hit
, 0xb3),
429 HISI_PMU_EVENT_ATTR(hpipe_hit
, 0xdb),
430 HISI_PMU_EVENT_ATTR(cring_rxdat_cnt
, 0xfa),
431 HISI_PMU_EVENT_ATTR(cring_txdat_cnt
, 0xfb),
432 HISI_PMU_EVENT_ATTR(uring_rxdat_cnt
, 0xfc),
433 HISI_PMU_EVENT_ATTR(uring_txdat_cnt
, 0xfd),
437 static const struct attribute_group hisi_uc_pmu_events_group
= {
439 .attrs
= hisi_uc_pmu_events_attr
,
442 static DEVICE_ATTR(cpumask
, 0444, hisi_cpumask_sysfs_show
, NULL
);
444 static struct attribute
*hisi_uc_pmu_cpumask_attrs
[] = {
445 &dev_attr_cpumask
.attr
,
449 static const struct attribute_group hisi_uc_pmu_cpumask_attr_group
= {
450 .attrs
= hisi_uc_pmu_cpumask_attrs
,
453 static struct device_attribute hisi_uc_pmu_identifier_attr
=
454 __ATTR(identifier
, 0444, hisi_uncore_pmu_identifier_attr_show
, NULL
);
456 static struct attribute
*hisi_uc_pmu_identifier_attrs
[] = {
457 &hisi_uc_pmu_identifier_attr
.attr
,
461 static const struct attribute_group hisi_uc_pmu_identifier_group
= {
462 .attrs
= hisi_uc_pmu_identifier_attrs
,
465 static const struct attribute_group
*hisi_uc_pmu_attr_groups
[] = {
466 &hisi_uc_pmu_format_group
,
467 &hisi_uc_pmu_events_group
,
468 &hisi_uc_pmu_cpumask_attr_group
,
469 &hisi_uc_pmu_identifier_group
,
473 static const struct hisi_uncore_ops hisi_uncore_uc_pmu_ops
= {
474 .check_filter
= hisi_uc_pmu_check_filter
,
475 .write_evtype
= hisi_uc_pmu_write_evtype
,
476 .get_event_idx
= hisi_uncore_pmu_get_event_idx
,
477 .start_counters
= hisi_uc_pmu_start_counters
,
478 .stop_counters
= hisi_uc_pmu_stop_counters
,
479 .enable_counter
= hisi_uc_pmu_enable_counter
,
480 .disable_counter
= hisi_uc_pmu_disable_counter
,
481 .enable_counter_int
= hisi_uc_pmu_enable_counter_int
,
482 .disable_counter_int
= hisi_uc_pmu_disable_counter_int
,
483 .write_counter
= hisi_uc_pmu_write_counter
,
484 .read_counter
= hisi_uc_pmu_read_counter
,
485 .get_int_status
= hisi_uc_pmu_get_int_status
,
486 .clear_int_status
= hisi_uc_pmu_clear_int_status
,
487 .enable_filter
= hisi_uc_pmu_enable_filter
,
488 .disable_filter
= hisi_uc_pmu_disable_filter
,
491 static int hisi_uc_pmu_dev_probe(struct platform_device
*pdev
,
492 struct hisi_pmu
*uc_pmu
)
496 ret
= hisi_uc_pmu_init_data(pdev
, uc_pmu
);
500 ret
= hisi_uncore_pmu_init_irq(uc_pmu
, pdev
);
504 uc_pmu
->pmu_events
.attr_groups
= hisi_uc_pmu_attr_groups
;
505 uc_pmu
->check_event
= HISI_UC_EVTYPE_MASK
;
506 uc_pmu
->ops
= &hisi_uncore_uc_pmu_ops
;
507 uc_pmu
->counter_bits
= HISI_UC_CNTR_REG_BITS
;
508 uc_pmu
->num_counters
= HISI_UC_NR_COUNTERS
;
509 uc_pmu
->dev
= &pdev
->dev
;
515 static void hisi_uc_pmu_remove_cpuhp_instance(void *hotplug_node
)
517 cpuhp_state_remove_instance_nocalls(hisi_uc_pmu_online
, hotplug_node
);
520 static void hisi_uc_pmu_unregister_pmu(void *pmu
)
522 perf_pmu_unregister(pmu
);
525 static int hisi_uc_pmu_probe(struct platform_device
*pdev
)
527 struct hisi_pmu
*uc_pmu
;
531 uc_pmu
= devm_kzalloc(&pdev
->dev
, sizeof(*uc_pmu
), GFP_KERNEL
);
535 platform_set_drvdata(pdev
, uc_pmu
);
537 ret
= hisi_uc_pmu_dev_probe(pdev
, uc_pmu
);
541 name
= devm_kasprintf(&pdev
->dev
, GFP_KERNEL
, "hisi_sccl%d_uc%d_%u",
542 uc_pmu
->sccl_id
, uc_pmu
->ccl_id
, uc_pmu
->sub_id
);
546 ret
= cpuhp_state_add_instance(hisi_uc_pmu_online
, &uc_pmu
->node
);
548 return dev_err_probe(&pdev
->dev
, ret
, "Error registering hotplug\n");
550 ret
= devm_add_action_or_reset(&pdev
->dev
,
551 hisi_uc_pmu_remove_cpuhp_instance
,
556 hisi_pmu_init(uc_pmu
, THIS_MODULE
);
558 ret
= perf_pmu_register(&uc_pmu
->pmu
, name
, -1);
562 return devm_add_action_or_reset(&pdev
->dev
,
563 hisi_uc_pmu_unregister_pmu
,
567 static const struct acpi_device_id hisi_uc_pmu_acpi_match
[] = {
571 MODULE_DEVICE_TABLE(acpi
, hisi_uc_pmu_acpi_match
);
573 static struct platform_driver hisi_uc_pmu_driver
= {
575 .name
= "hisi_uc_pmu",
576 .acpi_match_table
= hisi_uc_pmu_acpi_match
,
578 * We have not worked out a safe bind/unbind process,
579 * Forcefully unbinding during sampling will lead to a
580 * kernel panic, so this is not supported yet.
582 .suppress_bind_attrs
= true,
584 .probe
= hisi_uc_pmu_probe
,
587 static int __init
hisi_uc_pmu_module_init(void)
591 ret
= cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN
,
592 "perf/hisi/uc:online",
593 hisi_uncore_pmu_online_cpu
,
594 hisi_uncore_pmu_offline_cpu
);
596 pr_err("UC PMU: Error setup hotplug, ret = %d\n", ret
);
599 hisi_uc_pmu_online
= ret
;
601 ret
= platform_driver_register(&hisi_uc_pmu_driver
);
603 cpuhp_remove_multi_state(hisi_uc_pmu_online
);
607 module_init(hisi_uc_pmu_module_init
);
609 static void __exit
hisi_uc_pmu_module_exit(void)
611 platform_driver_unregister(&hisi_uc_pmu_driver
);
612 cpuhp_remove_multi_state(hisi_uc_pmu_online
);
614 module_exit(hisi_uc_pmu_module_exit
);
616 MODULE_DESCRIPTION("HiSilicon SoC UC uncore PMU driver");
617 MODULE_LICENSE("GPL");
618 MODULE_AUTHOR("Junhao He <hejunhao3@huawei.com>");