diff options
-rw-r--r-- | drivers/perf/arm_pmu.c | 53 | ||||
-rw-r--r-- | include/linux/perf/arm_pmu.h | 1 |
2 files changed, 38 insertions, 16 deletions
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index ae9fc6c6add3..f6ab4f7f75bf 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c | |||
@@ -685,6 +685,9 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) | |||
685 | return 0; | 685 | return 0; |
686 | } | 686 | } |
687 | 687 | ||
688 | static DEFINE_MUTEX(arm_pmu_mutex); | ||
689 | static LIST_HEAD(arm_pmu_list); | ||
690 | |||
688 | /* | 691 | /* |
689 | * PMU hardware loses all context when a CPU goes offline. | 692 | * PMU hardware loses all context when a CPU goes offline. |
690 | * When a CPU is hotplugged back in, since some hardware registers are | 693 | * When a CPU is hotplugged back in, since some hardware registers are |
@@ -693,12 +696,17 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler) | |||
693 | */ | 696 | */ |
694 | static int arm_perf_starting_cpu(unsigned int cpu) | 697 | static int arm_perf_starting_cpu(unsigned int cpu) |
695 | { | 698 | { |
696 | if (!__oprofile_cpu_pmu) | 699 | struct arm_pmu *pmu; |
697 | return 0; | 700 | |
698 | if (!cpumask_test_cpu(cpu, &__oprofile_cpu_pmu->supported_cpus)) | 701 | mutex_lock(&arm_pmu_mutex); |
699 | return 0; | 702 | list_for_each_entry(pmu, &arm_pmu_list, entry) { |
700 | if (__oprofile_cpu_pmu->reset) | 703 | |
701 | __oprofile_cpu_pmu->reset(__oprofile_cpu_pmu); | 704 | if (!cpumask_test_cpu(cpu, &pmu->supported_cpus)) |
705 | continue; | ||
706 | if (pmu->reset) | ||
707 | pmu->reset(pmu); | ||
708 | } | ||
709 | mutex_unlock(&arm_pmu_mutex); | ||
702 | return 0; | 710 | return 0; |
703 | } | 711 | } |
704 | 712 | ||
@@ -810,11 +818,9 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) | |||
810 | if (!cpu_hw_events) | 818 | if (!cpu_hw_events) |
811 | return -ENOMEM; | 819 | return -ENOMEM; |
812 | 820 | ||
813 | err = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_STARTING, | 821 | mutex_lock(&arm_pmu_mutex); |
814 | "AP_PERF_ARM_STARTING", | 822 | list_add_tail(&cpu_pmu->entry, &arm_pmu_list); |
815 | arm_perf_starting_cpu, NULL); | 823 | mutex_unlock(&arm_pmu_mutex); |
816 | if (err) | ||
817 | goto out_hw_events; | ||
818 | 824 | ||
819 | err = cpu_pm_pmu_register(cpu_pmu); | 825 | err = cpu_pm_pmu_register(cpu_pmu); |
820 | if (err) | 826 | if (err) |
@@ -850,8 +856,9 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu) | |||
850 | return 0; | 856 | return 0; |
851 | 857 | ||
852 | out_unregister: | 858 | out_unregister: |
853 | cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_STARTING); | 859 | mutex_lock(&arm_pmu_mutex); |
854 | out_hw_events: | 860 | list_del(&cpu_pmu->entry); |
861 | mutex_unlock(&arm_pmu_mutex); | ||
855 | free_percpu(cpu_hw_events); | 862 | free_percpu(cpu_hw_events); |
856 | return err; | 863 | return err; |
857 | } | 864 | } |
@@ -859,7 +866,9 @@ out_hw_events: | |||
859 | static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) | 866 | static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) |
860 | { | 867 | { |
861 | cpu_pm_pmu_unregister(cpu_pmu); | 868 | cpu_pm_pmu_unregister(cpu_pmu); |
862 | cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_STARTING); | 869 | mutex_lock(&arm_pmu_mutex); |
870 | list_del(&cpu_pmu->entry); | ||
871 | mutex_unlock(&arm_pmu_mutex); | ||
863 | free_percpu(cpu_pmu->hw_events); | 872 | free_percpu(cpu_pmu->hw_events); |
864 | } | 873 | } |
865 | 874 | ||
@@ -1019,8 +1028,6 @@ int arm_pmu_device_probe(struct platform_device *pdev, | |||
1019 | if (ret) | 1028 | if (ret) |
1020 | goto out_destroy; | 1029 | goto out_destroy; |
1021 | 1030 | ||
1022 | WARN(__oprofile_cpu_pmu, "%s(): missing PMU strucure for CPU-hotplug\n", | ||
1023 | __func__); | ||
1024 | if (!__oprofile_cpu_pmu) | 1031 | if (!__oprofile_cpu_pmu) |
1025 | __oprofile_cpu_pmu = pmu; | 1032 | __oprofile_cpu_pmu = pmu; |
1026 | 1033 | ||
@@ -1038,3 +1045,17 @@ out_free: | |||
1038 | kfree(pmu); | 1045 | kfree(pmu); |
1039 | return ret; | 1046 | return ret; |
1040 | } | 1047 | } |
1048 | |||
1049 | static int arm_pmu_hp_init(void) | ||
1050 | { | ||
1051 | int ret; | ||
1052 | |||
1053 | ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_STARTING, | ||
1054 | "AP_PERF_ARM_STARTING", | ||
1055 | arm_perf_starting_cpu, NULL); | ||
1056 | if (ret) | ||
1057 | pr_err("CPU hotplug notifier for ARM PMU could not be registered: %d\n", | ||
1058 | ret); | ||
1059 | return ret; | ||
1060 | } | ||
1061 | subsys_initcall(arm_pmu_hp_init); | ||
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h index e6ed34eb2b2b..e18843809eec 100644 --- a/include/linux/perf/arm_pmu.h +++ b/include/linux/perf/arm_pmu.h | |||
@@ -109,6 +109,7 @@ struct arm_pmu { | |||
109 | DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS); | 109 | DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS); |
110 | struct platform_device *plat_device; | 110 | struct platform_device *plat_device; |
111 | struct pmu_hw_events __percpu *hw_events; | 111 | struct pmu_hw_events __percpu *hw_events; |
112 | struct list_head entry; | ||
112 | struct notifier_block cpu_pm_nb; | 113 | struct notifier_block cpu_pm_nb; |
113 | }; | 114 | }; |
114 | 115 | ||