linux-pci.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override
@ 2014-04-04 20:19 Alex Williamson
  2014-04-09  1:47 ` [PATCH] driver core: platform: add device binding path 'driver_override' Kim Phillips
                   ` (2 more replies)
  0 siblings, 3 replies; 5+ messages in thread
From: Alex Williamson @ 2014-04-04 20:19 UTC (permalink / raw)
  To: bhelgaas, linux-pci
  Cc: agraf, kvm, konrad.wilk, kim.phillips, gregkh, stuart.yoder,
	linux-kernel, libvir-list, iommu, tech, kvmarm, christoffer.dall

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/preferred_driver
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 (preferred
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>
---

Changes since RFC:
 - Add ABI documentation (gregkh)
 - Documentation wording clarification (Christoffer)

Nobody puked on the RFC and platform folks have posted a working
version of this for platform devices, so I guess the only thing left
to do is formally propose this as a new driver binding mechanism.  I
don't see much incentive to push this into the driver core since the
match ultimately needs to be done by the bus driver.  I think this is
therefore like new_id/remove_id where PCI and USB implement separate,
but consistent interfaces.

I've pruned the CC list a bit from the RFC, but I've added libvirt
folks since I expect they would be the first userspace tool that would
adopt this.  Thanks,

Alex

 Documentation/ABI/testing/sysfs-bus-pci |   21 ++++++++++++++++
 drivers/pci/pci-driver.c                |   25 +++++++++++++++++--
 drivers/pci/pci-sysfs.c                 |   40 +++++++++++++++++++++++++++++++
 include/linux/pci.h                     |    1 +
 4 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index a3c5a66..898ddc4 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -250,3 +250,24 @@ Description:
 		valid.  For example, writing a 2 to this file when sriov_numvfs
 		is not 0 and not 2 already will return an error. Writing a 10
 		when the value of sriov_totalvfs is 8 will return an error.
+
+What:		/sys/bus/pci/devices/.../driver_override
+Date:		April 2014
+Contact:	Alex Williamson <alex.williamson@redhat.com>
+Description:
+		This file allows the driver for a device to be specified which
+		will override standard static and dynamic ID matching.  When
+		specified, only a driver with a name matching the value written
+		to driver_override will have an opportunity to bind to the
+		device.  The override is specified by writing a string to the
+		driver_override file (echo pci-stub > driver_override) and
+		may be cleared with an empty string (echo > driver_override).
+		This returns the device to standard matching rules binding.
+		Writing to driver_override does not automatically unbind the
+		device from its current driver or make any attempt to
+		automatically load the specified driver.  If no driver with a
+		matching name is currently loaded in the kernel, the device
+		will not bind to any driver.  This also allows devices to
+		opt-out of driver binding using a driver_override name such as
+		"none".  Only a single driver may be specified in the override,
+		there is no support for parsing delimiters.
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 25f0bc6..f780eb8 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,
 	return NULL;
 }
 
+static const struct pci_device_id pci_device_id_any = {
+	.vendor = PCI_ANY_ID,
+	.device = PCI_ANY_ID,
+	.subvendor = PCI_ANY_ID,
+	.subdevice = PCI_ANY_ID,
+};
+
 /**
  * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
  * @drv: the PCI driver to match against
@@ -229,18 +236,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
 						    struct pci_dev *dev)
 {
 	struct pci_dynid *dynid;
+	const struct pci_device_id *found_id = NULL;
+
+	/* When driver_override is set, only bind to the matching driver */
+	if (dev->driver_override && strcmp(dev->driver_override, drv->name))
+		return NULL;
 
 	/* Look at the dynamic ids first, before the static ones */
 	spin_lock(&drv->dynids.lock);
 	list_for_each_entry(dynid, &drv->dynids.list, node) {
 		if (pci_match_one_device(&dynid->id, dev)) {
-			spin_unlock(&drv->dynids.lock);
-			return &dynid->id;
+			found_id = &dynid->id;
+			break;
 		}
 	}
 	spin_unlock(&drv->dynids.lock);
 
