diff options
author | Mark Rutland <mark.rutland@arm.com> | 2017-04-11 04:39:53 -0400 |
---|---|---|
committer | Will Deacon <will.deacon@arm.com> | 2017-04-11 11:29:54 -0400 |
commit | 18bfcfe51b8f60b69ab012888dea8061a9cd3381 (patch) | |
tree | 1b24520d4c02227265176bcb2a559baa84c862ef | |
parent | 3cf7ee98b8489fd2ff58374e3882a666f81d629f (diff) |
drivers/perf: arm_pmu: split out platform device probe logic
Now that we've split the pdev and DT probing logic from the runtime
management, let's move the former into its own file. We gain a few lines
due to the copyright header and includes, but this should keep the logic
clearly separated, and paves the way for adding ACPI support in a
similar fashion.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Jeremy Linton <jeremy.linton@arm.com>
[will: rename nr_irqs to avoid conflict with global variable]
Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r-- | drivers/perf/Makefile | 2 | ||||
-rw-r--r-- | drivers/perf/arm_pmu.c | 226 | ||||
-rw-r--r-- | drivers/perf/arm_pmu_platform.c | 235 | ||||
-rw-r--r-- | include/linux/perf/arm_pmu.h | 7 |
4 files changed, 247 insertions, 223 deletions
diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile index ef0c6b210345..925cd3903029 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile | |||
@@ -1,4 +1,4 @@ | |||
1 | obj-$(CONFIG_ARM_PMU) += arm_pmu.o | 1 | obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o |
2 | obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o | 2 | obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o |
3 | obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o | 3 | obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o |
4 | obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o | 4 | obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o |
diff --git a/drivers/perf/arm_pmu.c b/drivers/perf/arm_pmu.c index f387d6153099..b3bedfa512eb 100644 --- a/drivers/perf/arm_pmu.c +++ b/drivers/perf/arm_pmu.c | |||
@@ -16,7 +16,6 @@ | |||
16 | #include <linux/cpu_pm.h> | 16 | #include <linux/cpu_pm.h> |
17 | #include <linux/export.h> | 17 | #include <linux/export.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/of_device.h> | ||
20 | #include <linux/perf/arm_pmu.h> | 19 | #include <linux/perf/arm_pmu.h> |
21 | #include <linux/platform_device.h> | 20 | #include <linux/platform_device.h> |
22 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
@@ -25,7 +24,6 @@ | |||
25 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
26 | #include <linux/irqdesc.h> | 25 | #include <linux/irqdesc.h> |
27 | 26 | ||
28 | #include <asm/cputype.h> | ||
29 | #include <asm/irq_regs.h> | 27 | #include <asm/irq_regs.h> |
30 | 28 | ||
31 | static int | 29 | static int |
@@ -544,7 +542,7 @@ static void armpmu_free_irq(struct arm_pmu *armpmu, int cpu) | |||
544 | free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); | 542 | free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, cpu)); |
545 | } | 543 | } |
546 | 544 | ||
547 | static void armpmu_free_irqs(struct arm_pmu *armpmu) | 545 | void armpmu_free_irqs(struct arm_pmu *armpmu) |
548 | { | 546 | { |
549 | int cpu; | 547 | int cpu; |
550 | 548 | ||
@@ -589,7 +587,7 @@ static int armpmu_request_irq(struct arm_pmu *armpmu, int cpu) | |||
589 | return 0; | 587 | return 0; |
590 | } | 588 | } |
591 | 589 | ||
592 | static int armpmu_request_irqs(struct arm_pmu *armpmu) | 590 | int armpmu_request_irqs(struct arm_pmu *armpmu) |
593 | { | 591 | { |
594 | int cpu, err; | 592 | int cpu, err; |
595 | 593 | ||
@@ -783,161 +781,7 @@ static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu) | |||
783 | &cpu_pmu->node); | 781 | &cpu_pmu->node); |
784 | } | 782 | } |
785 | 783 | ||
786 | /* | 784 | struct arm_pmu *armpmu_alloc(void) |
787 | * CPU PMU identification and probing. | ||
788 | */ | ||
789 | static int probe_current_pmu(struct arm_pmu *pmu, | ||
790 | const struct pmu_probe_info *info) | ||
791 | { | ||
792 | int cpu = get_cpu(); | ||
793 | unsigned int cpuid = read_cpuid_id(); | ||
794 | int ret = -ENODEV; | ||
795 | |||
796 | pr_info("probing PMU on CPU %d\n", cpu); | ||
797 | |||
798 | for (; info->init != NULL; info++) { | ||
799 | if ((cpuid & info->mask) != info->cpuid) | ||
800 | continue; | ||
801 | ret = info->init(pmu); | ||
802 | break; | ||
803 | } | ||
804 | |||
805 | put_cpu(); | ||
806 | return ret; | ||
807 | } | ||
808 | |||
809 | static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq) | ||
810 | { | ||
811 | int cpu, ret; | ||
812 | struct pmu_hw_events __percpu *hw_events = pmu->hw_events; | ||
813 | |||
814 | ret = irq_get_percpu_devid_partition(irq, &pmu->supported_cpus); | ||
815 | if (ret) | ||
816 | return ret; | ||
817 | |||
818 | for_each_cpu(cpu, &pmu->supported_cpus) | ||
819 | per_cpu(hw_events->irq, cpu) = irq; | ||
820 | |||
821 | return 0; | ||
822 | } | ||
823 | |||
824 | static bool pmu_has_irq_affinity(struct device_node *node) | ||
825 | { | ||
826 | return !!of_find_property(node, "interrupt-affinity", NULL); | ||
827 | } | ||
828 | |||
829 | static int pmu_parse_irq_affinity(struct device_node *node, int i) | ||
830 | { | ||
831 | struct device_node *dn; | ||
832 | int cpu; | ||
833 | |||
834 | /* | ||
835 | * If we don't have an interrupt-affinity property, we guess irq | ||
836 | * affinity matches our logical CPU order, as we used to assume. | ||
837 | * This is fragile, so we'll warn in pmu_parse_irqs(). | ||
838 | */ | ||
839 | if (!pmu_has_irq_affinity(node)) | ||
840 | return i; | ||
841 | |||
842 | dn = of_parse_phandle(node, "interrupt-affinity", i); | ||
843 | if (!dn) { | ||
844 | pr_warn("failed to parse interrupt-affinity[%d] for %s\n", | ||
845 | i, node->name); | ||
846 | return -EINVAL; | ||
847 | } | ||
848 | |||
849 | /* Now look up the logical CPU number */ | ||
850 | for_each_possible_cpu(cpu) { | ||
851 | struct device_node *cpu_dn; | ||
852 | |||
853 | cpu_dn = of_cpu_device_node_get(cpu); | ||
854 | of_node_put(cpu_dn); | ||
855 | |||
856 | if (dn == cpu_dn) | ||
857 | break; | ||
858 | } | ||
859 | |||
860 | if (cpu >= nr_cpu_ids) { | ||
861 | pr_warn("failed to find logical CPU for %s\n", dn->name); | ||
862 | } | ||
863 | |||
864 | of_node_put(dn); | ||
865 | |||
866 | return cpu; | ||
867 | } | ||
868 | |||
869 | static int pmu_parse_irqs(struct arm_pmu *pmu) | ||
870 | { | ||
871 | int i = 0, irqs; | ||
872 | struct platform_device *pdev = pmu->plat_device; | ||
873 | struct pmu_hw_events __percpu *hw_events = pmu->hw_events; | ||
874 | |||
875 | irqs = platform_irq_count(pdev); | ||
876 | if (irqs < 0) { | ||
877 | pr_err("unable to count PMU IRQs\n"); | ||
878 | return irqs; | ||
879 | } | ||
880 | |||
881 | /* | ||
882 | * In this case we have no idea which CPUs are covered by the PMU. | ||
883 | * To match our prior behaviour, we assume all CPUs in this case. | ||
884 | */ | ||
885 | if (irqs == 0) { | ||
886 | pr_warn("no irqs for PMU, sampling events not supported\n"); | ||
887 | pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; | ||
888 | cpumask_setall(&pmu->supported_cpus); | ||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | if (irqs == 1) { | ||
893 | int irq = platform_get_irq(pdev, 0); | ||
894 | if (irq && irq_is_percpu(irq)) | ||
895 | return pmu_parse_percpu_irq(pmu, irq); | ||
896 | } | ||
897 | |||
898 | if (!pmu_has_irq_affinity(pdev->dev.of_node)) { | ||
899 | pr_warn("no interrupt-affinity property for %s, guessing.\n", | ||
900 | of_node_full_name(pdev->dev.of_node)); | ||
901 | } | ||
902 | |||
903 | /* | ||
904 | * Some platforms have all PMU IRQs OR'd into a single IRQ, with a | ||
905 | * special platdata function that attempts to demux them. | ||
906 | */ | ||
907 | if (dev_get_platdata(&pdev->dev)) | ||
908 | cpumask_setall(&pmu->supported_cpus); | ||
909 | |||
910 | for (i = 0; i < irqs; i++) { | ||
911 | int cpu, irq; | ||
912 | |||
913 | irq = platform_get_irq(pdev, i); | ||
914 | if (WARN_ON(irq <= 0)) | ||
915 | continue; | ||
916 | |||
917 | if (irq_is_percpu(irq)) { | ||
918 | pr_warn("multiple PPIs or mismatched SPI/PPI detected\n"); | ||
919 | return -EINVAL; | ||
920 | } | ||
921 | |||
922 | cpu = pmu_parse_irq_affinity(pdev->dev.of_node, i); | ||
923 | if (cpu < 0) | ||
924 | return cpu; | ||
925 | if (cpu >= nr_cpu_ids) | ||
926 | continue; | ||
927 | |||
928 | if (per_cpu(hw_events->irq, cpu)) { | ||
929 | pr_warn("multiple PMU IRQs for the same CPU detected\n"); | ||
930 | return -EINVAL; | ||
931 | } | ||
932 | |||
933 | per_cpu(hw_events->irq, cpu) = irq; | ||
934 | cpumask_set_cpu(cpu, &pmu->supported_cpus); | ||
935 | } | ||
936 | |||
937 | return 0; | ||
938 | } | ||
939 | |||
940 | static struct arm_pmu *armpmu_alloc(void) | ||
941 | { | 785 | { |
942 | struct arm_pmu *pmu; | 786 | struct arm_pmu *pmu; |
943 | int cpu; | 787 | int cpu; |
@@ -994,7 +838,7 @@ out: | |||
994 | return NULL; | 838 | return NULL; |
995 | } | 839 | } |
996 | 840 | ||
997 | static void armpmu_free(struct arm_pmu *pmu) | 841 | void armpmu_free(struct arm_pmu *pmu) |
998 | { | 842 | { |
999 | free_percpu(pmu->hw_events); | 843 | free_percpu(pmu->hw_events); |
1000 | kfree(pmu); | 844 | kfree(pmu); |
@@ -1025,68 +869,6 @@ out_destroy: | |||
1025 | return ret; | 869 | return ret; |
1026 | } | 870 | } |
1027 | 871 | ||
1028 | int arm_pmu_device_probe(struct platform_device *pdev, | ||
1029 | const struct of_device_id *of_table, | ||
1030 | const struct pmu_probe_info *probe_table) | ||
1031 | { | ||
1032 | const struct of_device_id *of_id; | ||
1033 | armpmu_init_fn init_fn; | ||
1034 | struct device_node *node = pdev->dev.of_node; | ||
1035 | struct arm_pmu *pmu; | ||
1036 | int ret = -ENODEV; | ||
1037 | |||
1038 | pmu = armpmu_alloc(); | ||
1039 | if (!pmu) | ||
1040 | return -ENOMEM; | ||
1041 | |||
1042 | pmu->plat_device = pdev; | ||
1043 | |||
1044 | ret = pmu_parse_irqs(pmu); | ||
1045 | if (ret) | ||
1046 | goto out_free; | ||
1047 | |||
1048 | if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { | ||
1049 | init_fn = of_id->data; | ||
1050 | |||
1051 | pmu->secure_access = of_property_read_bool(pdev->dev.of_node, | ||
1052 | "secure-reg-access"); | ||
1053 | |||
1054 | /* arm64 systems boot only as non-secure */ | ||
1055 | if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) { | ||
1056 | pr_warn("ignoring \"secure-reg-access\" property for arm64\n"); | ||
1057 | pmu->secure_access = false; | ||
1058 | } | ||
1059 | |||
1060 | ret = init_fn(pmu); | ||
1061 | } else if (probe_table) { | ||
1062 | cpumask_setall(&pmu->supported_cpus); | ||
1063 | ret = probe_current_pmu(pmu, probe_table); | ||
1064 | } | ||
1065 | |||
1066 | if (ret) { | ||
1067 | pr_info("%s: failed to probe PMU!\n", of_node_full_name(node)); | ||
1068 | goto out_free; | ||
1069 | } | ||
1070 | |||
1071 | ret = armpmu_request_irqs(pmu); | ||
1072 | if (ret) | ||
1073 | goto out_free_irqs; | ||
1074 | |||
1075 | ret = armpmu_register(pmu); | ||
1076 | if (ret) | ||
1077 | goto out_free; | ||
1078 | |||
1079 | return 0; | ||
1080 | |||
1081 | out_free_irqs: | ||
1082 | armpmu_free_irqs(pmu); | ||
1083 | out_free: | ||
1084 | pr_info("%s: failed to register PMU devices!\n", | ||
1085 | of_node_full_name(node)); | ||
1086 | armpmu_free(pmu); | ||
1087 | return ret; | ||
1088 | } | ||
1089 | |||
1090 | static int arm_pmu_hp_init(void) | 872 | static int arm_pmu_hp_init(void) |
1091 | { | 873 | { |
1092 | int ret; | 874 | int ret; |
diff --git a/drivers/perf/arm_pmu_platform.c b/drivers/perf/arm_pmu_platform.c new file mode 100644 index 000000000000..69255f53057a --- /dev/null +++ b/drivers/perf/arm_pmu_platform.c | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * platform_device probing code for ARM performance counters. | ||
3 | * | ||
4 | * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles | ||
5 | * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com> | ||
6 | */ | ||
7 | #define pr_fmt(fmt) "hw perfevents: " fmt | ||
8 | |||
9 | #include <linux/bug.h> | ||
10 | #include <linux/cpumask.h> | ||
11 | #include <linux/device.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/irq.h> | ||
14 | #include <linux/irqdesc.h> | ||
15 | #include <linux/kconfig.h> | ||
16 | #include <linux/of.h> | ||
17 | #include <linux/of_device.h> | ||
18 | #include <linux/percpu.h> | ||
19 | #include <linux/perf/arm_pmu.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | #include <linux/printk.h> | ||
22 | #include <linux/smp.h> | ||
23 | |||
24 | static int probe_current_pmu(struct arm_pmu *pmu, | ||
25 | const struct pmu_probe_info *info) | ||
26 | { | ||
27 | int cpu = get_cpu(); | ||
28 | unsigned int cpuid = read_cpuid_id(); | ||
29 | int ret = -ENODEV; | ||
30 | |||
31 | pr_info("probing PMU on CPU %d\n", cpu); | ||
32 | |||
33 | for (; info->init != NULL; info++) { | ||
34 | if ((cpuid & info->mask) != info->cpuid) | ||
35 | continue; | ||
36 | ret = info->init(pmu); | ||
37 | break; | ||
38 | } | ||
39 | |||
40 | put_cpu(); | ||
41 | return ret; | ||
42 | } | ||
43 | |||
44 | static int pmu_parse_percpu_irq(struct arm_pmu *pmu, int irq) | ||
45 | { | ||
46 | int cpu, ret; | ||
47 | struct pmu_hw_events __percpu *hw_events = pmu->hw_events; | ||
48 | |||
49 | ret = irq_get_percpu_devid_partition(irq, &pmu->supported_cpus); | ||
50 | if (ret) | ||
51 | return ret; | ||
52 | |||
53 | for_each_cpu(cpu, &pmu->supported_cpus) | ||
54 | per_cpu(hw_events->irq, cpu) = irq; | ||
55 | |||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | static bool pmu_has_irq_affinity(struct device_node *node) | ||
60 | { | ||
61 | return !!of_find_property(node, "interrupt-affinity", NULL); | ||
62 | } | ||
63 | |||
64 | static int pmu_parse_irq_affinity(struct device_node *node, int i) | ||
65 | { | ||
66 | struct device_node *dn; | ||
67 | int cpu; | ||
68 | |||
69 | /* | ||
70 | * If we don't have an interrupt-affinity property, we guess irq | ||
71 | * affinity matches our logical CPU order, as we used to assume. | ||
72 | * This is fragile, so we'll warn in pmu_parse_irqs(). | ||
73 | */ | ||
74 | if (!pmu_has_irq_affinity(node)) | ||
75 | return i; | ||
76 | |||
77 | dn = of_parse_phandle(node, "interrupt-affinity", i); | ||
78 | if (!dn) { | ||
79 | pr_warn("failed to parse interrupt-affinity[%d] for %s\n", | ||
80 | i, node->name); | ||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | /* Now look up the logical CPU number */ | ||
85 | for_each_possible_cpu(cpu) { | ||
86 | struct device_node *cpu_dn; | ||
87 | |||
88 | cpu_dn = of_cpu_device_node_get(cpu); | ||
89 | of_node_put(cpu_dn); | ||
90 | |||
91 | if (dn == cpu_dn) | ||
92 | break; | ||
93 | } | ||
94 | |||
95 | if (cpu >= nr_cpu_ids) { | ||
96 | pr_warn("failed to find logical CPU for %s\n", dn->name); | ||
97 | } | ||
98 | |||
99 | of_node_put(dn); | ||
100 | |||
101 | return cpu; | ||
102 | } | ||
103 | |||
104 | static int pmu_parse_irqs(struct arm_pmu *pmu) | ||
105 | { | ||
106 | int i = 0, num_irqs; | ||
107 | struct platform_device *pdev = pmu->plat_device; | ||
108 | struct pmu_hw_events __percpu *hw_events = pmu->hw_events; | ||
109 | |||
110 | num_irqs = platform_irq_count(pdev); | ||
111 | if (num_irqs < 0) { | ||
112 | pr_err("unable to count PMU IRQs\n"); | ||
113 | return num_irqs; | ||
114 | } | ||
115 | |||
116 | /* | ||
117 | * In this case we have no idea which CPUs are covered by the PMU. | ||
118 | * To match our prior behaviour, we assume all CPUs in this case. | ||
119 | */ | ||
120 | if (num_irqs == 0) { | ||
121 | pr_warn("no irqs for PMU, sampling events not supported\n"); | ||
122 | pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT; | ||
123 | cpumask_setall(&pmu->supported_cpus); | ||
124 | return 0; | ||
125 | } | ||
126 | |||
127 | if (num_irqs == 1) { | ||
128 | int irq = platform_get_irq(pdev, 0); | ||
129 | if (irq && irq_is_percpu(irq)) | ||
130 | return pmu_parse_percpu_irq(pmu, irq); | ||
131 | } | ||
132 | |||
133 | if (!pmu_has_irq_affinity(pdev->dev.of_node)) { | ||
134 | pr_warn("no interrupt-affinity property for %s, guessing.\n", | ||
135 | of_node_full_name(pdev->dev.of_node)); | ||
136 | } | ||
137 | |||
138 | /* | ||
139 | * Some platforms have all PMU IRQs OR'd into a single IRQ, with a | ||
140 | * special platdata function that attempts to demux them. | ||
141 | */ | ||
142 | if (dev_get_platdata(&pdev->dev)) | ||
143 | cpumask_setall(&pmu->supported_cpus); | ||
144 | |||
145 | for (i = 0; i < num_irqs; i++) { | ||
146 | int cpu, irq; | ||
147 | |||
148 | irq = platform_get_irq(pdev, i); | ||
149 | if (WARN_ON(irq <= 0)) | ||
150 | continue; | ||
151 | |||
152 | if (irq_is_percpu(irq)) { | ||
153 | pr_warn("multiple PPIs or mismatched SPI/PPI detected\n"); | ||
154 | return -EINVAL; | ||
155 | } | ||
156 | |||
157 | cpu = pmu_parse_irq_affinity(pdev->dev.of_node, i); | ||
158 | if (cpu < 0) | ||
159 | return cpu; | ||
160 | if (cpu >= nr_cpu_ids) | ||
161 | continue; | ||
162 | |||
163 | if (per_cpu(hw_events->irq, cpu)) { | ||
164 | pr_warn("multiple PMU IRQs for the same CPU detected\n"); | ||
165 | return -EINVAL; | ||
166 | } | ||
167 | |||
168 | per_cpu(hw_events->irq, cpu) = irq; | ||
169 | cpumask_set_cpu(cpu, &pmu->supported_cpus); | ||
170 | } | ||
171 | |||
172 | return 0; | ||
173 | } | ||
174 | |||
175 | int arm_pmu_device_probe(struct platform_device *pdev, | ||
176 | const struct of_device_id *of_table, | ||
177 | const struct pmu_probe_info *probe_table) | ||
178 | { | ||
179 | const struct of_device_id *of_id; | ||
180 | armpmu_init_fn init_fn; | ||
181 | struct device_node *node = pdev->dev.of_node; | ||
182 | struct arm_pmu *pmu; | ||
183 | int ret = -ENODEV; | ||
184 | |||
185 | pmu = armpmu_alloc(); | ||
186 | if (!pmu) | ||
187 | return -ENOMEM; | ||
188 | |||
189 | pmu->plat_device = pdev; | ||
190 | |||
191 | ret = pmu_parse_irqs(pmu); | ||
192 | if (ret) | ||
193 | goto out_free; | ||
194 | |||
195 | if (node && (of_id = of_match_node(of_table, pdev->dev.of_node))) { | ||
196 | init_fn = of_id->data; | ||
197 | |||
198 | pmu->secure_access = of_property_read_bool(pdev->dev.of_node, | ||
199 | "secure-reg-access"); | ||
200 | |||
201 | /* arm64 systems boot only as non-secure */ | ||
202 | if (IS_ENABLED(CONFIG_ARM64) && pmu->secure_access) { | ||
203 | pr_warn("ignoring \"secure-reg-access\" property for arm64\n"); | ||
204 | pmu->secure_access = false; | ||
205 | } | ||
206 | |||
207 | ret = init_fn(pmu); | ||
208 | } else if (probe_table) { | ||
209 | cpumask_setall(&pmu->supported_cpus); | ||
210 | ret = probe_current_pmu(pmu, probe_table); | ||
211 | } | ||
212 | |||
213 | if (ret) { | ||
214 | pr_info("%s: failed to probe PMU!\n", of_node_full_name(node)); | ||
215 | goto out_free; | ||
216 | } | ||
217 | |||
218 | ret = armpmu_request_irqs(pmu); | ||
219 | if (ret) | ||
220 | goto out_free_irqs; | ||
221 | |||
222 | ret = armpmu_register(pmu); | ||
223 | if (ret) | ||
224 | goto out_free; | ||
225 | |||
226 | return 0; | ||
227 | |||
228 | out_free_irqs: | ||
229 | armpmu_free_irqs(pmu); | ||
230 | out_free: | ||
231 | pr_info("%s: failed to register PMU devices!\n", | ||
232 | of_node_full_name(node)); | ||
233 | armpmu_free(pmu); | ||
234 | return ret; | ||
235 | } | ||
diff --git a/include/linux/perf/arm_pmu.h b/include/linux/perf/arm_pmu.h index 4249914315a4..25556ebb1c7b 100644 --- a/include/linux/perf/arm_pmu.h +++ b/include/linux/perf/arm_pmu.h | |||
@@ -159,6 +159,13 @@ int arm_pmu_device_probe(struct platform_device *pdev, | |||
159 | const struct of_device_id *of_table, | 159 | const struct of_device_id *of_table, |
160 | const struct pmu_probe_info *probe_table); | 160 | const struct pmu_probe_info *probe_table); |
161 | 161 | ||
162 | /* Internal functions only for core arm_pmu code */ | ||
163 | struct arm_pmu *armpmu_alloc(void); | ||
164 | void armpmu_free(struct arm_pmu *pmu); | ||
165 | int armpmu_register(struct arm_pmu *pmu); | ||
166 | int armpmu_request_irqs(struct arm_pmu *armpmu); | ||
167 | void armpmu_free_irqs(struct arm_pmu *armpmu); | ||
168 | |||
162 | #define ARMV8_PMU_PDEV_NAME "armv8-pmu" | 169 | #define ARMV8_PMU_PDEV_NAME "armv8-pmu" |
163 | 170 | ||
164 | #endif /* CONFIG_ARM_PMU */ | 171 | #endif /* CONFIG_ARM_PMU */ |