diff options
| -rw-r--r-- | arch/powerpc/kernel/pci_32.c | 98 |
1 files changed, 53 insertions, 45 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index ab5887bff02a..8336deafc624 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c | |||
| @@ -736,25 +736,51 @@ scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* | |||
| 736 | return NULL; | 736 | return NULL; |
| 737 | } | 737 | } |
| 738 | 738 | ||
| 739 | static int | 739 | static struct device_node *scan_OF_for_pci_dev(struct device_node *parent, |
| 740 | scan_OF_pci_childs_iterator(struct device_node* node, void* data) | 740 | unsigned int devfn) |
| 741 | { | 741 | { |
| 742 | const unsigned int *reg; | 742 | struct device_node *np = NULL; |
| 743 | u8* fdata = (u8*)data; | 743 | const u32 *reg; |
| 744 | 744 | unsigned int psize; | |
| 745 | reg = get_property(node, "reg", NULL); | 745 | |
| 746 | if (reg && ((reg[0] >> 8) & 0xff) == fdata[1] | 746 | while ((np = of_get_next_child(parent, np)) != NULL) { |
| 747 | && ((reg[0] >> 16) & 0xff) == fdata[0]) | 747 | reg = get_property(np, "reg", &psize); |
| 748 | return 1; | 748 | if (reg == NULL || psize < 4) |
| 749 | return 0; | 749 | continue; |
| 750 | if (((reg[0] >> 8) & 0xff) == devfn) | ||
| 751 | return np; | ||
| 752 | } | ||
| 753 | return NULL; | ||
| 750 | } | 754 | } |
| 751 | 755 | ||
| 752 | static struct device_node* | 756 | |
| 753 | scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | 757 | static struct device_node *scan_OF_for_pci_bus(struct pci_bus *bus) |
| 754 | { | 758 | { |
| 755 | u8 filter_data[2] = {bus, dev_fn}; | 759 | struct device_node *parent, *np; |
| 760 | |||
| 761 | /* Are we a root bus ? */ | ||
| 762 | if (bus->self == NULL || bus->parent == NULL) { | ||
| 763 | struct pci_controller *hose = pci_bus_to_hose(bus->number); | ||
| 764 | if (hose == NULL) | ||
| 765 | return NULL; | ||
| 766 | return of_node_get(hose->arch_data); | ||
| 767 | } | ||
| 768 | |||
| 769 | /* not a root bus, we need to get our parent */ | ||
| 770 | parent = scan_OF_for_pci_bus(bus->parent); | ||
| 771 | if (parent == NULL) | ||
| 772 | return NULL; | ||
| 773 | |||
| 774 | /* now iterate for children for a match */ | ||
| 775 | np = scan_OF_for_pci_dev(parent, bus->self->devfn); | ||
| 776 | of_node_put(parent); | ||
| 756 | 777 | ||
| 757 | return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data); | 778 | /* sanity check */ |
| 779 | if (strcmp(np->type, "pci") != 0) | ||
| 780 | printk(KERN_WARNING "pci: wrong type \"%s\" for bridge %s\n", | ||
| 781 | np->type, np->full_name); | ||
| 782 | |||
| 783 | return np; | ||
| 758 | } | 784 | } |
| 759 | 785 | ||
| 760 | /* | 786 | /* |
| @@ -763,43 +789,25 @@ scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) | |||
| 763 | struct device_node * | 789 | struct device_node * |
| 764 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) | 790 | pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) |
| 765 | { | 791 | { |
| 766 | struct pci_controller *hose; | 792 | struct device_node *parent, *np; |
| 767 | struct device_node *node; | ||
| 768 | int busnr; | ||
| 769 | 793 | ||
| 770 | if (!have_of) | 794 | if (!have_of) |
| 771 | return NULL; | 795 | return NULL; |
| 772 | |||
| 773 | /* Lookup the hose */ | ||
| 774 | busnr = bus->number; | ||
| 775 | hose = pci_bus_to_hose(busnr); | ||
| 776 | if (!hose) | ||
| 777 | return NULL; | ||
| 778 | 796 | ||
| 779 | /* Check it has an OF node associated */ | 797 | DBG("pci_busdev_to_OF_node(%d,0x%x)\n", bus->number, devfn); |
| 780 | node = (struct device_node *) hose->arch_data; | 798 | parent = scan_OF_for_pci_bus(bus); |
| 781 | if (!node) | 799 | if (parent == NULL) |
| 782 | return NULL; | 800 | return NULL; |
| 783 | 801 | DBG(" parent is %s\n", parent ? parent->full_name : "<NULL>"); | |
| 784 | /* Fixup bus number according to what OF think it is. */ | 802 | np = scan_OF_for_pci_dev(parent, devfn); |
| 785 | #ifdef CONFIG_PPC_PMAC | 803 | of_node_put(parent); |
| 786 | /* The G5 need a special case here. Basically, we don't remap all | 804 | DBG(" result is %s\n", np ? np->full_name : "<NULL>"); |
| 787 | * busses on it so we don't create the pci-OF-map. However, we do | 805 | |
| 788 | * remap the AGP bus and so have to deal with it. A future better | 806 | /* XXX most callers don't release the returned node |
| 789 | * fix has to be done by making the remapping per-host and always | 807 | * mostly because ppc64 doesn't increase the refcount, |
| 790 | * filling the pci_to_OF map. --BenH | 808 | * we need to fix that. |
| 791 | */ | 809 | */ |
| 792 | if (machine_is(powermac) && busnr >= 0xf0) | 810 | return np; |
| 793 | busnr -= 0xf0; | ||
| 794 | else | ||
| 795 | #endif | ||
| 796 | if (pci_to_OF_bus_map) | ||
| 797 | busnr = pci_to_OF_bus_map[busnr]; | ||
| 798 | if (busnr == 0xff) | ||
| 799 | return NULL; | ||
| 800 | |||
| 801 | /* Now, lookup childs of the hose */ | ||
| 802 | return scan_OF_childs_for_device(node->child, busnr, devfn); | ||
| 803 | } | 811 | } |
| 804 | EXPORT_SYMBOL(pci_busdev_to_OF_node); | 812 | EXPORT_SYMBOL(pci_busdev_to_OF_node); |
| 805 | 813 | ||
