Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARM: 8256/1: driver coamba: add device binding path 'driver_override'

As already demonstrated with PCI [1] and the platform bus [2], a
driver_override property in sysfs can be used to bypass the id
matching of a device to a AMBA driver. This can be used by VFIO to
bind to any AMBA device requested by the user.

[1] http://lists-archives.com/linux-kernel/28030441-pci-introduce-new-device-binding-path-using-pci_dev-driver_override.html
[2] https://www.redhat.com/archives/libvir-list/2014-April/msg00382.html

Signed-off-by: Antonios Motakis <a.motakis@virtualopensystems.com>
Reviewed-by: Kim Phillips <kim.phillips@freescale.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>

authored by

Antonios Motakis and committed by
Russell King
3cf38571 8684014d

+68
+20
Documentation/ABI/testing/sysfs-bus-amba
··· 1 + What: /sys/bus/amba/devices/.../driver_override 2 + Date: September 2014 3 + Contact: Antonios Motakis <a.motakis@virtualopensystems.com> 4 + Description: 5 + This file allows the driver for a device to be specified which 6 + will override standard OF, ACPI, ID table, and name matching. 7 + When specified, only a driver with a name matching the value 8 + written to driver_override will have an opportunity to bind to 9 + the device. The override is specified by writing a string to the 10 + driver_override file (echo vfio-amba > driver_override) and may 11 + be cleared with an empty string (echo > driver_override). 12 + This returns the device to standard matching rules binding. 13 + Writing to driver_override does not automatically unbind the 14 + device from its current driver or make any attempt to 15 + automatically load the specified driver. If no driver with a 16 + matching name is currently loaded in the kernel, the device will 17 + not bind to any driver. This also allows devices to opt-out of 18 + driver binding using a driver_override name such as "none". 19 + Only a single driver may be specified in the override, there is 20 + no support for parsing delimiters.
+47
drivers/amba/bus.c
··· 18 18 #include <linux/pm_domain.h> 19 19 #include <linux/amba/bus.h> 20 20 #include <linux/sizes.h> 21 + #include <linux/limits.h> 21 22 22 23 #include <asm/irq.h> 23 24 ··· 44 43 struct amba_device *pcdev = to_amba_device(dev); 45 44 struct amba_driver *pcdrv = to_amba_driver(drv); 46 45 46 + /* When driver_override is set, only bind to the matching driver */ 47 + if (pcdev->driver_override) 48 + return !strcmp(pcdev->driver_override, drv->name); 49 + 47 50 return amba_lookup(pcdrv->id_table, pcdev) != NULL; 48 51 } 49 52 ··· 62 57 63 58 retval = add_uevent_var(env, "MODALIAS=amba:d%08X", pcdev->periphid); 64 59 return retval; 60 + } 61 + 62 + static ssize_t driver_override_show(struct device *_dev, 63 + struct device_attribute *attr, char *buf) 64 + { 65 + struct amba_device *dev = to_amba_device(_dev); 66 + 67 + if (!dev->driver_override) 68 + return 0; 69 + 70 + return sprintf(buf, "%s\n", dev->driver_override); 71 + } 72 + 73 + static ssize_t driver_override_store(struct device *_dev, 74 + struct device_attribute *attr, 75 + const char *buf, size_t count) 76 + { 77 + struct amba_device *dev = to_amba_device(_dev); 78 + char *driver_override, *old = dev->driver_override, *cp; 79 + 80 + if (count > PATH_MAX) 81 + return -EINVAL; 82 + 83 + driver_override = kstrndup(buf, count, GFP_KERNEL); 84 + if (!driver_override) 85 + return -ENOMEM; 86 + 87 + cp = strchr(driver_override, '\n'); 88 + if (cp) 89 + *cp = '\0'; 90 + 91 + if (strlen(driver_override)) { 92 + dev->driver_override = driver_override; 93 + } else { 94 + kfree(driver_override); 95 + dev->driver_override = NULL; 96 + } 97 + 98 + kfree(old); 99 + 100 + return count; 65 101 } 66 102 67 103 #define amba_attr_func(name,fmt,arg...) \ ··· 127 81 static struct device_attribute amba_dev_attrs[] = { 128 82 __ATTR_RO(id), 129 83 __ATTR_RO(resource), 84 + __ATTR_RW(driver_override), 130 85 __ATTR_NULL, 131 86 }; 132 87
+1
include/linux/amba/bus.h
··· 33 33 struct clk *pclk; 34 34 unsigned int periphid; 35 35 unsigned int irq[AMBA_NR_IRQS]; 36 + char *driver_override; 36 37 }; 37 38 38 39 struct amba_driver {