提交 539fec78 编写于 作者: S Stefano Garzarella 提交者: Michael S. Tsirkin

vdpa: add driver_override support

`driver_override` allows to control which of the vDPA bus drivers
binds to a vDPA device.

If `driver_override` is not set, the previous behaviour is followed:
devices use the first vDPA bus driver loaded (unless auto binding
is disabled).

Tested on Fedora 34 with driverctl(8):
  $ modprobe virtio-vdpa
  $ modprobe vhost-vdpa
  $ modprobe vdpa-sim-net

  $ vdpa dev add mgmtdev vdpasim_net name dev1

  # dev1 is attached to the first vDPA bus driver loaded
  $ driverctl -b vdpa list-devices
    dev1 virtio_vdpa

  $ driverctl -b vdpa set-override dev1 vhost_vdpa

  $ driverctl -b vdpa list-devices
    dev1 vhost_vdpa [*]

  Note: driverctl(8) integrates with udev so the binding is
  preserved.
Suggested-by: NJason Wang <jasowang@redhat.com>
Acked-by: NJason Wang <jasowang@redhat.com>
Signed-off-by: NStefano Garzarella <sgarzare@redhat.com>
Link: https://lore.kernel.org/r/20211126164753.181829-3-sgarzare@redhat.comSigned-off-by: NMichael S. Tsirkin <mst@redhat.com>
上级 9c25cdeb
...@@ -35,3 +35,23 @@ Description: ...@@ -35,3 +35,23 @@ Description:
Writing a device name to this file will cause the driver to Writing a device name to this file will cause the driver to
attempt to unbind from the device. This may be useful when attempt to unbind from the device. This may be useful when
overriding default bindings. overriding default bindings.
What: /sys/bus/vdpa/devices/.../driver_override
Date: November 2021
Contact: virtualization@lists.linux-foundation.org
Description:
This file allows the driver for a device to be specified.
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 vhost-vdpa > 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.
...@@ -52,8 +52,81 @@ static void vdpa_dev_remove(struct device *d) ...@@ -52,8 +52,81 @@ static void vdpa_dev_remove(struct device *d)
drv->remove(vdev); drv->remove(vdev);
} }
static int vdpa_dev_match(struct device *dev, struct device_driver *drv)
{
struct vdpa_device *vdev = dev_to_vdpa(dev);
/* Check override first, and if set, only use the named driver */
if (vdev->driver_override)
return strcmp(vdev->driver_override, drv->name) == 0;
/* Currently devices must be supported by all vDPA bus drivers */
return 1;
}
static ssize_t driver_override_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct vdpa_device *vdev = dev_to_vdpa(dev);
const char *driver_override, *old;
char *cp;
/* We need to keep extra room for a newline */
if (count >= (PAGE_SIZE - 1))
return -EINVAL;
driver_override = kstrndup(buf, count, GFP_KERNEL);
if (!driver_override)
return -ENOMEM;
cp = strchr(driver_override, '\n');
if (cp)
*cp = '\0';
device_lock(dev);
old = vdev->driver_override;
if (strlen(driver_override)) {
vdev->driver_override = driver_override;
} else {
kfree(driver_override);
vdev->driver_override = NULL;
}
device_unlock(dev);
kfree(old);
return count;
}
static ssize_t driver_override_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct vdpa_device *vdev = dev_to_vdpa(dev);
ssize_t len;
device_lock(dev);
len = snprintf(buf, PAGE_SIZE, "%s\n", vdev->driver_override);
device_unlock(dev);
return len;
}
static DEVICE_ATTR_RW(driver_override);
static struct attribute *vdpa_dev_attrs[] = {
&dev_attr_driver_override.attr,
NULL,
};
static const struct attribute_group vdpa_dev_group = {
.attrs = vdpa_dev_attrs,
};
__ATTRIBUTE_GROUPS(vdpa_dev);
static struct bus_type vdpa_bus = { static struct bus_type vdpa_bus = {
.name = "vdpa", .name = "vdpa",
.dev_groups = vdpa_dev_groups,
.match = vdpa_dev_match,
.probe = vdpa_dev_probe, .probe = vdpa_dev_probe,
.remove = vdpa_dev_remove, .remove = vdpa_dev_remove,
}; };
...@@ -68,6 +141,7 @@ static void vdpa_release_dev(struct device *d) ...@@ -68,6 +141,7 @@ static void vdpa_release_dev(struct device *d)
ida_simple_remove(&vdpa_index_ida, vdev->index); ida_simple_remove(&vdpa_index_ida, vdev->index);
mutex_destroy(&vdev->cf_mutex); mutex_destroy(&vdev->cf_mutex);
kfree(vdev->driver_override);
kfree(vdev); kfree(vdev);
} }
......
...@@ -64,6 +64,7 @@ struct vdpa_mgmt_dev; ...@@ -64,6 +64,7 @@ struct vdpa_mgmt_dev;
* struct vdpa_device - representation of a vDPA device * struct vdpa_device - representation of a vDPA device
* @dev: underlying device * @dev: underlying device
* @dma_dev: the actual device that is performing DMA * @dma_dev: the actual device that is performing DMA
* @driver_override: driver name to force a match
* @config: the configuration ops for this device. * @config: the configuration ops for this device.
* @cf_mutex: Protects get and set access to configuration layout. * @cf_mutex: Protects get and set access to configuration layout.
* @index: device index * @index: device index
...@@ -76,6 +77,7 @@ struct vdpa_mgmt_dev; ...@@ -76,6 +77,7 @@ struct vdpa_mgmt_dev;
struct vdpa_device { struct vdpa_device {
struct device dev; struct device dev;
struct device *dma_dev; struct device *dma_dev;
const char *driver_override;
const struct vdpa_config_ops *config; const struct vdpa_config_ops *config;
struct mutex cf_mutex; /* Protects get/set config */ struct mutex cf_mutex; /* Protects get/set config */
unsigned int index; unsigned int index;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册