1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * cbe_regs.c |
4 | * |
5 | * Accessor routines for the various MMIO register blocks of the CBE |
6 | * |
7 | * (c) 2006 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. |
8 | */ |
9 | |
10 | #include <linux/percpu.h> |
11 | #include <linux/types.h> |
12 | #include <linux/export.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_address.h> |
15 | #include <linux/pgtable.h> |
16 | |
17 | #include <asm/io.h> |
18 | #include <asm/ptrace.h> |
19 | #include <asm/cell-regs.h> |
20 | |
21 | /* |
22 | * Current implementation uses "cpu" nodes. We build our own mapping |
23 | * array of cpu numbers to cpu nodes locally for now to allow interrupt |
24 | * time code to have a fast path rather than call of_get_cpu_node(). If |
25 | * we implement cpu hotplug, we'll have to install an appropriate notifier |
26 | * in order to release references to the cpu going away |
27 | */ |
28 | static struct cbe_regs_map |
29 | { |
30 | struct device_node *cpu_node; |
31 | struct device_node *be_node; |
32 | struct cbe_pmd_regs __iomem *pmd_regs; |
33 | struct cbe_iic_regs __iomem *iic_regs; |
34 | struct cbe_mic_tm_regs __iomem *mic_tm_regs; |
35 | struct cbe_pmd_shadow_regs pmd_shadow_regs; |
36 | } cbe_regs_maps[MAX_CBE]; |
37 | static int cbe_regs_map_count; |
38 | |
39 | static struct cbe_thread_map |
40 | { |
41 | struct device_node *cpu_node; |
42 | struct device_node *be_node; |
43 | struct cbe_regs_map *regs; |
44 | unsigned int thread_id; |
45 | unsigned int cbe_id; |
46 | } cbe_thread_map[NR_CPUS]; |
47 | |
48 | static cpumask_t cbe_local_mask[MAX_CBE] = { [0 ... MAX_CBE-1] = {CPU_BITS_NONE} }; |
49 | static cpumask_t cbe_first_online_cpu = { CPU_BITS_NONE }; |
50 | |
51 | static struct cbe_regs_map *cbe_find_map(struct device_node *np) |
52 | { |
53 | int i; |
54 | struct device_node *tmp_np; |
55 | |
56 | if (!of_node_is_type(np, type: "spe" )) { |
57 | for (i = 0; i < cbe_regs_map_count; i++) |
58 | if (cbe_regs_maps[i].cpu_node == np || |
59 | cbe_regs_maps[i].be_node == np) |
60 | return &cbe_regs_maps[i]; |
61 | return NULL; |
62 | } |
63 | |
64 | if (np->data) |
65 | return np->data; |
66 | |
67 | /* walk up path until cpu or be node was found */ |
68 | tmp_np = np; |
69 | do { |
70 | tmp_np = tmp_np->parent; |
71 | /* on a correct devicetree we wont get up to root */ |
72 | BUG_ON(!tmp_np); |
73 | } while (!of_node_is_type(np: tmp_np, type: "cpu" ) || |
74 | !of_node_is_type(np: tmp_np, type: "be" )); |
75 | |
76 | np->data = cbe_find_map(np: tmp_np); |
77 | |
78 | return np->data; |
79 | } |
80 | |
81 | struct cbe_pmd_regs __iomem *cbe_get_pmd_regs(struct device_node *np) |
82 | { |
83 | struct cbe_regs_map *map = cbe_find_map(np); |
84 | if (map == NULL) |
85 | return NULL; |
86 | return map->pmd_regs; |
87 | } |
88 | EXPORT_SYMBOL_GPL(cbe_get_pmd_regs); |
89 | |
90 | struct cbe_pmd_regs __iomem *cbe_get_cpu_pmd_regs(int cpu) |
91 | { |
92 | struct cbe_regs_map *map = cbe_thread_map[cpu].regs; |
93 | if (map == NULL) |
94 | return NULL; |
95 | return map->pmd_regs; |
96 | } |
97 | EXPORT_SYMBOL_GPL(cbe_get_cpu_pmd_regs); |
98 | |
99 | struct cbe_pmd_shadow_regs *cbe_get_pmd_shadow_regs(struct device_node *np) |
100 | { |
101 | struct cbe_regs_map *map = cbe_find_map(np); |
102 | if (map == NULL) |
103 | return NULL; |
104 | return &map->pmd_shadow_regs; |
105 | } |
106 | |
107 | struct cbe_pmd_shadow_regs *cbe_get_cpu_pmd_shadow_regs(int cpu) |
108 | { |
109 | struct cbe_regs_map *map = cbe_thread_map[cpu].regs; |
110 | if (map == NULL) |
111 | return NULL; |
112 | return &map->pmd_shadow_regs; |
113 | } |
114 | |
115 | struct cbe_iic_regs __iomem *cbe_get_iic_regs(struct device_node *np) |
116 | { |
117 | struct cbe_regs_map *map = cbe_find_map(np); |
118 | if (map == NULL) |
119 | return NULL; |
120 | return map->iic_regs; |
121 | } |
122 | |
123 | struct cbe_iic_regs __iomem *cbe_get_cpu_iic_regs(int cpu) |
124 | { |
125 | struct cbe_regs_map *map = cbe_thread_map[cpu].regs; |
126 | if (map == NULL) |
127 | return NULL; |
128 | return map->iic_regs; |
129 | } |
130 | |
131 | struct cbe_mic_tm_regs __iomem *cbe_get_mic_tm_regs(struct device_node *np) |
132 | { |
133 | struct cbe_regs_map *map = cbe_find_map(np); |
134 | if (map == NULL) |
135 | return NULL; |
136 | return map->mic_tm_regs; |
137 | } |
138 | |
139 | struct cbe_mic_tm_regs __iomem *cbe_get_cpu_mic_tm_regs(int cpu) |
140 | { |
141 | struct cbe_regs_map *map = cbe_thread_map[cpu].regs; |
142 | if (map == NULL) |
143 | return NULL; |
144 | return map->mic_tm_regs; |
145 | } |
146 | EXPORT_SYMBOL_GPL(cbe_get_cpu_mic_tm_regs); |
147 | |
148 | u32 cbe_get_hw_thread_id(int cpu) |
149 | { |
150 | return cbe_thread_map[cpu].thread_id; |
151 | } |
152 | EXPORT_SYMBOL_GPL(cbe_get_hw_thread_id); |
153 | |
154 | u32 cbe_cpu_to_node(int cpu) |
155 | { |
156 | return cbe_thread_map[cpu].cbe_id; |
157 | } |
158 | EXPORT_SYMBOL_GPL(cbe_cpu_to_node); |
159 | |
160 | u32 cbe_node_to_cpu(int node) |
161 | { |
162 | return cpumask_first(srcp: &cbe_local_mask[node]); |
163 | |
164 | } |
165 | EXPORT_SYMBOL_GPL(cbe_node_to_cpu); |
166 | |
167 | static struct device_node *__init cbe_get_be_node(int cpu_id) |
168 | { |
169 | struct device_node *np; |
170 | |
171 | for_each_node_by_type (np, "be" ) { |
172 | int len,i; |
173 | const phandle *cpu_handle; |
174 | |
175 | cpu_handle = of_get_property(node: np, name: "cpus" , lenp: &len); |
176 | |
177 | /* |
178 | * the CAB SLOF tree is non compliant, so we just assume |
179 | * there is only one node |
180 | */ |
181 | if (WARN_ON_ONCE(!cpu_handle)) |
182 | return np; |
183 | |
184 | for (i = 0; i < len; i++) { |
185 | struct device_node *ch_np = of_find_node_by_phandle(handle: cpu_handle[i]); |
186 | struct device_node *ci_np = of_get_cpu_node(cpu: cpu_id, NULL); |
187 | |
188 | of_node_put(node: ch_np); |
189 | of_node_put(node: ci_np); |
190 | |
191 | if (ch_np == ci_np) |
192 | return np; |
193 | } |
194 | } |
195 | |
196 | return NULL; |
197 | } |
198 | |
199 | static void __init cbe_fill_regs_map(struct cbe_regs_map *map) |
200 | { |
201 | if(map->be_node) { |
202 | struct device_node *be, *np, *parent_np; |
203 | |
204 | be = map->be_node; |
205 | |
206 | for_each_node_by_type(np, "pervasive" ) { |
207 | parent_np = of_get_parent(node: np); |
208 | if (parent_np == be) |
209 | map->pmd_regs = of_iomap(node: np, index: 0); |
210 | of_node_put(node: parent_np); |
211 | } |
212 | |
213 | for_each_node_by_type(np, "CBEA-Internal-Interrupt-Controller" ) { |
214 | parent_np = of_get_parent(node: np); |
215 | if (parent_np == be) |
216 | map->iic_regs = of_iomap(node: np, index: 2); |
217 | of_node_put(node: parent_np); |
218 | } |
219 | |
220 | for_each_node_by_type(np, "mic-tm" ) { |
221 | parent_np = of_get_parent(node: np); |
222 | if (parent_np == be) |
223 | map->mic_tm_regs = of_iomap(node: np, index: 0); |
224 | of_node_put(node: parent_np); |
225 | } |
226 | } else { |
227 | struct device_node *cpu; |
228 | /* That hack must die die die ! */ |
229 | const struct address_prop { |
230 | unsigned long address; |
231 | unsigned int len; |
232 | } __attribute__((packed)) *prop; |
233 | |
234 | cpu = map->cpu_node; |
235 | |
236 | prop = of_get_property(node: cpu, name: "pervasive" , NULL); |
237 | if (prop != NULL) |
238 | map->pmd_regs = ioremap(offset: prop->address, size: prop->len); |
239 | |
240 | prop = of_get_property(node: cpu, name: "iic" , NULL); |
241 | if (prop != NULL) |
242 | map->iic_regs = ioremap(offset: prop->address, size: prop->len); |
243 | |
244 | prop = of_get_property(node: cpu, name: "mic-tm" , NULL); |
245 | if (prop != NULL) |
246 | map->mic_tm_regs = ioremap(offset: prop->address, size: prop->len); |
247 | } |
248 | } |
249 | |
250 | |
251 | void __init cbe_regs_init(void) |
252 | { |
253 | int i; |
254 | unsigned int thread_id; |
255 | struct device_node *cpu; |
256 | |
257 | /* Build local fast map of CPUs */ |
258 | for_each_possible_cpu(i) { |
259 | cbe_thread_map[i].cpu_node = of_get_cpu_node(cpu: i, thread: &thread_id); |
260 | cbe_thread_map[i].be_node = cbe_get_be_node(cpu_id: i); |
261 | cbe_thread_map[i].thread_id = thread_id; |
262 | } |
263 | |
264 | /* Find maps for each device tree CPU */ |
265 | for_each_node_by_type(cpu, "cpu" ) { |
266 | struct cbe_regs_map *map; |
267 | unsigned int cbe_id; |
268 | |
269 | cbe_id = cbe_regs_map_count++; |
270 | map = &cbe_regs_maps[cbe_id]; |
271 | |
272 | if (cbe_regs_map_count > MAX_CBE) { |
273 | printk(KERN_ERR "cbe_regs: More BE chips than supported" |
274 | "!\n" ); |
275 | cbe_regs_map_count--; |
276 | of_node_put(node: cpu); |
277 | return; |
278 | } |
279 | of_node_put(node: map->cpu_node); |
280 | map->cpu_node = of_node_get(node: cpu); |
281 | |
282 | for_each_possible_cpu(i) { |
283 | struct cbe_thread_map *thread = &cbe_thread_map[i]; |
284 | |
285 | if (thread->cpu_node == cpu) { |
286 | thread->regs = map; |
287 | thread->cbe_id = cbe_id; |
288 | map->be_node = thread->be_node; |
289 | cpumask_set_cpu(cpu: i, dstp: &cbe_local_mask[cbe_id]); |
290 | if(thread->thread_id == 0) |
291 | cpumask_set_cpu(cpu: i, dstp: &cbe_first_online_cpu); |
292 | } |
293 | } |
294 | |
295 | cbe_fill_regs_map(map); |
296 | } |
297 | } |
298 | |
299 | |