xref: /linux/drivers/perf/hisilicon/hisi_uncore_uc_pmu.c (revision d2c9a99135da931377240942d44f3dea104cedb8)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HiSilicon SoC UC (unified cache) uncore Hardware event counters support
4  *
5  * Copyright (C) 2023 HiSilicon Limited
6  *
7  * This code is based on the uncore PMUs like hisi_uncore_l3c_pmu.
8  */
9 #include <linux/cpuhotplug.h>
10 #include <linux/interrupt.h>
11 #include <linux/irq.h>
12 #include <linux/list.h>
13 
14 #include "hisi_uncore_pmu.h"
15 
16 /* Dynamic CPU hotplug state used by UC PMU */
17 static enum cpuhp_state hisi_uc_pmu_online;
18 
19 /* UC register definition */
20 #define HISI_UC_INT_MASK_REG		0x0800
21 #define HISI_UC_INT_STS_REG		0x0808
22 #define HISI_UC_INT_CLEAR_REG		0x080c
23 #define HISI_UC_TRACETAG_CTRL_REG	0x1b2c
24 #define HISI_UC_TRACETAG_REQ_MSK	GENMASK(9, 7)
25 #define HISI_UC_TRACETAG_MARK_EN	BIT(0)
26 #define HISI_UC_TRACETAG_REQ_EN		(HISI_UC_TRACETAG_MARK_EN | BIT(2))
27 #define HISI_UC_TRACETAG_SRCID_EN	BIT(3)
28 #define HISI_UC_SRCID_CTRL_REG		0x1b40
29 #define HISI_UC_SRCID_MSK		GENMASK(14, 1)
30 #define HISI_UC_EVENT_CTRL_REG		0x1c00
31 #define HISI_UC_EVENT_TRACETAG_EN	BIT(29)
32 #define HISI_UC_EVENT_URING_MSK		GENMASK(28, 27)
33 #define HISI_UC_EVENT_GLB_EN		BIT(26)
34 #define HISI_UC_VERSION_REG		0x1cf0
35 #define HISI_UC_EVTYPE_REGn(n)		(0x1d00 + (n) * 4)
36 #define HISI_UC_EVTYPE_MASK		GENMASK(7, 0)
37 #define HISI_UC_CNTR_REGn(n)		(0x1e00 + (n) * 8)
38 
39 #define HISI_UC_NR_COUNTERS		0x8
40 #define HISI_UC_V2_NR_EVENTS		0xFF
41 #define HISI_UC_CNTR_REG_BITS		64
42 
43 #define HISI_UC_RD_REQ_TRACETAG		0x4
44 #define HISI_UC_URING_EVENT_MIN		0x47
45 #define HISI_UC_URING_EVENT_MAX		0x59
46 
47 HISI_PMU_EVENT_ATTR_EXTRACTOR(rd_req_en, config1, 0, 0);
48 HISI_PMU_EVENT_ATTR_EXTRACTOR(uring_channel, config1, 5, 4);
49 HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid, config1, 19, 6);
50 HISI_PMU_EVENT_ATTR_EXTRACTOR(srcid_en, config1, 20, 20);
51 
hisi_uc_pmu_check_filter(struct perf_event * event)52 static int hisi_uc_pmu_check_filter(struct perf_event *event)
53 {
54 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
55 
56 	if (hisi_get_srcid_en(event) && !hisi_get_rd_req_en(event)) {
57 		dev_err(uc_pmu->dev,
58 			"rcid_en depends on rd_req_en being enabled!\n");
59 		return -EINVAL;
60 	}
61 
62 	if (!hisi_get_uring_channel(event))
63 		return 0;
64 
65 	if ((HISI_GET_EVENTID(event) < HISI_UC_URING_EVENT_MIN) ||
66 	    (HISI_GET_EVENTID(event) > HISI_UC_URING_EVENT_MAX))
67 		dev_warn(uc_pmu->dev,
68 			 "Only events: [%#x ~ %#x] support channel filtering!",
69 			 HISI_UC_URING_EVENT_MIN, HISI_UC_URING_EVENT_MAX);
70 
71 	return 0;
72 }
73 
hisi_uc_pmu_config_req_tracetag(struct perf_event * event)74 static void hisi_uc_pmu_config_req_tracetag(struct perf_event *event)
75 {
76 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
77 	u32 val;
78 
79 	if (!hisi_get_rd_req_en(event))
80 		return;
81 
82 	val = readl(uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
83 
84 	/* The request-type has been configured */
85 	if (FIELD_GET(HISI_UC_TRACETAG_REQ_MSK, val) == HISI_UC_RD_REQ_TRACETAG)
86 		return;
87 
88 	/* Set request-type for tracetag, only read request is supported! */
89 	val &= ~HISI_UC_TRACETAG_REQ_MSK;
90 	val |= FIELD_PREP(HISI_UC_TRACETAG_REQ_MSK, HISI_UC_RD_REQ_TRACETAG);
91 	val |= HISI_UC_TRACETAG_REQ_EN;
92 	writel(val, uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
93 }
94 
hisi_uc_pmu_clear_req_tracetag(struct perf_event * event)95 static void hisi_uc_pmu_clear_req_tracetag(struct perf_event *event)
96 {
97 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
98 	u32 val;
99 
100 	if (!hisi_get_rd_req_en(event))
101 		return;
102 
103 	val = readl(uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
104 
105 	/* Do nothing, the request-type tracetag has been cleaned up */
106 	if (FIELD_GET(HISI_UC_TRACETAG_REQ_MSK, val) == 0)
107 		return;
108 
109 	/* Clear request-type */
110 	val &= ~HISI_UC_TRACETAG_REQ_MSK;
111 	val &= ~HISI_UC_TRACETAG_REQ_EN;
112 	writel(val, uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
113 }
114 
hisi_uc_pmu_config_srcid_tracetag(struct perf_event * event)115 static void hisi_uc_pmu_config_srcid_tracetag(struct perf_event *event)
116 {
117 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
118 	u32 val;
119 
120 	if (!hisi_get_srcid_en(event))
121 		return;
122 
123 	val = readl(uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
124 
125 	/* Do nothing, the source id has been configured */
126 	if (FIELD_GET(HISI_UC_TRACETAG_SRCID_EN, val))
127 		return;
128 
129 	/* Enable source id tracetag */
130 	val |= HISI_UC_TRACETAG_SRCID_EN;
131 	writel(val, uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
132 
133 	val = readl(uc_pmu->base + HISI_UC_SRCID_CTRL_REG);
134 	val &= ~HISI_UC_SRCID_MSK;
135 	val |= FIELD_PREP(HISI_UC_SRCID_MSK, hisi_get_srcid(event));
136 	writel(val, uc_pmu->base + HISI_UC_SRCID_CTRL_REG);
137 
138 	/* Depend on request-type tracetag enabled */
139 	hisi_uc_pmu_config_req_tracetag(event);
140 }
141 
hisi_uc_pmu_clear_srcid_tracetag(struct perf_event * event)142 static void hisi_uc_pmu_clear_srcid_tracetag(struct perf_event *event)
143 {
144 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
145 	u32 val;
146 
147 	if (!hisi_get_srcid_en(event))
148 		return;
149 
150 	val = readl(uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
151 
152 	/* Do nothing, the source id has been cleaned up */
153 	if (FIELD_GET(HISI_UC_TRACETAG_SRCID_EN, val) == 0)
154 		return;
155 
156 	hisi_uc_pmu_clear_req_tracetag(event);
157 
158 	/* Disable source id tracetag */
159 	val &= ~HISI_UC_TRACETAG_SRCID_EN;
160 	writel(val, uc_pmu->base + HISI_UC_TRACETAG_CTRL_REG);
161 
162 	val = readl(uc_pmu->base + HISI_UC_SRCID_CTRL_REG);
163 	val &= ~HISI_UC_SRCID_MSK;
164 	writel(val, uc_pmu->base + HISI_UC_SRCID_CTRL_REG);
165 }
166 
hisi_uc_pmu_config_uring_channel(struct perf_event * event)167 static void hisi_uc_pmu_config_uring_channel(struct perf_event *event)
168 {
169 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
170 	u32 uring_channel = hisi_get_uring_channel(event);
171 	u32 val;
172 
173 	/* Do nothing if not being set or is set explicitly to zero (default) */
174 	if (uring_channel == 0)
175 		return;
176 
177 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
178 
179 	/* Do nothing, the uring_channel has been configured */
180 	if (uring_channel == FIELD_GET(HISI_UC_EVENT_URING_MSK, val))
181 		return;
182 
183 	val &= ~HISI_UC_EVENT_URING_MSK;
184 	val |= FIELD_PREP(HISI_UC_EVENT_URING_MSK, uring_channel);
185 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
186 }
187 
hisi_uc_pmu_clear_uring_channel(struct perf_event * event)188 static void hisi_uc_pmu_clear_uring_channel(struct perf_event *event)
189 {
190 	struct hisi_pmu *uc_pmu = to_hisi_pmu(event->pmu);
191 	u32 val;
192 
193 	/* Do nothing if not being set or is set explicitly to zero (default) */
194 	if (hisi_get_uring_channel(event) == 0)
195 		return;
196 
197 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
198 
199 	/* Do nothing, the uring_channel has been cleaned up */
200 	if (FIELD_GET(HISI_UC_EVENT_URING_MSK, val) == 0)
201 		return;
202 
203 	val &= ~HISI_UC_EVENT_URING_MSK;
204 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
205 }
206 
hisi_uc_pmu_enable_filter(struct perf_event * event)207 static void hisi_uc_pmu_enable_filter(struct perf_event *event)
208 {
209 	if (event->attr.config1 == 0)
210 		return;
211 
212 	hisi_uc_pmu_config_uring_channel(event);
213 	hisi_uc_pmu_config_req_tracetag(event);
214 	hisi_uc_pmu_config_srcid_tracetag(event);
215 }
216 
hisi_uc_pmu_disable_filter(struct perf_event * event)217 static void hisi_uc_pmu_disable_filter(struct perf_event *event)
218 {
219 	if (event->attr.config1 == 0)
220 		return;
221 
222 	hisi_uc_pmu_clear_srcid_tracetag(event);
223 	hisi_uc_pmu_clear_req_tracetag(event);
224 	hisi_uc_pmu_clear_uring_channel(event);
225 }
226 
hisi_uc_pmu_write_evtype(struct hisi_pmu * uc_pmu,int idx,u32 type)227 static void hisi_uc_pmu_write_evtype(struct hisi_pmu *uc_pmu, int idx, u32 type)
228 {
229 	u32 val;
230 
231 	/*
232 	 * Select the appropriate event select register.
233 	 * There are 2 32-bit event select registers for the
234 	 * 8 hardware counters, each event code is 8-bit wide.
235 	 */
236 	val = readl(uc_pmu->base + HISI_UC_EVTYPE_REGn(idx / 4));
237 	val &= ~(HISI_UC_EVTYPE_MASK << HISI_PMU_EVTYPE_SHIFT(idx));
238 	val |= (type << HISI_PMU_EVTYPE_SHIFT(idx));
239 	writel(val, uc_pmu->base + HISI_UC_EVTYPE_REGn(idx / 4));
240 }
241 
hisi_uc_pmu_start_counters(struct hisi_pmu * uc_pmu)242 static void hisi_uc_pmu_start_counters(struct hisi_pmu *uc_pmu)
243 {
244 	u32 val;
245 
246 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
247 	val |= HISI_UC_EVENT_GLB_EN;
248 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
249 }
250 
hisi_uc_pmu_stop_counters(struct hisi_pmu * uc_pmu)251 static void hisi_uc_pmu_stop_counters(struct hisi_pmu *uc_pmu)
252 {
253 	u32 val;
254 
255 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
256 	val &= ~HISI_UC_EVENT_GLB_EN;
257 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
258 }
259 
hisi_uc_pmu_enable_counter(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc)260 static void hisi_uc_pmu_enable_counter(struct hisi_pmu *uc_pmu,
261 					struct hw_perf_event *hwc)
262 {
263 	u32 val;
264 
265 	/* Enable counter index */
266 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
267 	val |= (1 << hwc->idx);
268 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
269 }
270 
hisi_uc_pmu_disable_counter(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc)271 static void hisi_uc_pmu_disable_counter(struct hisi_pmu *uc_pmu,
272 					struct hw_perf_event *hwc)
273 {
274 	u32 val;
275 
276 	/* Clear counter index */
277 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
278 	val &= ~(1 << hwc->idx);
279 	writel(val, uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
280 }
281 
hisi_uc_pmu_read_counter(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc)282 static u64 hisi_uc_pmu_read_counter(struct hisi_pmu *uc_pmu,
283 				    struct hw_perf_event *hwc)
284 {
285 	return readq(uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx));
286 }
287 
hisi_uc_pmu_get_glb_en_state(struct hisi_pmu * uc_pmu)288 static bool hisi_uc_pmu_get_glb_en_state(struct hisi_pmu *uc_pmu)
289 {
290 	u32 val;
291 
292 	val = readl(uc_pmu->base + HISI_UC_EVENT_CTRL_REG);
293 	return !!FIELD_GET(HISI_UC_EVENT_GLB_EN, val);
294 }
295 
hisi_uc_pmu_write_counter_normal(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc,u64 val)296 static void hisi_uc_pmu_write_counter_normal(struct hisi_pmu *uc_pmu,
297 				      struct hw_perf_event *hwc, u64 val)
298 {
299 	writeq(val, uc_pmu->base + HISI_UC_CNTR_REGn(hwc->idx));
300 }
301 
hisi_uc_pmu_write_counter_quirk_v2(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc,u64 val)302 static void hisi_uc_pmu_write_counter_quirk_v2(struct hisi_pmu *uc_pmu,
303 				      struct hw_perf_event *hwc, u64 val)
304 {
305 	hisi_uc_pmu_start_counters(uc_pmu);
306 	hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val);
307 	hisi_uc_pmu_stop_counters(uc_pmu);
308 }
309 
hisi_uc_pmu_write_counter(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc,u64 val)310 static void hisi_uc_pmu_write_counter(struct hisi_pmu *uc_pmu,
311 				      struct hw_perf_event *hwc, u64 val)
312 {
313 	bool enable = hisi_uc_pmu_get_glb_en_state(uc_pmu);
314 	bool erratum = uc_pmu->identifier == HISI_PMU_V2;
315 
316 	/*
317 	 * HiSilicon UC PMU v2 suffers the erratum 162700402 that the
318 	 * PMU counter cannot be set due to the lack of clock under power
319 	 * saving mode. This will lead to error or inaccurate counts.
320 	 * The clock can be enabled by the PMU global enabling control.
321 	 * The irq handler and pmu_start() will call the function to set
322 	 * period. If the function under irq context, the PMU has been
323 	 * enabled therefore we set counter directly. Other situations
324 	 * the PMU is disabled, we need to enable it to turn on the
325 	 * counter clock to set period, and then restore PMU enable
326 	 * status, the counter can hold its value without a clock.
327 	 */
328 	if (enable || !erratum)
329 		hisi_uc_pmu_write_counter_normal(uc_pmu, hwc, val);
330 	else
331 		hisi_uc_pmu_write_counter_quirk_v2(uc_pmu, hwc, val);
332 }
333 
hisi_uc_pmu_enable_counter_int(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc)334 static void hisi_uc_pmu_enable_counter_int(struct hisi_pmu *uc_pmu,
335 					   struct hw_perf_event *hwc)
336 {
337 	u32 val;
338 
339 	val = readl(uc_pmu->base + HISI_UC_INT_MASK_REG);
340 	val &= ~(1 << hwc->idx);
341 	writel(val, uc_pmu->base + HISI_UC_INT_MASK_REG);
342 }
343 
hisi_uc_pmu_disable_counter_int(struct hisi_pmu * uc_pmu,struct hw_perf_event * hwc)344 static void hisi_uc_pmu_disable_counter_int(struct hisi_pmu *uc_pmu,
345 					    struct hw_perf_event *hwc)
346 {
347 	u32 val;
348 
349 	val = readl(uc_pmu->base + HISI_UC_INT_MASK_REG);
350 	val |= (1 << hwc->idx);
351 	writel(val, uc_pmu->base + HISI_UC_INT_MASK_REG);
352 }
353 
hisi_uc_pmu_get_int_status(struct hisi_pmu * uc_pmu)354 static u32 hisi_uc_pmu_get_int_status(struct hisi_pmu *uc_pmu)
355 {
356 	return readl(uc_pmu->base + HISI_UC_INT_STS_REG);
357 }
358 
hisi_uc_pmu_clear_int_status(struct hisi_pmu * uc_pmu,int idx)359 static void hisi_uc_pmu_clear_int_status(struct hisi_pmu *uc_pmu, int idx)
360 {
361 	writel(1 << idx, uc_pmu->base + HISI_UC_INT_CLEAR_REG);
362 }
363 
hisi_uc_pmu_init_data(struct platform_device * pdev,struct hisi_pmu * uc_pmu)364 static int hisi_uc_pmu_init_data(struct platform_device *pdev,
365 				 struct hisi_pmu *uc_pmu)
366 {
367 	hisi_uncore_pmu_init_topology(uc_pmu, &pdev->dev);
368 
369 	/*
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.
373 	 */
374 	if (uc_pmu->topo.sccl_id < 0) {
375 		dev_err(&pdev->dev, "Can not read uc sccl-id!\n");
376 		return -EINVAL;
377 	}
378 
379 	if (uc_pmu->topo.ccl_id < 0) {
380 		dev_err(&pdev->dev, "Can not read uc ccl-id!\n");
381 		return -EINVAL;
382 	}
383 
384 	if (uc_pmu->topo.sub_id < 0) {
385 		dev_err(&pdev->dev, "Can not read sub-id!\n");
386 		return -EINVAL;
387 	}
388 
389 	uc_pmu->base = devm_platform_ioremap_resource(pdev, 0);
390 	if (IS_ERR(uc_pmu->base)) {
391 		dev_err(&pdev->dev, "ioremap failed for uc_pmu resource\n");
392 		return PTR_ERR(uc_pmu->base);
393 	}
394 
395 	uc_pmu->identifier = readl(uc_pmu->base + HISI_UC_VERSION_REG);
396 
397 	return 0;
398 }
399 
400 static struct attribute *hisi_uc_pmu_format_attr[] = {
401 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
402 	HISI_PMU_FORMAT_ATTR(rd_req_en, "config1:0-0"),
403 	HISI_PMU_FORMAT_ATTR(uring_channel, "config1:4-5"),
404 	HISI_PMU_FORMAT_ATTR(srcid, "config1:6-19"),
405 	HISI_PMU_FORMAT_ATTR(srcid_en, "config1:20-20"),
406 	NULL
407 };
408 
409 static const struct attribute_group hisi_uc_pmu_format_group = {
410 	.name = "format",
411 	.attrs = hisi_uc_pmu_format_attr,
412 };
413 
414 static struct attribute *hisi_uc_pmu_events_attr[] = {
415 	HISI_PMU_EVENT_ATTR(sq_time,		0x00),
416 	HISI_PMU_EVENT_ATTR(pq_time,		0x01),
417 	HISI_PMU_EVENT_ATTR(hbm_time,		0x02),
418 	HISI_PMU_EVENT_ATTR(iq_comp_time_cring,	0x03),
419 	HISI_PMU_EVENT_ATTR(iq_comp_time_uring,	0x05),
420 	HISI_PMU_EVENT_ATTR(cpu_rd,		0x10),
421 	HISI_PMU_EVENT_ATTR(cpu_rd64,		0x17),
422 	HISI_PMU_EVENT_ATTR(cpu_rs64,		0x19),
423 	HISI_PMU_EVENT_ATTR(cpu_mru,		0x1c),
424 	HISI_PMU_EVENT_ATTR(cycles,		0x95),
425 	HISI_PMU_EVENT_ATTR(spipe_hit,		0xb3),
426 	HISI_PMU_EVENT_ATTR(hpipe_hit,		0xdb),
427 	HISI_PMU_EVENT_ATTR(cring_rxdat_cnt,	0xfa),
428 	HISI_PMU_EVENT_ATTR(cring_txdat_cnt,	0xfb),
429 	HISI_PMU_EVENT_ATTR(uring_rxdat_cnt,	0xfc),
430 	HISI_PMU_EVENT_ATTR(uring_txdat_cnt,	0xfd),
431 	NULL
432 };
433 
434 static const struct attribute_group hisi_uc_pmu_events_group = {
435 	.name = "events",
436 	.attrs = hisi_uc_pmu_events_attr,
437 };
438 
439 static const struct attribute_group *hisi_uc_pmu_attr_groups[] = {
440 	&hisi_uc_pmu_format_group,
441 	&hisi_uc_pmu_events_group,
442 	&hisi_pmu_cpumask_attr_group,
443 	&hisi_pmu_identifier_group,
444 	NULL
445 };
446 
447 static const struct hisi_uncore_ops hisi_uncore_uc_pmu_ops = {
448 	.check_filter		= hisi_uc_pmu_check_filter,
449 	.write_evtype		= hisi_uc_pmu_write_evtype,
450 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
451 	.start_counters		= hisi_uc_pmu_start_counters,
452 	.stop_counters		= hisi_uc_pmu_stop_counters,
453 	.enable_counter		= hisi_uc_pmu_enable_counter,
454 	.disable_counter	= hisi_uc_pmu_disable_counter,
455 	.enable_counter_int	= hisi_uc_pmu_enable_counter_int,
456 	.disable_counter_int	= hisi_uc_pmu_disable_counter_int,
457 	.write_counter		= hisi_uc_pmu_write_counter,
458 	.read_counter		= hisi_uc_pmu_read_counter,
459 	.get_int_status		= hisi_uc_pmu_get_int_status,
460 	.clear_int_status	= hisi_uc_pmu_clear_int_status,
461 	.enable_filter		= hisi_uc_pmu_enable_filter,
462 	.disable_filter		= hisi_uc_pmu_disable_filter,
463 };
464 
hisi_uc_pmu_dev_probe(struct platform_device * pdev,struct hisi_pmu * uc_pmu)465 static int hisi_uc_pmu_dev_probe(struct platform_device *pdev,
466 				 struct hisi_pmu *uc_pmu)
467 {
468 	int ret;
469 
470 	ret = hisi_uc_pmu_init_data(pdev, uc_pmu);
471 	if (ret)
472 		return ret;
473 
474 	ret = hisi_uncore_pmu_init_irq(uc_pmu, pdev);
475 	if (ret)
476 		return ret;
477 
478 	uc_pmu->pmu_events.attr_groups = hisi_uc_pmu_attr_groups;
479 	uc_pmu->check_event = HISI_UC_EVTYPE_MASK;
480 	uc_pmu->ops = &hisi_uncore_uc_pmu_ops;
481 	uc_pmu->counter_bits = HISI_UC_CNTR_REG_BITS;
482 	uc_pmu->num_counters = HISI_UC_NR_COUNTERS;
483 	uc_pmu->dev = &pdev->dev;
484 	uc_pmu->on_cpu = -1;
485 
486 	return 0;
487 }
488 
hisi_uc_pmu_remove_cpuhp_instance(void * hotplug_node)489 static void hisi_uc_pmu_remove_cpuhp_instance(void *hotplug_node)
490 {
491 	cpuhp_state_remove_instance_nocalls(hisi_uc_pmu_online, hotplug_node);
492 }
493 
hisi_uc_pmu_unregister_pmu(void * pmu)494 static void hisi_uc_pmu_unregister_pmu(void *pmu)
495 {
496 	perf_pmu_unregister(pmu);
497 }
498 
hisi_uc_pmu_probe(struct platform_device * pdev)499 static int hisi_uc_pmu_probe(struct platform_device *pdev)
500 {
501 	struct hisi_pmu *uc_pmu;
502 	char *name;
503 	int ret;
504 
505 	uc_pmu = devm_kzalloc(&pdev->dev, sizeof(*uc_pmu), GFP_KERNEL);
506 	if (!uc_pmu)
507 		return -ENOMEM;
508 
509 	platform_set_drvdata(pdev, uc_pmu);
510 
511 	ret = hisi_uc_pmu_dev_probe(pdev, uc_pmu);
512 	if (ret)
513 		return ret;
514 
515 	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%d_uc%d_%d",
516 			      uc_pmu->topo.sccl_id, uc_pmu->topo.ccl_id,
517 			      uc_pmu->topo.sub_id);
518 	if (!name)
519 		return -ENOMEM;
520 
521 	ret = cpuhp_state_add_instance(hisi_uc_pmu_online, &uc_pmu->node);
522 	if (ret)
523 		return dev_err_probe(&pdev->dev, ret, "Error registering hotplug\n");
524 
525 	ret = devm_add_action_or_reset(&pdev->dev,
526 				       hisi_uc_pmu_remove_cpuhp_instance,
527 				       &uc_pmu->node);
528 	if (ret)
529 		return ret;
530 
531 	hisi_pmu_init(uc_pmu, THIS_MODULE);
532 
533 	ret = perf_pmu_register(&uc_pmu->pmu, name, -1);
534 	if (ret)
535 		return ret;
536 
537 	return devm_add_action_or_reset(&pdev->dev,
538 					hisi_uc_pmu_unregister_pmu,
539 					&uc_pmu->pmu);
540 }
541 
542 static const struct acpi_device_id hisi_uc_pmu_acpi_match[] = {
543 	{ "HISI0291", },
544 	{}
545 };
546 MODULE_DEVICE_TABLE(acpi, hisi_uc_pmu_acpi_match);
547 
548 static struct platform_driver hisi_uc_pmu_driver = {
549 	.driver = {
550 		.name = "hisi_uc_pmu",
551 		.acpi_match_table = hisi_uc_pmu_acpi_match,
552 		/*
553 		 * We have not worked out a safe bind/unbind process,
554 		 * Forcefully unbinding during sampling will lead to a
555 		 * kernel panic, so this is not supported yet.
556 		 */
557 		.suppress_bind_attrs = true,
558 	},
559 	.probe = hisi_uc_pmu_probe,
560 };
561 
hisi_uc_pmu_module_init(void)562 static int __init hisi_uc_pmu_module_init(void)
563 {
564 	int ret;
565 
566 	ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
567 				      "perf/hisi/uc:online",
568 				      hisi_uncore_pmu_online_cpu,
569 				      hisi_uncore_pmu_offline_cpu);
570 	if (ret < 0) {
571 		pr_err("UC PMU: Error setup hotplug, ret = %d\n", ret);
572 		return ret;
573 	}
574 	hisi_uc_pmu_online = ret;
575 
576 	ret = platform_driver_register(&hisi_uc_pmu_driver);
577 	if (ret)
578 		cpuhp_remove_multi_state(hisi_uc_pmu_online);
579 
580 	return ret;
581 }
582 module_init(hisi_uc_pmu_module_init);
583 
hisi_uc_pmu_module_exit(void)584 static void __exit hisi_uc_pmu_module_exit(void)
585 {
586 	platform_driver_unregister(&hisi_uc_pmu_driver);
587 	cpuhp_remove_multi_state(hisi_uc_pmu_online);
588 }
589 module_exit(hisi_uc_pmu_module_exit);
590 
591 MODULE_IMPORT_NS("HISI_PMU");
592 MODULE_DESCRIPTION("HiSilicon SoC UC uncore PMU driver");
593 MODULE_LICENSE("GPL");
594 MODULE_AUTHOR("Junhao He <hejunhao3@huawei.com>");
595