diff options
Diffstat (limited to 'arch')
-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 | ||