aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAntonios Motakis <a.motakis@virtualopensystems.com>2015-01-06 05:15:11 -0500
committerRussell King <rmk+kernel@arm.linux.org.uk>2015-02-10 05:23:15 -0500
commit3cf385713460eb2bb4cb7ceb8ed89833b00b594b (patch)
treeb9c51c20e360b31aa2a567d3857b3039d6e08fdf
parent8684014d71e259f62f7dc24a20324e232806b2ef (diff)
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>
-rw-r--r--Documentation/ABI/testing/sysfs-bus-amba20
-rw-r--r--drivers/amba/bus.c47
-rw-r--r--include/linux/amba/bus.h1
3 files changed, 68 insertions, 0 deletions
diff --git a/Documentation/ABI/testing/sysfs-bus-amba b/Documentation/ABI/testing/sysfs-bus-amba
new file mode 100644
index 000000000000..e7b54677cfbe
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-amba
@@ -0,0 +1,20 @@
1What: /sys/bus/amba/devices/.../driver_override
2Date: September 2014
3Contact: Antonios Motakis <a.motakis@virtualopensystems.com>
4Description:
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.
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 52ddd9fbb55e..f0099360039e 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -18,6 +18,7 @@
18#include <linux/pm_domain.h> 18#include <linux/pm_domain.h>
19#include <linux/amba/bus.h> 19#include <linux/amba/bus.h>
20#include <linux/sizes.h> 20#include <linux/sizes.h>
21#include <linux/limits.h>
21 22
22#include <asm/irq.h> 23#include <asm/irq.h>
23 24
@@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv)
43 struct amba_device *pcdev = to_amba_device(dev); 44 struct amba_device *pcdev = to_amba_device(dev);
44 struct amba_driver *pcdrv = to_amba_driver(drv); 45 struct amba_driver *pcdrv = to_amba_driver(drv);
45 46
47 /* When driver_override is set, only bind to the matching driver */
48 if (pcdev->driver_override)
49 return !strcmp(pcdev->driver_override, drv->name);
50
46 return amba_lookup(pcdrv->id_table, pcdev) != NULL; 51 return amba_lookup(pcdrv->id_table, pcdev) != NULL;
47} 52}
48 53
@@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
59 return retval; 64 return retval;
60} 65}
61 66
67static ssize_t driver_override_show(struct device *_dev,
68 struct device_attribute *attr, char *buf)
69{
70 struct amba_device *dev = to_amba_device(_dev);
71
72 if (!dev->driver_override)
73 return 0;
74
75 return sprintf(buf, "%s\n", dev->driver_override);
76}
77
78static ssize_t driver_override_store(struct device *_dev,
79 struct device_attribute *attr,
80 const char *buf, size_t count)
81{
82 struct amba_device *dev = to_amba_device(_dev);
83 char *driver_override, *old = dev->driver_override, *cp;
84
85 if (count > PATH_MAX)
86 return -EINVAL;
87
88 driver_override = kstrndup(buf, count, GFP_KERNEL);
89 if (!driver_override)
90 return -ENOMEM;
91
92 cp = strchr(driver_override, '\n');
93 if (cp)
94 *cp = '\0';
95
96 if (strlen(driver_override)) {
97 dev->driver_override = driver_override;
98 } else {
99 kfree(driver_override);
100 dev->driver_override = NULL;
101 }
102
103 kfree(old);
104
105 return count;
106}
107
62#define amba_attr_func(name,fmt,arg...) \ 108#define amba_attr_func(name,fmt,arg...) \
63static ssize_t name##_show(struct device *_dev, \ 109static ssize_t name##_show(struct device *_dev, \
64 struct device_attribute *attr, char *buf) \ 110 struct device_attribute *attr, char *buf) \
@@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
81static struct device_attribute amba_dev_attrs[] = { 127static struct device_attribute amba_dev_attrs[] = {
82 __ATTR_RO(id), 128 __ATTR_RO(id),
83 __ATTR_RO(resource), 129 __ATTR_RO(resource),
130 __ATTR_RW(driver_override),
84 __ATTR_NULL, 131 __ATTR_NULL,
85}; 132};
86 133
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index 0ab5f8e0dea2..50fc66868402 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -33,6 +33,7 @@ struct amba_device {
33 struct clk *pclk; 33 struct clk *pclk;
34 unsigned int periphid; 34 unsigned int periphid;
35 unsigned int irq[AMBA_NR_IRQS]; 35 unsigned int irq[AMBA_NR_IRQS];
36 char *driver_override;
36}; 37};
37 38
38struct amba_driver { 39struct amba_driver {