patch-2.4.18 linux/arch/ppc/kernel/pci.c
Next file: linux/arch/ppc/kernel/pmac_backlight.c
Previous file: linux/arch/ppc/kernel/open_pic.c
Back to the patch index
Back to the overall index
- Lines: 214
- Date:
Mon Feb 4 18:47:24 2002
- Orig file:
linux.orig/arch/ppc/kernel/pci.c
- Orig date:
Mon Feb 18 20:18:39 2002
diff -Naur -X /home/marcelo/lib/dontdiff linux.orig/arch/ppc/kernel/pci.c linux/arch/ppc/kernel/pci.c
@@ -1,5 +1,5 @@
/*
- * BK Id: SCCS/s.pci.c 1.35 11/13/01 08:19:57 trini
+ * BK Id: SCCS/s.pci.c 1.40 01/25/02 15:15:24 benh
*/
/*
* Common pmac/prep/chrp pci routines. -- Cort
@@ -19,6 +19,7 @@
#include <asm/processor.h>
#include <asm/io.h>
#include <asm/prom.h>
+#include <asm/sections.h>
#include <asm/pci-bridge.h>
#include <asm/residual.h>
#include <asm/byteorder.h>
@@ -66,7 +67,7 @@
{ PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources },
#ifdef CONFIG_ALL_PPC
/* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */
- { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_DEVICE_ID_TI_1211, pcibios_fixup_cardbus },
+ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus },
#endif /* CONFIG_ALL_PPC */
{ 0 }
};
@@ -175,18 +176,25 @@
static void
pcibios_fixup_cardbus(struct pci_dev* dev)
{
+ if (_machine != _MACH_Pmac)
+ return;
/*
* Fix the interrupt routing on the TI1211 chip on the 1999
* G3 powerbook, which doesn't get initialized properly by OF.
+ * Same problem with the 1410 of the new titanium pbook which
+ * has the same register.
*/
if (dev->vendor == PCI_VENDOR_ID_TI
- && dev->device == PCI_DEVICE_ID_TI_1211) {
- u32 val;
+ && (dev->device == PCI_DEVICE_ID_TI_1211 ||
+ dev->device == PCI_DEVICE_ID_TI_1410)) {
+ u8 val;
/* 0x8c == TI122X_IRQMUX, 2 says to route the INTA
signal out the MFUNC0 pin */
- if (pci_read_config_dword(dev, 0x8c, &val) == 0
- && val == 0)
- pci_write_config_dword(dev, 0x8c, 2);
+ if (pci_read_config_byte(dev, 0x8c, &val) == 0)
+ pci_write_config_byte(dev, 0x8c, (val & ~0x0f) | 2);
+ /* Disable ISA interrupt mode */
+ if (pci_read_config_byte(dev, 0x92, &val) == 0)
+ pci_write_config_byte(dev, 0x92, val & ~0x06);
}
}
#endif /* CONFIG_ALL_PPC */
@@ -276,9 +284,17 @@
if (bus->parent == NULL)
pr = (res->flags & IORESOURCE_IO)?
&ioport_resource: &iomem_resource;
- else
+ else {
pr = pci_find_parent_resource(bus->self, res);
-
+ if (pr == res) {
+ /* this happens when the generic PCI
+ * code (wrongly) decides that this
+ * bridge is transparent -- paulus
+ */
+ continue;
+ }
+ }
+
if (pr && request_resource(pr, res) == 0)
continue;
printk(KERN_ERR "PCI: Cannot allocate resource region "
@@ -438,7 +454,7 @@
/*
* Functions below are used on OpenFirmware machines.
*/
-static void
+static void __openfirmware
make_one_node_map(struct device_node* node, u8 pci_bus)
{
int *bus_range;
@@ -472,7 +488,7 @@
}
}
-void
+void __openfirmware
pcibios_make_OF_bus_map(void)
{
int i;
@@ -512,17 +528,17 @@
#endif
}
-static struct device_node*
-scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+typedef int (*pci_OF_scan_iterator)(struct device_node* node, void* data);
+
+static struct device_node* __openfirmware
+scan_OF_pci_childs(struct device_node* node, pci_OF_scan_iterator filter, void* data)
{
struct device_node* sub_node;
for (; node != 0;node = node->sibling) {
- unsigned int *class_code, *reg;
+ unsigned int *class_code;
- reg = (unsigned int *) get_property(node, "reg", 0);
- if (reg && ((reg[0] >> 8) & 0xff) == dev_fn
- && ((reg[0] >> 16) & 0xff) == bus)
+ if (filter(node, data))
return node;
/* For PCI<->PCI bridges or CardBus bridges, we go down
@@ -535,13 +551,34 @@
(*class_code >> 8) != PCI_CLASS_BRIDGE_CARDBUS)) &&
strcmp(node->name, "multifunc-device"))
continue;
- sub_node = scan_OF_childs_for_device(node->child, bus, dev_fn);
+ sub_node = scan_OF_pci_childs(node->child, filter, data);
if (sub_node)
return sub_node;
}
return NULL;
}
+static int
+scan_OF_pci_childs_iterator(struct device_node* node, void* data)
+{
+ unsigned int *reg;
+ u8* fdata = (u8*)data;
+
+ reg = (unsigned int *) get_property(node, "reg", 0);
+ if (reg && ((reg[0] >> 8) & 0xff) == fdata[1]
+ && ((reg[0] >> 16) & 0xff) == fdata[0])
+ return 1;
+ return 0;
+}
+
+static struct device_node* __openfirmware
+scan_OF_childs_for_device(struct device_node* node, u8 bus, u8 dev_fn)
+{
+ u8 filter_data[2] = {bus, dev_fn};
+
+ return scan_OF_pci_childs(node, scan_OF_pci_childs_iterator, filter_data);
+}
+
/*
* Scans the OF tree for a device node matching a PCI device
*/
@@ -598,6 +635,12 @@
return NULL;
}
+static int __openfirmware
+find_OF_pci_device_filter(struct device_node* node, void* data)
+{
+ return ((void *)node == data);
+}
+
/*
* Returns the PCI device matching a given OF node
*/
@@ -605,21 +648,40 @@
pci_device_from_OF_node(struct device_node* node, u8* bus, u8* devfn)
{
unsigned int *reg;
- int i;
+ struct pci_controller* hose;
+ struct pci_dev* dev;
if (!have_of)
return -ENODEV;
+ /* Make sure it's really a PCI device */
+ hose = pci_find_hose_for_OF_device(node);
+ if (!hose || !hose->arch_data)
+ return -ENODEV;
+ if (!scan_OF_pci_childs(((struct device_node*)hose->arch_data)->child,
+ find_OF_pci_device_filter, (void *)node))
+ return -ENODEV;
reg = (unsigned int *) get_property(node, "reg", 0);
if (!reg)
return -ENODEV;
*bus = (reg[0] >> 16) & 0xff;
- for (i=0; pci_to_OF_bus_map && i<pci_bus_count; i++)
- if (pci_to_OF_bus_map[i] == *bus) {
- *bus = i;
- break;
- }
*devfn = ((reg[0] >> 8) & 0xff);
- return 0;
+
+ /* Ok, here we need some tweak. If we have already renumbered
+ * all busses, we can't rely on the OF bus number any more.
+ * the pci_to_OF_bus_map is not enough as several PCI busses
+ * may match the same OF bus number.
+ */
+ if (!pci_to_OF_bus_map)
+ return 0;
+ pci_for_each_dev(dev) {
+ if (pci_to_OF_bus_map[dev->bus->number] != *bus)
+ continue;
+ if (dev->devfn != *devfn)
+ continue;
+ *bus = dev->bus->number;
+ return 0;
+ }
+ return -ENODEV;
}
void __init
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)