hc
2023-12-08 01573e231f18eb2d99162747186f59511f56b64d
kernel/arch/arc/kernel/perf_event.c
....@@ -1,15 +1,10 @@
1
-/*
2
- * Linux performance counter support for ARC700 series
3
- *
4
- * Copyright (C) 2013-2015 Synopsys, Inc. (www.synopsys.com)
5
- *
6
- * This code is inspired by the perf support of various other architectures.
7
- *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License version 2 as
10
- * published by the Free Software Foundation.
11
- *
12
- */
1
+// SPDX-License-Identifier: GPL-2.0+
2
+//
3
+// Linux performance counter support for ARC CPUs.
4
+// This code is inspired by the perf support of various other architectures.
5
+//
6
+// Copyright (C) 2013-2018 Synopsys, Inc. (www.synopsys.com)
7
+
138 #include <linux/errno.h>
149 #include <linux/interrupt.h>
1510 #include <linux/module.h>
....@@ -19,12 +14,31 @@
1914 #include <asm/arcregs.h>
2015 #include <asm/stacktrace.h>
2116
17
+/* HW holds 8 symbols + one for null terminator */
18
+#define ARCPMU_EVENT_NAME_LEN 9
19
+
20
+enum arc_pmu_attr_groups {
21
+ ARCPMU_ATTR_GR_EVENTS,
22
+ ARCPMU_ATTR_GR_FORMATS,
23
+ ARCPMU_NR_ATTR_GR
24
+};
25
+
26
+struct arc_pmu_raw_event_entry {
27
+ char name[ARCPMU_EVENT_NAME_LEN];
28
+};
29
+
2230 struct arc_pmu {
2331 struct pmu pmu;
2432 unsigned int irq;
2533 int n_counters;
34
+ int n_events;
2635 u64 max_period;
2736 int ev_hw_idx[PERF_COUNT_ARC_HW_MAX];
37
+
38
+ struct arc_pmu_raw_event_entry *raw_entry;
39
+ struct attribute **attrs;
40
+ struct perf_pmu_events_attr *attr;
41
+ const struct attribute_group *attr_groups[ARCPMU_NR_ATTR_GR + 1];
2842 };
2943
3044 struct arc_pmu_cpu {
....@@ -49,6 +63,7 @@
4963 {
5064 struct arc_callchain_trace *ctrl = data;
5165 struct perf_callchain_entry_ctx *entry = ctrl->perf_stuff;
66
+
5267 perf_callchain_store(entry, addr);
5368
5469 if (ctrl->depth++ < 3)
....@@ -57,8 +72,8 @@
5772 return -1;
5873 }
5974
60
-void
61
-perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
75
+void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
76
+ struct pt_regs *regs)
6277 {
6378 struct arc_callchain_trace ctrl = {
6479 .depth = 0,
....@@ -68,8 +83,8 @@
6883 arc_unwind_core(NULL, regs, callchain_trace, &ctrl);
6984 }
7085
71
-void
72
-perf_callchain_user(struct perf_callchain_entry_ctx *entry, struct pt_regs *regs)
86
+void perf_callchain_user(struct perf_callchain_entry_ctx *entry,
87
+ struct pt_regs *regs)
7388 {
7489 /*
7590 * User stack can't be unwound trivially with kernel dwarf unwinder
....@@ -82,10 +97,10 @@
8297 static DEFINE_PER_CPU(struct arc_pmu_cpu, arc_pmu_cpu);
8398
8499 /* read counter #idx; note that counter# != event# on ARC! */
85
-static uint64_t arc_pmu_read_counter(int idx)
100
+static u64 arc_pmu_read_counter(int idx)
86101 {
87
- uint32_t tmp;
88
- uint64_t result;
102
+ u32 tmp;
103
+ u64 result;
89104
90105 /*
91106 * ARC supports making 'snapshots' of the counters, so we don't
....@@ -94,7 +109,7 @@
94109 write_aux_reg(ARC_REG_PCT_INDEX, idx);
95110 tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
96111 write_aux_reg(ARC_REG_PCT_CONTROL, tmp | ARC_REG_PCT_CONTROL_SN);
97
- result = (uint64_t) (read_aux_reg(ARC_REG_PCT_SNAPH)) << 32;
112
+ result = (u64) (read_aux_reg(ARC_REG_PCT_SNAPH)) << 32;
98113 result |= read_aux_reg(ARC_REG_PCT_SNAPL);
99114
100115 return result;
....@@ -103,9 +118,9 @@
103118 static void arc_perf_event_update(struct perf_event *event,
104119 struct hw_perf_event *hwc, int idx)
105120 {
106
- uint64_t prev_raw_count = local64_read(&hwc->prev_count);
107
- uint64_t new_raw_count = arc_pmu_read_counter(idx);
108
- int64_t delta = new_raw_count - prev_raw_count;
121
+ u64 prev_raw_count = local64_read(&hwc->prev_count);
122
+ u64 new_raw_count = arc_pmu_read_counter(idx);
123
+ s64 delta = new_raw_count - prev_raw_count;
109124
110125 /*
111126 * We aren't afraid of hwc->prev_count changing beneath our feet
....@@ -155,7 +170,7 @@
155170 int ret;
156171
157172 if (!is_sampling_event(event)) {
158
- hwc->sample_period = arc_pmu->max_period;
173
+ hwc->sample_period = arc_pmu->max_period;
159174 hwc->last_period = hwc->sample_period;
160175 local64_set(&hwc->period_left, hwc->sample_period);
161176 }
....@@ -192,6 +207,18 @@
192207 pr_debug("init cache event with h/w %08x \'%s\'\n",
193208 (int)hwc->config, arc_pmu_ev_hw_map[ret]);
194209 return 0;
210
+
211
+ case PERF_TYPE_RAW:
212
+ if (event->attr.config >= arc_pmu->n_events)
213
+ return -ENOENT;
214
+
215
+ hwc->config |= event->attr.config;
216
+ pr_debug("init raw event with idx %lld \'%s\'\n",
217
+ event->attr.config,
218
+ arc_pmu->raw_entry[event->attr.config].name);
219
+
220
+ return 0;
221
+
195222 default:
196223 return -ENOENT;
197224 }
....@@ -200,7 +227,7 @@
200227 /* starts all counters */
201228 static void arc_pmu_enable(struct pmu *pmu)
202229 {
203
- uint32_t tmp;
230
+ u32 tmp;
204231 tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
205232 write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x1);
206233 }
....@@ -208,7 +235,7 @@
208235 /* stops all counters */
209236 static void arc_pmu_disable(struct pmu *pmu)
210237 {
211
- uint32_t tmp;
238
+ u32 tmp;
212239 tmp = read_aux_reg(ARC_REG_PCT_CONTROL);
213240 write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x0);
214241 }
....@@ -228,7 +255,7 @@
228255 local64_set(&hwc->period_left, left);
229256 hwc->last_period = period;
230257 overflow = 1;
231
- } else if (unlikely(left <= 0)) {
258
+ } else if (unlikely(left <= 0)) {
232259 /* left underflowed by less than period. */
233260 left += period;
234261 local64_set(&hwc->period_left, left);
....@@ -246,8 +273,8 @@
246273 write_aux_reg(ARC_REG_PCT_INDEX, idx);
247274
248275 /* Write value */
249
- write_aux_reg(ARC_REG_PCT_COUNTL, (u32)value);
250
- write_aux_reg(ARC_REG_PCT_COUNTH, (value >> 32));
276
+ write_aux_reg(ARC_REG_PCT_COUNTL, lower_32_bits(value));
277
+ write_aux_reg(ARC_REG_PCT_COUNTH, upper_32_bits(value));
251278
252279 perf_event_update_userpage(event);
253280
....@@ -277,7 +304,7 @@
277304 /* Enable interrupt for this counter */
278305 if (is_sampling_event(event))
279306 write_aux_reg(ARC_REG_PCT_INT_CTRL,
280
- read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx));
307
+ read_aux_reg(ARC_REG_PCT_INT_CTRL) | BIT(idx));
281308
282309 /* enable ARC pmu here */
283310 write_aux_reg(ARC_REG_PCT_INDEX, idx); /* counter # */
....@@ -295,9 +322,9 @@
295322 * Reset interrupt flag by writing of 1. This is required
296323 * to make sure pending interrupt was not left.
297324 */
298
- write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx);
325
+ write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx));
299326 write_aux_reg(ARC_REG_PCT_INT_CTRL,
300
- read_aux_reg(ARC_REG_PCT_INT_CTRL) & ~(1 << idx));
327
+ read_aux_reg(ARC_REG_PCT_INT_CTRL) & ~BIT(idx));
301328 }
302329
303330 if (!(event->hw.state & PERF_HES_STOPPED)) {
....@@ -349,9 +376,10 @@
349376
350377 if (is_sampling_event(event)) {
351378 /* Mimic full counter overflow as other arches do */
352
- write_aux_reg(ARC_REG_PCT_INT_CNTL, (u32)arc_pmu->max_period);
379
+ write_aux_reg(ARC_REG_PCT_INT_CNTL,
380
+ lower_32_bits(arc_pmu->max_period));
353381 write_aux_reg(ARC_REG_PCT_INT_CNTH,
354
- (arc_pmu->max_period >> 32));
382
+ upper_32_bits(arc_pmu->max_period));
355383 }
356384
357385 write_aux_reg(ARC_REG_PCT_CONFIG, 0);
....@@ -392,7 +420,7 @@
392420 idx = __ffs(active_ints);
393421
394422 /* Reset interrupt flag by writing of 1 */
395
- write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx);
423
+ write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx));
396424
397425 /*
398426 * On reset of "interrupt active" bit corresponding
....@@ -400,7 +428,7 @@
400428 * Now we need to re-enable interrupt for the counter.
401429 */
402430 write_aux_reg(ARC_REG_PCT_INT_CTRL,
403
- read_aux_reg(ARC_REG_PCT_INT_CTRL) | (1 << idx));
431
+ read_aux_reg(ARC_REG_PCT_INT_CTRL) | BIT(idx));
404432
405433 event = pmu_cpu->act_counter[idx];
406434 hwc = &event->hw;
....@@ -414,7 +442,7 @@
414442 arc_pmu_stop(event, 0);
415443 }
416444
417
- active_ints &= ~(1U << idx);
445
+ active_ints &= ~BIT(idx);
418446 } while (active_ints);
419447
420448 done:
....@@ -441,19 +469,108 @@
441469 write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff);
442470 }
443471
472
+/* Event field occupies the bottom 15 bits of our config field */
473
+PMU_FORMAT_ATTR(event, "config:0-14");
474
+static struct attribute *arc_pmu_format_attrs[] = {
475
+ &format_attr_event.attr,
476
+ NULL,
477
+};
478
+
479
+static struct attribute_group arc_pmu_format_attr_gr = {
480
+ .name = "format",
481
+ .attrs = arc_pmu_format_attrs,
482
+};
483
+
484
+static ssize_t arc_pmu_events_sysfs_show(struct device *dev,
485
+ struct device_attribute *attr,
486
+ char *page)
487
+{
488
+ struct perf_pmu_events_attr *pmu_attr;
489
+
490
+ pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr);
491
+ return sprintf(page, "event=0x%04llx\n", pmu_attr->id);
492
+}
493
+
494
+/*
495
+ * We don't add attrs here as we don't have pre-defined list of perf events.
496
+ * We will generate and add attrs dynamically in probe() after we read HW
497
+ * configuration.
498
+ */
499
+static struct attribute_group arc_pmu_events_attr_gr = {
500
+ .name = "events",
501
+};
502
+
503
+static void arc_pmu_add_raw_event_attr(int j, char *str)
504
+{
505
+ memmove(arc_pmu->raw_entry[j].name, str, ARCPMU_EVENT_NAME_LEN - 1);
506
+ arc_pmu->attr[j].attr.attr.name = arc_pmu->raw_entry[j].name;
507
+ arc_pmu->attr[j].attr.attr.mode = VERIFY_OCTAL_PERMISSIONS(0444);
508
+ arc_pmu->attr[j].attr.show = arc_pmu_events_sysfs_show;
509
+ arc_pmu->attr[j].id = j;
510
+ arc_pmu->attrs[j] = &(arc_pmu->attr[j].attr.attr);
511
+}
512
+
513
+static int arc_pmu_raw_alloc(struct device *dev)
514
+{
515
+ arc_pmu->attr = devm_kmalloc_array(dev, arc_pmu->n_events + 1,
516
+ sizeof(*arc_pmu->attr), GFP_KERNEL | __GFP_ZERO);
517
+ if (!arc_pmu->attr)
518
+ return -ENOMEM;
519
+
520
+ arc_pmu->attrs = devm_kmalloc_array(dev, arc_pmu->n_events + 1,
521
+ sizeof(*arc_pmu->attrs), GFP_KERNEL | __GFP_ZERO);
522
+ if (!arc_pmu->attrs)
523
+ return -ENOMEM;
524
+
525
+ arc_pmu->raw_entry = devm_kmalloc_array(dev, arc_pmu->n_events,
526
+ sizeof(*arc_pmu->raw_entry), GFP_KERNEL | __GFP_ZERO);
527
+ if (!arc_pmu->raw_entry)
528
+ return -ENOMEM;
529
+
530
+ return 0;
531
+}
532
+
533
+static inline bool event_in_hw_event_map(int i, char *name)
534
+{
535
+ if (!arc_pmu_ev_hw_map[i])
536
+ return false;
537
+
538
+ if (!strlen(arc_pmu_ev_hw_map[i]))
539
+ return false;
540
+
541
+ if (strcmp(arc_pmu_ev_hw_map[i], name))
542
+ return false;
543
+
544
+ return true;
545
+}
546
+
547
+static void arc_pmu_map_hw_event(int j, char *str)
548
+{
549
+ int i;
550
+
551
+ /* See if HW condition has been mapped to a perf event_id */
552
+ for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) {
553
+ if (event_in_hw_event_map(i, str)) {
554
+ pr_debug("mapping perf event %2d to h/w event \'%8s\' (idx %d)\n",
555
+ i, str, j);
556
+ arc_pmu->ev_hw_idx[i] = j;
557
+ }
558
+ }
559
+}
560
+
444561 static int arc_pmu_device_probe(struct platform_device *pdev)
445562 {
446563 struct arc_reg_pct_build pct_bcr;
447564 struct arc_reg_cc_build cc_bcr;
448
- int i, j, has_interrupts;
565
+ int i, has_interrupts, irq = -1;
449566 int counter_size; /* in bits */
450567
451568 union cc_name {
452569 struct {
453
- uint32_t word0, word1;
570
+ u32 word0, word1;
454571 char sentinel;
455572 } indiv;
456
- char str[9];
573
+ char str[ARCPMU_EVENT_NAME_LEN];
457574 } cc_name;
458575
459576
....@@ -463,13 +580,20 @@
463580 return -ENODEV;
464581 }
465582 BUILD_BUG_ON(ARC_PERF_MAX_COUNTERS > 32);
466
- BUG_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS);
583
+ if (WARN_ON(pct_bcr.c > ARC_PERF_MAX_COUNTERS))
584
+ return -EINVAL;
467585
468586 READ_BCR(ARC_REG_CC_BUILD, cc_bcr);
469
- BUG_ON(!cc_bcr.v); /* Counters exist but No countable conditions ? */
587
+ if (WARN(!cc_bcr.v, "Counters exist but No countable conditions?"))
588
+ return -EINVAL;
470589
471590 arc_pmu = devm_kzalloc(&pdev->dev, sizeof(struct arc_pmu), GFP_KERNEL);
472591 if (!arc_pmu)
592
+ return -ENOMEM;
593
+
594
+ arc_pmu->n_events = cc_bcr.c;
595
+
596
+ if (arc_pmu_raw_alloc(&pdev->dev))
473597 return -ENOMEM;
474598
475599 has_interrupts = is_isa_arcv2() ? pct_bcr.i : 0;
....@@ -481,29 +605,25 @@
481605
482606 pr_info("ARC perf\t: %d counters (%d bits), %d conditions%s\n",
483607 arc_pmu->n_counters, counter_size, cc_bcr.c,
484
- has_interrupts ? ", [overflow IRQ support]":"");
608
+ has_interrupts ? ", [overflow IRQ support]" : "");
485609
486
- cc_name.str[8] = 0;
610
+ cc_name.str[ARCPMU_EVENT_NAME_LEN - 1] = 0;
487611 for (i = 0; i < PERF_COUNT_ARC_HW_MAX; i++)
488612 arc_pmu->ev_hw_idx[i] = -1;
489613
490614 /* loop thru all available h/w condition indexes */
491
- for (j = 0; j < cc_bcr.c; j++) {
492
- write_aux_reg(ARC_REG_CC_INDEX, j);
615
+ for (i = 0; i < cc_bcr.c; i++) {
616
+ write_aux_reg(ARC_REG_CC_INDEX, i);
493617 cc_name.indiv.word0 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME0));
494618 cc_name.indiv.word1 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME1));
495619
496
- /* See if it has been mapped to a perf event_id */
497
- for (i = 0; i < ARRAY_SIZE(arc_pmu_ev_hw_map); i++) {
498
- if (arc_pmu_ev_hw_map[i] &&
499
- !strcmp(arc_pmu_ev_hw_map[i], cc_name.str) &&
500
- strlen(arc_pmu_ev_hw_map[i])) {
501
- pr_debug("mapping perf event %2d to h/w event \'%8s\' (idx %d)\n",
502
- i, cc_name.str, j);
503
- arc_pmu->ev_hw_idx[i] = j;
504
- }
505
- }
620
+ arc_pmu_map_hw_event(i, cc_name.str);
621
+ arc_pmu_add_raw_event_attr(i, cc_name.str);
506622 }
623
+
624
+ arc_pmu_events_attr_gr.attrs = arc_pmu->attrs;
625
+ arc_pmu->attr_groups[ARCPMU_ATTR_GR_EVENTS] = &arc_pmu_events_attr_gr;
626
+ arc_pmu->attr_groups[ARCPMU_ATTR_GR_FORMATS] = &arc_pmu_format_attr_gr;
507627
508628 arc_pmu->pmu = (struct pmu) {
509629 .pmu_enable = arc_pmu_enable,
....@@ -514,38 +634,44 @@
514634 .start = arc_pmu_start,
515635 .stop = arc_pmu_stop,
516636 .read = arc_pmu_read,
637
+ .attr_groups = arc_pmu->attr_groups,
517638 };
518639
519640 if (has_interrupts) {
520
- int irq = platform_get_irq(pdev, 0);
641
+ irq = platform_get_irq(pdev, 0);
642
+ if (irq >= 0) {
643
+ int ret;
521644
522
- if (irq < 0) {
523
- pr_err("Cannot get IRQ number for the platform\n");
524
- return -ENODEV;
645
+ arc_pmu->irq = irq;
646
+
647
+ /* intc map function ensures irq_set_percpu_devid() called */
648
+ ret = request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
649
+ this_cpu_ptr(&arc_pmu_cpu));
650
+
651
+ if (!ret)
652
+ on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
653
+ else
654
+ irq = -1;
525655 }
526656
527
- arc_pmu->irq = irq;
657
+ }
528658
529
- /* intc map function ensures irq_set_percpu_devid() called */
530
- request_percpu_irq(irq, arc_pmu_intr, "ARC perf counters",
531
- this_cpu_ptr(&arc_pmu_cpu));
532
-
533
- on_each_cpu(arc_cpu_pmu_irq_init, &irq, 1);
534
-
535
- } else
659
+ if (irq == -1)
536660 arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
537661
538
- return perf_pmu_register(&arc_pmu->pmu, pdev->name, PERF_TYPE_RAW);
662
+ /*
663
+ * perf parser doesn't really like '-' symbol in events name, so let's
664
+ * use '_' in arc pct name as it goes to kernel PMU event prefix.
665
+ */
666
+ return perf_pmu_register(&arc_pmu->pmu, "arc_pct", PERF_TYPE_RAW);
539667 }
540668
541
-#ifdef CONFIG_OF
542669 static const struct of_device_id arc_pmu_match[] = {
543670 { .compatible = "snps,arc700-pct" },
544671 { .compatible = "snps,archs-pct" },
545672 {},
546673 };
547674 MODULE_DEVICE_TABLE(of, arc_pmu_match);
548
-#endif
549675
550676 static struct platform_driver arc_pmu_driver = {
551677 .driver = {