aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorMatthew Wilcox <matthew@wil.cx>2009-12-13 08:10:02 -0500
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-02-22 19:15:16 -0500
commitf07852d6442c46c50b59c7e2acc8a1b291f9ab6d (patch)
treed855a7bc7df8f3e84f1d267e060537ec011477c6 /drivers/pci
parentbee415ce427d1eab6cfb30221461c7d20cbf1903 (diff)
PCI: Rewrite pci_scan_slot
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>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/probe.c56
1 files changed, 47 insertions, 9 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 446e4a94d7d3..dd64310a735e 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1081,6 +1081,37 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
1081} 1081}
1082EXPORT_SYMBOL(pci_scan_single_device); 1082EXPORT_SYMBOL(pci_scan_single_device);
1083 1083
1084static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
1085{
1086 u16 cap;
1087 unsigned pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
1088 if (!pos)
1089 return 0;
1090 pci_read_config_word(dev, pos + 4, &cap);
1091 return cap >> 8;
1092}
1093
1094static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
1095{
1096 return (fn + 1) % 8;
1097}
1098
1099static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
1100{
1101 return 0;
1102}
1103
1104static int only_one_child(struct pci_bus *bus)
1105{
1106 struct pci_dev *parent = bus->self;
1107 if (!parent || !pci_is_pcie(parent))
1108 return 0;
1109 if (parent->pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
1110 parent->pcie_type == PCI_EXP_TYPE_DOWNSTREAM)
1111 return 1;
1112 return 0;
1113}
1114
1084/** 1115/**
1085 * pci_scan_slot - scan a PCI slot on a bus for devices. 1116 * pci_scan_slot - scan a PCI slot on a bus for devices.
1086 * @bus: PCI bus to scan 1117 * @bus: PCI bus to scan
@@ -1094,21 +1125,28 @@ EXPORT_SYMBOL(pci_scan_single_device);
1094 */ 1125 */
1095int pci_scan_slot(struct pci_bus *bus, int devfn) 1126int pci_scan_slot(struct pci_bus *bus, int devfn)
1096{ 1127{
1097 int fn, nr = 0; 1128 unsigned fn, nr = 0;
1098 struct pci_dev *dev; 1129 struct pci_dev *dev;
1130 unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
1131
1132 if (only_one_child(bus) && (devfn > 0))
1133 return 0; /* Already scanned the entire slot */
1099 1134
1100 dev = pci_scan_single_device(bus, devfn); 1135 dev = pci_scan_single_device(bus, devfn);
1101 if (dev && !dev->is_added) /* new device? */ 1136 if (dev && !dev->is_added) /* new device? */
1102 nr++; 1137 nr++;
1103 1138
1104 if (dev && dev->multifunction) { 1139 if (pci_ari_enabled(bus))
1105 for (fn = 1; fn < 8; fn++) { 1140 next_fn = next_ari_fn;
1106 dev = pci_scan_single_device(bus, devfn + fn); 1141 else if (dev && dev->multifunction)
1107 if (dev) { 1142 next_fn = next_trad_fn;
1108 if (!dev->is_added) 1143
1109 nr++; 1144 for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
1110 dev->multifunction = 1; 1145 dev = pci_scan_single_device(bus, devfn + fn);
1111 } 1146 if (dev) {
1147 if (!dev->is_added)
1148 nr++;
1149 dev->multifunction = 1;
1112 } 1150 }
1113 } 1151 }
1114 1152