aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Rutland <mark.rutland@arm.com>2017-04-11 04:39:53 -0400
committerWill Deacon <will.deacon@arm.com>2017-04-11 11:29:54 -0400
commit18bfcfe51b8f60b69ab012888dea8061a9cd3381 (patch)
tree1b24520d4c02227265176bcb2a559baa84c862ef
parent3cf7ee98b8489fd2ff58374e3882a666f81d629f (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/Makefile2
-rw-r--r--drivers/perf/arm_pmu.c226
-rw-r--r--drivers/perf/arm_pmu_platform.c235
-rw-r--r--include/linux/perf/arm_pmu.h7
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 @@
1obj-$(CONFIG_ARM_PMU) += arm_pmu.o 1obj-$(CONFIG_ARM_PMU) += arm_pmu.o arm_pmu_platform.o
2obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o 2obj-$(CONFIG_QCOM_L2_PMU) += qcom_l2_pmu.o
3obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o 3obj-$(CONFIG_QCOM_L3_PMU) += qcom_l3_pmu.o
4obj-$(CONFIG_XGENE_PMU) += xgene_pmu.o 4obj-$(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
31static int 29static 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
547static void armpmu_free_irqs(struct arm_pmu *armpmu) 545void 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
592static int armpmu_request_irqs(struct arm_pmu *armpmu) 590int 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/* 784struct arm_pmu *armpmu_alloc(void)
787 * CPU PMU identification and probing.
788 */
789static 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
809static 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
824static bool pmu_has_irq_affinity(struct device_node *node)
825{
826 return !!of_find_property(node, "interrupt-affinity", NULL);
827}
828
829static 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
869static 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
940static 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
997static void armpmu_free(struct arm_pmu *pmu) 841void 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
1028int 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
1081out_free_irqs:
1082 armpmu_free_irqs(pmu);
1083out_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
1090static int arm_pmu_hp_init(void) 872static 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
24static 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
44static 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
59static bool pmu_has_irq_affinity(struct device_node *node)
60{
61 return !!of_find_property(node, "interrupt-affinity", NULL);
62}
63
64static 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
104static 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
175int 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
228out_free_irqs:
229 armpmu_free_irqs(pmu);
230out_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 */
163struct arm_pmu *armpmu_alloc(void);
164void armpmu_free(struct arm_pmu *pmu);
165int armpmu_register(struct arm_pmu *pmu);
166int armpmu_request_irqs(struct arm_pmu *armpmu);
167void 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 */