diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci-driver.c | 25 | ||||
-rw-r--r-- | drivers/pci/pci-sysfs.c | 40 | ||||
-rw-r--r-- | drivers/pci/probe.c | 1 |
3 files changed, 63 insertions, 3 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c index d911e0c1f359..4393c12e9135 100644 --- a/drivers/pci/pci-driver.c +++ b/drivers/pci/pci-driver.c | |||
@@ -216,6 +216,13 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids, | |||
216 | return NULL; | 216 | return NULL; |
217 | } | 217 | } |
218 | 218 | ||
219 | static const struct pci_device_id pci_device_id_any = { | ||
220 | .vendor = PCI_ANY_ID, | ||
221 | .device = PCI_ANY_ID, | ||
222 | .subvendor = PCI_ANY_ID, | ||
223 | .subdevice = PCI_ANY_ID, | ||
224 | }; | ||
225 | |||
219 | /** | 226 | /** |
220 | * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure | 227 | * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure |
221 | * @drv: the PCI driver to match against | 228 | * @drv: the PCI driver to match against |
@@ -229,18 +236,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv, | |||
229 | struct pci_dev *dev) | 236 | struct pci_dev *dev) |
230 | { | 237 | { |
231 | struct pci_dynid *dynid; | 238 | struct pci_dynid *dynid; |
239 | const struct pci_device_id *found_id = NULL; | ||
240 | |||
241 | /* When driver_override is set, only bind to the matching driver */ | ||
242 | if (dev->driver_override && strcmp(dev->driver_override, drv->name)) | ||
243 | return NULL; | ||
232 | 244 | ||
233 | /* Look at the dynamic ids first, before the static ones */ | 245 | /* Look at the dynamic ids first, before the static ones */ |
234 | spin_lock(&drv->dynids.lock); | 246 | spin_lock(&drv->dynids.lock); |
235 | list_for_each_entry(dynid, &drv->dynids.list, node) { | 247 | list_for_each_entry(dynid, &drv->dynids.list, node) { |
236 | if (pci_match_one_device(&dynid->id, dev)) { | 248 | if (pci_match_one_device(&dynid->id, dev)) { |
237 | spin_unlock(&drv->dynids.lock); | 249 | found_id = &dynid->id; |
238 | return &dynid->id; | 250 | break; |
239 | } | 251 | } |
240 | } | 252 | } |
241 | spin_unlock(&drv->dynids.lock); | 253 | spin_unlock(&drv->dynids.lock); |
242 | 254 | ||
243 | return pci_match_id(drv->id_table, dev); | 255 | if (!found_id) |
256 | found_id = pci_match_id(drv->id_table, dev); | ||
257 | |||
258 | /* driver_override will always match, send a dummy id */ | ||
259 | if (!found_id && dev->driver_override) | ||
260 | found_id = &pci_device_id_any; | ||
261 | |||
262 | return found_id; | ||
244 | } | 263 | } |
245 | 264 | ||
246 | struct drv_dev_and_id { | 265 | struct drv_dev_and_id { |
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 4e0acefb7565..faa4ab554d68 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c | |||
@@ -499,6 +499,45 @@ static struct device_attribute sriov_numvfs_attr = | |||
499 | sriov_numvfs_show, sriov_numvfs_store); | 499 | sriov_numvfs_show, sriov_numvfs_store); |
500 | #endif /* CONFIG_PCI_IOV */ | 500 | #endif /* CONFIG_PCI_IOV */ |
501 | 501 | ||
502 | static ssize_t driver_override_store(struct device *dev, | ||
503 | struct device_attribute *attr, | ||
504 | const char *buf, size_t count) | ||
505 | { | ||
506 | struct pci_dev *pdev = to_pci_dev(dev); | ||
507 | char *driver_override, *old = pdev->driver_override, *cp; | ||
508 | |||
509 | if (count > PATH_MAX) | ||
510 | return -EINVAL; | ||
511 | |||
512 | driver_override = kstrndup(buf, count, GFP_KERNEL); | ||
513 | if (!driver_override) | ||
514 | return -ENOMEM; | ||
515 | |||
516 | cp = strchr(driver_override, '\n'); | ||
517 | if (cp) | ||
518 | *cp = '\0'; | ||
519 | |||
520 | if (strlen(driver_override)) { | ||
521 | pdev->driver_override = driver_override; | ||
522 | } else { | ||
523 | kfree(driver_override); | ||
524 | pdev->driver_override = NULL; | ||
525 | } | ||
526 | |||
527 | kfree(old); | ||
528 | |||
529 | return count; | ||
530 | } | ||
531 | |||
532 | static ssize_t driver_override_show(struct device *dev, | ||
533 | struct device_attribute *attr, char *buf) | ||
534 | { | ||
535 | struct pci_dev *pdev = to_pci_dev(dev); | ||
536 | |||
537 | return sprintf(buf, "%s\n", pdev->driver_override); | ||
538 | } | ||
539 | static DEVICE_ATTR_RW(driver_override); | ||
540 | |||
502 | static struct attribute *pci_dev_attrs[] = { | 541 | static struct attribute *pci_dev_attrs[] = { |
503 | &dev_attr_resource.attr, | 542 | &dev_attr_resource.attr, |
504 | &dev_attr_vendor.attr, | 543 | &dev_attr_vendor.attr, |
@@ -521,6 +560,7 @@ static struct attribute *pci_dev_attrs[] = { | |||
521 | #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) | 560 | #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI) |
522 | &dev_attr_d3cold_allowed.attr, | 561 | &dev_attr_d3cold_allowed.attr, |
523 | #endif | 562 | #endif |
563 | &dev_attr_driver_override.attr, | ||
524 | NULL, | 564 | NULL, |
525 | }; | 565 | }; |
526 | 566 | ||
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index ef09f5f2fe6c..54268de45f59 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -1215,6 +1215,7 @@ static void pci_release_dev(struct device *dev) | |||
1215 | pci_release_of_node(pci_dev); | 1215 | pci_release_of_node(pci_dev); |
1216 | pcibios_release_device(pci_dev); | 1216 | pcibios_release_device(pci_dev); |
1217 | pci_bus_put(pci_dev->bus); | 1217 | pci_bus_put(pci_dev->bus); |
1218 | kfree(pci_dev->driver_override); | ||
1218 | kfree(pci_dev); | 1219 | kfree(pci_dev); |
1219 | } | 1220 | } |
1220 | 1221 | ||