aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/prom.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2005-12-13 02:01:21 -0500
committerPaul Mackerras <paulus@samba.org>2006-01-08 22:53:55 -0500
commitcc5d0189b9ba95260857a5018a1c2fef90008507 (patch)
tree1202c94b6b3cb81a96d0a0e54424cad10eef68bb /arch/powerpc/kernel/prom.c
parent9cf84d7c97992dbe5360b241327341c07ce30fc9 (diff)
[PATCH] powerpc: Remove device_node addrs/n_addr
The pre-parsed addrs/n_addrs fields in struct device_node are finally gone. Remove the dodgy heuristics that did that parsing at boot and remove the fields themselves since we now have a good replacement with the new OF parsing code. This patch also fixes a bunch of drivers to use the new code instead, so that at least pmac32, pseries, iseries and g5 defconfigs build. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
Diffstat (limited to 'arch/powerpc/kernel/prom.c')
-rw-r--r--arch/powerpc/kernel/prom.c424
1 files changed, 10 insertions, 414 deletions
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c
index 7e798d5b03b4..1b97e13657e5 100644
--- a/arch/powerpc/kernel/prom.c
+++ b/arch/powerpc/kernel/prom.c
@@ -57,21 +57,6 @@
57#define DBG(fmt...) 57#define DBG(fmt...)
58#endif 58#endif
59 59
60struct pci_reg_property {
61 struct pci_address addr;
62 u32 size_hi;
63 u32 size_lo;
64};
65
66struct isa_reg_property {
67 u32 space;
68 u32 address;
69 u32 size;
70};
71
72
73typedef int interpret_func(struct device_node *, unsigned long *,
74 int, int, int);
75 60
76static int __initdata dt_root_addr_cells; 61static int __initdata dt_root_addr_cells;
77static int __initdata dt_root_size_cells; 62static int __initdata dt_root_size_cells;
@@ -410,237 +395,19 @@ static int __devinit finish_node_interrupts(struct device_node *np,
410 return 0; 395 return 0;
411} 396}
412 397
413static int __devinit interpret_pci_props(struct device_node *np,
414 unsigned long *mem_start,
415 int naddrc, int nsizec,
416 int measure_only)
417{
418 struct address_range *adr;
419 struct pci_reg_property *pci_addrs;
420 int i, l, n_addrs;
421
422 pci_addrs = (struct pci_reg_property *)
423 get_property(np, "assigned-addresses", &l);
424 if (!pci_addrs)
425 return 0;
426
427 n_addrs = l / sizeof(*pci_addrs);
428
429 adr = prom_alloc(n_addrs * sizeof(*adr), mem_start);
430 if (!adr)
431 return -ENOMEM;
432
433 if (measure_only)
434 return 0;
435
436 np->addrs = adr;
437 np->n_addrs = n_addrs;
438
439 for (i = 0; i < n_addrs; i++) {
440 adr[i].space = pci_addrs[i].addr.a_hi;
441 adr[i].address = pci_addrs[i].addr.a_lo |
442 ((u64)pci_addrs[i].addr.a_mid << 32);
443 adr[i].size = pci_addrs[i].size_lo;
444 }
445
446 return 0;
447}
448
449static int __init interpret_dbdma_props(struct device_node *np,
450 unsigned long *mem_start,
451 int naddrc, int nsizec,
452 int measure_only)
453{
454 struct reg_property32 *rp;
455 struct address_range *adr;
456 unsigned long base_address;
457 int i, l;
458 struct device_node *db;
459
460 base_address = 0;
461 if (!measure_only) {
462 for (db = np->parent; db != NULL; db = db->parent) {
463 if (!strcmp(db->type, "dbdma") && db->n_addrs != 0) {
464 base_address = db->addrs[0].address;
465 break;
466 }
467 }
468 }
469
470 rp = (struct reg_property32 *) get_property(np, "reg", &l);
471 if (rp != 0 && l >= sizeof(struct reg_property32)) {
472 i = 0;
473 adr = (struct address_range *) (*mem_start);
474 while ((l -= sizeof(struct reg_property32)) >= 0) {
475 if (!measure_only) {
476 adr[i].space = 2;
477 adr[i].address = rp[i].address + base_address;
478 adr[i].size = rp[i].size;
479 }
480 ++i;
481 }
482 np->addrs = adr;
483 np->n_addrs = i;
484 (*mem_start) += i * sizeof(struct address_range);
485 }
486
487 return 0;
488}
489
490static int __init interpret_macio_props(struct device_node *np,
491 unsigned long *mem_start,
492 int naddrc, int nsizec,
493 int measure_only)
494{
495 struct reg_property32 *rp;
496 struct address_range *adr;
497 unsigned long base_address;
498 int i, l;
499 struct device_node *db;
500
501 base_address = 0;
502 if (!measure_only) {
503 for (db = np->parent; db != NULL; db = db->parent) {
504 if (!strcmp(db->type, "mac-io") && db->n_addrs != 0) {
505 base_address = db->addrs[0].address;
506 break;
507 }
508 }
509 }
510
511 rp = (struct reg_property32 *) get_property(np, "reg", &l);
512 if (rp != 0 && l >= sizeof(struct reg_property32)) {
513 i = 0;
514 adr = (struct address_range *) (*mem_start);
515 while ((l -= sizeof(struct reg_property32)) >= 0) {
516 if (!measure_only) {
517 adr[i].space = 2;
518 adr[i].address = rp[i].address + base_address;
519 adr[i].size = rp[i].size;
520 }
521 ++i;
522 }
523 np->addrs = adr;
524 np->n_addrs = i;
525 (*mem_start) += i * sizeof(struct address_range);
526 }
527
528 return 0;
529}
530
531static int __init interpret_isa_props(struct device_node *np,
532 unsigned long *mem_start,
533 int naddrc, int nsizec,
534 int measure_only)
535{
536 struct isa_reg_property *rp;
537 struct address_range *adr;
538 int i, l;
539
540 rp = (struct isa_reg_property *) get_property(np, "reg", &l);
541 if (rp != 0 && l >= sizeof(struct isa_reg_property)) {
542 i = 0;
543 adr = (struct address_range *) (*mem_start);
544 while ((l -= sizeof(struct isa_reg_property)) >= 0) {
545 if (!measure_only) {
546 adr[i].space = rp[i].space;
547 adr[i].address = rp[i].address;
548 adr[i].size = rp[i].size;
549 }
550 ++i;
551 }
552 np->addrs = adr;
553 np->n_addrs = i;
554 (*mem_start) += i * sizeof(struct address_range);
555 }
556
557 return 0;
558}
559
560static int __init interpret_root_props(struct device_node *np,
561 unsigned long *mem_start,
562 int naddrc, int nsizec,
563 int measure_only)
564{
565 struct address_range *adr;
566 int i, l;
567 unsigned int *rp;
568 int rpsize = (naddrc + nsizec) * sizeof(unsigned int);
569
570 rp = (unsigned int *) get_property(np, "linux,usable-memory", &l);
571 if (rp == NULL)
572 rp = (unsigned int *) get_property(np, "reg", &l);
573
574 if (rp != 0 && l >= rpsize) {
575 i = 0;
576 adr = (struct address_range *) (*mem_start);
577 while ((l -= rpsize) >= 0) {
578 if (!measure_only) {
579 adr[i].space = 0;
580 adr[i].address = rp[naddrc - 1];
581 adr[i].size = rp[naddrc + nsizec - 1];
582 }
583 ++i;
584 rp += naddrc + nsizec;
585 }
586 np->addrs = adr;
587 np->n_addrs = i;
588 (*mem_start) += i * sizeof(struct address_range);
589 }
590
591 return 0;
592}
593
594static int __devinit finish_node(struct device_node *np, 398static int __devinit finish_node(struct device_node *np,
595 unsigned long *mem_start, 399 unsigned long *mem_start,
596 interpret_func *ifunc,
597 int naddrc, int nsizec,
598 int measure_only) 400 int measure_only)
599{ 401{
600 struct device_node *child; 402 struct device_node *child;
601 int *ip, rc = 0; 403 int rc = 0;
602
603 /* get the device addresses and interrupts */
604 if (ifunc != NULL)
605 rc = ifunc(np, mem_start, naddrc, nsizec, measure_only);
606 if (rc)
607 goto out;
608 404
609 rc = finish_node_interrupts(np, mem_start, measure_only); 405 rc = finish_node_interrupts(np, mem_start, measure_only);
610 if (rc) 406 if (rc)
611 goto out; 407 goto out;
612 408
613 /* Look for #address-cells and #size-cells properties. */
614 ip = (int *) get_property(np, "#address-cells", NULL);
615 if (ip != NULL)
616 naddrc = *ip;
617 ip = (int *) get_property(np, "#size-cells", NULL);
618 if (ip != NULL)
619 nsizec = *ip;
620
621 if (!strcmp(np->name, "device-tree") || np->parent == NULL)
622 ifunc = interpret_root_props;
623 else if (np->type == 0)
624 ifunc = NULL;
625 else if (!strcmp(np->type, "pci") || !strcmp(np->type, "vci"))
626 ifunc = interpret_pci_props;
627 else if (!strcmp(np->type, "dbdma"))
628 ifunc = interpret_dbdma_props;
629 else if (!strcmp(np->type, "mac-io") || ifunc == interpret_macio_props)
630 ifunc = interpret_macio_props;
631 else if (!strcmp(np->type, "isa"))
632 ifunc = interpret_isa_props;
633 else if (!strcmp(np->name, "uni-n") || !strcmp(np->name, "u3"))
634 ifunc = interpret_root_props;
635 else if (!((ifunc == interpret_dbdma_props
636 || ifunc == interpret_macio_props)
637 && (!strcmp(np->type, "escc")
638 || !strcmp(np->type, "media-bay"))))
639 ifunc = NULL;
640
641 for (child = np->child; child != NULL; child = child->sibling) { 409 for (child = np->child; child != NULL; child = child->sibling) {
642 rc = finish_node(child, mem_start, ifunc, 410 rc = finish_node(child, mem_start, measure_only);
643 naddrc, nsizec, measure_only);
644 if (rc) 411 if (rc)
645 goto out; 412 goto out;
646 } 413 }
@@ -702,10 +469,10 @@ void __init finish_device_tree(void)
702 * reason and then remove those additional 16 bytes 469 * reason and then remove those additional 16 bytes
703 */ 470 */
704 size = 16; 471 size = 16;
705 finish_node(allnodes, &size, NULL, 0, 0, 1); 472 finish_node(allnodes, &size, 1);
706 size -= 16; 473 size -= 16;
707 end = start = (unsigned long) __va(lmb_alloc(size, 128)); 474 end = start = (unsigned long) __va(lmb_alloc(size, 128));
708 finish_node(allnodes, &end, NULL, 0, 0, 0); 475 finish_node(allnodes, &end, 0);
709 BUG_ON(end != start + size); 476 BUG_ON(end != start + size);
710 477
711 DBG(" <- finish_device_tree\n"); 478 DBG(" <- finish_device_tree\n");
@@ -1822,7 +1589,6 @@ static void of_node_release(struct kref *kref)
1822 prop = next; 1589 prop = next;
1823 } 1590 }
1824 kfree(node->intrs); 1591 kfree(node->intrs);
1825 kfree(node->addrs);
1826 kfree(node->full_name); 1592 kfree(node->full_name);
1827 kfree(node->data); 1593 kfree(node->data);
1828 kfree(node); 1594 kfree(node);
@@ -1904,9 +1670,7 @@ void of_detach_node(const struct device_node *np)
1904 * This should probably be split up into smaller chunks. 1670 * This should probably be split up into smaller chunks.
1905 */ 1671 */
1906 1672
1907static int of_finish_dynamic_node(struct device_node *node, 1673static int of_finish_dynamic_node(struct device_node *node)
1908 unsigned long *unused1, int unused2,
1909 int unused3, int unused4)
1910{ 1674{
1911 struct device_node *parent = of_get_parent(node); 1675 struct device_node *parent = of_get_parent(node);
1912 int err = 0; 1676 int err = 0;
@@ -1927,7 +1691,8 @@ static int of_finish_dynamic_node(struct device_node *node,
1927 return -ENODEV; 1691 return -ENODEV;
1928 1692
1929 /* fix up new node's linux_phandle field */ 1693 /* fix up new node's linux_phandle field */
1930 if ((ibm_phandle = (unsigned int *)get_property(node, "ibm,phandle", NULL))) 1694 if ((ibm_phandle = (unsigned int *)get_property(node,
1695 "ibm,phandle", NULL)))
1931 node->linux_phandle = *ibm_phandle; 1696 node->linux_phandle = *ibm_phandle;
1932 1697
1933out: 1698out:
@@ -1942,7 +1707,9 @@ static int prom_reconfig_notifier(struct notifier_block *nb,
1942 1707
1943 switch (action) { 1708 switch (action) {
1944 case PSERIES_RECONFIG_ADD: 1709 case PSERIES_RECONFIG_ADD:
1945 err = finish_node(node, NULL, of_finish_dynamic_node, 0, 0, 0); 1710 err = of_finish_dynamic_node(node);
1711 if (!err)
1712 finish_node(node, NULL, 0);
1946 if (err < 0) { 1713 if (err < 0) {
1947 printk(KERN_ERR "finish_node returned %d\n", err); 1714 printk(KERN_ERR "finish_node returned %d\n", err);
1948 err = NOTIFY_BAD; 1715 err = NOTIFY_BAD;
@@ -2016,175 +1783,4 @@ int prom_add_property(struct device_node* np, struct property* prop)
2016 return 0; 1783 return 0;
2017} 1784}
2018 1785
2019/* I quickly hacked that one, check against spec ! */
2020static inline unsigned long
2021bus_space_to_resource_flags(unsigned int bus_space)
2022{
2023 u8 space = (bus_space >> 24) & 0xf;
2024 if (space == 0)
2025 space = 0x02;
2026 if (space == 0x02)
2027 return IORESOURCE_MEM;
2028 else if (space == 0x01)
2029 return IORESOURCE_IO;
2030 else {
2031 printk(KERN_WARNING "prom.c: bus_space_to_resource_flags(), space: %x\n",
2032 bus_space);
2033 return 0;
2034 }
2035}
2036
2037#ifdef CONFIG_PCI
2038static struct resource *find_parent_pci_resource(struct pci_dev* pdev,
2039 struct address_range *range)
2040{
2041 unsigned long mask;
2042 int i;
2043
2044 /* Check this one */
2045 mask = bus_space_to_resource_flags(range->space);
2046 for (i=0; i<DEVICE_COUNT_RESOURCE; i++) {
2047 if ((pdev->resource[i].flags & mask) == mask &&
2048 pdev->resource[i].start <= range->address &&
2049 pdev->resource[i].end > range->address) {
2050 if ((range->address + range->size - 1) > pdev->resource[i].end) {
2051 /* Add better message */
2052 printk(KERN_WARNING "PCI/OF resource overlap !\n");
2053 return NULL;
2054 }
2055 break;
2056 }
2057 }
2058 if (i == DEVICE_COUNT_RESOURCE)
2059 return NULL;
2060 return &pdev->resource[i];
2061}
2062
2063/*
2064 * Request an OF device resource. Currently handles child of PCI devices,
2065 * or other nodes attached to the root node. Ultimately, put some
2066 * link to resources in the OF node.
2067 */
2068struct resource *request_OF_resource(struct device_node* node, int index,
2069 const char* name_postfix)
2070{
2071 struct pci_dev* pcidev;
2072 u8 pci_bus, pci_devfn;
2073 unsigned long iomask;
2074 struct device_node* nd;
2075 struct resource* parent;
2076 struct resource *res = NULL;
2077 int nlen, plen;
2078
2079 if (index >= node->n_addrs)
2080 goto fail;
2081
2082 /* Sanity check on bus space */
2083 iomask = bus_space_to_resource_flags(node->addrs[index].space);
2084 if (iomask & IORESOURCE_MEM)
2085 parent = &iomem_resource;
2086 else if (iomask & IORESOURCE_IO)
2087 parent = &ioport_resource;
2088 else
2089 goto fail;
2090
2091 /* Find a PCI parent if any */
2092 nd = node;
2093 pcidev = NULL;
2094 while (nd) {
2095 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
2096 pcidev = pci_find_slot(pci_bus, pci_devfn);
2097 if (pcidev) break;
2098 nd = nd->parent;
2099 }
2100 if (pcidev)
2101 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
2102 if (!parent) {
2103 printk(KERN_WARNING "request_OF_resource(%s), parent not found\n",
2104 node->name);
2105 goto fail;
2106 }
2107
2108 res = __request_region(parent, node->addrs[index].address,
2109 node->addrs[index].size, NULL);
2110 if (!res)
2111 goto fail;
2112 nlen = strlen(node->name);
2113 plen = name_postfix ? strlen(name_postfix) : 0;
2114 res->name = (const char *)kmalloc(nlen+plen+1, GFP_KERNEL);
2115 if (res->name) {
2116 strcpy((char *)res->name, node->name);
2117 if (plen)
2118 strcpy((char *)res->name+nlen, name_postfix);
2119 }
2120 return res;
2121fail:
2122 return NULL;
2123}
2124EXPORT_SYMBOL(request_OF_resource);
2125
2126int release_OF_resource(struct device_node *node, int index)
2127{
2128 struct pci_dev* pcidev;
2129 u8 pci_bus, pci_devfn;
2130 unsigned long iomask, start, end;
2131 struct device_node* nd;
2132 struct resource* parent;
2133 struct resource *res = NULL;
2134
2135 if (index >= node->n_addrs)
2136 return -EINVAL;
2137
2138 /* Sanity check on bus space */
2139 iomask = bus_space_to_resource_flags(node->addrs[index].space);
2140 if (iomask & IORESOURCE_MEM)
2141 parent = &iomem_resource;
2142 else if (iomask & IORESOURCE_IO)
2143 parent = &ioport_resource;
2144 else
2145 return -EINVAL;
2146
2147 /* Find a PCI parent if any */
2148 nd = node;
2149 pcidev = NULL;
2150 while(nd) {
2151 if (!pci_device_from_OF_node(nd, &pci_bus, &pci_devfn))
2152 pcidev = pci_find_slot(pci_bus, pci_devfn);
2153 if (pcidev) break;
2154 nd = nd->parent;
2155 }
2156 if (pcidev)
2157 parent = find_parent_pci_resource(pcidev, &node->addrs[index]);
2158 if (!parent) {
2159 printk(KERN_WARNING "release_OF_resource(%s), parent not found\n",
2160 node->name);
2161 return -ENODEV;
2162 }
2163 1786
2164 /* Find us in the parent and its childs */
2165 res = parent->child;
2166 start = node->addrs[index].address;
2167 end = start + node->addrs[index].size - 1;
2168 while (res) {
2169 if (res->start == start && res->end == end &&
2170 (res->flags & IORESOURCE_BUSY))
2171 break;
2172 if (res->start <= start && res->end >= end)
2173 res = res->child;
2174 else
2175 res = res->sibling;
2176 }
2177 if (!res)
2178 return -ENODEV;
2179
2180 if (res->name) {
2181 kfree(res->name);
2182 res->name = NULL;
2183 }
2184 release_resource(res);
2185 kfree(res);
2186
2187 return 0;
2188}
2189EXPORT_SYMBOL(release_OF_resource);
2190#endif /* CONFIG_PCI */