b.liu | e958203 | 2025-04-17 19:18:16 +0800 | [diff] [blame^] | 1 | From f2991d30ff590bf932483a6dfc16c7ebe2f83341 Mon Sep 17 00:00:00 2001 |
| 2 | From: Laurentiu Tudor <laurentiu.tudor@nxp.com> |
| 3 | Date: Fri, 13 Apr 2018 12:42:40 +0300 |
| 4 | Subject: [PATCH] bus: fsl-mc: add device binding path 'driver_override' |
| 5 | |
| 6 | This patch is required for vfio-fsl-mc meta driver to successfully bind |
| 7 | layerscape container devices for device passthrough. This patch adds |
| 8 | a mechanism to allow a layerscape device to specify a driver rather than |
| 9 | a layerscape driver provide a device match. |
| 10 | |
| 11 | This patch is based on following proposed patches for PCI and platform |
| 12 | devices |
| 13 | - https://lkml.org/lkml/2014/4/8/571 :- For Platform devices |
| 14 | - http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html |
| 15 | :- For PCI devices |
| 16 | |
| 17 | Example to allow a device (dprc.1) to specifically bind |
| 18 | with driver (vfio-fsl-mc):- |
| 19 | - echo vfio-fsl-mc > /sys/bus/fsl-mc/devices/dprc.1/driver_override |
| 20 | - echo dprc.1 > /sys/bus/fsl-mc/drivers/fsl_mc_dprc/unbind |
| 21 | - echo dprc.1 > /sys/bus/fsl-mc/drivers/vfio-fsl-mc/bind |
| 22 | |
| 23 | Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com> |
| 24 | Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> |
| 25 | --- |
| 26 | drivers/bus/fsl-mc/fsl-mc-bus.c | 53 +++++++++++++++++++++++++++++++++++++++++ |
| 27 | 1 file changed, 53 insertions(+) |
| 28 | |
| 29 | --- a/drivers/bus/fsl-mc/fsl-mc-bus.c |
| 30 | +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c |
| 31 | @@ -83,6 +83,12 @@ static int fsl_mc_bus_match(struct devic |
| 32 | struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); |
| 33 | bool found = false; |
| 34 | |
| 35 | + /* When driver_override is set, only bind to the matching driver */ |
| 36 | + if (mc_dev->driver_override) { |
| 37 | + found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); |
| 38 | + goto out; |
| 39 | + } |
| 40 | + |
| 41 | if (!mc_drv->match_id_table) |
| 42 | goto out; |
| 43 | |
| 44 | @@ -147,8 +153,52 @@ static ssize_t modalias_show(struct devi |
| 45 | } |
| 46 | static DEVICE_ATTR_RO(modalias); |
| 47 | |
| 48 | +static ssize_t driver_override_store(struct device *dev, |
| 49 | + struct device_attribute *attr, |
| 50 | + const char *buf, size_t count) |
| 51 | +{ |
| 52 | + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); |
| 53 | + const char *driver_override, *old = mc_dev->driver_override; |
| 54 | + char *cp; |
| 55 | + |
| 56 | + if (WARN_ON(dev->bus != &fsl_mc_bus_type)) |
| 57 | + return -EINVAL; |
| 58 | + |
| 59 | + if (count >= (PAGE_SIZE - 1)) |
| 60 | + return -EINVAL; |
| 61 | + |
| 62 | + driver_override = kstrndup(buf, count, GFP_KERNEL); |
| 63 | + if (!driver_override) |
| 64 | + return -ENOMEM; |
| 65 | + |
| 66 | + cp = strchr(driver_override, '\n'); |
| 67 | + if (cp) |
| 68 | + *cp = '\0'; |
| 69 | + |
| 70 | + if (strlen(driver_override)) { |
| 71 | + mc_dev->driver_override = driver_override; |
| 72 | + } else { |
| 73 | + kfree(driver_override); |
| 74 | + mc_dev->driver_override = NULL; |
| 75 | + } |
| 76 | + |
| 77 | + kfree(old); |
| 78 | + |
| 79 | + return count; |
| 80 | +} |
| 81 | + |
| 82 | +static ssize_t driver_override_show(struct device *dev, |
| 83 | + struct device_attribute *attr, char *buf) |
| 84 | +{ |
| 85 | + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); |
| 86 | + |
| 87 | + return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); |
| 88 | +} |
| 89 | +static DEVICE_ATTR_RW(driver_override); |
| 90 | + |
| 91 | static struct attribute *fsl_mc_dev_attrs[] = { |
| 92 | &dev_attr_modalias.attr, |
| 93 | + &dev_attr_driver_override.attr, |
| 94 | NULL, |
| 95 | }; |
| 96 | |
| 97 | @@ -749,6 +799,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_add); |
| 98 | */ |
| 99 | void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) |
| 100 | { |
| 101 | + kfree(mc_dev->driver_override); |
| 102 | + mc_dev->driver_override = NULL; |
| 103 | + |
| 104 | /* |
| 105 | * The device-specific remove callback will get invoked by device_del() |
| 106 | */ |