There is no need for changes to arch-specific code, as everything
is hidden in pci_scan_bus(). However, it's possible to use
pci_scan_bus_parented() and pci_probe_resources() directly,
because some arch-specific fixups between these two might
be useful.
Note: on powermacs, if the I/O ASIC is behind PCI-PCI bridge, the
bridge device probably should be marked as "skip_probe" as well.
Ivan.
diff -urpN 2.5.55/drivers/pci/probe.c linux/drivers/pci/probe.c
--- 2.5.55/drivers/pci/probe.c Thu Jan 9 07:04:19 2003
+++ linux/drivers/pci/probe.c Thu Jan 9 13:47:47 2003
@@ -47,8 +47,17 @@ static void pci_read_bases(struct pci_de
{
unsigned int pos, reg, next;
u32 l, sz;
+ u16 cmd;
struct resource *res;
+ if (dev->skip_probe)
+ return;
+
+ /* Disable I/O & memory decoding while we size the BARs. */
+ pci_read_config_word(dev, PCI_COMMAND, &cmd);
+ pci_write_config_word(dev, PCI_COMMAND,
+ cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY));
+
for(pos=0; pos<howmany; pos = next) {
next = pos+1;
res = &dev->resource[pos];
@@ -96,6 +105,9 @@ static void pci_read_bases(struct pci_de
#endif
}
}
+
+ pci_write_config_word(dev, PCI_COMMAND, cmd);
+
if (rom) {
dev->rom_base_reg = rom;
res = &dev->resource[PCI_ROM_RESOURCE];
@@ -342,7 +354,7 @@ static void pci_read_irq(struct pci_dev
* @dev: the device structure to fill
*
* Initialize the device structure with information about the device's
- * vendor,class,memory and IO-space addresses,IRQ lines etc.
+ * vendor, memory and IO-space addresses, IRQ lines etc.
* Called at initialisation of the PCI subsystem and by CardBus services.
* Returns 0 on success and -1 if unknown type of device (not normal, bridge
* or CardBus).
@@ -351,14 +363,9 @@ int pci_setup_device(struct pci_dev * de
{
u32 class;
- sprintf(dev->slot_name, "%02x:%02x.%d", dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
- sprintf(dev->dev.name, "PCI device %04x:%04x", dev->vendor, dev->device);
INIT_LIST_HEAD(&dev->pools);
- pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
- class >>= 8; /* upper 3 bytes */
- dev->class = class;
- class >>= 8;
+ class = dev->class >> 8;
DBG("Found %02x:%02x [%04x/%04x] %06x %02x\n", dev->bus->number, dev->devfn, dev->vendor, dev->device, class, dev->hdr_type);
@@ -410,8 +417,8 @@ int pci_setup_device(struct pci_dev * de
}
/*
- * Read the config data for a PCI device, sanity-check it
- * and fill in the dev structure...
+ * Read the config data for a PCI device and fill in
+ * the dev structure...
*/
struct pci_dev * __devinit pci_scan_device(struct pci_dev *temp)
{
@@ -433,18 +440,23 @@ struct pci_dev * __devinit pci_scan_devi
dev->vendor = l & 0xffff;
dev->device = (l >> 16) & 0xffff;
+ pci_read_config_dword(dev, PCI_CLASS_REVISION, &l);
+ dev->class = l >> 8; /* upper 3 bytes */
+
/* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer)
set this higher, assuming the system even supports it. */
dev->dma_mask = 0xffffffff;
- if (pci_setup_device(dev) < 0) {
- kfree(dev);
- return NULL;
- }
pci_name_device(dev);
+ sprintf(dev->slot_name, "%02x:%02x.%d",
+ dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+
+ /* Early fixups, before probing the BARs */
+ pci_fixup_device(PCI_FIXUP_EARLY, dev);
+
/* now put in global tree */
- strcpy(dev->dev.bus_id,dev->slot_name);
+ strcpy(dev->dev.bus_id, dev->slot_name);
dev->dev.dma_mask = &dev->dma_mask;
device_register(&dev->dev);
@@ -480,13 +492,12 @@ struct pci_dev * __devinit pci_scan_slot
* the per-bus list of devices and add the /proc entry.
*/
pci_insert_device (dev, bus);
-
- /* Fix up broken headers */
- pci_fixup_device(PCI_FIXUP_HEADER, dev);
}
return first_dev;
}
+/* First phase of device discovery. Build the bus tree, collect header types,
+ class codes, device and vendor IDs. Perform early fixups. */
unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
{
unsigned int devfn, max, pass;
@@ -510,11 +521,8 @@ unsigned int __devinit pci_do_scan_bus(s
}
/*
- * After performing arch-dependent fixup of the bus, look behind
- * all PCI-to-PCI bridges on this bus.
+ * Look behind all PCI-to-PCI bridges on this bus.
*/
- DBG("Fixups for bus %02x\n", bus->number);
- pcibios_fixup_bus(bus);
for (pass=0; pass < 2; pass++)
for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) {
dev = pci_dev_b(ln);
@@ -545,6 +553,38 @@ int __devinit pci_bus_exists(const struc
return 0;
}
+/* Second phase of device discovery. Probe the BARs, fill in the rest
+ of pci_dev structure, perform device and bus fixups. */
+void __devinit pci_probe_resources(struct pci_bus *bus)
+{
+ struct list_head *ln;
+
+ if (!bus)
+ return;
+
+ for (ln = bus->devices.next; ln != &bus->devices; ln = ln->next) {
+ struct pci_dev *dev = pci_dev_b(ln);
+
+ if (pci_setup_device(dev) < 0) {
+ pci_remove_device(dev);
+ kfree(dev);
+ }
+
+ /* Fix up broken headers */
+ pci_fixup_device(PCI_FIXUP_HEADER, dev);
+ }
+
+ /*
+ * After performing arch-dependent fixup of the bus, look behind
+ * all PCI-to-PCI bridges on this bus.
+ */
+ DBG("Fixups for bus %02x\n", bus->number);
+ pcibios_fixup_bus(bus);
+
+ for (ln = bus->children.next; ln != &bus->children; ln = ln->next)
+ pci_probe_resources(pci_bus_b(ln));
+}
+
struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, int bus)
{
struct pci_bus *b;
@@ -600,4 +640,5 @@ EXPORT_SYMBOL(pci_do_scan_bus);
EXPORT_SYMBOL(pci_scan_slot);
EXPORT_SYMBOL(pci_scan_bus);
EXPORT_SYMBOL(pci_scan_bridge);
+EXPORT_SYMBOL(pci_probe_resources);
#endif
diff -urpN 2.5.55/include/linux/pci.h linux/include/linux/pci.h
--- 2.5.55/include/linux/pci.h Thu Jan 9 07:04:13 2003
+++ linux/include/linux/pci.h Thu Jan 9 13:40:32 2003
@@ -412,7 +412,8 @@ struct pci_dev {
char slot_name[8]; /* slot name */
/* These fields are used by common fixups */
- unsigned int transparent:1; /* Transparent PCI bridge */
+ unsigned int transparent:1, /* Transparent PCI bridge */
+ skip_probe:1; /* Don't probe the BARs */
};
#define pci_dev_g(n) list_entry(n, struct pci_dev, global_list)
@@ -544,11 +545,14 @@ void pcibios_fixup_pbus_ranges(struct pc
/* Generic PCI functions used internally */
+void pci_probe_resources(struct pci_bus *bus);
int pci_bus_exists(const struct list_head *list, int nr);
struct pci_bus *pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata);
static inline struct pci_bus *pci_scan_bus(int bus, struct pci_ops *ops, void *sysdata)
{
- return pci_scan_bus_parented(NULL, bus, ops, sysdata);
+ struct pci_bus *pbus = pci_scan_bus_parented(NULL, bus, ops, sysdata);
+ pci_probe_resources(pbus);
+ return pbus;
}
struct pci_bus *pci_alloc_primary_bus_parented(struct device * parent, int bus);
static inline struct pci_bus *pci_alloc_primary_bus(int bus)
@@ -809,8 +813,11 @@ struct pci_fixup {
extern struct pci_fixup pcibios_fixups[];
-#define PCI_FIXUP_HEADER 1 /* Called immediately after reading configuration header */
-#define PCI_FIXUP_FINAL 2 /* Final phase of device fixups */
+#define PCI_FIXUP_EARLY 1 /* Called immediately after reading
+ device/vendor IDs and class code */
+#define PCI_FIXUP_HEADER 2 /* Called after reading configuration
+ header (including BARs) */
+#define PCI_FIXUP_FINAL 3 /* Final phase of device fixups */
void pci_fixup_device(int pass, struct pci_dev *dev);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/