aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/admin-guide/kernel-parameters.txt8
-rw-r--r--drivers/pci/pci.c118
2 files changed, 103 insertions, 23 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index ab36fb34ed01..4fa4c9ff04ae 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3000,7 +3000,7 @@
3000 or a set of devices (<pci_dev>). These are 3000 or a set of devices (<pci_dev>). These are
3001 specified in one of the following formats: 3001 specified in one of the following formats:
3002 3002
3003 [<domain>:]<bus>:<device>.<func> 3003 [<domain>:]<bus>:<dev>.<func>[/<dev>.<func>]*
3004 pci:<vendor>:<device>[:<subvendor>:<subdevice>] 3004 pci:<vendor>:<device>[:<subvendor>:<subdevice>]
3005 3005
3006 Note: the first format specifies a PCI 3006 Note: the first format specifies a PCI
@@ -3009,7 +3009,11 @@
3009 firmware changes, or due to changes caused 3009 firmware changes, or due to changes caused
3010 by other kernel parameters. If the 3010 by other kernel parameters. If the
3011 domain is left unspecified, it is 3011 domain is left unspecified, it is
3012 taken to be zero. The second format 3012 taken to be zero. Optionally, a path
3013 to a device through multiple device/function
3014 addresses can be specified after the base
3015 address (this is more robust against
3016 renumbering issues). The second format
3013 selects devices using IDs from the 3017 selects devices using IDs from the
3014 configuration space which may match multiple 3018 configuration space which may match multiple
3015 devices in the system. 3019 devices in the system.
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 1574b2da25e7..a6c38b15ac33 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -192,6 +192,89 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
192#endif 192#endif
193 193
194/** 194/**
195 * pci_dev_str_match_path - test if a path string matches a device
196 * @dev: the PCI device to test
197 * @p: string to match the device against
198 * @endptr: pointer to the string after the match
199 *
200 * Test if a string (typically from a kernel parameter) formatted as a
201 * path of device/function addresses matches a PCI device. The string must
202 * be of the form:
203 *
204 * [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
205 *
206 * A path for a device can be obtained using 'lspci -t'. Using a path
207 * is more robust against bus renumbering than using only a single bus,
208 * device and function address.
209 *
210 * Returns 1 if the string matches the device, 0 if it does not and
211 * a negative error code if it fails to parse the string.
212 */
213static int pci_dev_str_match_path(struct pci_dev *dev, const char *path,
214 const char **endptr)
215{
216 int ret;
217 int seg, bus, slot, func;
218 char *wpath, *p;
219 char end;
220
221 *endptr = strchrnul(path, ';');
222
223 wpath = kmemdup_nul(path, *endptr - path, GFP_KERNEL);
224 if (!wpath)
225 return -ENOMEM;
226
227 while (1) {
228 p = strrchr(wpath, '/');
229 if (!p)
230 break;
231 ret = sscanf(p, "/%x.%x%c", &slot, &func, &end);
232 if (ret != 2) {
233 ret = -EINVAL;
234 goto free_and_exit;
235 }
236
237 if (dev->devfn != PCI_DEVFN(slot, func)) {
238 ret = 0;
239 goto free_and_exit;
240 }
241
242 /*
243 * Note: we don't need to get a reference to the upstream
244 * bridge because we hold a reference to the top level
245 * device which should hold a reference to the bridge,
246 * and so on.
247 */
248 dev = pci_upstream_bridge(dev);
249 if (!dev) {
250 ret = 0;
251 goto free_and_exit;
252 }
253
254 *p = 0;
255 }
256
257 ret = sscanf(wpath, "%x:%x:%x.%x%c", &seg, &bus, &slot,
258 &func, &end);
259 if (ret != 4) {
260 seg = 0;
261 ret = sscanf(wpath, "%x:%x.%x%c", &bus, &slot, &func, &end);
262 if (ret != 3) {
263 ret = -EINVAL;
264 goto free_and_exit;
265 }
266 }
267
268 ret = (seg == pci_domain_nr(dev->bus) &&
269 bus == dev->bus->number &&
270 dev->devfn == PCI_DEVFN(slot, func));
271
272free_and_exit:
273 kfree(wpath);
274 return ret;
275}
276
277/**
195 * pci_dev_str_match - test if a string matches a device 278 * pci_dev_str_match - test if a string matches a device
196 * @dev: the PCI device to test 279 * @dev: the PCI device to test
197 * @p: string to match the device against 280 * @p: string to match the device against
@@ -200,13 +283,16 @@ EXPORT_SYMBOL_GPL(pci_ioremap_wc_bar);
200 * Test if a string (typically from a kernel parameter) matches a specified 283 * Test if a string (typically from a kernel parameter) matches a specified
201 * PCI device. The string may be of one of the following formats: 284 * PCI device. The string may be of one of the following formats:
202 * 285 *
203 * [<domain>:]<bus>:<device>.<func> 286 * [<domain>:]<bus>:<device>.<func>[/<device>.<func>]*
204 * pci:<vendor>:<device>[:<subvendor>:<subdevice>] 287 * pci:<vendor>:<device>[:<subvendor>:<subdevice>]
205 * 288 *
206 * The first format specifies a PCI bus/device/function address which 289 * The first format specifies a PCI bus/device/function address which
207 * may change if new hardware is inserted, if motherboard firmware changes, 290 * may change if new hardware is inserted, if motherboard firmware changes,
208 * or due to changes caused in kernel parameters. If the domain is 291 * or due to changes caused in kernel parameters. If the domain is
209 * left unspecified, it is taken to be 0. 292 * left unspecified, it is taken to be 0. In order to be robust against
293 * bus renumbering issues, a path of PCI device/function numbers may be used
294 * to address the specific device. The path for a device can be determined
295 * through the use of 'lspci -t'.
210 * 296 *
211 * The second format matches devices using IDs in the configuration 297 * The second format matches devices using IDs in the configuration
212 * space which may match multiple devices in the system. A value of 0 298 * space which may match multiple devices in the system. A value of 0
@@ -222,7 +308,7 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
222 const char **endptr) 308 const char **endptr)
223{ 309{
224 int ret; 310 int ret;
225 int seg, bus, slot, func, count; 311 int count;
226 unsigned short vendor, device, subsystem_vendor, subsystem_device; 312 unsigned short vendor, device, subsystem_vendor, subsystem_device;
227 313
228 if (strncmp(p, "pci:", 4) == 0) { 314 if (strncmp(p, "pci:", 4) == 0) {
@@ -248,25 +334,15 @@ static int pci_dev_str_match(struct pci_dev *dev, const char *p,
248 (!subsystem_device || 334 (!subsystem_device ||
249 subsystem_device == dev->subsystem_device)) 335 subsystem_device == dev->subsystem_device))
250 goto found; 336 goto found;
251
252 } else { 337 } else {
253 /* PCI Bus, Device, Function IDs are specified */ 338 /*
254 ret = sscanf(p, "%x:%x:%x.%x%n", &seg, &bus, &slot, 339 * PCI Bus, Device, Function IDs are specified
255 &func, &count); 340 * (optionally, may include a path of devfns following it)
256 if (ret != 4) { 341 */
257 seg = 0; 342 ret = pci_dev_str_match_path(dev, p, &p);
258 ret = sscanf(p, "%x:%x.%x%n", &bus, &slot, 343 if (ret < 0)
259 &func, &count); 344 return ret;
260 if (ret != 3) 345 else if (ret)
261 return -EINVAL;
262 }
263
264 p += count;
265
266 if (seg == pci_domain_nr(dev->bus) &&
267 bus == dev->bus->number &&
268 slot == PCI_SLOT(dev->devfn) &&
269 func == PCI_FUNC(dev->devfn))
270 goto found; 346 goto found;
271 } 347 }
272 348