aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom_parse.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-11-30 00:57:28 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:51:26 -0500
commitd2dd482bc17c3bc240045f80a7c4b4d5cea5e29c (patch)
tree9c40a9ab9a04839f2d578f9d47985b399074ce58 /arch/powerpc/kernel/prom_parse.c
parentbb6b9b28d6847bc71f910e2e82c9040ff4b97ec0 (diff)
[PATCH] powerpc: Update OF address parsers
This updates the OF address parsers to return the IO flags indicating the type of address obtained. It also adds a PCI call for converting physical addresses that hit IO space into into IO tokens, and add routines that return the translated addresses into struct resource 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.c165
1 files changed, 146 insertions, 19 deletions
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 23c85af53d47..5b764277f470 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -4,7 +4,9 @@
4#include <linux/string.h> 4#include <linux/string.h>
5#include <linux/pci_regs.h> 5#include <linux/pci_regs.h>
6#include <linux/module.h> 6#include <linux/module.h>
7#include <linux/ioport.h>
7#include <asm/prom.h> 8#include <asm/prom.h>
9#include <asm/pci-bridge.h>
8 10
9#ifdef DEBUG 11#ifdef DEBUG
10#define DBG(fmt...) do { printk(fmt); } while(0) 12#define DBG(fmt...) do { printk(fmt); } while(0)
@@ -54,6 +56,7 @@ struct of_bus {
54 int *addrc, int *sizec); 56 int *addrc, int *sizec);
55 u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna); 57 u64 (*map)(u32 *addr, u32 *range, int na, int ns, int pna);
56 int (*translate)(u32 *addr, u64 offset, int na); 58 int (*translate)(u32 *addr, u64 offset, int na);
59 unsigned int (*get_flags)(u32 *addr);
57}; 60};
58 61
59 62
@@ -61,8 +64,8 @@ struct of_bus {
61 * Default translator (generic bus) 64 * Default translator (generic bus)
62 */ 65 */
63 66
64static void of_default_count_cells(struct device_node *dev, 67static void of_bus_default_count_cells(struct device_node *dev,
65 int *addrc, int *sizec) 68 int *addrc, int *sizec)
66{ 69{
67 if (addrc) 70 if (addrc)
68 *addrc = prom_n_addr_cells(dev); 71 *addrc = prom_n_addr_cells(dev);
@@ -70,7 +73,7 @@ static void of_default_count_cells(struct device_node *dev,
70 *sizec = prom_n_size_cells(dev); 73 *sizec = prom_n_size_cells(dev);
71} 74}
72 75
73static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna) 76static u64 of_bus_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
74{ 77{
75 u64 cp, s, da; 78 u64 cp, s, da;
76 79
@@ -86,7 +89,7 @@ static u64 of_default_map(u32 *addr, u32 *range, int na, int ns, int pna)
86 return da - cp; 89 return da - cp;
87} 90}
88 91
89static int of_default_translate(u32 *addr, u64 offset, int na) 92static int of_bus_default_translate(u32 *addr, u64 offset, int na)
90{ 93{
91 u64 a = of_read_addr(addr, na); 94 u64 a = of_read_addr(addr, na);
92 memset(addr, 0, na * 4); 95 memset(addr, 0, na * 4);
@@ -98,6 +101,11 @@ static int of_default_translate(u32 *addr, u64 offset, int na)
98 return 0; 101 return 0;
99} 102}
100 103
104static unsigned int of_bus_default_get_flags(u32 *addr)
105{
106 return IORESOURCE_MEM;
107}
108
101 109
102/* 110/*
103 * PCI bus specific translator 111 * PCI bus specific translator
@@ -139,7 +147,24 @@ static u64 of_bus_pci_map(u32 *addr, u32 *range, int na, int ns, int pna)
139 147
140static int of_bus_pci_translate(u32 *addr, u64 offset, int na) 148static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
141{ 149{
142 return of_default_translate(addr + 1, offset, na - 1); 150 return of_bus_default_translate(addr + 1, offset, na - 1);
151}
152
153static unsigned int of_bus_pci_get_flags(u32 *addr)
154{
155 unsigned int flags = 0;
156 u32 w = addr[0];
157
158 switch((w >> 24) & 0x03) {
159 case 0x01:
160 flags |= IORESOURCE_IO;
161 case 0x02: /* 32 bits */
162 case 0x03: /* 64 bits */
163 flags |= IORESOURCE_MEM;
164 }
165 if (w & 0x40000000)
166 flags |= IORESOURCE_PREFETCH;
167 return flags;
143} 168}
144 169
145/* 170/*
@@ -182,9 +207,22 @@ static u64 of_bus_isa_map(u32 *addr, u32 *range, int na, int ns, int pna)
182 207
183static int of_bus_isa_translate(u32 *addr, u64 offset, int na) 208static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
184{ 209{
185 return of_default_translate(addr + 1, offset, na - 1); 210 return of_bus_default_translate(addr + 1, offset, na - 1);
211}
212
213static unsigned int of_bus_isa_get_flags(u32 *addr)
214{
215 unsigned int flags = 0;
216 u32 w = addr[0];
217
218 if (w & 1)
219 flags |= IORESOURCE_IO;
220 else
221 flags |= IORESOURCE_MEM;
222 return flags;
186} 223}
187 224
225
188/* 226/*
189 * Array of bus specific translators 227 * Array of bus specific translators
190 */ 228 */
@@ -198,6 +236,7 @@ static struct of_bus of_busses[] = {
198 .count_cells = of_bus_pci_count_cells, 236 .count_cells = of_bus_pci_count_cells,
199 .map = of_bus_pci_map, 237 .map = of_bus_pci_map,
200 .translate = of_bus_pci_translate, 238 .translate = of_bus_pci_translate,
239 .get_flags = of_bus_pci_get_flags,
201 }, 240 },
202 /* ISA */ 241 /* ISA */
203 { 242 {
@@ -207,15 +246,17 @@ static struct of_bus of_busses[] = {
207 .count_cells = of_bus_isa_count_cells, 246 .count_cells = of_bus_isa_count_cells,
208 .map = of_bus_isa_map, 247 .map = of_bus_isa_map,
209 .translate = of_bus_isa_translate, 248 .translate = of_bus_isa_translate,
249 .get_flags = of_bus_isa_get_flags,
210 }, 250 },
211 /* Default */ 251 /* Default */
212 { 252 {
213 .name = "default", 253 .name = "default",
214 .addresses = "reg", 254 .addresses = "reg",
215 .match = NULL, 255 .match = NULL,
216 .count_cells = of_default_count_cells, 256 .count_cells = of_bus_default_count_cells,
217 .map = of_default_map, 257 .map = of_bus_default_map,
218 .translate = of_default_translate, 258 .translate = of_bus_default_translate,
259 .get_flags = of_bus_default_get_flags,
219 }, 260 },
220}; 261};
221 262
@@ -254,7 +295,8 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
254 ranges = (u32 *)get_property(parent, "ranges", &rlen); 295 ranges = (u32 *)get_property(parent, "ranges", &rlen);
255 if (ranges == NULL || rlen == 0) { 296 if (ranges == NULL || rlen == 0) {
256 offset = of_read_addr(addr, na); 297 offset = of_read_addr(addr, na);
257 memset(addr, 0, pna); 298 memset(addr, 0, pna * 4);
299 DBG("OF: no ranges, 1:1 translation\n");
258 goto finish; 300 goto finish;
259 } 301 }
260 302
@@ -370,7 +412,8 @@ u64 of_translate_address(struct device_node *dev, u32 *in_addr)
370} 412}
371EXPORT_SYMBOL(of_translate_address); 413EXPORT_SYMBOL(of_translate_address);
372 414
373u32 *of_get_address(struct device_node *dev, int index, u64 *size) 415u32 *of_get_address(struct device_node *dev, int index, u64 *size,
416 unsigned int *flags)
374{ 417{
375 u32 *prop; 418 u32 *prop;
376 unsigned int psize; 419 unsigned int psize;
@@ -399,22 +442,106 @@ u32 *of_get_address(struct device_node *dev, int index, u64 *size)
399 if (i == index) { 442 if (i == index) {
400 if (size) 443 if (size)
401 *size = of_read_addr(prop + na, ns); 444 *size = of_read_addr(prop + na, ns);
445 if (flags)
446 *flags = bus->get_flags(prop);
402 return prop; 447 return prop;
403 } 448 }
404 return NULL; 449 return NULL;
405} 450}
406EXPORT_SYMBOL(of_get_address); 451EXPORT_SYMBOL(of_get_address);
407 452
408u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size) 453u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
454 unsigned int *flags)
409{ 455{
410 u32 *addr; 456 u32 *prop;
411 int index; 457 unsigned int psize;
458 struct device_node *parent;
459 struct of_bus *bus;
460 int onesize, i, na, ns;
412 461
413 for (index = 0; (addr = of_get_address(dev, index, size)) != NULL; 462 /* Get parent & match bus type */
414 index++) { 463 parent = of_get_parent(dev);
415 if ((addr[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) 464 if (parent == NULL)
416 return addr; 465 return NULL;
417 } 466 bus = of_match_bus(parent);
467 if (strcmp(bus->name, "pci"))
468 return NULL;
469 bus->count_cells(dev, &na, &ns);
470 of_node_put(parent);
471 if (!OF_CHECK_COUNTS(na, ns))
472 return NULL;
473
474 /* Get "reg" or "assigned-addresses" property */
475 prop = (u32 *)get_property(dev, bus->addresses, &psize);
476 if (prop == NULL)
477 return NULL;
478 psize /= 4;
479
480 onesize = na + ns;
481 for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
482 if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
483 if (size)
484 *size = of_read_addr(prop + na, ns);
485 if (flags)
486 *flags = bus->get_flags(prop);
487 return prop;
488 }
418 return NULL; 489 return NULL;
419} 490}
420EXPORT_SYMBOL(of_get_pci_address); 491EXPORT_SYMBOL(of_get_pci_address);
492
493static int __of_address_to_resource(struct device_node *dev, u32 *addrp,
494 u64 size, unsigned int flags,
495 struct resource *r)
496{
497 u64 taddr;
498
499 if ((flags & (IORESOURCE_IO | IORESOURCE_MEM)) == 0)
500 return -EINVAL;
501 taddr = of_translate_address(dev, addrp);
502 if (taddr == OF_BAD_ADDR)
503 return -EINVAL;
504 memset(r, 0, sizeof(struct resource));
505 if (flags & IORESOURCE_IO) {
506 unsigned int port;
507 port = pci_address_to_pio(taddr);
508 if (port == (unsigned int)-1)
509 return -EINVAL;
510 r->start = port;
511 r->end = port + size - 1;
512 } else {
513 r->start = taddr;
514 r->end = taddr + size - 1;
515 }
516 r->flags = flags;
517 r->name = dev->name;
518 return 0;
519}
520
521int of_address_to_resource(struct device_node *dev, int index,
522 struct resource *r)
523{
524 u32 *addrp;
525 u64 size;
526 unsigned int flags;
527
528 addrp = of_get_address(dev, index, &size, &flags);
529 if (addrp == NULL)
530 return -EINVAL;
531 return __of_address_to_resource(dev, addrp, size, flags, r);
532}
533EXPORT_SYMBOL_GPL(of_address_to_resource);
534
535int of_pci_address_to_resource(struct device_node *dev, int bar,
536 struct resource *r)
537{
538 u32 *addrp;
539 u64 size;
540 unsigned int flags;
541
542 addrp = of_get_pci_address(dev, bar, &size, &flags);
543 if (addrp == NULL)
544 return -EINVAL;
545 return __of_address_to_resource(dev, addrp, size, flags, r);
546}
547EXPORT_SYMBOL_GPL(of_pci_address_to_resource);