Skip to content

Commit

Permalink
PCI: Rewrite pci_scan_slot
Browse files Browse the repository at this point in the history
The Alternate Routing-ID Interpretation capability allows a single device
to have up to 256 functions.  They can be populated sparsely, so the
current technique of scanning every eighth function is not guaranteed
to find them all.  By introducing a 'next_fn' function pointer, we can
use the linked list of functions in the ARI capability to scan all the
functions which exist.

We can then speed up the pci_scan_slot by skipping the scan of subsequent
devfns for PCIe devices which are the direct children of Root Ports or
Downstream Ports.  These devices are only permitted to implement device
0, unless they are ARI devices, in which case they'll be scanned by the
ARI code above.

Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
  • Loading branch information
Matthew Wilcox authored and Jesse Barnes committed Feb 23, 2010
1 parent bee415c commit f07852d
Showing 1 changed file with 47 additions and 9 deletions.
56 changes: 47 additions & 9 deletions drivers/pci/probe.c
Original file line number Diff line number Diff line change
Expand Up @@ -1081,6 +1081,37 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
}
EXPORT_SYMBOL(pci_scan_single_device);

static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
{
u16 cap;
unsigned pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
if (!pos)
return 0;
pci_read_config_word(dev, pos + 4, &cap);
return cap >> 8;
}

static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
{
return (fn + 1) % 8;
}

static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
{
return 0;
}

static int only_one_child(struct pci_bus *bus)
{
struct pci_dev *parent = bus->self;
if (!parent || !pci_is_pcie(parent))
return 0;
if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
return 1;
return 0;
}

/**
* pci_scan_slot - scan a PCI slot on a bus for devices.
* @bus: PCI bus to scan
Expand All @@ -1094,21 +1125,28 @@ EXPORT_SYMBOL(pci_scan_single_device);
*/
int pci_scan_slot(struct pci_bus *bus, int devfn)
{
int fn, nr = 0;
unsigned fn, nr = 0;
struct pci_dev *dev;
unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;

if (only_one_child(bus) && (devfn > 0))
return 0; /* Already scanned the entire slot */

dev = pci_scan_single_device(bus, devfn);
if (dev && !dev->is_added) /* new device? */
nr++;

if (dev && dev->multifunction) {
for (fn = 1; fn < 8; fn++) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)
nr++;
dev->multifunction = 1;
}
if (pci_ari_enabled(bus))
next_fn = next_ari_fn;
else if (dev && dev->multifunction)
next_fn = next_trad_fn;

for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
dev = pci_scan_single_device(bus, devfn + fn);
if (dev) {
if (!dev->is_added)
nr++;
dev->multifunction = 1;
}
}

Expand Down

0 comments on commit f07852d

Please sign in to comment.