Skip to content

Commit 782a985

Browse files
awilliambjorn-helgaas
authored andcommitted
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 <[email protected]> Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Konrad Rzeszutek Wilk <[email protected]> Reviewed-by: Alexander Graf <[email protected]> Acked-by: Greg Kroah-Hartman <[email protected]>
1 parent 3cb30b7 commit 782a985

File tree

5 files changed

+85
-3
lines changed

5 files changed

+85
-3
lines changed

Documentation/ABI/testing/sysfs-bus-pci

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,3 +250,24 @@ Description:
250250
valid. For example, writing a 2 to this file when sriov_numvfs
251251
is not 0 and not 2 already will return an error. Writing a 10
252252
when the value of sriov_totalvfs is 8 will return an error.
253+
254+
What: /sys/bus/pci/devices/.../driver_override
255+
Date: April 2014
256+
Contact: Alex Williamson <[email protected]>
257+
Description:
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.

drivers/pci/pci-driver.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,13 @@ const struct pci_device_id *pci_match_id(const struct pci_device_id *ids,
216216
return NULL;
217217
}
218218

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+
219226
/**
220227
* pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
221228
* @drv: the PCI driver to match against
@@ -229,18 +236,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
229236
struct pci_dev *dev)
230237
{
231238
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;
232244

233245
/* Look at the dynamic ids first, before the static ones */
234246
spin_lock(&drv->dynids.lock);
235247
list_for_each_entry(dynid, &drv->dynids.list, node) {
236248
if (pci_match_one_device(&dynid->id, dev)) {
237-
spin_unlock(&drv->dynids.lock);
238-
return &dynid->id;
249+
found_id = &dynid->id;
250+
break;
239251
}
240252
}
241253
spin_unlock(&drv->dynids.lock);
242254

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;
244263
}
245264

246265
struct drv_dev_and_id {

drivers/pci/pci-sysfs.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,45 @@ static struct device_attribute sriov_numvfs_attr =
499499
sriov_numvfs_show, sriov_numvfs_store);
500500
#endif /* CONFIG_PCI_IOV */
501501

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+
502541
static struct attribute *pci_dev_attrs[] = {
503542
&dev_attr_resource.attr,
504543
&dev_attr_vendor.attr,
@@ -521,6 +560,7 @@ static struct attribute *pci_dev_attrs[] = {
521560
#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
522561
&dev_attr_d3cold_allowed.attr,
523562
#endif
563+
&dev_attr_driver_override.attr,
524564
NULL,
525565
};
526566

drivers/pci/probe.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,6 +1215,7 @@ static void pci_release_dev(struct device *dev)
12151215
pci_release_of_node(pci_dev);
12161216
pcibios_release_device(pci_dev);
12171217
pci_bus_put(pci_dev->bus);
1218+
kfree(pci_dev->driver_override);
12181219
kfree(pci_dev);
12191220
}
12201221

include/linux/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ struct pci_dev {
365365
#endif
366366
phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
367367
size_t romlen; /* Length of ROM if it's not from the BAR */
368+
char *driver_override; /* Driver name to force a match */
368369
};
369370

370371
static inline struct pci_dev *pci_physfn(struct pci_dev *dev)

0 commit comments

Comments
 (0)