[patch 2.5] PCI: allow alternative methods for probing the BARs

From: Ivan Kokshaysky (ink@jurassic.park.msu.ru)
Date: Sun Jan 05 2003 - 07:37:35 EST


Hopefully this patch should solve most problems with probing the BARs.
The changes are quite minimal as everything still is done in one pass.
- Added another level of fixups (PCI_FIXUP_EARLY), called with only
  device/vendor IDs and class code filled in, before sizing the BARs.
- pci_read_bases won't probe the BAR if the respective resource has
  non-zero flags.

This allows to implement numerous alternative probing methods for
particular architecture/device/BAR. Some of possible variants:
get information from firmware and don't touch the BAR at all;
write the BAR value into respective resource->start and set
resource->end according to the chip manual without probing;
disable the device, call generic pci_read_bases(), re-enable the device;
probe with value other than 0xffffffff and so on.

Besides, this would easily solve one interesting (though unrelated) problem.
There are quite a few devices (IDE controllers, AGP aperture stuff,
some bridges) that significantly change their PCI header including BARs,
class code etc. depending on some configuration bits, so it might be useful
to program the device into desired state before probing.

Ivan.

--- 2.5.54/drivers/pci/probe.c Thu Jan 2 06:22:34 2003
+++ linux/drivers/pci/probe.c Sat Jan 4 19:02:19 2003
@@ -53,6 +53,9 @@ static void pci_read_bases(struct pci_de
                 next = pos+1;
                 res = &dev->resource[pos];
                 res->name = dev->dev.name;
+ /* Skip already probed resources */
+ if (res->flags)
+ continue;
                 reg = PCI_BASE_ADDRESS_0 + (pos << 2);
                 pci_read_config_dword(dev, reg, &l);
                 pci_write_config_dword(dev, reg, ~0);
@@ -355,10 +358,7 @@ int pci_setup_device(struct pci_dev * de
         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);
 
@@ -433,9 +433,16 @@ 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;
+
+ /* Early fixups, before probing the BARs */
+ pci_fixup_device(PCI_FIXUP_EARLY, dev);
+
         if (pci_setup_device(dev) < 0) {
                 kfree(dev);
                 return NULL;
--- 2.5.54/include/linux/pci.h Thu Jan 2 06:21:56 2003
+++ linux/include/linux/pci.h Sun Jan 5 15:27:51 2003
@@ -809,8 +809,12 @@ 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
+ header type, 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/



This archive was generated by hypermail 2b29 : Tue Jan 07 2003 - 22:00:28 EST