-	return pci_match_id(drv->id_table, dev);
+	if (!found_id)
+		found_id = pci_match_id(drv->id_table, dev);
+
+	/* driver_override will always match, send a dummy id */
+	if (!found_id && dev->driver_override)
+		found_id = &pci_device_id_any;
+
+	return found_id;
 }
 
 struct drv_dev_and_id {
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 276ef9c..70cb39d 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -510,6 +510,45 @@ static struct device_attribute sriov_numvfs_attr =
 		       sriov_numvfs_show, sriov_numvfs_store);
 #endif /* CONFIG_PCI_IOV */
 
+static ssize_t driver_override_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	char *driver_override, *old = pdev->driver_override;
+
+	if (count > PATH_MAX)
+		return -EINVAL;
+
+	driver_override = kstrndup(buf, count, GFP_KERNEL);
+	if (!driver_override)
+		return -ENOMEM;
+
+	while (strlen(driver_override) &&
+	       driver_override[strlen(driver_override) - 1] == '\n')
+		driver_override[strlen(driver_override) - 1] = '\0';
+
+	if (strlen(driver_override)) {
+		pdev->driver_override = driver_override;
+	} else {
+		kfree(driver_override);
+		pdev->driver_override = NULL;
+	}
+
+	kfree(old);
+
+	return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+
+	return sprintf(buf, "%s\n", pdev->driver_override);
+}
+static DEVICE_ATTR_RW(driver_override);
+
 static struct attribute *pci_dev_attrs[] = {
 	&dev_attr_resource.attr,
 	&dev_attr_vendor.attr,
@@ -532,6 +571,7 @@ static struct attribute *pci_dev_attrs[] = {
 #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
 	&dev_attr_d3cold_allowed.attr,
 #endif
+	&dev_attr_driver_override.attr,
 	NULL,
 };
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 33aa2ca..6b666af 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -364,6 +364,7 @@ struct pci_dev {
 #endif
 	phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
 	size_t romlen; /* Length of ROM if it's not from the BAR */
+	char *driver_override; /* Driver name to force a match */
 };
 
 static inline struct pci_dev *pci_physfn(struct pci_dev *dev)


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* [PATCH] driver core: platform: add device binding path 'driver_override'
  2014-04-04 20:19 [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Alex Williamson
@ 2014-04-09  1:47 ` Kim Phillips
  2014-04-10 20:03   ` Stuart Yoder
  2014-04-10 19:30 ` [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Stuart Yoder
  2014-05-06 17:22 ` Alex Williamson
  2 siblings, 1 reply; 5+ messages in thread
From: Kim Phillips @ 2014-04-09  1:47 UTC (permalink / raw)
  To: Alex Williamson, gregkh
  Cc: bhelgaas, linux-pci, kvm, konrad.wilk, stuart.yoder, libvir-list,
	iommu, tech, kvmarm, linux-kernel, Guenter Roeck,
	christoffer.dall

Needed by platform device drivers, such as the vfio-platform driver [1],
in order to bypass the existing OF, ACPI, id_table and name string matches,
and successfully be able to be bound to any device, like so:

echo vfio-platform > /sys/bus/platform/devices/fff51000.ethernet/driver_override
echo fff51000.ethernet > /sys/bus/platform/devices/fff51000.ethernet/driver/unbind
echo fff51000.ethernet > /sys/bus/platform/drivers_probe

This mimics "PCI: Introduce new device binding path using
pci_dev.driver_override" [2], which is an interface enhancement
for more deterministic PCI device binding, e.g., when in the
presence of hotplug.

[1] http://lkml.iu.edu/hypermail/linux/kernel/1402.1/00177.html
[2] http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html

Suggested-by: Alex Williamson <alex.williamson@redhat.com>
Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
---
changes since RFC:
- fixed message Subject to properly reflect a new platform device
patch (instead of leaving it as a reply to the PCI version)
- addressed Guenter Roeck's comment
- updated [2] with link to later (Apr.4th) revision of the PCI patch
- updated documentation to address Christoffer Dall's comments to
  previous version of [2]
- added a Suggested-by, and re-posted as a reply to the PCI patch,
  should they be applied together

 Documentation/ABI/testing/sysfs-bus-platform | 20 ++++++++++++
 drivers/base/platform.c                      | 46 ++++++++++++++++++++++++++++
 include/linux/platform_device.h              |  1 +
 3 files changed, 67 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-platform

diff --git a/Documentation/ABI/testing/sysfs-bus-platform b/Documentation/ABI/testing/sysfs-bus-platform
new file mode 100644
index 0000000..5172a61
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-platform
@@ -0,0 +1,20 @@
+What:		/sys/bus/platform/devices/.../driver_override
+Date:		April 2014
+Contact:	Kim Phillips <kim.phillips@freescale.com>
+Description:
+		This file allows the driver for a device to be specified which
+		will override standard OF, ACPI, ID table, and name matching.
+		When specified, only a driver with a name matching the value
+		written to driver_override will have an opportunity to bind
+		to the device.  The override is specified by writing a string
+		to the driver_override file (echo vfio-platform > \
+		driver_override) and may be cleared with an empty string
+		(echo > driver_override).  This returns the device to standard
+		matching rules binding.  Writing to driver_override does not
+		automatically unbind the device from its current driver or make
+		any attempt to automatically load the specified driver.  If no
+		driver with a matching name is currently loaded in the kernel,
+		the device will not bind to any driver.  This also allows
+		devices to opt-out of driver binding using a driver_override
+		name such as "none".  Only a single driver may be specified in
+		the override, there is no support for parsing delimiters.
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index e714709..a0909cb 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -22,6 +22,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/idr.h>
 #include <linux/acpi.h>
+#include <linux/limits.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -690,8 +691,49 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
 }
 static DEVICE_ATTR_RO(modalias);
 
+static ssize_t driver_override_store(struct device *dev,
+				     struct device_attribute *attr,
+				     const char *buf, size_t count)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	char *driver_override, *old = pdev->driver_override, *cp;
+
+	if (count > PATH_MAX)
+		return -EINVAL;
+
+	driver_override = kstrndup(buf, count, GFP_KERNEL);
+	if (!driver_override)
+		return -ENOMEM;
+
+	cp = strchr(driver_override, '\n');
+	if (cp)
+		*cp = '\0';
+
+	if (strlen(driver_override)) {
+		pdev->driver_override = driver_override;
+	} else {
+		kfree(driver_override);
+		pdev->driver_override = NULL;
+	}
+
+	kfree(old);
+
+	return count;
+}
+
+static ssize_t driver_override_show(struct device *dev,
+				    struct device_attribute *attr, char *buf)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+
+	return sprintf(buf, "%s\n", pdev->driver_override);
+}
+static DEVICE_ATTR_RW(driver_override);
+
+
 static struct attribute *platform_dev_attrs[] = {
 	&dev_attr_modalias.attr,
+	&dev_attr_driver_override.attr,
 	NULL,
 };
 ATTRIBUTE_GROUPS(platform_dev);
