aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2014-05-20 10:53:21 -0400
committerBjorn Helgaas <bhelgaas@google.com>2014-05-28 18:04:53 -0400
commit782a985d7af26db39e86070d28f987cad21313c0 (patch)
tree637034dde8f75f513c4fdde6450773c4adc96e8f
parent3cb30b73ad71b384c6289243d4ccd31ab90bce6f (diff)
PCI: Introduce new device binding path using pci_dev.driver_override
The driver_override field allows us to specify the driver for a device rather than relying on the driver to provide a positive match of the device. This shortcuts the existing process of looking up the vendor and device ID, adding them to the driver new_id, binding the device, then removing the ID, but it also provides a couple advantages. First, the above existing process allows the driver to bind to any device matching the new_id for the window where it's enabled. This is often not desired, such as the case of trying to bind a single device to a meta driver like pci-stub or vfio-pci. Using driver_override we can do this deterministically using: echo pci-stub > /sys/bus/pci/devices/0000:03:00.0/driver_override echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind echo 0000:03:00.0 > /sys/bus/pci/drivers_probe Previously we could not invoke drivers_probe after adding a device to new_id for a driver as we get non-deterministic behavior whether the driver we intend or the standard driver will claim the device. Now it becomes a deterministic process, only the driver matching driver_override will probe the device. To return the device to the standard driver, we simply clear the driver_override and reprobe the device: echo > /sys/bus/pci/devices/0000:03:00.0/driver_override echo 0000:03:00.0 > /sys/bus/pci/devices/0000:03:00.0/driver/unbind echo 0000:03:00.0 > /sys/bus/pci/drivers_probe Another advantage to this approach is that we can specify a driver override to force a specific binding or prevent any binding. For instance when an IOMMU group is exposed to userspace through VFIO we require that all devices within that group are owned by VFIO. However, devices can be hot-added into an IOMMU group, in which case we want to prevent the device from binding to any driver (override driver = "none") or perhaps have it automatically bind to vfio-pci. With driver_override it's a simple matter for this field to be set internally when the device is first discovered to prevent driver matches. Signed-off-by: Alex Williamson <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Reviewed-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Reviewed-by: Alexander Graf <agraf@suse.de> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci21
-rw-r--r--drivers/pci/pci-driver.c25
-rw-r--r--drivers/pci/pci-sysfs.c40
-rw-r--r--drivers/pci/probe.c1
-rw-r--r--include/linux/pci.h1
5 files changed, 85 insertions, 3 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index a3c5a6685036..898ddc4440e6 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -250,3 +250,24 @@ Description:
250 valid. For example, writing a 2 to this file when sriov_numvfs 250 valid. For example, writing a 2 to this file when sriov_numvfs
251 is not 0 and not 2 already will return an error. Writing a 10 251 is not 0 and not 2 already will return an error. Writing a 10
252 when the value of sriov_totalvfs is 8 will return an error. 252 when the value of sriov_totalvfs is 8 will return an error.
253
254What: /sys/bus/pci/devices/.../driver_override
255Date: April 2014
256Contact: Alex Williamson <alex.williamson@redhat.com>
257Description:
258 This file allows the driver for a device to be specified which
259 will override standard static and dynamic ID matching. When
260 specified, only a driver with a name matching the value written
261 to driver_override will have an opportunity to bind to the
262 device. The override is specified by writing a string to the
263 driver_override file (echo pci-stub > driver_override) and
264 may be cleared with an empty string (echo > driver_override).
265 This returns the device to standard matching rules binding.
266 Writing to driver_override does not automatically unbind the
267 device from its current driver or make any attempt to
268 automatically load the specified driver. If no driver with a
269 matching name is currently loaded in the kernel, the device
270 will not bind to any driver. This also allows devices to
271 opt-out of driver binding using a driver_override name such as
272 "none". Only a single driver may be specified in the override,
273 there is no support for parsing delimiters.
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
219static 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
246struct drv_dev_and_id { 265struct 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
502static 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
532static 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}
539static DEVICE_ATTR_RW(driver_override);
540
502static struct attribute *pci_dev_attrs[] = { 541static 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
diff --git a/include/linux/pci.h b/include/linux/pci.h
index aab57b4abe7f..b72af276f591 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -365,6 +365,7 @@ struct pci_dev {
365#endif 365#endif
366 phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */ 366 phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
367 size_t romlen; /* Length of ROM if it's not from the BAR */ 367 size_t romlen; /* Length of ROM if it's not from the BAR */
368 char *driver_override; /* Driver name to force a match */
368}; 369};
369 370
370static inline struct pci_dev *pci_physfn(struct pci_dev *dev) 371static inline struct pci_dev *pci_physfn(struct pci_dev *dev)