diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2005-12-13 02:01:21 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-01-08 22:53:55 -0500 |
commit | cc5d0189b9ba95260857a5018a1c2fef90008507 (patch) | |
tree | 1202c94b6b3cb81a96d0a0e54424cad10eef68bb /arch/powerpc/kernel/prom.c | |
parent | 9cf84d7c97992dbe5360b241327341c07ce30fc9 (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.c | 424 |
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 | ||
60 | struct pci_reg_property { | ||
61 | struct pci_address addr; | ||
62 | u32 size_hi; | ||
63 | u32 size_lo; | ||
64 | }; | ||
65 | |||
66 | struct isa_reg_property { | ||
67 | u32 space; | ||
68 | u32 address; | ||
69 | u32 size; | ||
70 | }; | ||
71 | |||
72 | |||
73 | typedef int interpret_func(struct device_node *, unsigned long *, | ||
74 | int, int, int); | ||
75 | 60 | ||
76 | static int __initdata dt_root_addr_cells; | 61 | static int __initdata dt_root_addr_cells; |
77 | static int __initdata dt_root_size_cells; | 62 | static 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 | ||
413 | static 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 | |||
449 | static 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 | |||
490 | static 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 | |||
531 | static 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 | |||
560 | static 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 | |||
594 | static int __devinit finish_node(struct device_node *np, | 398 | static 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 | ||
1907 | static int of_finish_dynamic_node(struct device_node *node, | 1673 | static 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 | ||
1933 | out: | 1698 | out: |
@@ -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 ! */ | ||
2020 | static inline unsigned long | ||
2021 | bus_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 | ||
2038 | static 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 | */ | ||
2068 | struct 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; | ||
2121 | fail: | ||
2122 | return NULL; | ||
2123 | } | ||
2124 | EXPORT_SYMBOL(request_OF_resource); | ||
2125 | |||
2126 | int 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 | } | ||
2189 | EXPORT_SYMBOL(release_OF_resource); | ||
2190 | #endif /* CONFIG_PCI */ | ||