1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * HiSilicon SoC L3C uncore Hardware event counters support
4  *
5  * Copyright (C) 2017 Hisilicon Limited
6  * Author: Anurup M <anurup.m@huawei.com>
7  *         Shaokun Zhang <zhangshaokun@hisilicon.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/platform_device.h>
18 #include <linux/smp.h>
19 
20 #include "hisi_uncore_pmu.h"
21 
22 /* L3C register definition */
23 #define L3C_PERF_CTRL		0x0408
24 #define L3C_INT_MASK		0x0800
25 #define L3C_INT_STATUS		0x0808
26 #define L3C_INT_CLEAR		0x080c
27 #define L3C_EVENT_CTRL	        0x1c00
28 #define L3C_EVENT_TYPE0		0x1d00
29 /*
30  * Each counter is 48-bits and [48:63] are reserved
31  * which are Read-As-Zero and Writes-Ignored.
32  */
33 #define L3C_CNTR0_LOWER		0x1e00
34 
35 /* L3C has 8-counters */
36 #define L3C_NR_COUNTERS		0x8
37 
38 #define L3C_PERF_CTRL_EN	0x20000
39 #define L3C_EVTYPE_NONE		0xff
40 
41 /*
42  * Select the counter register offset using the counter index
43  */
44 static u32 hisi_l3c_pmu_get_counter_offset(int cntr_idx)
45 {
46 	return (L3C_CNTR0_LOWER + (cntr_idx * 8));
47 }
48 
49 static u64 hisi_l3c_pmu_read_counter(struct hisi_pmu *l3c_pmu,
50 				     struct hw_perf_event *hwc)
51 {
52 	u32 idx = hwc->idx;
53 
54 	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
55 		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
56 		return 0;
57 	}
58 
59 	/* Read 64-bits and the upper 16 bits are RAZ */
60 	return readq(l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
61 }
62 
63 static void hisi_l3c_pmu_write_counter(struct hisi_pmu *l3c_pmu,
64 				       struct hw_perf_event *hwc, u64 val)
65 {
66 	u32 idx = hwc->idx;
67 
68 	if (!hisi_uncore_pmu_counter_valid(l3c_pmu, idx)) {
69 		dev_err(l3c_pmu->dev, "Unsupported event index:%d!\n", idx);
70 		return;
71 	}
72 
73 	/* Write 64-bits and the upper 16 bits are WI */
74 	writeq(val, l3c_pmu->base + hisi_l3c_pmu_get_counter_offset(idx));
75 }
76 
77 static void hisi_l3c_pmu_write_evtype(struct hisi_pmu *l3c_pmu, int idx,
78 				      u32 type)
79 {
80 	u32 reg, reg_idx, shift, val;
81 
82 	/*
83 	 * Select the appropriate event select register(L3C_EVENT_TYPE0/1).
84 	 * There are 2 event select registers for the 8 hardware counters.
85 	 * Event code is 8-bits and for the former 4 hardware counters,
86 	 * L3C_EVENT_TYPE0 is chosen. For the latter 4 hardware counters,
87 	 * L3C_EVENT_TYPE1 is chosen.
88 	 */
89 	reg = L3C_EVENT_TYPE0 + (idx / 4) * 4;
90 	reg_idx = idx % 4;
91 	shift = 8 * reg_idx;
92 
93 	/* Write event code to L3C_EVENT_TYPEx Register */
94 	val = readl(l3c_pmu->base + reg);
95 	val &= ~(L3C_EVTYPE_NONE << shift);
96 	val |= (type << shift);
97 	writel(val, l3c_pmu->base + reg);
98 }
99 
100 static void hisi_l3c_pmu_start_counters(struct hisi_pmu *l3c_pmu)
101 {
102 	u32 val;
103 
104 	/*
105 	 * Set perf_enable bit in L3C_PERF_CTRL register to start counting
106 	 * for all enabled counters.
107 	 */
108 	val = readl(l3c_pmu->base + L3C_PERF_CTRL);
109 	val |= L3C_PERF_CTRL_EN;
110 	writel(val, l3c_pmu->base + L3C_PERF_CTRL);
111 }
112 
113 static void hisi_l3c_pmu_stop_counters(struct hisi_pmu *l3c_pmu)
114 {
115 	u32 val;
116 
117 	/*
118 	 * Clear perf_enable bit in L3C_PERF_CTRL register to stop counting
119 	 * for all enabled counters.
120 	 */
121 	val = readl(l3c_pmu->base + L3C_PERF_CTRL);
122 	val &= ~(L3C_PERF_CTRL_EN);
123 	writel(val, l3c_pmu->base + L3C_PERF_CTRL);
124 }
125 
126 static void hisi_l3c_pmu_enable_counter(struct hisi_pmu *l3c_pmu,
127 					struct hw_perf_event *hwc)
128 {
129 	u32 val;
130 
131 	/* Enable counter index in L3C_EVENT_CTRL register */
132 	val = readl(l3c_pmu->base + L3C_EVENT_CTRL);
133 	val |= (1 << hwc->idx);
134 	writel(val, l3c_pmu->base + L3C_EVENT_CTRL);
135 }
136 
137 static void hisi_l3c_pmu_disable_counter(struct hisi_pmu *l3c_pmu,
138 					 struct hw_perf_event *hwc)
139 {
140 	u32 val;
141 
142 	/* Clear counter index in L3C_EVENT_CTRL register */
143 	val = readl(l3c_pmu->base + L3C_EVENT_CTRL);
144 	val &= ~(1 << hwc->idx);
145 	writel(val, l3c_pmu->base + L3C_EVENT_CTRL);
146 }
147 
148 static void hisi_l3c_pmu_enable_counter_int(struct hisi_pmu *l3c_pmu,
149 					    struct hw_perf_event *hwc)
150 {
151 	u32 val;
152 
153 	val = readl(l3c_pmu->base + L3C_INT_MASK);
154 	/* Write 0 to enable interrupt */
155 	val &= ~(1 << hwc->idx);
156 	writel(val, l3c_pmu->base + L3C_INT_MASK);
157 }
158 
159 static void hisi_l3c_pmu_disable_counter_int(struct hisi_pmu *l3c_pmu,
160 					     struct hw_perf_event *hwc)
161 {
162 	u32 val;
163 
164 	val = readl(l3c_pmu->base + L3C_INT_MASK);
165 	/* Write 1 to mask interrupt */
166 	val |= (1 << hwc->idx);
167 	writel(val, l3c_pmu->base + L3C_INT_MASK);
168 }
169 
170 static irqreturn_t hisi_l3c_pmu_isr(int irq, void *dev_id)
171 {
172 	struct hisi_pmu *l3c_pmu = dev_id;
173 	struct perf_event *event;
174 	unsigned long overflown;
175 	int idx;
176 
177 	/* Read L3C_INT_STATUS register */
178 	overflown = readl(l3c_pmu->base + L3C_INT_STATUS);
179 	if (!overflown)
180 		return IRQ_NONE;
181 
182 	/*
183 	 * Find the counter index which overflowed if the bit was set
184 	 * and handle it.
185 	 */
186 	for_each_set_bit(idx, &overflown, L3C_NR_COUNTERS) {
187 		/* Write 1 to clear the IRQ status flag */
188 		writel((1 << idx), l3c_pmu->base + L3C_INT_CLEAR);
189 
190 		/* Get the corresponding event struct */
191 		event = l3c_pmu->pmu_events.hw_events[idx];
192 		if (!event)
193 			continue;
194 
195 		hisi_uncore_pmu_event_update(event);
196 		hisi_uncore_pmu_set_event_period(event);
197 	}
198 
199 	return IRQ_HANDLED;
200 }
201 
202 static int hisi_l3c_pmu_init_irq(struct hisi_pmu *l3c_pmu,
203 				 struct platform_device *pdev)
204 {
205 	int irq, ret;
206 
207 	/* Read and init IRQ */
208 	irq = platform_get_irq(pdev, 0);
209 	if (irq < 0) {
210 		dev_err(&pdev->dev, "L3C PMU get irq fail; irq:%d\n", irq);
211 		return irq;
212 	}
213 
214 	ret = devm_request_irq(&pdev->dev, irq, hisi_l3c_pmu_isr,
215 			       IRQF_NOBALANCING | IRQF_NO_THREAD,
216 			       dev_name(&pdev->dev), l3c_pmu);
217 	if (ret < 0) {
218 		dev_err(&pdev->dev,
219 			"Fail to request IRQ:%d ret:%d\n", irq, ret);
220 		return ret;
221 	}
222 
223 	l3c_pmu->irq = irq;
224 
225 	return 0;
226 }
227 
228 static const struct acpi_device_id hisi_l3c_pmu_acpi_match[] = {
229 	{ "HISI0213", },
230 	{},
231 };
232 MODULE_DEVICE_TABLE(acpi, hisi_l3c_pmu_acpi_match);
233 
234 static int hisi_l3c_pmu_init_data(struct platform_device *pdev,
235 				  struct hisi_pmu *l3c_pmu)
236 {
237 	unsigned long long id;
238 	struct resource *res;
239 	acpi_status status;
240 
241 	status = acpi_evaluate_integer(ACPI_HANDLE(&pdev->dev),
242 				       "_UID", NULL, &id);
243 	if (ACPI_FAILURE(status))
244 		return -EINVAL;
245 
246 	l3c_pmu->index_id = id;
247 
248 	/*
249 	 * Use the SCCL_ID and CCL_ID to identify the L3C PMU, while
250 	 * SCCL_ID is in MPIDR[aff2] and CCL_ID is in MPIDR[aff1].
251 	 */
252 	if (device_property_read_u32(&pdev->dev, "hisilicon,scl-id",
253 				     &l3c_pmu->sccl_id)) {
254 		dev_err(&pdev->dev, "Can not read l3c sccl-id!\n");
255 		return -EINVAL;
256 	}
257 
258 	if (device_property_read_u32(&pdev->dev, "hisilicon,ccl-id",
259 				     &l3c_pmu->ccl_id)) {
260 		dev_err(&pdev->dev, "Can not read l3c ccl-id!\n");
261 		return -EINVAL;
262 	}
263 
264 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
265 	l3c_pmu->base = devm_ioremap_resource(&pdev->dev, res);
266 	if (IS_ERR(l3c_pmu->base)) {
267 		dev_err(&pdev->dev, "ioremap failed for l3c_pmu resource\n");
268 		return PTR_ERR(l3c_pmu->base);
269 	}
270 
271 	return 0;
272 }
273 
274 static struct attribute *hisi_l3c_pmu_format_attr[] = {
275 	HISI_PMU_FORMAT_ATTR(event, "config:0-7"),
276 	NULL,
277 };
278 
279 static const struct attribute_group hisi_l3c_pmu_format_group = {
280 	.name = "format",
281 	.attrs = hisi_l3c_pmu_format_attr,
282 };
283 
284 static struct attribute *hisi_l3c_pmu_events_attr[] = {
285 	HISI_PMU_EVENT_ATTR(rd_cpipe,		0x00),
286 	HISI_PMU_EVENT_ATTR(wr_cpipe,		0x01),
287 	HISI_PMU_EVENT_ATTR(rd_hit_cpipe,	0x02),
288 	HISI_PMU_EVENT_ATTR(wr_hit_cpipe,	0x03),
289 	HISI_PMU_EVENT_ATTR(victim_num,		0x04),
290 	HISI_PMU_EVENT_ATTR(rd_spipe,		0x20),
291 	HISI_PMU_EVENT_ATTR(wr_spipe,		0x21),
292 	HISI_PMU_EVENT_ATTR(rd_hit_spipe,	0x22),
293 	HISI_PMU_EVENT_ATTR(wr_hit_spipe,	0x23),
294 	HISI_PMU_EVENT_ATTR(back_invalid,	0x29),
295 	HISI_PMU_EVENT_ATTR(retry_cpu,		0x40),
296 	HISI_PMU_EVENT_ATTR(retry_ring,		0x41),
297 	HISI_PMU_EVENT_ATTR(prefetch_drop,	0x42),
298 	NULL,
299 };
300 
301 static const struct attribute_group hisi_l3c_pmu_events_group = {
302 	.name = "events",
303 	.attrs = hisi_l3c_pmu_events_attr,
304 };
305 
306 static DEVICE_ATTR(cpumask, 0444, hisi_cpumask_sysfs_show, NULL);
307 
308 static struct attribute *hisi_l3c_pmu_cpumask_attrs[] = {
309 	&dev_attr_cpumask.attr,
310 	NULL,
311 };
312 
313 static const struct attribute_group hisi_l3c_pmu_cpumask_attr_group = {
314 	.attrs = hisi_l3c_pmu_cpumask_attrs,
315 };
316 
317 static const struct attribute_group *hisi_l3c_pmu_attr_groups[] = {
318 	&hisi_l3c_pmu_format_group,
319 	&hisi_l3c_pmu_events_group,
320 	&hisi_l3c_pmu_cpumask_attr_group,
321 	NULL,
322 };
323 
324 static const struct hisi_uncore_ops hisi_uncore_l3c_ops = {
325 	.write_evtype		= hisi_l3c_pmu_write_evtype,
326 	.get_event_idx		= hisi_uncore_pmu_get_event_idx,
327 	.start_counters		= hisi_l3c_pmu_start_counters,
328 	.stop_counters		= hisi_l3c_pmu_stop_counters,
329 	.enable_counter		= hisi_l3c_pmu_enable_counter,
330 	.disable_counter	= hisi_l3c_pmu_disable_counter,
331 	.enable_counter_int	= hisi_l3c_pmu_enable_counter_int,
332 	.disable_counter_int	= hisi_l3c_pmu_disable_counter_int,
333 	.write_counter		= hisi_l3c_pmu_write_counter,
334 	.read_counter		= hisi_l3c_pmu_read_counter,
335 };
336 
337 static int hisi_l3c_pmu_dev_probe(struct platform_device *pdev,
338 				  struct hisi_pmu *l3c_pmu)
339 {
340 	int ret;
341 
342 	ret = hisi_l3c_pmu_init_data(pdev, l3c_pmu);
343 	if (ret)
344 		return ret;
345 
346 	ret = hisi_l3c_pmu_init_irq(l3c_pmu, pdev);
347 	if (ret)
348 		return ret;
349 
350 	l3c_pmu->num_counters = L3C_NR_COUNTERS;
351 	l3c_pmu->counter_bits = 48;
352 	l3c_pmu->ops = &hisi_uncore_l3c_ops;
353 	l3c_pmu->dev = &pdev->dev;
354 	l3c_pmu->on_cpu = -1;
355 	l3c_pmu->check_event = 0x59;
356 
357 	return 0;
358 }
359 
360 static int hisi_l3c_pmu_probe(struct platform_device *pdev)
361 {
362 	struct hisi_pmu *l3c_pmu;
363 	char *name;
364 	int ret;
365 
366 	l3c_pmu = devm_kzalloc(&pdev->dev, sizeof(*l3c_pmu), GFP_KERNEL);
367 	if (!l3c_pmu)
368 		return -ENOMEM;
369 
370 	platform_set_drvdata(pdev, l3c_pmu);
371 
372 	ret = hisi_l3c_pmu_dev_probe(pdev, l3c_pmu);
373 	if (ret)
374 		return ret;
375 
376 	ret = cpuhp_state_add_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
377 				       &l3c_pmu->node);
378 	if (ret) {
379 		dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
380 		return ret;
381 	}
382 
383 	name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "hisi_sccl%u_l3c%u",
384 			      l3c_pmu->sccl_id, l3c_pmu->index_id);
385 	l3c_pmu->pmu = (struct pmu) {
386 		.name		= name,
387 		.task_ctx_nr	= perf_invalid_context,
388 		.event_init	= hisi_uncore_pmu_event_init,
389 		.pmu_enable	= hisi_uncore_pmu_enable,
390 		.pmu_disable	= hisi_uncore_pmu_disable,
391 		.add		= hisi_uncore_pmu_add,
392 		.del		= hisi_uncore_pmu_del,
393 		.start		= hisi_uncore_pmu_start,
394 		.stop		= hisi_uncore_pmu_stop,
395 		.read		= hisi_uncore_pmu_read,
396 		.attr_groups	= hisi_l3c_pmu_attr_groups,
397 		.capabilities	= PERF_PMU_CAP_NO_EXCLUDE,
398 	};
399 
400 	ret = perf_pmu_register(&l3c_pmu->pmu, name, -1);
401 	if (ret) {
402 		dev_err(l3c_pmu->dev, "L3C PMU register failed!\n");
403 		cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
404 					    &l3c_pmu->node);
405 	}
406 
407 	return ret;
408 }
409 
410 static int hisi_l3c_pmu_remove(struct platform_device *pdev)
411 {
412 	struct hisi_pmu *l3c_pmu = platform_get_drvdata(pdev);
413 
414 	perf_pmu_unregister(&l3c_pmu->pmu);
415 	cpuhp_state_remove_instance(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
416 				    &l3c_pmu->node);
417 
418 	return 0;
419 }
420 
421 static struct platform_driver hisi_l3c_pmu_driver = {
422 	.driver = {
423 		.name = "hisi_l3c_pmu",
424 		.acpi_match_table = ACPI_PTR(hisi_l3c_pmu_acpi_match),
425 	},
426 	.probe = hisi_l3c_pmu_probe,
427 	.remove = hisi_l3c_pmu_remove,
428 };
429 
430 static int __init hisi_l3c_pmu_module_init(void)
431 {
432 	int ret;
433 
434 	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE,
435 				      "AP_PERF_ARM_HISI_L3_ONLINE",
436 				      hisi_uncore_pmu_online_cpu,
437 				      hisi_uncore_pmu_offline_cpu);
438 	if (ret) {
439 		pr_err("L3C PMU: Error setup hotplug, ret = %d\n", ret);
440 		return ret;
441 	}
442 
443 	ret = platform_driver_register(&hisi_l3c_pmu_driver);
444 	if (ret)
445 		cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
446 
447 	return ret;
448 }
449 module_init(hisi_l3c_pmu_module_init);
450 
451 static void __exit hisi_l3c_pmu_module_exit(void)
452 {
453 	platform_driver_unregister(&hisi_l3c_pmu_driver);
454 	cpuhp_remove_multi_state(CPUHP_AP_PERF_ARM_HISI_L3_ONLINE);
455 }
456 module_exit(hisi_l3c_pmu_module_exit);
457 
458 MODULE_DESCRIPTION("HiSilicon SoC L3C uncore PMU driver");
459 MODULE_LICENSE("GPL v2");
460 MODULE_AUTHOR("Anurup M <anurup.m@huawei.com>");
461 MODULE_AUTHOR("Shaokun Zhang <zhangshaokun@hisilicon.com>");
462