diff options
Diffstat (limited to 'arch/arm/kernel/perf_event.c')
-rw-r--r-- | arch/arm/kernel/perf_event.c | 347 |
1 files changed, 51 insertions, 296 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index ab243b87118d..93971b1a4f0b 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -12,68 +12,15 @@ | |||
12 | */ | 12 | */ |
13 | #define pr_fmt(fmt) "hw perfevents: " fmt | 13 | #define pr_fmt(fmt) "hw perfevents: " fmt |
14 | 14 | ||
15 | #include <linux/bitmap.h> | ||
16 | #include <linux/interrupt.h> | ||
17 | #include <linux/kernel.h> | 15 | #include <linux/kernel.h> |
18 | #include <linux/export.h> | ||
19 | #include <linux/perf_event.h> | ||
20 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
21 | #include <linux/spinlock.h> | 17 | #include <linux/pm_runtime.h> |
22 | #include <linux/uaccess.h> | 18 | #include <linux/uaccess.h> |
23 | 19 | ||
24 | #include <asm/cputype.h> | ||
25 | #include <asm/irq.h> | ||
26 | #include <asm/irq_regs.h> | 20 | #include <asm/irq_regs.h> |
27 | #include <asm/pmu.h> | 21 | #include <asm/pmu.h> |
28 | #include <asm/stacktrace.h> | 22 | #include <asm/stacktrace.h> |
29 | 23 | ||
30 | /* | ||
31 | * ARMv6 supports a maximum of 3 events, starting from index 0. If we add | ||
32 | * another platform that supports more, we need to increase this to be the | ||
33 | * largest of all platforms. | ||
34 | * | ||
35 | * ARMv7 supports up to 32 events: | ||
36 | * cycle counter CCNT + 31 events counters CNT0..30. | ||
37 | * Cortex-A8 has 1+4 counters, Cortex-A9 has 1+6 counters. | ||
38 | */ | ||
39 | #define ARMPMU_MAX_HWEVENTS 32 | ||
40 | |||
41 | static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events); | ||
42 | static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask); | ||
43 | static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events); | ||
44 | |||
45 | #define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu)) | ||
46 | |||
47 | /* Set at runtime when we know what CPU type we are. */ | ||
48 | static struct arm_pmu *cpu_pmu; | ||
49 | |||
50 | const char *perf_pmu_name(void) | ||
51 | { | ||
52 | if (!cpu_pmu) | ||
53 | return NULL; | ||
54 | |||
55 | return cpu_pmu->pmu.name; | ||
56 | } | ||
57 | EXPORT_SYMBOL_GPL(perf_pmu_name); | ||
58 | |||
59 | int perf_num_counters(void) | ||
60 | { | ||
61 | int max_events = 0; | ||
62 | |||
63 | if (cpu_pmu != NULL) | ||
64 | max_events = cpu_pmu->num_events; | ||
65 | |||
66 | return max_events; | ||
67 | } | ||
68 | EXPORT_SYMBOL_GPL(perf_num_counters); | ||
69 | |||
70 | #define HW_OP_UNSUPPORTED 0xFFFF | ||
71 | |||
72 | #define C(_x) \ | ||
73 | PERF_COUNT_HW_CACHE_##_x | ||
74 | |||
75 | #define CACHE_OP_UNSUPPORTED 0xFFFF | ||
76 | |||
77 | static int | 24 | static int |
78 | armpmu_map_cache_event(const unsigned (*cache_map) | 25 | armpmu_map_cache_event(const unsigned (*cache_map) |
79 | [PERF_COUNT_HW_CACHE_MAX] | 26 | [PERF_COUNT_HW_CACHE_MAX] |
@@ -104,7 +51,7 @@ armpmu_map_cache_event(const unsigned (*cache_map) | |||
104 | } | 51 | } |
105 | 52 | ||
106 | static int | 53 | static int |
107 | armpmu_map_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) | 54 | armpmu_map_hw_event(const unsigned (*event_map)[PERF_COUNT_HW_MAX], u64 config) |
108 | { | 55 | { |
109 | int mapping = (*event_map)[config]; | 56 | int mapping = (*event_map)[config]; |
110 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; | 57 | return mapping == HW_OP_UNSUPPORTED ? -ENOENT : mapping; |
@@ -116,19 +63,20 @@ armpmu_map_raw_event(u32 raw_event_mask, u64 config) | |||
116 | return (int)(config & raw_event_mask); | 63 | return (int)(config & raw_event_mask); |
117 | } | 64 | } |
118 | 65 | ||
119 | static int map_cpu_event(struct perf_event *event, | 66 | int |
120 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], | 67 | armpmu_map_event(struct perf_event *event, |
121 | const unsigned (*cache_map) | 68 | const unsigned (*event_map)[PERF_COUNT_HW_MAX], |
122 | [PERF_COUNT_HW_CACHE_MAX] | 69 | const unsigned (*cache_map) |
123 | [PERF_COUNT_HW_CACHE_OP_MAX] | 70 | [PERF_COUNT_HW_CACHE_MAX] |
124 | [PERF_COUNT_HW_CACHE_RESULT_MAX], | 71 | [PERF_COUNT_HW_CACHE_OP_MAX] |
125 | u32 raw_event_mask) | 72 | [PERF_COUNT_HW_CACHE_RESULT_MAX], |
73 | u32 raw_event_mask) | ||
126 | { | 74 | { |
127 | u64 config = event->attr.config; | 75 | u64 config = event->attr.config; |
128 | 76 | ||
129 | switch (event->attr.type) { | 77 | switch (event->attr.type) { |
130 | case PERF_TYPE_HARDWARE: | 78 | case PERF_TYPE_HARDWARE: |
131 | return armpmu_map_event(event_map, config); | 79 | return armpmu_map_hw_event(event_map, config); |
132 | case PERF_TYPE_HW_CACHE: | 80 | case PERF_TYPE_HW_CACHE: |
133 | return armpmu_map_cache_event(cache_map, config); | 81 | return armpmu_map_cache_event(cache_map, config); |
134 | case PERF_TYPE_RAW: | 82 | case PERF_TYPE_RAW: |
@@ -222,7 +170,6 @@ armpmu_stop(struct perf_event *event, int flags) | |||
222 | */ | 170 | */ |
223 | if (!(hwc->state & PERF_HES_STOPPED)) { | 171 | if (!(hwc->state & PERF_HES_STOPPED)) { |
224 | armpmu->disable(hwc, hwc->idx); | 172 | armpmu->disable(hwc, hwc->idx); |
225 | barrier(); /* why? */ | ||
226 | armpmu_event_update(event, hwc, hwc->idx); | 173 | armpmu_event_update(event, hwc, hwc->idx); |
227 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; | 174 | hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE; |
228 | } | 175 | } |
@@ -350,99 +297,41 @@ validate_group(struct perf_event *event) | |||
350 | return 0; | 297 | return 0; |
351 | } | 298 | } |
352 | 299 | ||
353 | static irqreturn_t armpmu_platform_irq(int irq, void *dev) | 300 | static irqreturn_t armpmu_dispatch_irq(int irq, void *dev) |
354 | { | 301 | { |
355 | struct arm_pmu *armpmu = (struct arm_pmu *) dev; | 302 | struct arm_pmu *armpmu = (struct arm_pmu *) dev; |
356 | struct platform_device *plat_device = armpmu->plat_device; | 303 | struct platform_device *plat_device = armpmu->plat_device; |
357 | struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); | 304 | struct arm_pmu_platdata *plat = dev_get_platdata(&plat_device->dev); |
358 | 305 | ||
359 | return plat->handle_irq(irq, dev, armpmu->handle_irq); | 306 | if (plat && plat->handle_irq) |
307 | return plat->handle_irq(irq, dev, armpmu->handle_irq); | ||
308 | else | ||
309 | return armpmu->handle_irq(irq, dev); | ||
360 | } | 310 | } |
361 | 311 | ||
362 | static void | 312 | static void |
363 | armpmu_release_hardware(struct arm_pmu *armpmu) | 313 | armpmu_release_hardware(struct arm_pmu *armpmu) |
364 | { | 314 | { |
365 | int i, irq, irqs; | 315 | armpmu->free_irq(); |
366 | struct platform_device *pmu_device = armpmu->plat_device; | 316 | pm_runtime_put_sync(&armpmu->plat_device->dev); |
367 | struct arm_pmu_platdata *plat = | ||
368 | dev_get_platdata(&pmu_device->dev); | ||
369 | |||
370 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
371 | |||
372 | for (i = 0; i < irqs; ++i) { | ||
373 | if (!cpumask_test_and_clear_cpu(i, &armpmu->active_irqs)) | ||
374 | continue; | ||
375 | irq = platform_get_irq(pmu_device, i); | ||
376 | if (irq >= 0) { | ||
377 | if (plat && plat->disable_irq) | ||
378 | plat->disable_irq(irq); | ||
379 | free_irq(irq, armpmu); | ||
380 | } | ||
381 | } | ||
382 | |||
383 | release_pmu(armpmu->type); | ||
384 | } | 317 | } |
385 | 318 | ||
386 | static int | 319 | static int |
387 | armpmu_reserve_hardware(struct arm_pmu *armpmu) | 320 | armpmu_reserve_hardware(struct arm_pmu *armpmu) |
388 | { | 321 | { |
389 | struct arm_pmu_platdata *plat; | 322 | int err; |
390 | irq_handler_t handle_irq; | ||
391 | int i, err, irq, irqs; | ||
392 | struct platform_device *pmu_device = armpmu->plat_device; | 323 | struct platform_device *pmu_device = armpmu->plat_device; |
393 | 324 | ||
394 | if (!pmu_device) | 325 | if (!pmu_device) |
395 | return -ENODEV; | 326 | return -ENODEV; |
396 | 327 | ||
397 | err = reserve_pmu(armpmu->type); | 328 | pm_runtime_get_sync(&pmu_device->dev); |
329 | err = armpmu->request_irq(armpmu_dispatch_irq); | ||
398 | if (err) { | 330 | if (err) { |
399 | pr_warning("unable to reserve pmu\n"); | 331 | armpmu_release_hardware(armpmu); |
400 | return err; | 332 | return err; |
401 | } | 333 | } |
402 | 334 | ||
403 | plat = dev_get_platdata(&pmu_device->dev); | ||
404 | if (plat && plat->handle_irq) | ||
405 | handle_irq = armpmu_platform_irq; | ||
406 | else | ||
407 | handle_irq = armpmu->handle_irq; | ||
408 | |||
409 | irqs = min(pmu_device->num_resources, num_possible_cpus()); | ||
410 | if (irqs < 1) { | ||
411 | pr_err("no irqs for PMUs defined\n"); | ||
412 | return -ENODEV; | ||
413 | } | ||
414 | |||
415 | for (i = 0; i < irqs; ++i) { | ||
416 | err = 0; | ||
417 | irq = platform_get_irq(pmu_device, i); | ||
418 | if (irq < 0) | ||
419 | continue; | ||
420 | |||
421 | /* | ||
422 | * If we have a single PMU interrupt that we can't shift, | ||
423 | * assume that we're running on a uniprocessor machine and | ||
424 | * continue. Otherwise, continue without this interrupt. | ||
425 | */ | ||
426 | if (irq_set_affinity(irq, cpumask_of(i)) && irqs > 1) { | ||
427 | pr_warning("unable to set irq affinity (irq=%d, cpu=%u)\n", | ||
428 | irq, i); | ||
429 | continue; | ||
430 | } | ||
431 | |||
432 | err = request_irq(irq, handle_irq, | ||
433 | IRQF_DISABLED | IRQF_NOBALANCING, | ||
434 | "arm-pmu", armpmu); | ||
435 | if (err) { | ||
436 | pr_err("unable to request IRQ%d for ARM PMU counters\n", | ||
437 | irq); | ||
438 | armpmu_release_hardware(armpmu); | ||
439 | return err; | ||
440 | } else if (plat && plat->enable_irq) | ||
441 | plat->enable_irq(irq); | ||
442 | |||
443 | cpumask_set_cpu(i, &armpmu->active_irqs); | ||
444 | } | ||
445 | |||
446 | return 0; | 335 | return 0; |
447 | } | 336 | } |
448 | 337 | ||
@@ -581,6 +470,32 @@ static void armpmu_disable(struct pmu *pmu) | |||
581 | armpmu->stop(); | 470 | armpmu->stop(); |
582 | } | 471 | } |
583 | 472 | ||
473 | #ifdef CONFIG_PM_RUNTIME | ||
474 | static int armpmu_runtime_resume(struct device *dev) | ||
475 | { | ||
476 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | ||
477 | |||
478 | if (plat && plat->runtime_resume) | ||
479 | return plat->runtime_resume(dev); | ||
480 | |||
481 | return 0; | ||
482 | } | ||
483 | |||
484 | static int armpmu_runtime_suspend(struct device *dev) | ||
485 | { | ||
486 | struct arm_pmu_platdata *plat = dev_get_platdata(dev); | ||
487 | |||
488 | if (plat && plat->runtime_suspend) | ||
489 | return plat->runtime_suspend(dev); | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | #endif | ||
494 | |||
495 | const struct dev_pm_ops armpmu_dev_pm_ops = { | ||
496 | SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL) | ||
497 | }; | ||
498 | |||
584 | static void __init armpmu_init(struct arm_pmu *armpmu) | 499 | static void __init armpmu_init(struct arm_pmu *armpmu) |
585 | { | 500 | { |
586 | atomic_set(&armpmu->active_events, 0); | 501 | atomic_set(&armpmu->active_events, 0); |
@@ -598,174 +513,14 @@ static void __init armpmu_init(struct arm_pmu *armpmu) | |||
598 | }; | 513 | }; |
599 | } | 514 | } |
600 | 515 | ||
601 | int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) | 516 | int armpmu_register(struct arm_pmu *armpmu, char *name, int type) |
602 | { | 517 | { |
603 | armpmu_init(armpmu); | 518 | armpmu_init(armpmu); |
519 | pr_info("enabled with %s PMU driver, %d counters available\n", | ||
520 | armpmu->name, armpmu->num_events); | ||
604 | return perf_pmu_register(&armpmu->pmu, name, type); | 521 | return perf_pmu_register(&armpmu->pmu, name, type); |
605 | } | 522 | } |
606 | 523 | ||
607 | /* Include the PMU-specific implementations. */ | ||
608 | #include "perf_event_xscale.c" | ||
609 | #include "perf_event_v6.c" | ||
610 | #include "perf_event_v7.c" | ||
611 | |||
612 | /* | ||
613 | * Ensure the PMU has sane values out of reset. | ||
614 | * This requires SMP to be available, so exists as a separate initcall. | ||
615 | */ | ||
616 | static int __init | ||
617 | cpu_pmu_reset(void) | ||
618 | { | ||
619 | if (cpu_pmu && cpu_pmu->reset) | ||
620 | return on_each_cpu(cpu_pmu->reset, NULL, 1); | ||
621 | return 0; | ||
622 | } | ||
623 | arch_initcall(cpu_pmu_reset); | ||
624 | |||
625 | /* | ||
626 | * PMU platform driver and devicetree bindings. | ||
627 | */ | ||
628 | static struct of_device_id armpmu_of_device_ids[] = { | ||
629 | {.compatible = "arm,cortex-a9-pmu"}, | ||
630 | {.compatible = "arm,cortex-a8-pmu"}, | ||
631 | {.compatible = "arm,arm1136-pmu"}, | ||
632 | {.compatible = "arm,arm1176-pmu"}, | ||
633 | {}, | ||
634 | }; | ||
635 | |||
636 | static struct platform_device_id armpmu_plat_device_ids[] = { | ||
637 | {.name = "arm-pmu"}, | ||
638 | {}, | ||
639 | }; | ||
640 | |||
641 | static int __devinit armpmu_device_probe(struct platform_device *pdev) | ||
642 | { | ||
643 | if (!cpu_pmu) | ||
644 | return -ENODEV; | ||
645 | |||
646 | cpu_pmu->plat_device = pdev; | ||
647 | return 0; | ||
648 | } | ||
649 | |||
650 | static struct platform_driver armpmu_driver = { | ||
651 | .driver = { | ||
652 | .name = "arm-pmu", | ||
653 | .of_match_table = armpmu_of_device_ids, | ||
654 | }, | ||
655 | .probe = armpmu_device_probe, | ||
656 | .id_table = armpmu_plat_device_ids, | ||
657 | }; | ||
658 | |||
659 | static int __init register_pmu_driver(void) | ||
660 | { | ||
661 | return platform_driver_register(&armpmu_driver); | ||
662 | } | ||
663 | device_initcall(register_pmu_driver); | ||
664 | |||
665 | static struct pmu_hw_events *armpmu_get_cpu_events(void) | ||
666 | { | ||
667 | return &__get_cpu_var(cpu_hw_events); | ||
668 | } | ||
669 | |||
670 | static void __init cpu_pmu_init(struct arm_pmu *armpmu) | ||
671 | { | ||
672 | int cpu; | ||
673 | for_each_possible_cpu(cpu) { | ||
674 | struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu); | ||
675 | events->events = per_cpu(hw_events, cpu); | ||
676 | events->used_mask = per_cpu(used_mask, cpu); | ||
677 | raw_spin_lock_init(&events->pmu_lock); | ||
678 | } | ||
679 | armpmu->get_hw_events = armpmu_get_cpu_events; | ||
680 | armpmu->type = ARM_PMU_DEVICE_CPU; | ||
681 | } | ||
682 | |||
683 | /* | ||
684 | * PMU hardware loses all context when a CPU goes offline. | ||
685 | * When a CPU is hotplugged back in, since some hardware registers are | ||
686 | * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading | ||
687 | * junk values out of them. | ||
688 | */ | ||
689 | static int __cpuinit pmu_cpu_notify(struct notifier_block *b, | ||
690 | unsigned long action, void *hcpu) | ||
691 | { | ||
692 | if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING) | ||
693 | return NOTIFY_DONE; | ||
694 | |||
695 | if (cpu_pmu && cpu_pmu->reset) | ||
696 | cpu_pmu->reset(NULL); | ||
697 | |||
698 | return NOTIFY_OK; | ||
699 | } | ||
700 | |||
701 | static struct notifier_block __cpuinitdata pmu_cpu_notifier = { | ||
702 | .notifier_call = pmu_cpu_notify, | ||
703 | }; | ||
704 | |||
705 | /* | ||
706 | * CPU PMU identification and registration. | ||
707 | */ | ||
708 | static int __init | ||
709 | init_hw_perf_events(void) | ||
710 | { | ||
711 | unsigned long cpuid = read_cpuid_id(); | ||
712 | unsigned long implementor = (cpuid & 0xFF000000) >> 24; | ||
713 | unsigned long part_number = (cpuid & 0xFFF0); | ||
714 | |||
715 | /* ARM Ltd CPUs. */ | ||
716 | if (0x41 == implementor) { | ||
717 | switch (part_number) { | ||
718 | case 0xB360: /* ARM1136 */ | ||
719 | case 0xB560: /* ARM1156 */ | ||
720 | case 0xB760: /* ARM1176 */ | ||
721 | cpu_pmu = armv6pmu_init(); | ||
722 | break; | ||
723 | case 0xB020: /* ARM11mpcore */ | ||
724 | cpu_pmu = armv6mpcore_pmu_init(); | ||
725 | break; | ||
726 | case 0xC080: /* Cortex-A8 */ | ||
727 | cpu_pmu = armv7_a8_pmu_init(); | ||
728 | break; | ||
729 | case 0xC090: /* Cortex-A9 */ | ||
730 | cpu_pmu = armv7_a9_pmu_init(); | ||
731 | break; | ||
732 | case 0xC050: /* Cortex-A5 */ | ||
733 | cpu_pmu = armv7_a5_pmu_init(); | ||
734 | break; | ||
735 | case 0xC0F0: /* Cortex-A15 */ | ||
736 | cpu_pmu = armv7_a15_pmu_init(); | ||
737 | break; | ||
738 | case 0xC070: /* Cortex-A7 */ | ||
739 | cpu_pmu = armv7_a7_pmu_init(); | ||
740 | break; | ||
741 | } | ||
742 | /* Intel CPUs [xscale]. */ | ||
743 | } else if (0x69 == implementor) { | ||
744 | part_number = (cpuid >> 13) & 0x7; | ||
745 | switch (part_number) { | ||
746 | case 1: | ||
747 | cpu_pmu = xscale1pmu_init(); | ||
748 | break; | ||
749 | case 2: | ||
750 | cpu_pmu = xscale2pmu_init(); | ||
751 | break; | ||
752 | } | ||
753 | } | ||
754 | |||
755 | if (cpu_pmu) { | ||
756 | pr_info("enabled with %s PMU driver, %d counters available\n", | ||
757 | cpu_pmu->name, cpu_pmu->num_events); | ||
758 | cpu_pmu_init(cpu_pmu); | ||
759 | register_cpu_notifier(&pmu_cpu_notifier); | ||
760 | armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW); | ||
761 | } else { | ||
762 | pr_info("no hardware support available\n"); | ||
763 | } | ||
764 | |||
765 | return 0; | ||
766 | } | ||
767 | early_initcall(init_hw_perf_events); | ||
768 | |||
769 | /* | 524 | /* |
770 | * Callchain handling code. | 525 | * Callchain handling code. |
771 | */ | 526 | */ |