`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.
Unified · Split
| @@ -35,3 +35,23 @@ Description: · 34 unmodified lines | |||
| 35 | Writing a device name to this file will cause the driver to | 35 | Writing a device name to this file will cause the driver to |
| 36 | attempt to unbind from the device. This may be useful when | 36 | attempt to unbind from the device. This may be useful when |
| 37 | overriding default bindings. | 37 | overriding default bindings. |
| 38 | |||
| 39 | What: /sys/bus/vdpa/devices/.../driver_override | ||
| 40 | Date: November 2021 | ||
| 41 | Contact: virtualization@lists.linux-foundation.org | ||
| 42 | Description: | ||
| 43 | This file allows the driver for a device to be specified. | ||
| 44 | When specified, only a driver with a name matching the value | ||
| 45 | written to driver_override will have an opportunity to bind to | ||
| 46 | the device. The override is specified by writing a string to the | ||
| 47 | driver_override file (echo vhost-vdpa > driver_override) and may | ||
| 48 | be cleared with an empty string (echo > driver_override). | ||
| 49 | This returns the device to standard matching rules binding. | ||
| 50 | Writing to driver_override does not automatically unbind the | ||
| 51 | device from its current driver or make any attempt to | ||
| 52 | automatically load the specified driver. If no driver with a | ||
| 53 | matching name is currently loaded in the kernel, the device will | ||
| 54 | not bind to any driver. This also allows devices to opt-out of | ||
| 55 | driver binding using a driver_override name such as "none". | ||
| 56 | Only a single driver may be specified in the override, there is | ||
| 57 | no support for parsing delimiters. | ||
| @@ -52,8 +52,81 @@ static void vdpa_dev_remove(struct device *d) · 51 unmodified lines | |||
| 52 | drv->remove(vdev); | 52 | drv->remove(vdev); |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static int vdpa_dev_match(struct device *dev, struct device_driver *drv) | ||
| 56 | { | ||
| 57 | struct vdpa_device *vdev = dev_to_vdpa(dev); | ||
| 58 | |||
| 59 | /* Check override first, and if set, only use the named driver */ | ||
| 60 | if (vdev->driver_override) | ||
| 61 | return strcmp(vdev->driver_override, drv->name) == 0; | ||
| 62 | |||
| 63 | /* Currently devices must be supported by all vDPA bus drivers */ | ||
| 64 | return 1; | ||
| 65 | } | ||
| 66 | |||
| 67 | static ssize_t driver_override_store(struct device *dev, | ||
| 68 | struct device_attribute *attr, | ||
| 69 | const char *buf, size_t count) | ||
| 70 | { | ||
| 71 | struct vdpa_device *vdev = dev_to_vdpa(dev); | ||
| 72 | const char *driver_override, *old; | ||
| 73 | char *cp; | ||
| 74 | |||
| 75 | /* We need to keep extra room for a newline */ | ||
| 76 | if (count >= (PAGE_SIZE - 1)) | ||
| 77 | return -EINVAL; | ||
| 78 | |||
| 79 | driver_override = kstrndup(buf, count, GFP_KERNEL); | ||
| 80 | if (!driver_override) | ||
| 81 | return -ENOMEM; | ||
| 82 | |||
| 83 | cp = strchr(driver_override, '\n'); | ||
| 84 | if (cp) | ||
| 85 | *cp = '\0'; | ||
| 86 | |||
| 87 | device_lock(dev); | ||
| 88 | old = vdev->driver_override; | ||
| 89 | if (strlen(driver_override)) { | ||
| 90 | vdev->driver_override = driver_override; | ||
| 91 | } else { | ||
| 92 | kfree(driver_override); | ||
| 93 | vdev->driver_override = NULL; | ||
| 94 | } | ||
| 95 | device_unlock(dev); | ||
| 96 | |||
| 97 | kfree(old); | ||
| 98 | |||
| 99 | return count; | ||
| 100 | } | ||
| 101 | |||
| 102 | static ssize_t driver_override_show(struct device *dev, | ||
| 103 | struct device_attribute *attr, char *buf) | ||
| 104 | { | ||
| 105 | struct vdpa_device *vdev = dev_to_vdpa(dev); | ||
| 106 | ssize_t len; | ||
| 107 | |||
| 108 | device_lock(dev); | ||
| 109 | len = snprintf(buf, PAGE_SIZE, "%s\n", vdev->driver_override); | ||
| 110 | device_unlock(dev); | ||
| 111 | |||
| 112 | return len; | ||
| 113 | } | ||
| 114 | static DEVICE_ATTR_RW(driver_override); | ||
| 115 | |||
| 116 | static struct attribute *vdpa_dev_attrs[] = { | ||
| 117 | &dev_attr_driver_override.attr, | ||
| 118 | NULL, | ||
| 119 | }; | ||
| 120 | |||
| 121 | static const struct attribute_group vdpa_dev_group = { | ||
| 122 | .attrs = vdpa_dev_attrs, | ||
| 123 | }; | ||
| 124 | __ATTRIBUTE_GROUPS(vdpa_dev); | ||
| 125 | |||
| 55 | static struct bus_type vdpa_bus = { | 126 | static struct bus_type vdpa_bus = { |
| 56 | .name = "vdpa", | 127 | .name = "vdpa", |
| 128 | .dev_groups = vdpa_dev_groups, | ||
| 129 | .match = vdpa_dev_match, | ||
| 57 | .probe = vdpa_dev_probe, | 130 | .probe = vdpa_dev_probe, |
| 58 | .remove = vdpa_dev_remove, | 131 | .remove = vdpa_dev_remove, |
| 59 | }; | 132 | }; |
| @@ -68,6 +141,7 @@ static void vdpa_release_dev(struct device *d) · 8 unmodified lines | |||
| 68 | 141 | ||
| 69 | ida_simple_remove(&vdpa_index_ida, vdev->index); | 142 | ida_simple_remove(&vdpa_index_ida, vdev->index); |
| 70 | mutex_destroy(&vdev->cf_mutex); | 143 | mutex_destroy(&vdev->cf_mutex); |
| 144 | kfree(vdev->driver_override); | ||
| 71 | kfree(vdev); | 145 | kfree(vdev); |
| 72 | } | 146 | } |
| 73 | 147 | ||
| @@ -64,6 +64,7 @@ struct vdpa_mgmt_dev; · 63 unmodified lines | |||
| 64 | * struct vdpa_device - representation of a vDPA device | 64 | * struct vdpa_device - representation of a vDPA device |
| 65 | * @dev: underlying device | 65 | * @dev: underlying device |
| 66 | * @dma_dev: the actual device that is performing DMA | 66 | * @dma_dev: the actual device that is performing DMA |
| 67 | * @driver_override: driver name to force a match | ||
| 67 | * @config: the configuration ops for this device. | 68 | * @config: the configuration ops for this device. |
| 68 | * @cf_mutex: Protects get and set access to configuration layout. | 69 | * @cf_mutex: Protects get and set access to configuration layout. |
| 69 | * @index: device index | 70 | * @index: device index |
| @@ -76,6 +77,7 @@ struct vdpa_mgmt_dev; · 6 unmodified lines | |||
| 76 | struct vdpa_device { | 77 | struct vdpa_device { |
| 77 | struct device dev; | 78 | struct device dev; |
| 78 | struct device *dma_dev; | 79 | struct device *dma_dev; |
| 80 | const char *driver_override; | ||
| 79 | const struct vdpa_config_ops *config; | 81 | const struct vdpa_config_ops *config; |
| 80 | struct mutex cf_mutex; /* Protects get/set config */ | 82 | struct mutex cf_mutex; /* Protects get/set config */ |
| 81 | unsigned int index; | 83 | unsigned int index; |