aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom_parse.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-23 01:53:42 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:49:46 -0500
commitd1405b869850982f05c7ec0d3f137ca27588192f (patch)
treeb95b4e6e36f654205ad720609734a5b2ca549de0 /arch/powerpc/kernel/prom_parse.c
parentbcb05504edf0e27a648aa1059cbb71e8746758a1 (diff)
[PATCH] powerpc: Add OF address parsing code (#2)
Parsing addresses extracted from Open Firmware isn't a simple matter. We have various bits of code that try to do it in various place, including some heuristics in prom.c that pre-parse addresses at boot and fill device-nodes "addrs", but those are dodgy at best and I want to deprecate them. So this patch introduces a new set of routines that should be capable of parsing most types of addresses and translating them into CPU physical addresses. It currently works for things on PCI busses and ISA busses and should work on "standard" busses like the root bus or the MacIO bus that don't put funky flags in addresses. If you have other bus types that do use funky flags, you'll have to add new bus type translators, which is fairly easy. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom_parse.c')
-rw-r--r--arch/powerpc/kernel/prom_parse.c420
1 files changed, 420 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
new file mode 100644
index 000000000000..9c2a5be7a56a
--- /dev/null
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -0,0 +1,420 @@
1#undef DEBUG
2
3#include <linux/kernel.h>
4#include <linux/string.h>
5#include <linux/pci_regs.h>
6#include <linux/module.h>
7#include <asm/prom.h>
8
9#ifdef DEBUG
10#define DBG(fmt...) do { printk(fmt); } while(0)
11#else
12#define DBG(fmt...) do { } while(0)
13#endif
14
15#ifdef CONFIG_PPC64
16#define PRu64 "%lx"
17#else
18#define PRu64 "%llx"
19#endif
20
21/* Max address size we deal with */
22#define OF_MAX_ADDR_CELLS 4
23#define OF_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS && \
24 (ns) > 0)
25
26/* Debug utility */
27#ifdef DEBUG
28static void of_dump_addr(const char *s, u32 *addr, int na)
29{
30 printk("%s", s);
31 while(na--)
32 printk(" %08x", *(addr++));
33 printk("\n");
34}
35#else
36static void of_dump_addr(const char *s, u32 *addr, int na) { }
37#endif
38
39/* Read a big address */
40static inline u64 of_read_addr(u32 *cell, int size)
41{
42 u64 r = 0;
43 while (size--)
44 r = (r << 32) | *(cell++);
45 return r;
46}
47
48/* Callbacks for bus specific translators */
49struct of_bus {
50 const char *name;
51 const char *addresses;
52 int (*match)(struct device_node *parent);
53 void (*count_cells)(struct device_node *child,
54 int *addrc, int *sizec);
55 u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
56 int (*translate)(u32 *addr, u64 offset, int na);
57};
58
59
60/*
61 * Default translator (generic bus)
62 */
63
64static void of_default_count_cells(struct device_node *dev,
65 int *addrc, int *sizec)
66{
67 if (addrc)
68 *addrc = prom_n_addr_cells(dev);
69 if (sizec)
70 *sizec = prom_n_size_cells(dev);
71}
72
73static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
74{
75 u64 cp, s, da;
76
77 cp = of_read_addr(range, na);
78 s = of_read_addr(range + na + pna, ns);
79 da = of_read_addr(addr, na);
80
81 DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
82 cp, s, da);
83
84 if (da < cp || da >= (cp + s))
85 return OF_BAD_ADDR;
86 return da - cp;
87}
88
89static int of_default_translate(u32 *addr, u64 offset, int na)
90{
91 u64 a = of_read_addr(addr, na);
92 memset(addr, 0, na * 4);
93 a += offset;
94 if (na > 1)
95 addr[na - 2] = a >> 32;
96 addr[na - 1] = a & 0xffffffffu;
97
98 return 0;
99}
100
101
102/*
103 * PCI bus specific translator
104 */
105
106static int of_bus_pci_match(struct device_node *np)
107{
108 return !strcmp(np->type, "pci");
109}
110
111static void of_bus_pci_count_cells(struct device_node *np,
112 int *addrc, int *sizec)
113{
114 if (addrc)
115 *addrc = 3;
116 if (sizec)
117 *sizec = 2;
118}
119
120static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
121{
122 u64 cp, s, da;
123
124 /* Check address type match */
125 if ((addr[0] ^ range[0]) & 0x03000000)
126 return OF_BAD_ADDR;
127
128 /* Read address values, skipping high cell */
129 cp = of_read_addr(range + 1, na - 1);
130 s = of_read_addr(range + na + pna, ns);
131 da = of_read_addr(addr + 1, na - 1);
132
133 DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
134
135 if (da < cp || da >= (cp + s))
136 return OF_BAD_ADDR;
137 return da - cp;
138}
139
140static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
141{
142 return of_default_translate(addr + 1, offset, na - 1);
143}
144
145/*
146 * ISA bus specific translator
147 */
148
149static int of_bus_isa_match(struct device_node *np)
150{
151 return !strcmp(np->name, "isa");
152}
153
154static void of_bus_isa_count_cells(struct device_node *child,
155 int *addrc, int *sizec)
156{
157 if (addrc)
158 *addrc = 2;
159 if (sizec)
160 *sizec = 1;
161}
162
163static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
164{
165 u64 cp, s, da;
166
167 /* Check address type match */
168 if ((addr[0] ^ range[0]) & 0x00000001)
169 return OF_BAD_ADDR;
170
171 /* Read address values, skipping high cell */
172 cp = of_read_addr(range + 1, na - 1);
173 s = of_read_addr(range + na + pna, ns);
174 da = of_read_addr(addr + 1, na - 1);
175
176 DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
177
178 if (da < cp || da >= (cp + s))
179 return OF_BAD_ADDR;
180 return da - cp;
181}
182
183static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
184{
185 return of_default_translate(addr + 1, offset, na - 1);
186}
187
188/*
189 * Array of bus specific translators
190 */
191
192static struct of_bus of_busses[] = {
193 /* PCI */
194 {
195 .name = "pci",
196 .addresses = "assigned-addresses",
197 .match = of_bus_pci_match,
198 .count_cells = of_bus_pci_count_cells,
199 .map = of_bus_pci_map,
200 .translate = of_bus_pci_translate,
201 },
202 /* ISA */
203 {
204 .name = "isa",
205 .addresses = "reg",
206 .match = of_bus_isa_match,
207 .count_cells = of_bus_isa_count_cells,
208 .map = of_bus_isa_map,
209 .translate = of_bus_isa_translate,
210 },
211 /* Default */
212 {
213 .name = "default",
214 .addresses = "reg",
215 .match = NULL,
216 .count_cells = of_default_count_cells,
217 .map = of_default_map,
218 .translate = of_default_translate,
219 },
220};
221
222static struct of_bus *of_match_bus(struct device_node *np)
223{
224 int i;
225
226 for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
227 if (!of_busses[i].match || of_busses[i].match(np))
228 return &of_busses[i];
229 BUG();
230 return NULL;
231}
232
233static int of_translate_one(struct device_node *parent, struct of_bus *bus,
234 struct of_bus *pbus, u32 *addr,
235 int na, int ns, int pna)
236{
237 u32 *ranges;
238 unsigned int rlen;
239 int rone;
240 u64 offset = OF_BAD_ADDR;
241
242 /* Normally, an absence of a "ranges" property means we are
243 * crossing a non-translatable boundary, and thus the addresses
244 * below the current not cannot be converted to CPU physical ones.
245 * Unfortunately, while this is very clear in the spec, it's not
246 * what Apple understood, and they do have things like /uni-n or
247 * /ht nodes with no "ranges" property and a lot of perfectly
248 * useable mapped devices below them. Thus we treat the absence of
249 * "ranges" as equivalent to an empty "ranges" property which means
250 * a 1:1 translation at that level. It's up to the caller not to try
251 * to translate addresses that aren't supposed to be translated in
252 * the first place. --BenH.
253 */
254 ranges = (u32 *)get_property(parent, "ranges", &rlen);
255 if (ranges == NULL || rlen == 0) {
256 offset = of_read_addr(addr, na);
257 memset(addr, 0, pna);
258 goto finish;
259 }
260
261 DBG("OF: walking ranges...\n");
262
263 /* Now walk through the ranges */
264 rlen /= 4;
265 rone = na + pna + ns;
266 for (; rlen >= rone; rlen -= rone, ranges += rone) {
267 offset = bus->map(addr, ranges, na, ns, pna);
268 if (offset != OF_BAD_ADDR)
269 break;
270 }
271 if (offset == OF_BAD_ADDR) {
272 DBG("OF: not found !\n");
273 return 1;
274 }
275 memcpy(addr, ranges + na, 4 * pna);
276
277 finish:
278 of_dump_addr("OF: parent translation for:", addr, pna);
279 DBG("OF: with offset: %lx\n", offset);
280
281 /* Translate it into parent bus space */
282 return pbus->translate(addr, offset, pna);
283}
284
285
286/*
287 * Translate an address from the device-tree into a CPU physical address,
288 * this walks up the tree and applies the various bus mappings on the
289 * way.
290 *
291 * Note: We consider that crossing any level with #size-cells == 0 to mean
292 * that translation is impossible (that is we are not dealing with a value
293 * that can be mapped to a cpu physical address). This is not really specified
294 * that way, but this is traditionally the way IBM at least do things
295 */
296u64 of_translate_address(struct device_node *dev, u32 *in_addr)
297{
298 struct device_node *parent = NULL;
299 struct of_bus *bus, *pbus;
300 u32 addr[OF_MAX_ADDR_CELLS];
301 int na, ns, pna, pns;
302 u64 result = OF_BAD_ADDR;
303
304 DBG("OF: ** translation for device %s **\n", dev->full_name);
305
306 /* Increase refcount at current level */
307 of_node_get(dev);
308
309 /* Get parent & match bus type */
310 parent = of_get_parent(dev);
311 if (parent == NULL)
312 goto bail;
313 bus = of_match_bus(parent);
314
315 /* Cound address cells & copy address locally */
316 bus->count_cells(dev, &na, &ns);
317 if (!OF_CHECK_COUNTS(na, ns)) {
318 printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
319 dev->full_name);
320 goto bail;
321 }
322 memcpy(addr, in_addr, na * 4);
323
324 DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
325 bus->name, na, ns, parent->full_name);
326 of_dump_addr("OF: translating address:", addr, na);
327
328 /* Translate */
329 for (;;) {
330 /* Switch to parent bus */
331 of_node_put(dev);
332 dev = parent;
333 parent = of_get_parent(dev);
334
335 /* If root, we have finished */
336 if (parent == NULL) {
337 DBG("OF: reached root node\n");
338 result = of_read_addr(addr, na);
339 break;
340 }
341
342 /* Get new parent bus and counts */
343 pbus = of_match_bus(parent);
344 pbus->count_cells(dev, &pna, &pns);
345 if (!OF_CHECK_COUNTS(pna, pns)) {
346 printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
347 dev->full_name);
348 break;
349 }
350
351 DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
352 pbus->name, pna, pns, parent->full_name);
353
354 /* Apply bus translation */
355 if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
356 break;
357
358 /* Complete the move up one level */
359 na = pna;
360 ns = pns;
361 bus = pbus;
362
363 of_dump_addr("OF: one level translation:", addr, na);
364 }
365 bail:
366 of_node_put(parent);
367 of_node_put(dev);
368
369 return result;
370}
371EXPORT_SYMBOL(of_translate_address);
372
373u32 *of_get_address(struct device_node *dev, int index, u64 *size)
374{
375 u32 *prop;
376 unsigned int psize;
377 struct device_node *parent;
378 struct of_bus *bus;
379 int onesize, i, na, ns;
380
381 /* Get parent & match bus type */
382 parent = of_get_parent(dev);
383 if (parent == NULL)
384 return NULL;
385 bus = of_match_bus(parent);
386 bus->count_cells(dev, &na, &ns);
387 of_node_put(parent);
388 if (!OF_CHECK_COUNTS(na, ns))
389 return NULL;
390
391 /* Get "reg" or "assigned-addresses" property */
392 prop = (u32 *)get_property(dev, bus->addresses, &psize);
393 if (prop == NULL)
394 return NULL;
395 psize /= 4;
396
397 onesize = na + ns;
398 for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
399 if (i == index) {
400 if (size)
401 *size = of_read_addr(prop + na, ns);
402 return prop;
403 }
404 return NULL;
405}
406EXPORT_SYMBOL(of_get_address);
407
408u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size)
409{
410 u32 *addr;
411 int index;
412
413 for (index = 0; (addr = of_get_address(dev, index, size)) != NULL;
414 index++) {
415 if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0))
416 return addr;
417 }
418 return NULL;
419}
420EXPORT_SYMBOL(of_get_pci_address);