.. | .. |
---|
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 | + |
---|
13 | 8 | #include <linux/errno.h> |
---|
14 | 9 | #include <linux/interrupt.h> |
---|
15 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
19 | 14 | #include <asm/arcregs.h> |
---|
20 | 15 | #include <asm/stacktrace.h> |
---|
21 | 16 | |
---|
| 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 | + |
---|
22 | 30 | struct arc_pmu { |
---|
23 | 31 | struct pmu pmu; |
---|
24 | 32 | unsigned int irq; |
---|
25 | 33 | int n_counters; |
---|
| 34 | + int n_events; |
---|
26 | 35 | u64 max_period; |
---|
27 | 36 | 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]; |
---|
28 | 42 | }; |
---|
29 | 43 | |
---|
30 | 44 | struct arc_pmu_cpu { |
---|
.. | .. |
---|
49 | 63 | { |
---|
50 | 64 | struct arc_callchain_trace *ctrl = data; |
---|
51 | 65 | struct perf_callchain_entry_ctx *entry = ctrl->perf_stuff; |
---|
| 66 | + |
---|
52 | 67 | perf_callchain_store(entry, addr); |
---|
53 | 68 | |
---|
54 | 69 | if (ctrl->depth++ < 3) |
---|
.. | .. |
---|
57 | 72 | return -1; |
---|
58 | 73 | } |
---|
59 | 74 | |
---|
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) |
---|
62 | 77 | { |
---|
63 | 78 | struct arc_callchain_trace ctrl = { |
---|
64 | 79 | .depth = 0, |
---|
.. | .. |
---|
68 | 83 | arc_unwind_core(NULL, regs, callchain_trace, &ctrl); |
---|
69 | 84 | } |
---|
70 | 85 | |
---|
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) |
---|
73 | 88 | { |
---|
74 | 89 | /* |
---|
75 | 90 | * User stack can't be unwound trivially with kernel dwarf unwinder |
---|
.. | .. |
---|
82 | 97 | static DEFINE_PER_CPU(struct arc_pmu_cpu, arc_pmu_cpu); |
---|
83 | 98 | |
---|
84 | 99 | /* 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) |
---|
86 | 101 | { |
---|
87 | | - uint32_t tmp; |
---|
88 | | - uint64_t result; |
---|
| 102 | + u32 tmp; |
---|
| 103 | + u64 result; |
---|
89 | 104 | |
---|
90 | 105 | /* |
---|
91 | 106 | * ARC supports making 'snapshots' of the counters, so we don't |
---|
.. | .. |
---|
94 | 109 | write_aux_reg(ARC_REG_PCT_INDEX, idx); |
---|
95 | 110 | tmp = read_aux_reg(ARC_REG_PCT_CONTROL); |
---|
96 | 111 | 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; |
---|
98 | 113 | result |= read_aux_reg(ARC_REG_PCT_SNAPL); |
---|
99 | 114 | |
---|
100 | 115 | return result; |
---|
.. | .. |
---|
103 | 118 | static void arc_perf_event_update(struct perf_event *event, |
---|
104 | 119 | struct hw_perf_event *hwc, int idx) |
---|
105 | 120 | { |
---|
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; |
---|
109 | 124 | |
---|
110 | 125 | /* |
---|
111 | 126 | * We aren't afraid of hwc->prev_count changing beneath our feet |
---|
.. | .. |
---|
155 | 170 | int ret; |
---|
156 | 171 | |
---|
157 | 172 | if (!is_sampling_event(event)) { |
---|
158 | | - hwc->sample_period = arc_pmu->max_period; |
---|
| 173 | + hwc->sample_period = arc_pmu->max_period; |
---|
159 | 174 | hwc->last_period = hwc->sample_period; |
---|
160 | 175 | local64_set(&hwc->period_left, hwc->sample_period); |
---|
161 | 176 | } |
---|
.. | .. |
---|
192 | 207 | pr_debug("init cache event with h/w %08x \'%s\'\n", |
---|
193 | 208 | (int)hwc->config, arc_pmu_ev_hw_map[ret]); |
---|
194 | 209 | 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 | + |
---|
195 | 222 | default: |
---|
196 | 223 | return -ENOENT; |
---|
197 | 224 | } |
---|
.. | .. |
---|
200 | 227 | /* starts all counters */ |
---|
201 | 228 | static void arc_pmu_enable(struct pmu *pmu) |
---|
202 | 229 | { |
---|
203 | | - uint32_t tmp; |
---|
| 230 | + u32 tmp; |
---|
204 | 231 | tmp = read_aux_reg(ARC_REG_PCT_CONTROL); |
---|
205 | 232 | write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x1); |
---|
206 | 233 | } |
---|
.. | .. |
---|
208 | 235 | /* stops all counters */ |
---|
209 | 236 | static void arc_pmu_disable(struct pmu *pmu) |
---|
210 | 237 | { |
---|
211 | | - uint32_t tmp; |
---|
| 238 | + u32 tmp; |
---|
212 | 239 | tmp = read_aux_reg(ARC_REG_PCT_CONTROL); |
---|
213 | 240 | write_aux_reg(ARC_REG_PCT_CONTROL, (tmp & 0xffff0000) | 0x0); |
---|
214 | 241 | } |
---|
.. | .. |
---|
228 | 255 | local64_set(&hwc->period_left, left); |
---|
229 | 256 | hwc->last_period = period; |
---|
230 | 257 | overflow = 1; |
---|
231 | | - } else if (unlikely(left <= 0)) { |
---|
| 258 | + } else if (unlikely(left <= 0)) { |
---|
232 | 259 | /* left underflowed by less than period. */ |
---|
233 | 260 | left += period; |
---|
234 | 261 | local64_set(&hwc->period_left, left); |
---|
.. | .. |
---|
246 | 273 | write_aux_reg(ARC_REG_PCT_INDEX, idx); |
---|
247 | 274 | |
---|
248 | 275 | /* 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)); |
---|
251 | 278 | |
---|
252 | 279 | perf_event_update_userpage(event); |
---|
253 | 280 | |
---|
.. | .. |
---|
277 | 304 | /* Enable interrupt for this counter */ |
---|
278 | 305 | if (is_sampling_event(event)) |
---|
279 | 306 | 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)); |
---|
281 | 308 | |
---|
282 | 309 | /* enable ARC pmu here */ |
---|
283 | 310 | write_aux_reg(ARC_REG_PCT_INDEX, idx); /* counter # */ |
---|
.. | .. |
---|
295 | 322 | * Reset interrupt flag by writing of 1. This is required |
---|
296 | 323 | * to make sure pending interrupt was not left. |
---|
297 | 324 | */ |
---|
298 | | - write_aux_reg(ARC_REG_PCT_INT_ACT, 1 << idx); |
---|
| 325 | + write_aux_reg(ARC_REG_PCT_INT_ACT, BIT(idx)); |
---|
299 | 326 | 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)); |
---|
301 | 328 | } |
---|
302 | 329 | |
---|
303 | 330 | if (!(event->hw.state & PERF_HES_STOPPED)) { |
---|
.. | .. |
---|
349 | 376 | |
---|
350 | 377 | if (is_sampling_event(event)) { |
---|
351 | 378 | /* 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)); |
---|
353 | 381 | write_aux_reg(ARC_REG_PCT_INT_CNTH, |
---|
354 | | - (arc_pmu->max_period >> 32)); |
---|
| 382 | + upper_32_bits(arc_pmu->max_period)); |
---|
355 | 383 | } |
---|
356 | 384 | |
---|
357 | 385 | write_aux_reg(ARC_REG_PCT_CONFIG, 0); |
---|
.. | .. |
---|
392 | 420 | idx = __ffs(active_ints); |
---|
393 | 421 | |
---|
394 | 422 | /* 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)); |
---|
396 | 424 | |
---|
397 | 425 | /* |
---|
398 | 426 | * On reset of "interrupt active" bit corresponding |
---|
.. | .. |
---|
400 | 428 | * Now we need to re-enable interrupt for the counter. |
---|
401 | 429 | */ |
---|
402 | 430 | 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)); |
---|
404 | 432 | |
---|
405 | 433 | event = pmu_cpu->act_counter[idx]; |
---|
406 | 434 | hwc = &event->hw; |
---|
.. | .. |
---|
414 | 442 | arc_pmu_stop(event, 0); |
---|
415 | 443 | } |
---|
416 | 444 | |
---|
417 | | - active_ints &= ~(1U << idx); |
---|
| 445 | + active_ints &= ~BIT(idx); |
---|
418 | 446 | } while (active_ints); |
---|
419 | 447 | |
---|
420 | 448 | done: |
---|
.. | .. |
---|
441 | 469 | write_aux_reg(ARC_REG_PCT_INT_ACT, 0xffffffff); |
---|
442 | 470 | } |
---|
443 | 471 | |
---|
| 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 | + |
---|
444 | 561 | static int arc_pmu_device_probe(struct platform_device *pdev) |
---|
445 | 562 | { |
---|
446 | 563 | struct arc_reg_pct_build pct_bcr; |
---|
447 | 564 | struct arc_reg_cc_build cc_bcr; |
---|
448 | | - int i, j, has_interrupts; |
---|
| 565 | + int i, has_interrupts, irq = -1; |
---|
449 | 566 | int counter_size; /* in bits */ |
---|
450 | 567 | |
---|
451 | 568 | union cc_name { |
---|
452 | 569 | struct { |
---|
453 | | - uint32_t word0, word1; |
---|
| 570 | + u32 word0, word1; |
---|
454 | 571 | char sentinel; |
---|
455 | 572 | } indiv; |
---|
456 | | - char str[9]; |
---|
| 573 | + char str[ARCPMU_EVENT_NAME_LEN]; |
---|
457 | 574 | } cc_name; |
---|
458 | 575 | |
---|
459 | 576 | |
---|
.. | .. |
---|
463 | 580 | return -ENODEV; |
---|
464 | 581 | } |
---|
465 | 582 | 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; |
---|
467 | 585 | |
---|
468 | 586 | 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; |
---|
470 | 589 | |
---|
471 | 590 | arc_pmu = devm_kzalloc(&pdev->dev, sizeof(struct arc_pmu), GFP_KERNEL); |
---|
472 | 591 | if (!arc_pmu) |
---|
| 592 | + return -ENOMEM; |
---|
| 593 | + |
---|
| 594 | + arc_pmu->n_events = cc_bcr.c; |
---|
| 595 | + |
---|
| 596 | + if (arc_pmu_raw_alloc(&pdev->dev)) |
---|
473 | 597 | return -ENOMEM; |
---|
474 | 598 | |
---|
475 | 599 | has_interrupts = is_isa_arcv2() ? pct_bcr.i : 0; |
---|
.. | .. |
---|
481 | 605 | |
---|
482 | 606 | pr_info("ARC perf\t: %d counters (%d bits), %d conditions%s\n", |
---|
483 | 607 | arc_pmu->n_counters, counter_size, cc_bcr.c, |
---|
484 | | - has_interrupts ? ", [overflow IRQ support]":""); |
---|
| 608 | + has_interrupts ? ", [overflow IRQ support]" : ""); |
---|
485 | 609 | |
---|
486 | | - cc_name.str[8] = 0; |
---|
| 610 | + cc_name.str[ARCPMU_EVENT_NAME_LEN - 1] = 0; |
---|
487 | 611 | for (i = 0; i < PERF_COUNT_ARC_HW_MAX; i++) |
---|
488 | 612 | arc_pmu->ev_hw_idx[i] = -1; |
---|
489 | 613 | |
---|
490 | 614 | /* 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); |
---|
493 | 617 | cc_name.indiv.word0 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME0)); |
---|
494 | 618 | cc_name.indiv.word1 = le32_to_cpu(read_aux_reg(ARC_REG_CC_NAME1)); |
---|
495 | 619 | |
---|
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); |
---|
506 | 622 | } |
---|
| 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; |
---|
507 | 627 | |
---|
508 | 628 | arc_pmu->pmu = (struct pmu) { |
---|
509 | 629 | .pmu_enable = arc_pmu_enable, |
---|
.. | .. |
---|
514 | 634 | .start = arc_pmu_start, |
---|
515 | 635 | .stop = arc_pmu_stop, |
---|
516 | 636 | .read = arc_pmu_read, |
---|
| 637 | + .attr_groups = arc_pmu->attr_groups, |
---|
517 | 638 | }; |
---|
518 | 639 | |
---|
519 | 640 | 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; |
---|
521 | 644 | |
---|
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; |
---|
525 | 655 | } |
---|
526 | 656 | |
---|
527 | | - arc_pmu->irq = irq; |
---|
| 657 | + } |
---|
528 | 658 | |
---|
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) |
---|
536 | 660 | arc_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; |
---|
537 | 661 | |
---|
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); |
---|
539 | 667 | } |
---|
540 | 668 | |
---|
541 | | -#ifdef CONFIG_OF |
---|
542 | 669 | static const struct of_device_id arc_pmu_match[] = { |
---|
543 | 670 | { .compatible = "snps,arc700-pct" }, |
---|
544 | 671 | { .compatible = "snps,archs-pct" }, |
---|
545 | 672 | {}, |
---|
546 | 673 | }; |
---|
547 | 674 | MODULE_DEVICE_TABLE(of, arc_pmu_match); |
---|
548 | | -#endif |
---|
549 | 675 | |
---|
550 | 676 | static struct platform_driver arc_pmu_driver = { |
---|
551 | 677 | .driver = { |
---|