diff options
-rw-r--r-- | drivers/pci/probe.c | 56 |
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 | } |
1082 | EXPORT_SYMBOL(pci_scan_single_device); | 1082 | EXPORT_SYMBOL(pci_scan_single_device); |
1083 | 1083 | ||
1084 | static 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 | |||
1094 | static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn) | ||
1095 | { | ||
1096 | return (fn + 1) % 8; | ||
1097 | } | ||
1098 | |||
1099 | static unsigned no_next_fn(struct pci_dev *dev, unsigned fn) | ||
1100 | { | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static 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 | */ |
1095 | int pci_scan_slot(struct pci_bus *bus, int devfn) | 1126 | int 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 | ||