aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--arch/powerpc/kernel/Makefile3
-rw-r--r--arch/powerpc/kernel/prom_parse.c420
-rw-r--r--include/asm-powerpc/mmu.h4
-rw-r--r--include/asm-powerpc/prom.h9
-rw-r--r--include/asm-ppc/prom.h10
5 files changed, 445 insertions, 1 deletions
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 78f7b90c98f8..aab0ae33a42a 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -12,7 +12,8 @@ CFLAGS_btext.o += -fPIC
12endif 12endif
13 13
14obj-y := semaphore.o cputable.o ptrace.o syscalls.o \ 14obj-y := semaphore.o cputable.o ptrace.o syscalls.o \
15 irq.o align.o signal_32.o pmc.o vdso.o 15 irq.o align.o signal_32.o pmc.o vdso.o \
16 prom_parse.o
16obj-y += vdso32/ 17obj-y += vdso32/
17obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \ 18obj-$(CONFIG_PPC64) += setup_64.o binfmt_elf32.o sys_ppc32.o \
18 signal_64.o ptrace32.o systbl.o \ 19 signal_64.o ptrace32.o systbl.o \
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);
diff --git a/include/asm-powerpc/mmu.h b/include/asm-powerpc/mmu.h
index 29b0bb0086d3..29613500c2c2 100644
--- a/include/asm-powerpc/mmu.h
+++ b/include/asm-powerpc/mmu.h
@@ -394,6 +394,10 @@ static inline unsigned long get_vsid(unsigned long context, unsigned long ea)
394#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS) 394#define VSID_SCRAMBLE(pvsid) (((pvsid) * VSID_MULTIPLIER) % VSID_MODULUS)
395#define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea)) 395#define KERNEL_VSID(ea) VSID_SCRAMBLE(GET_ESID(ea))
396 396
397/* Physical address used by some IO functions */
398typedef unsigned long phys_addr_t;
399
400
397#endif /* __ASSEMBLY */ 401#endif /* __ASSEMBLY */
398 402
399#endif /* CONFIG_PPC64 */ 403#endif /* CONFIG_PPC64 */
diff --git a/include/asm-powerpc/prom.h b/include/asm-powerpc/prom.h
index f999df1c5c90..fb732c992bd2 100644
--- a/include/asm-powerpc/prom.h
+++ b/include/asm-powerpc/prom.h
@@ -223,5 +223,14 @@ extern struct resource *request_OF_resource(struct device_node* node,
223 int index, const char* name_postfix); 223 int index, const char* name_postfix);
224extern int release_OF_resource(struct device_node* node, int index); 224extern int release_OF_resource(struct device_node* node, int index);
225 225
226/*
227 * Address translation function(s)
228 */
229#define OF_BAD_ADDR ((u64)-1)
230extern u64 of_translate_address(struct device_node *np, u32 *addr);
231extern u32 *of_get_address(struct device_node *dev, int index, u64 *size);
232extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size);
233
234
226#endif /* __KERNEL__ */ 235#endif /* __KERNEL__ */
227#endif /* _POWERPC_PROM_H */ 236#endif /* _POWERPC_PROM_H */
diff --git a/include/asm-ppc/prom.h b/include/asm-ppc/prom.h
index 3e39827ed566..a10a2d64b300 100644
--- a/include/asm-ppc/prom.h
+++ b/include/asm-ppc/prom.h
@@ -136,5 +136,15 @@ extern unsigned long sub_reloc_offset(unsigned long);
136#define PTRRELOC(x) ((typeof(x))add_reloc_offset((unsigned long)(x))) 136#define PTRRELOC(x) ((typeof(x))add_reloc_offset((unsigned long)(x)))
137#define PTRUNRELOC(x) ((typeof(x))sub_reloc_offset((unsigned long)(x))) 137#define PTRUNRELOC(x) ((typeof(x))sub_reloc_offset((unsigned long)(x)))
138 138
139
140/*
141 * Address translation function(s)
142 */
143#define OF_BAD_ADDR ((u64)-1)
144extern u64 of_translate_address(struct device_node *np, u32 *addr);
145extern u32 *of_get_address(struct device_node *dev, int index, u64 *size);
146extern u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size);
147
148
139#endif /* _PPC_PROM_H */ 149#endif /* _PPC_PROM_H */
140#endif /* __KERNEL__ */ 150#endif /* __KERNEL__ */