1 // SPDX-License-Identifier: GPL-2.0
2 /* Marvell CN10K LLC-TAD perf driver
4 * Copyright (C) 2021 Marvell
7 #define pr_fmt(fmt) "tad_pmu: " fmt
9 #include <linux/module.h>
11 #include <linux/of_address.h>
12 #include <linux/of_device.h>
13 #include <linux/cpuhotplug.h>
14 #include <linux/perf_event.h>
15 #include <linux/platform_device.h>
16 #include <linux/acpi.h>
18 #define TAD_PFC_OFFSET 0x800
19 #define TAD_PFC(counter) (TAD_PFC_OFFSET | (counter << 3))
20 #define TAD_PRF_OFFSET 0x900
21 #define TAD_PRF(counter) (TAD_PRF_OFFSET | (counter << 3))
22 #define TAD_PRF_CNTSEL_MASK 0xFF
23 #define TAD_MAX_COUNTERS 8
25 #define to_tad_pmu(p) (container_of(p, struct tad_pmu, pmu))
33 struct tad_region *regions;
36 struct hlist_node node;
37 struct perf_event *events[TAD_MAX_COUNTERS];
38 DECLARE_BITMAP(counters_map, TAD_MAX_COUNTERS);
41 static int tad_pmu_cpuhp_state;
43 static void tad_pmu_event_counter_read(struct perf_event *event)
45 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
46 struct hw_perf_event *hwc = &event->hw;
47 u32 counter_idx = hwc->idx;
52 prev = local64_read(&hwc->prev_count);
53 for (i = 0, new = 0; i < tad_pmu->region_cnt; i++)
54 new += readq(tad_pmu->regions[i].base +
55 TAD_PFC(counter_idx));
56 } while (local64_cmpxchg(&hwc->prev_count, prev, new) != prev);
58 local64_add(new - prev, &event->count);
61 static void tad_pmu_event_counter_stop(struct perf_event *event, int flags)
63 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
64 struct hw_perf_event *hwc = &event->hw;
65 u32 counter_idx = hwc->idx;
68 /* TAD()_PFC() stop counting on the write
69 * which sets TAD()_PRF()[CNTSEL] == 0
71 for (i = 0; i < tad_pmu->region_cnt; i++) {
72 writeq_relaxed(0, tad_pmu->regions[i].base +
73 TAD_PRF(counter_idx));
76 tad_pmu_event_counter_read(event);
77 hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
80 static void tad_pmu_event_counter_start(struct perf_event *event, int flags)
82 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
83 struct hw_perf_event *hwc = &event->hw;
84 u32 event_idx = event->attr.config;
85 u32 counter_idx = hwc->idx;
91 /* Typically TAD_PFC() are zeroed to start counting */
92 for (i = 0; i < tad_pmu->region_cnt; i++)
93 writeq_relaxed(0, tad_pmu->regions[i].base +
94 TAD_PFC(counter_idx));
96 /* TAD()_PFC() start counting on the write
97 * which sets TAD()_PRF()[CNTSEL] != 0
99 for (i = 0; i < tad_pmu->region_cnt; i++) {
100 reg_val = event_idx & 0xFF;
101 writeq_relaxed(reg_val, tad_pmu->regions[i].base +
102 TAD_PRF(counter_idx));
106 static void tad_pmu_event_counter_del(struct perf_event *event, int flags)
108 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
109 struct hw_perf_event *hwc = &event->hw;
112 tad_pmu_event_counter_stop(event, flags | PERF_EF_UPDATE);
113 tad_pmu->events[idx] = NULL;
114 clear_bit(idx, tad_pmu->counters_map);
117 static int tad_pmu_event_counter_add(struct perf_event *event, int flags)
119 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
120 struct hw_perf_event *hwc = &event->hw;
123 /* Get a free counter for this event */
124 idx = find_first_zero_bit(tad_pmu->counters_map, TAD_MAX_COUNTERS);
125 if (idx == TAD_MAX_COUNTERS)
128 set_bit(idx, tad_pmu->counters_map);
131 hwc->state = PERF_HES_STOPPED;
132 tad_pmu->events[idx] = event;
134 if (flags & PERF_EF_START)
135 tad_pmu_event_counter_start(event, flags);
140 static int tad_pmu_event_init(struct perf_event *event)
142 struct tad_pmu *tad_pmu = to_tad_pmu(event->pmu);
144 if (event->attr.type != event->pmu->type)
147 if (!event->attr.disabled)
150 if (event->state != PERF_EVENT_STATE_OFF)
153 event->cpu = tad_pmu->cpu;
155 event->hw.config_base = event->attr.config;
160 static ssize_t tad_pmu_event_show(struct device *dev,
161 struct device_attribute *attr, char *page)
163 struct perf_pmu_events_attr *pmu_attr;
165 pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
166 return sysfs_emit(page, "event=0x%02llx\n", pmu_attr->id);
169 #define TAD_PMU_EVENT_ATTR(name, config) \
170 PMU_EVENT_ATTR_ID(name, tad_pmu_event_show, config)
172 static struct attribute *tad_pmu_event_attrs[] = {
173 TAD_PMU_EVENT_ATTR(tad_none, 0x0),
174 TAD_PMU_EVENT_ATTR(tad_req_msh_in_any, 0x1),
175 TAD_PMU_EVENT_ATTR(tad_req_msh_in_mn, 0x2),
176 TAD_PMU_EVENT_ATTR(tad_req_msh_in_exlmn, 0x3),
177 TAD_PMU_EVENT_ATTR(tad_rsp_msh_in_any, 0x4),
178 TAD_PMU_EVENT_ATTR(tad_rsp_msh_in_mn, 0x5),
179 TAD_PMU_EVENT_ATTR(tad_rsp_msh_in_exlmn, 0x6),
180 TAD_PMU_EVENT_ATTR(tad_rsp_msh_in_dss, 0x7),
181 TAD_PMU_EVENT_ATTR(tad_rsp_msh_in_retry_dss, 0x8),
182 TAD_PMU_EVENT_ATTR(tad_dat_msh_in_any, 0x9),
183 TAD_PMU_EVENT_ATTR(tad_dat_msh_in_dss, 0xa),
184 TAD_PMU_EVENT_ATTR(tad_req_msh_out_any, 0xb),
185 TAD_PMU_EVENT_ATTR(tad_req_msh_out_dss_rd, 0xc),
186 TAD_PMU_EVENT_ATTR(tad_req_msh_out_dss_wr, 0xd),
187 TAD_PMU_EVENT_ATTR(tad_req_msh_out_evict, 0xe),
188 TAD_PMU_EVENT_ATTR(tad_rsp_msh_out_any, 0xf),
189 TAD_PMU_EVENT_ATTR(tad_rsp_msh_out_retry_exlmn, 0x10),
190 TAD_PMU_EVENT_ATTR(tad_rsp_msh_out_retry_mn, 0x11),
191 TAD_PMU_EVENT_ATTR(tad_rsp_msh_out_exlmn, 0x12),
192 TAD_PMU_EVENT_ATTR(tad_rsp_msh_out_mn, 0x13),
193 TAD_PMU_EVENT_ATTR(tad_snp_msh_out_any, 0x14),
194 TAD_PMU_EVENT_ATTR(tad_snp_msh_out_mn, 0x15),
195 TAD_PMU_EVENT_ATTR(tad_snp_msh_out_exlmn, 0x16),
196 TAD_PMU_EVENT_ATTR(tad_dat_msh_out_any, 0x17),
197 TAD_PMU_EVENT_ATTR(tad_dat_msh_out_fill, 0x18),
198 TAD_PMU_EVENT_ATTR(tad_dat_msh_out_dss, 0x19),
199 TAD_PMU_EVENT_ATTR(tad_alloc_dtg, 0x1a),
200 TAD_PMU_EVENT_ATTR(tad_alloc_ltg, 0x1b),
201 TAD_PMU_EVENT_ATTR(tad_alloc_any, 0x1c),
202 TAD_PMU_EVENT_ATTR(tad_hit_dtg, 0x1d),
203 TAD_PMU_EVENT_ATTR(tad_hit_ltg, 0x1e),
204 TAD_PMU_EVENT_ATTR(tad_hit_any, 0x1f),
205 TAD_PMU_EVENT_ATTR(tad_tag_rd, 0x20),
206 TAD_PMU_EVENT_ATTR(tad_dat_rd, 0x21),
207 TAD_PMU_EVENT_ATTR(tad_dat_rd_byp, 0x22),
208 TAD_PMU_EVENT_ATTR(tad_ifb_occ, 0x23),
209 TAD_PMU_EVENT_ATTR(tad_req_occ, 0x24),
213 static const struct attribute_group tad_pmu_events_attr_group = {
215 .attrs = tad_pmu_event_attrs,
218 PMU_FORMAT_ATTR(event, "config:0-7");
220 static struct attribute *tad_pmu_format_attrs[] = {
221 &format_attr_event.attr,
225 static struct attribute_group tad_pmu_format_attr_group = {
227 .attrs = tad_pmu_format_attrs,
230 static ssize_t tad_pmu_cpumask_show(struct device *dev,
231 struct device_attribute *attr, char *buf)
233 struct tad_pmu *tad_pmu = to_tad_pmu(dev_get_drvdata(dev));
235 return cpumap_print_to_pagebuf(true, buf, cpumask_of(tad_pmu->cpu));
238 static DEVICE_ATTR(cpumask, 0444, tad_pmu_cpumask_show, NULL);
240 static struct attribute *tad_pmu_cpumask_attrs[] = {
241 &dev_attr_cpumask.attr,
245 static struct attribute_group tad_pmu_cpumask_attr_group = {
246 .attrs = tad_pmu_cpumask_attrs,
249 static const struct attribute_group *tad_pmu_attr_groups[] = {
250 &tad_pmu_events_attr_group,
251 &tad_pmu_format_attr_group,
252 &tad_pmu_cpumask_attr_group,
256 static int tad_pmu_probe(struct platform_device *pdev)
258 struct device *dev = &pdev->dev;
259 struct tad_region *regions;
260 struct tad_pmu *tad_pmu;
261 struct resource *res;
262 u32 tad_pmu_page_size;
268 tad_pmu = devm_kzalloc(&pdev->dev, sizeof(*tad_pmu), GFP_KERNEL);
272 platform_set_drvdata(pdev, tad_pmu);
274 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
276 dev_err(&pdev->dev, "Mem resource not found\n");
280 ret = device_property_read_u32(dev, "marvell,tad-page-size",
283 dev_err(&pdev->dev, "Can't find tad-page-size property\n");
287 ret = device_property_read_u32(dev, "marvell,tad-pmu-page-size",
290 dev_err(&pdev->dev, "Can't find tad-pmu-page-size property\n");
294 ret = device_property_read_u32(dev, "marvell,tad-cnt", &tad_cnt);
296 dev_err(&pdev->dev, "Can't find tad-cnt property\n");
300 regions = devm_kcalloc(&pdev->dev, tad_cnt,
301 sizeof(*regions), GFP_KERNEL);
305 /* ioremap the distributed TAD pmu regions */
306 for (i = 0; i < tad_cnt && res->start < res->end; i++) {
307 regions[i].base = devm_ioremap(&pdev->dev,
310 if (!regions[i].base) {
311 dev_err(&pdev->dev, "TAD%d ioremap fail\n", i);
314 res->start += tad_page_size;
317 tad_pmu->regions = regions;
318 tad_pmu->region_cnt = tad_cnt;
320 tad_pmu->pmu = (struct pmu) {
322 .module = THIS_MODULE,
323 .attr_groups = tad_pmu_attr_groups,
324 .capabilities = PERF_PMU_CAP_NO_EXCLUDE |
325 PERF_PMU_CAP_NO_INTERRUPT,
326 .task_ctx_nr = perf_invalid_context,
328 .event_init = tad_pmu_event_init,
329 .add = tad_pmu_event_counter_add,
330 .del = tad_pmu_event_counter_del,
331 .start = tad_pmu_event_counter_start,
332 .stop = tad_pmu_event_counter_stop,
333 .read = tad_pmu_event_counter_read,
336 tad_pmu->cpu = raw_smp_processor_id();
338 /* Register pmu instance for cpu hotplug */
339 ret = cpuhp_state_add_instance_nocalls(tad_pmu_cpuhp_state,
342 dev_err(&pdev->dev, "Error %d registering hotplug\n", ret);
347 ret = perf_pmu_register(&tad_pmu->pmu, name, -1);
349 cpuhp_state_remove_instance_nocalls(tad_pmu_cpuhp_state,
355 static int tad_pmu_remove(struct platform_device *pdev)
357 struct tad_pmu *pmu = platform_get_drvdata(pdev);
359 cpuhp_state_remove_instance_nocalls(tad_pmu_cpuhp_state,
361 perf_pmu_unregister(&pmu->pmu);
367 static const struct of_device_id tad_pmu_of_match[] = {
368 { .compatible = "marvell,cn10k-tad-pmu", },
374 static const struct acpi_device_id tad_pmu_acpi_match[] = {
378 MODULE_DEVICE_TABLE(acpi, tad_pmu_acpi_match);
381 static struct platform_driver tad_pmu_driver = {
383 .name = "cn10k_tad_pmu",
384 .of_match_table = of_match_ptr(tad_pmu_of_match),
385 .acpi_match_table = ACPI_PTR(tad_pmu_acpi_match),
386 .suppress_bind_attrs = true,
388 .probe = tad_pmu_probe,
389 .remove = tad_pmu_remove,
392 static int tad_pmu_offline_cpu(unsigned int cpu, struct hlist_node *node)
394 struct tad_pmu *pmu = hlist_entry_safe(node, struct tad_pmu, node);
400 target = cpumask_any_but(cpu_online_mask, cpu);
401 if (target >= nr_cpu_ids)
404 perf_pmu_migrate_context(&pmu->pmu, cpu, target);
410 static int __init tad_pmu_init(void)
414 ret = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN,
415 "perf/cn10k/tadpmu:online",
417 tad_pmu_offline_cpu);
420 tad_pmu_cpuhp_state = ret;
421 ret = platform_driver_register(&tad_pmu_driver);
423 cpuhp_remove_multi_state(tad_pmu_cpuhp_state);
428 static void __exit tad_pmu_exit(void)
430 platform_driver_unregister(&tad_pmu_driver);
431 cpuhp_remove_multi_state(tad_pmu_cpuhp_state);
434 module_init(tad_pmu_init);
435 module_exit(tad_pmu_exit);
437 MODULE_DESCRIPTION("Marvell CN10K LLC-TAD Perf driver");
439 MODULE_LICENSE("GPL v2");