| From f2991d30ff590bf932483a6dfc16c7ebe2f83341 Mon Sep 17 00:00:00 2001 |
| From: Laurentiu Tudor <laurentiu.tudor@nxp.com> |
| Date: Fri, 13 Apr 2018 12:42:40 +0300 |
| Subject: [PATCH] bus: fsl-mc: add device binding path 'driver_override' |
| |
| This patch is required for vfio-fsl-mc meta driver to successfully bind |
| layerscape container devices for device passthrough. This patch adds |
| a mechanism to allow a layerscape device to specify a driver rather than |
| a layerscape driver provide a device match. |
| |
| This patch is based on following proposed patches for PCI and platform |
| devices |
| - https://lkml.org/lkml/2014/4/8/571 :- For Platform devices |
| - http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html |
| :- For PCI devices |
| |
| Example to allow a device (dprc.1) to specifically bind |
| with driver (vfio-fsl-mc):- |
| - echo vfio-fsl-mc > /sys/bus/fsl-mc/devices/dprc.1/driver_override |
| - echo dprc.1 > /sys/bus/fsl-mc/drivers/fsl_mc_dprc/unbind |
| - echo dprc.1 > /sys/bus/fsl-mc/drivers/vfio-fsl-mc/bind |
| |
| Signed-off-by: Bharat Bhushan <Bharat.Bhushan@nxp.com> |
| Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> |
| --- |
| drivers/bus/fsl-mc/fsl-mc-bus.c | 53 +++++++++++++++++++++++++++++++++++++++++ |
| 1 file changed, 53 insertions(+) |
| |
| --- a/drivers/bus/fsl-mc/fsl-mc-bus.c |
| +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c |
| @@ -83,6 +83,12 @@ static int fsl_mc_bus_match(struct devic |
| struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); |
| bool found = false; |
| |
| + /* When driver_override is set, only bind to the matching driver */ |
| + if (mc_dev->driver_override) { |
| + found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); |
| + goto out; |
| + } |
| + |
| if (!mc_drv->match_id_table) |
| goto out; |
| |
| @@ -147,8 +153,52 @@ static ssize_t modalias_show(struct devi |
| } |
| 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 fsl_mc_device *mc_dev = to_fsl_mc_device(dev); |
| + const char *driver_override, *old = mc_dev->driver_override; |
| + char *cp; |
| + |
| + if (WARN_ON(dev->bus != &fsl_mc_bus_type)) |
| + return -EINVAL; |
| + |
| + 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'; |
| + |
| + if (strlen(driver_override)) { |
| + mc_dev->driver_override = driver_override; |
| + } else { |
| + kfree(driver_override); |
| + mc_dev->driver_override = NULL; |
| + } |
| + |
| + kfree(old); |
| + |
| + return count; |
| +} |
| + |
| +static ssize_t driver_override_show(struct device *dev, |
| + struct device_attribute *attr, char *buf) |
| +{ |
| + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); |
| + |
| + return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); |
| +} |
| +static DEVICE_ATTR_RW(driver_override); |
| + |
| static struct attribute *fsl_mc_dev_attrs[] = { |
| &dev_attr_modalias.attr, |
| + &dev_attr_driver_override.attr, |
| NULL, |
| }; |
| |
| @@ -749,6 +799,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_add); |
| */ |
| void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) |
| { |
| + kfree(mc_dev->driver_override); |
| + mc_dev->driver_override = NULL; |
| + |
| /* |
| * The device-specific remove callback will get invoked by device_del() |
| */ |