diff options
author | Antonios Motakis <a.motakis@virtualopensystems.com> | 2015-01-06 05:15:11 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2015-02-10 05:23:15 -0500 |
commit | 3cf385713460eb2bb4cb7ceb8ed89833b00b594b (patch) | |
tree | b9c51c20e360b31aa2a567d3857b3039d6e08fdf | |
parent | 8684014d71e259f62f7dc24a20324e232806b2ef (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-amba | 20 | ||||
-rw-r--r-- | drivers/amba/bus.c | 47 | ||||
-rw-r--r-- | include/linux/amba/bus.h | 1 |
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 @@ | |||
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. | ||
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 | ||
67 | static 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 | |||
78 | static 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...) \ |
63 | static ssize_t name##_show(struct device *_dev, \ | 109 | static 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", | |||
81 | static struct device_attribute amba_dev_attrs[] = { | 127 | static 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 | ||
38 | struct amba_driver { | 39 | struct amba_driver { |