aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel/perf_event.c
diff options
context:
space:
mode:
authorWill Deacon <will.deacon@arm.com>2012-07-28 12:42:22 -0400
committerWill Deacon <will.deacon@arm.com>2012-08-23 06:35:52 -0400
commit04236f9fe07462849215c67cae6147661368bfad (patch)
treefef6161a18a418db56cb3acb6cae263c3af1f436 /arch/arm/kernel/perf_event.c
parent9f44f9a234020947dd16500a203c9580a66ed67d (diff)
ARM: perf: probe devicetree in preference to current CPU
The CPU PMU is probed using the current cpuid information as part of the early_initcall initialising the architecture perf backend. For architectures without NMI (such as ARM), this does not need to be performed early and can be deferred to the driver probe callback. This also allows us to probe the devicetree in preference to parsing the current cpuid, which may be invalid on a big.LITTLE multi-cluster system. This patch defers the PMU probing and uses the devicetree information when available. Signed-off-by: Will Deacon <will.deacon@arm.com>
Diffstat (limited to 'arch/arm/kernel/perf_event.c')
-rw-r--r--arch/arm/kernel/perf_event.c175
1 files changed, 91 insertions, 84 deletions
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 22ed5120a6ed..7c29914bdcc6 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -16,6 +16,7 @@
16#include <linux/interrupt.h> 16#include <linux/interrupt.h>
17#include <linux/kernel.h> 17#include <linux/kernel.h>
18#include <linux/export.h> 18#include <linux/export.h>
19#include <linux/of.h>
19#include <linux/perf_event.h> 20#include <linux/perf_event.h>
20#include <linux/platform_device.h> 21#include <linux/platform_device.h>
21#include <linux/spinlock.h> 22#include <linux/spinlock.h>
@@ -610,9 +611,11 @@ static void __init armpmu_init(struct arm_pmu *armpmu)
610 }; 611 };
611} 612}
612 613
613int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type) 614int armpmu_register(struct arm_pmu *armpmu, char *name, int type)
614{ 615{
615 armpmu_init(armpmu); 616 armpmu_init(armpmu);
617 pr_info("enabled with %s PMU driver, %d counters available\n",
618 armpmu->name, armpmu->num_events);
616 return perf_pmu_register(&armpmu->pmu, name, type); 619 return perf_pmu_register(&armpmu->pmu, name, type);
617} 620}
618 621
@@ -621,74 +624,12 @@ int __init armpmu_register(struct arm_pmu *armpmu, char *name, int type)
621#include "perf_event_v6.c" 624#include "perf_event_v6.c"
622#include "perf_event_v7.c" 625#include "perf_event_v7.c"
623 626
624/*
625 * Ensure the PMU has sane values out of reset.
626 * This requires SMP to be available, so exists as a separate initcall.
627 */
628static int __init
629cpu_pmu_reset(void)
630{
631 if (cpu_pmu && cpu_pmu->reset)
632 return on_each_cpu(cpu_pmu->reset, NULL, 1);
633 return 0;
634}
635arch_initcall(cpu_pmu_reset);
636
637/*
638 * PMU platform driver and devicetree bindings.
639 */
640static struct of_device_id armpmu_of_device_ids[] = {
641 {.compatible = "arm,cortex-a15-pmu"},
642 {.compatible = "arm,cortex-a9-pmu"},
643 {.compatible = "arm,cortex-a8-pmu"},
644 {.compatible = "arm,cortex-a7-pmu"},
645 {.compatible = "arm,cortex-a5-pmu"},
646 {.compatible = "arm,arm11mpcore-pmu"},
647 {.compatible = "arm,arm1176-pmu"},
648 {.compatible = "arm,arm1136-pmu"},
649 {},
650};
651
652static struct platform_device_id armpmu_plat_device_ids[] = {
653 {.name = "arm-pmu"},
654 {},
655};
656
657static int __devinit armpmu_device_probe(struct platform_device *pdev)
658{
659 if (!cpu_pmu)
660 return -ENODEV;
661
662 cpu_pmu->plat_device = pdev;
663 return 0;
664}
665
666static const struct dev_pm_ops armpmu_dev_pm_ops = {
667 SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
668};
669
670static struct platform_driver armpmu_driver = {
671 .driver = {
672 .name = "arm-pmu",
673 .pm = &armpmu_dev_pm_ops,
674 .of_match_table = armpmu_of_device_ids,
675 },
676 .probe = armpmu_device_probe,
677 .id_table = armpmu_plat_device_ids,
678};
679
680static int __init register_pmu_driver(void)
681{
682 return platform_driver_register(&armpmu_driver);
683}
684device_initcall(register_pmu_driver);
685
686static struct pmu_hw_events *armpmu_get_cpu_events(void) 627static struct pmu_hw_events *armpmu_get_cpu_events(void)
687{ 628{
688 return &__get_cpu_var(cpu_hw_events); 629 return &__get_cpu_var(cpu_hw_events);
689} 630}
690 631
691static void __init cpu_pmu_init(struct arm_pmu *armpmu) 632static void __devinit cpu_pmu_init(struct arm_pmu *cpu_pmu)
692{ 633{
693 int cpu; 634 int cpu;
694 for_each_possible_cpu(cpu) { 635 for_each_possible_cpu(cpu) {
@@ -697,7 +638,11 @@ static void __init cpu_pmu_init(struct arm_pmu *armpmu)
697 events->used_mask = per_cpu(used_mask, cpu); 638 events->used_mask = per_cpu(used_mask, cpu);
698 raw_spin_lock_init(&events->pmu_lock); 639 raw_spin_lock_init(&events->pmu_lock);
699 } 640 }
700 armpmu->get_hw_events = armpmu_get_cpu_events; 641 cpu_pmu->get_hw_events = armpmu_get_cpu_events;
642
643 /* Ensure the PMU has sane values out of reset. */
644 if (cpu_pmu && cpu_pmu->reset)
645 on_each_cpu(cpu_pmu->reset, NULL, 1);
701} 646}
702 647
703/* 648/*
@@ -722,41 +667,68 @@ static struct notifier_block __cpuinitdata pmu_cpu_notifier = {
722 .notifier_call = pmu_cpu_notify, 667 .notifier_call = pmu_cpu_notify,
723}; 668};
724 669
670static const struct dev_pm_ops armpmu_dev_pm_ops = {
671 SET_RUNTIME_PM_OPS(armpmu_runtime_suspend, armpmu_runtime_resume, NULL)
672};
673
674/*
675 * PMU platform driver and devicetree bindings.
676 */
677static struct of_device_id __devinitdata cpu_pmu_of_device_ids[] = {
678 {.compatible = "arm,cortex-a15-pmu", .data = armv7_a15_pmu_init},
679 {.compatible = "arm,cortex-a9-pmu", .data = armv7_a9_pmu_init},
680 {.compatible = "arm,cortex-a8-pmu", .data = armv7_a8_pmu_init},
681 {.compatible = "arm,cortex-a7-pmu", .data = armv7_a7_pmu_init},
682 {.compatible = "arm,cortex-a5-pmu", .data = armv7_a5_pmu_init},
683 {.compatible = "arm,arm11mpcore-pmu", .data = armv6mpcore_pmu_init},
684 {.compatible = "arm,arm1176-pmu", .data = armv6pmu_init},
685 {.compatible = "arm,arm1136-pmu", .data = armv6pmu_init},
686 {},
687};
688
689static struct platform_device_id __devinitdata cpu_pmu_plat_device_ids[] = {
690 {.name = "arm-pmu"},
691 {},
692};
693
725/* 694/*
726 * CPU PMU identification and registration. 695 * CPU PMU identification and probing.
727 */ 696 */
728static int __init 697static struct arm_pmu *__devinit probe_current_pmu(void)
729init_hw_perf_events(void)
730{ 698{
699 struct arm_pmu *pmu = NULL;
700 int cpu = get_cpu();
731 unsigned long cpuid = read_cpuid_id(); 701 unsigned long cpuid = read_cpuid_id();
732 unsigned long implementor = (cpuid & 0xFF000000) >> 24; 702 unsigned long implementor = (cpuid & 0xFF000000) >> 24;
733 unsigned long part_number = (cpuid & 0xFFF0); 703 unsigned long part_number = (cpuid & 0xFFF0);
734 704
705 pr_info("probing PMU on CPU %d\n", cpu);
706
735 /* ARM Ltd CPUs. */ 707 /* ARM Ltd CPUs. */
736 if (0x41 == implementor) { 708 if (0x41 == implementor) {
737 switch (part_number) { 709 switch (part_number) {
738 case 0xB360: /* ARM1136 */ 710 case 0xB360: /* ARM1136 */
739 case 0xB560: /* ARM1156 */ 711 case 0xB560: /* ARM1156 */
740 case 0xB760: /* ARM1176 */ 712 case 0xB760: /* ARM1176 */
741 cpu_pmu = armv6pmu_init(); 713 pmu = armv6pmu_init();
742 break; 714 break;
743 case 0xB020: /* ARM11mpcore */ 715 case 0xB020: /* ARM11mpcore */
744 cpu_pmu = armv6mpcore_pmu_init(); 716 pmu = armv6mpcore_pmu_init();
745 break; 717 break;
746 case 0xC080: /* Cortex-A8 */ 718 case 0xC080: /* Cortex-A8 */
747 cpu_pmu = armv7_a8_pmu_init(); 719 pmu = armv7_a8_pmu_init();
748 break; 720 break;
749 case 0xC090: /* Cortex-A9 */ 721 case 0xC090: /* Cortex-A9 */
750 cpu_pmu = armv7_a9_pmu_init(); 722 pmu = armv7_a9_pmu_init();
751 break; 723 break;
752 case 0xC050: /* Cortex-A5 */ 724 case 0xC050: /* Cortex-A5 */
753 cpu_pmu = armv7_a5_pmu_init(); 725 pmu = armv7_a5_pmu_init();
754 break; 726 break;
755 case 0xC0F0: /* Cortex-A15 */ 727 case 0xC0F0: /* Cortex-A15 */
756 cpu_pmu = armv7_a15_pmu_init(); 728 pmu = armv7_a15_pmu_init();
757 break; 729 break;
758 case 0xC070: /* Cortex-A7 */ 730 case 0xC070: /* Cortex-A7 */
759 cpu_pmu = armv7_a7_pmu_init(); 731 pmu = armv7_a7_pmu_init();
760 break; 732 break;
761 } 733 }
762 /* Intel CPUs [xscale]. */ 734 /* Intel CPUs [xscale]. */
@@ -764,27 +736,62 @@ init_hw_perf_events(void)
764 part_number = (cpuid >> 13) & 0x7; 736 part_number = (cpuid >> 13) & 0x7;
765 switch (part_number) { 737 switch (part_number) {
766 case 1: 738 case 1:
767 cpu_pmu = xscale1pmu_init(); 739 pmu = xscale1pmu_init();
768 break; 740 break;
769 case 2: 741 case 2:
770 cpu_pmu = xscale2pmu_init(); 742 pmu = xscale2pmu_init();
771 break; 743 break;
772 } 744 }
773 } 745 }
774 746
747 put_cpu();
748 return pmu;
749}
750
751static int __devinit cpu_pmu_device_probe(struct platform_device *pdev)
752{
753 const struct of_device_id *of_id;
754 struct arm_pmu *(*init_fn)(void);
755 struct device_node *node = pdev->dev.of_node;
756
775 if (cpu_pmu) { 757 if (cpu_pmu) {
776 pr_info("enabled with %s PMU driver, %d counters available\n", 758 pr_info("attempt to register multiple PMU devices!");
777 cpu_pmu->name, cpu_pmu->num_events); 759 return -ENOSPC;
778 cpu_pmu_init(cpu_pmu); 760 }
779 register_cpu_notifier(&pmu_cpu_notifier); 761
780 armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW); 762 if (node && (of_id = of_match_node(cpu_pmu_of_device_ids, pdev->dev.of_node))) {
763 init_fn = of_id->data;
764 cpu_pmu = init_fn();
781 } else { 765 } else {
782 pr_info("no hardware support available\n"); 766 cpu_pmu = probe_current_pmu();
783 } 767 }
784 768
769 if (!cpu_pmu)
770 return -ENODEV;
771
772 cpu_pmu->plat_device = pdev;
773 cpu_pmu_init(cpu_pmu);
774 register_cpu_notifier(&pmu_cpu_notifier);
775 armpmu_register(cpu_pmu, cpu_pmu->name, PERF_TYPE_RAW);
776
785 return 0; 777 return 0;
786} 778}
787early_initcall(init_hw_perf_events); 779
780static struct platform_driver cpu_pmu_driver = {
781 .driver = {
782 .name = "arm-pmu",
783 .pm = &armpmu_dev_pm_ops,
784 .of_match_table = cpu_pmu_of_device_ids,
785 },
786 .probe = cpu_pmu_device_probe,
787 .id_table = cpu_pmu_plat_device_ids,
788};
789
790static int __init register_pmu_driver(void)
791{
792 return platform_driver_register(&cpu_pmu_driver);
793}
794device_initcall(register_pmu_driver);
788 795
789/* 796/*
790 * Callchain handling code. 797 * Callchain handling code.