aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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__ */