aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2006-12-10 22:09:07 -0500
committerPaul Mackerras <paulus@samba.org>2006-12-10 22:45:53 -0500
commitdae4828d66ac6db353dee213c594257929a310cb (patch)
tree74bbab0309b57d5747726d44118ee26164723a35 /arch
parent74e95d5de9d8eb243cda68b546bdb29f6ef0f01c (diff)
[POWERPC] Fix irq routing on some 32-bit PowerMacs
The changes to use pci_read_irq_line() broke interrupt parsing on some 32-bit powermacs (oops). The reason is a bit obscure. The code to parse interrupts happens earlier now, during pcibios_fixup() as the PCI bus is being probed. However, the current implementation pci_device_to_OF_node() for 32-bit powerpc relies, on machines like PowerMac which renumber PCI buses, on a table called pci_OF_bus_map containing a map of bus numbers between the kernel and the firmware which is setup only later. Thus, it fails to match the device node. In addition, some of Apple internal PCI devices lack a proper PCI_INTERRUPT_PIN, thus preventing the fallback mapping code to work. This patch fixes it by making pci_device_to_OF_node() 32-bit implementation use a different algorithm that works without using the pci_OF_bus_map thing (which I intend to deprecate anyway). It's a bit slower but that function isn't called in any hot path hopefully. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/powerpc/kernel/pci_32.c98
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
739static int 739static struct device_node *scan_OF_for_pci_dev(struct device_node *parent,
740scan_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
752static struct device_node* 756
753scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn) 757static 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)
763struct device_node * 789struct device_node *
764pci_busdev_to_OF_node(struct pci_bus *bus, int devfn) 790pci_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}
804EXPORT_SYMBOL(pci_busdev_to_OF_node); 812EXPORT_SYMBOL(pci_busdev_to_OF_node);
805 813