@@ -747,6 +789,10 @@ static int platform_match(struct device *dev, struct device_driver *drv)
 	struct platform_device *pdev = to_platform_device(dev);
 	struct platform_driver *pdrv = to_platform_driver(drv);
 
+	/* When driver_override is set, only bind to the matching driver */
+	if (pdev->driver_override)
+		return !strcmp(pdev->driver_override, drv->name);
+
 	/* Attempt an OF style match first */
 	if (of_driver_match_device(dev, drv))
 		return 1;
diff --git a/include/linux/platform_device.h b/include/linux/platform_device.h
index 16f6654..153d303 100644
--- a/include/linux/platform_device.h
+++ b/include/linux/platform_device.h
@@ -28,6 +28,7 @@ struct platform_device {
 	struct resource	*resource;
 
 	const struct platform_device_id	*id_entry;
+	char *driver_override; /* Driver name to force a match */
 
 	/* MFD cell pointer */
 	struct mfd_cell *mfd_cell;
-- 
1.9.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* RE: [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override
  2014-04-04 20:19 [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Alex Williamson
  2014-04-09  1:47 ` [PATCH] driver core: platform: add device binding path 'driver_override' Kim Phillips
@ 2014-04-10 19:30 ` Stuart Yoder
  2014-05-06 17:22 ` Alex Williamson
  2 siblings, 0 replies; 5+ messages in thread
From: Stuart Yoder @ 2014-04-10 19:30 UTC (permalink / raw)
  To: Alex Williamson, bhelgaas, linux-pci
  Cc: agraf, kvm, konrad.wilk, kim.phillips, gregkh, linux-kernel,
	libvir-list, iommu, tech, kvmarm, christoffer.dall

DQoNCj4gLS0tLS1PcmlnaW5hbCBNZXNzYWdlLS0tLS0NCj4gRnJvbTogQWxleCBXaWxsaWFtc29u
IFttYWlsdG86YWxleC53aWxsaWFtc29uQHJlZGhhdC5jb21dDQo+IFNlbnQ6IEZyaWRheSwgQXBy
aWwgMDQsIDIwMTQgMzoxOSBQTQ0KPiBUbzogYmhlbGdhYXNAZ29vZ2xlLmNvbTsgbGludXgtcGNp
QHZnZXIua2VybmVsLm9yZw0KPiBDYzogYWdyYWZAc3VzZS5kZTsga3ZtQHZnZXIua2VybmVsLm9y
Zzsga29ucmFkLndpbGtAb3JhY2xlLmNvbTsNCj4ga2ltLnBoaWxsaXBzQGxpbmFyby5vcmc7IGdy
ZWdraEBsaW51eGZvdW5kYXRpb24ub3JnOyBZb2RlciBTdHVhcnQtQjA4MjQ4Ow0KPiBsaW51eC1r
ZXJuZWxAdmdlci5rZXJuZWwub3JnOyBsaWJ2aXItbGlzdEByZWRoYXQuY29tOyBpb21tdUBsaXN0
cy5saW51eC0NCj4gZm91bmRhdGlvbi5vcmc7IHRlY2hAdmlydHVhbG9wZW5zeXN0ZW1zLmNvbTsN
Cj4ga3ZtYXJtQGxpc3RzLmNzLmNvbHVtYmlhLmVkdTsgY2hyaXN0b2ZmZXIuZGFsbEBsaW5hcm8u
b3JnDQo+IFN1YmplY3Q6IFtQQVRDSF0gUENJOiBJbnRyb2R1Y2UgbmV3IGRldmljZSBiaW5kaW5n
IHBhdGggdXNpbmcNCj4gcGNpX2Rldi5kcml2ZXJfb3ZlcnJpZGUNCj4gDQo+IFRoZSBkcml2ZXJf
b3ZlcnJpZGUgZmllbGQgYWxsb3dzIHVzIHRvIHNwZWNpZnkgdGhlIGRyaXZlciBmb3IgYSBkZXZp
Y2UNCj4gcmF0aGVyIHRoYW4gcmVseWluZyBvbiB0aGUgZHJpdmVyIHRvIHByb3ZpZGUgYSBwb3Np
dGl2ZSBtYXRjaCBvZiB0aGUNCj4gZGV2aWNlLiAgVGhpcyBzaG9ydGN1dHMgdGhlIGV4aXN0aW5n
IHByb2Nlc3Mgb2YgbG9va2luZyB1cCB0aGUgdmVuZG9yDQo+IGFuZCBkZXZpY2UgSUQsIGFkZGlu
ZyB0aGVtIHRvIHRoZSBkcml2ZXIgbmV3X2lkLCBiaW5kaW5nIHRoZSBkZXZpY2UsDQo+IHRoZW4g
cmVtb3ZpbmcgdGhlIElELCBidXQgaXQgYWxzbyBwcm92aWRlcyBhIGNvdXBsZSBhZHZhbnRhZ2Vz
Lg0KPiANCj4gRmlyc3QsIHRoZSBhYm92ZSBleGlzdGluZyBwcm9jZXNzIGFsbG93cyB0aGUgZHJp
dmVyIHRvIGJpbmQgdG8gYW55DQo+IGRldmljZSBtYXRjaGluZyB0aGUgbmV3X2lkIGZvciB0aGUg
d2luZG93IHdoZXJlIGl0J3MgZW5hYmxlZC4gIFRoaXMgaXMNCj4gb2Z0ZW4gbm90IGRlc2lyZWQs
IHN1Y2ggYXMgdGhlIGNhc2Ugb2YgdHJ5aW5nIHRvIGJpbmQgYSBzaW5nbGUgZGV2aWNlDQo+IHRv
IGEgbWV0YSBkcml2ZXIgbGlrZSBwY2ktc3R1YiBvciB2ZmlvLXBjaS4gIFVzaW5nIGRyaXZlcl9v
dmVycmlkZSB3ZQ0KPiBjYW4gZG8gdGhpcyBkZXRlcm1pbmlzdGljYWxseSB1c2luZzoNCj4gDQo+
IGVjaG8gcGNpLXN0dWIgPiAvc3lzL2J1cy9wY2kvZGV2aWNlcy8wMDAwOjAzOjAwLjAvZHJpdmVy
X292ZXJyaWRlDQo+IGVjaG8gMDAwMDowMzowMC4wID4gL3N5cy9idXMvcGNpL2RldmljZXMvMDAw
MDowMzowMC4wL2RyaXZlci91bmJpbmQNCj4gZWNobyAwMDAwOjAzOjAwLjAgPiAvc3lzL2J1cy9w
Y2kvZHJpdmVyc19wcm9iZQ0KPiANCj4gUHJldmlvdXNseSB3ZSBjb3VsZCBub3QgaW52b2tlIGRy
aXZlcnNfcHJvYmUgYWZ0ZXIgYWRkaW5nIGEgZGV2aWNlDQo+IHRvIG5ld19pZCBmb3IgYSBkcml2
ZXIgYXMgd2UgZ2V0IG5vbi1kZXRlcm1pbmlzdGljIGJlaGF2aW9yIHdoZXRoZXINCj4gdGhlIGRy
aXZlciB3ZSBpbnRlbmQgb3IgdGhlIHN0YW5kYXJkIGRyaXZlciB3aWxsIGNsYWltIHRoZSBkZXZp
Y2UuDQo+IE5vdyBpdCBiZWNvbWVzIGEgZGV0ZXJtaW5pc3RpYyBwcm9jZXNzLCBvbmx5IHRoZSBk
cml2ZXIgbWF0Y2hpbmcNCj4gZHJpdmVyX292ZXJyaWRlIHdpbGwgcHJvYmUgdGhlIGRldmljZS4N
Cj4gDQo+IFRvIHJldHVybiB0aGUgZGV2aWNlIHRvIHRoZSBzdGFuZGFyZCBkcml2ZXIsIHdlIHNp
bXBseSBjbGVhciB0aGUNCj4gZHJpdmVyX292ZXJyaWRlIGFuZCByZXByb2JlIHRoZSBkZXZpY2U6
DQo+IA0KPiBlY2hvID4gL3N5cy9idXMvcGNpL2RldmljZXMvMDAwMDowMzowMC4wL3ByZWZlcnJl
ZF9kcml2ZXINCj4gZWNobyAwMDAwOjAzOjAwLjAgPiAvc3lzL2J1cy9wY2kvZGV2aWNlcy8wMDAw
OjAzOjAwLjAvZHJpdmVyL3VuYmluZA0KPiBlY2hvIDAwMDA6MDM6MDAuMCA+IC9zeXMvYnVzL3Bj
aS9kcml2ZXJzX3Byb2JlDQo+IA0KPiBBbm90aGVyIGFkdmFudGFnZSB0byB0aGlzIGFwcHJvYWNo
IGlzIHRoYXQgd2UgY2FuIHNwZWNpZnkgYSBkcml2ZXINCj4gb3ZlcnJpZGUgdG8gZm9yY2UgYSBz
cGVjaWZpYyBiaW5kaW5nIG9yIHByZXZlbnQgYW55IGJpbmRpbmcuICBGb3INCj4gaW5zdGFuY2Ug
d2hlbiBhbiBJT01NVSBncm91cCBpcyBleHBvc2VkIHRvIHVzZXJzcGFjZSB0aHJvdWdoIFZGSU8N
Cj4gd2UgcmVxdWlyZSB0aGF0IGFsbCBkZXZpY2VzIHdpdGhpbiB0aGF0IGdyb3VwIGFyZSBvd25l
ZCBieSBWRklPLg0KPiBIb3dldmVyLCBkZXZpY2VzIGNhbiBiZSBob3QtYWRkZWQgaW50byBhbiBJ
T01NVSBncm91cCwgaW4gd2hpY2ggY2FzZQ0KPiB3ZSB3YW50IHRvIHByZXZlbnQgdGhlIGRldmlj
ZSBmcm9tIGJpbmRpbmcgdG8gYW55IGRyaXZlciAocHJlZmVycmVkDQo+IGRyaXZlciA9ICJub25l
Iikgb3IgcGVyaGFwcyBoYXZlIGl0IGF1dG9tYXRpY2FsbHkgYmluZCB0byB2ZmlvLXBjaS4NCj4g
V2l0aCBkcml2ZXJfb3ZlcnJpZGUgaXQncyBhIHNpbXBsZSBtYXR0ZXIgZm9yIHRoaXMgZmllbGQg
dG8gYmUgc2V0DQo+IGludGVybmFsbHkgd2hlbiB0aGUgZGV2aWNlIGlzIGZpcnN0IGRpc2NvdmVy
ZWQgdG8gcHJldmVudCBkcml2ZXINCj4gbWF0Y2hlcy4NCj4gDQo+IFNpZ25lZC1vZmYtYnk6IEFs
ZXggV2lsbGlhbXNvbiA8YWxleC53aWxsaWFtc29uQHJlZGhhdC5jb20+DQo+IC0tLQ0KDQpSZXZp
ZXdlZC1ieTogU3R1YXJ0IFlvZGVyIDxzdHVhcnQueW9kZXJAZnJlZXNjYWxlLmNvbT4NCg==

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH] driver core: platform: add device binding path 'driver_override'
  2014-04-09  1:47 ` [PATCH] driver core: platform: add device binding path 'driver_override' Kim Phillips
@ 2014-04-10 20:03   ` Stuart Yoder
  0 siblings, 0 replies; 5+ messages in thread
From: Stuart Yoder @ 2014-04-10 20:03 UTC (permalink / raw)
  To: Kim Phillips, Alex Williamson, gregkh
  Cc: bhelgaas, linux-pci, kvm, konrad.wilk, libvir-list, iommu, tech,
	kvmarm, linux-kernel, Guenter Roeck, christoffer.dall



> -----Original Message-----
> From: Kim Phillips [mailto:kim.phillips@freescale.com]
> Sent: Tuesday, April 08, 2014 8:47 PM
> To: Alex Williamson; gregkh@linuxfoundation.org
> Cc: bhelgaas@google.com; linux-pci@vger.kernel.org; kvm@vger.kernel.org;
> konrad.wilk@oracle.com; Yoder Stuart-B08248; libvir-list@redhat.com;
> iommu@lists.linux-foundation.org; tech@virtualopensystems.com;
> kvmarm@lists.cs.columbia.edu; linux-kernel@vger.kernel.org; Guenter
> Roeck; christoffer.dall@linaro.org
> Subject: [PATCH] driver core: platform: add device binding path
> 'driver_override'
> 
> Needed by platform device drivers, such as the vfio-platform driver [1],
> in order to bypass the existing OF, ACPI, id_table and name string
> matches,
> and successfully be able to be bound to any device, like so:
> 
> echo vfio-platform >
> /sys/bus/platform/devices/fff51000.ethernet/driver_override
> echo fff51000.ethernet >
> /sys/bus/platform/devices/fff51000.ethernet/driver/unbind
> echo fff51000.ethernet > /sys/bus/platform/drivers_probe
> 
> This mimics "PCI: Introduce new device binding path using
> pci_dev.driver_override" [2], which is an interface enhancement
> for more deterministic PCI device binding, e.g., when in the
> presence of hotplug.
> 
> [1] http://lkml.iu.edu/hypermail/linux/kernel/1402.1/00177.html
> [2] http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-
> device-binding-path-using-pci_dev-driver_override.html
> 
> Suggested-by: Alex Williamson <alex.williamson@redhat.com>
> Signed-off-by: Kim Phillips <kim.phillips@freescale.com>
> ---

Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override
  2014-04-04 20:19 [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Alex Williamson
  2014-04-09  1:47 ` [PATCH] driver core: platform: add device binding path 'driver_override' Kim Phillips
  2014-04-10 19:30 ` [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Stuart Yoder
@ 2014-05-06 17:22 ` Alex Williamson
  2 siblings, 0 replies; 5+ messages in thread
From: Alex Williamson @ 2014-05-06 17:22 UTC (permalink / raw)
  To: Greg KH
  Cc: linux-pci, agraf, kvm, konrad.wilk, kim.phillips, gregkh,
	stuart.yoder, linux-kernel, libvir-list, iommu, tech, kvmarm,
	christoffer.dall, Bjorn Helgaas

Hi Greg,

I think Bjorn is waiting for an ack from you on this.  Do you approve of
this approach from a driver-core perspective?  Thanks,

Alex

On Fri, 2014-04-04 at 14:19 -0600, Alex Williamson wrote:
> 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/preferred_driver
> 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 (preferred
> 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>
> ---
> 
> Changes since RFC:
>  - Add ABI documentation (gregkh)
>  - Documentation wording clarification (Christoffer)
> 
> Nobody puked on the RFC and platform folks have posted a working
> version of this for platform devices, so I guess the only thing left
> to do is formally propose this as a new driver binding mechanism.  I
> don't see much incentive to push this into the driver core since the
> match ultimately needs to be done by the bus driver.  I think this is
> therefore like new_id/remove_id where PCI and USB implement separate,
> but consistent interfaces.
> 
> I've pruned the CC list a bit from the RFC, but I've added libvirt
> folks since I expect they would be the first userspace tool that would
> adopt this.  Thanks,
> 
> Alex
> 
>  Documentation/ABI/testing/sysfs-bus-pci |   21 ++++++++++++++++
>  drivers/pci/pci-driver.c                |   25 +++++++++++++++++--
>  drivers/pci/pci-sysfs.c                 |   40 +++++++++++++++++++++++++++++++
>  include/linux/pci.h                     |    1 +
>  4 files changed, 84 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
> index a3c5a66..898ddc4 100644
> --- a/Documentation/ABI/testing/sysfs-bus-pci
> +++ b/Documentation/ABI/testing/sysfs-bus-pci
> @@ -250,3 +250,24 @@ Description:
>  		valid.  For example, writing a 2 to this file when sriov_numvfs
>  		is not 0 and not 2 already will return an error. Writing a 10
>  		when the value of sriov_totalvfs is 8 will return an error.
> +
> +What:		/sys/bus/pci/devices/.../driver_override
> +Date:		April 2014
> +Contact:	Alex Williamson <alex.williamson@redhat.com>
> +Description:
> +		This file allows the driver for a device to be specified which
> +		will override standard static and dynamic ID matching.  When
> +		specified, only a driver with a name matching the value written
> +		to driver_override will have an opportunity to bind to the
> +		device.  The override is specified by writing a string to the
> +		driver_override file (echo pci-stub > driver_override) and
> +		may be cleared with an empty string (echo > driver_override).
> +		This returns the device to standard matching rules binding.
> +		Writing to driver_override does not automatically unbind the
> +		device from its current driver or make any attempt to
> +		automatically load the specified driver.  If no driver with a
> +		matching name is currently loaded in the kernel, the device
> +		will not bind to any driver.  This also allows devices to
> +		opt-out of driver binding using a driver_override name such as
> +		"none".  Only a single driver may be specified in the override,
> +		there is no support for parsing delimiters.
> diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
> index 25f0bc6..f780eb8 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,
>  	return NULL;
>  }
>  
> +static const struct pci_device_id pci_device_id_any = {
> +	.vendor = PCI_ANY_ID,
> +	.device = PCI_ANY_ID,
> +	.subvendor = PCI_ANY_ID,
> +	.subdevice = PCI_ANY_ID,
> +};
> +
>  /**
>   * pci_match_device - Tell if a PCI device structure has a matching PCI device id structure
>   * @drv: the PCI driver to match against
> @@ -229,18 +236,30 @@ static const struct pci_device_id *pci_match_device(struct pci_driver *drv,
>  						    struct pci_dev *dev)
>  {
>  	struct pci_dynid *dynid;
> +	const struct pci_device_id *found_id = NULL;
> +
> +	/* When driver_override is set, only bind to the matching driver */
> +	if (dev->driver_override && strcmp(dev->driver_override, drv->name))
> +		return NULL;
>  
>  	/* Look at the dynamic ids first, before the static ones */
>  	spin_lock(&drv->dynids.lock);
>  	list_for_each_entry(dynid, &drv->dynids.list, node) {
>  		if (pci_match_one_device(&dynid->id, dev)) {
> -			spin_unlock(&drv->dynids.lock);
> -			return &dynid->id;
> +			found_id = &dynid->id;
> +			break;
>  		}
>  	}
>  	spin_unlock(&drv->dynids.lock);
>  
> -	return pci_match_id(drv->id_table, dev);
> +	if (!found_id)
> +		found_id = pci_match_id(drv->id_table, dev);
> +
> +	/* driver_override will always match, send a dummy id */
> +	if (!found_id && dev->driver_override)
> +		found_id = &pci_device_id_any;
> +
> +	return found_id;
>  }
>  
>  struct drv_dev_and_id {
> diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
> index 276ef9c..70cb39d 100644
> --- a/drivers/pci/pci-sysfs.c
> +++ b/drivers/pci/pci-sysfs.c
> @@ -510,6 +510,45 @@ static struct device_attribute sriov_numvfs_attr =
>  		       sriov_numvfs_show, sriov_numvfs_store);
>  #endif /* CONFIG_PCI_IOV */
>  
> +static ssize_t driver_override_store(struct device *dev,
> +				     struct device_attribute *attr,
> +				     const char *buf, size_t count)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +	char *driver_override, *old = pdev->driver_override;
> +
> +	if (count > PATH_MAX)
> +		return -EINVAL;
> +
> +	driver_override = kstrndup(buf, count, GFP_KERNEL);
> +	if (!driver_override)
> +		return -ENOMEM;
> +
> +	while (strlen(driver_override) &&
> +	       driver_override[strlen(driver_override) - 1] == '\n')
> +		driver_override[strlen(driver_override) - 1] = '\0';
> +
> +	if (strlen(driver_override)) {
> +		pdev->driver_override = driver_override;
> +	} else {
> +		kfree(driver_override);
> +		pdev->driver_override = NULL;
> +	}
> +
> +	kfree(old);
> +
> +	return count;
> +}
> +
> +static ssize_t driver_override_show(struct device *dev,
> +				    struct device_attribute *attr, char *buf)
> +{
> +	struct pci_dev *pdev = to_pci_dev(dev);
> +
> +	return sprintf(buf, "%s\n", pdev->driver_override);
> +}
> +static DEVICE_ATTR_RW(driver_override);
> +
>  static struct attribute *pci_dev_attrs[] = {
>  	&dev_attr_resource.attr,
>  	&dev_attr_vendor.attr,
> @@ -532,6 +571,7 @@ static struct attribute *pci_dev_attrs[] = {
>  #if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
>  	&dev_attr_d3cold_allowed.attr,
>  #endif
> +	&dev_attr_driver_override.attr,
>  	NULL,
>  };
>  
> diff --git a/include/linux/pci.h b/include/linux/pci.h
> index 33aa2ca..6b666af 100644
> --- a/include/linux/pci.h
> +++ b/include/linux/pci.h
> @@ -364,6 +364,7 @@ struct pci_dev {
>  #endif
>  	phys_addr_t rom; /* Physical address of ROM if it's not from the BAR */
>  	size_t romlen; /* Length of ROM if it's not from the BAR */
> +	char *driver_override; /* Driver name to force a match */
>  };
>  
>  static inline struct pci_dev *pci_physfn(struct pci_dev *dev)
> 




^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2014-05-06 17:22 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-04-04 20:19 [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Alex Williamson
2014-04-09  1:47 ` [PATCH] driver core: platform: add device binding path 'driver_override' Kim Phillips
2014-04-10 20:03   ` Stuart Yoder
2014-04-10 19:30 ` [PATCH] PCI: Introduce new device binding path using pci_dev.driver_override Stuart Yoder
2014-05-06 17:22 ` Alex Williamson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).