mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									8684014d71
								
							
						
					
					
						commit
						3cf3857134
					
				
					 3 changed files with 68 additions and 0 deletions
				
			
		
							
								
								
									
										20
									
								
								Documentation/ABI/testing/sysfs-bus-amba
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								Documentation/ABI/testing/sysfs-bus-amba
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					What:		/sys/bus/amba/devices/.../driver_override
 | 
				
			||||||
 | 
					Date:		September 2014
 | 
				
			||||||
 | 
					Contact:	Antonios Motakis <a.motakis@virtualopensystems.com>
 | 
				
			||||||
 | 
					Description:
 | 
				
			||||||
 | 
							This file allows the driver for a device to be specified which
 | 
				
			||||||
 | 
							will override standard OF, ACPI, ID table, and name matching.
 | 
				
			||||||
 | 
							When specified, only a driver with a name matching the value
 | 
				
			||||||
 | 
							written to driver_override will have an opportunity to bind to
 | 
				
			||||||
 | 
							the device. The override is specified by writing a string to the
 | 
				
			||||||
 | 
							driver_override file (echo vfio-amba > driver_override)	and may
 | 
				
			||||||
 | 
							be cleared with an empty string (echo > driver_override).
 | 
				
			||||||
 | 
							This returns the device to standard matching rules binding.
 | 
				
			||||||
 | 
							Writing to driver_override does not automatically unbind the
 | 
				
			||||||
 | 
							device from its current driver or make any attempt to
 | 
				
			||||||
 | 
							automatically load the specified driver. If no driver with a
 | 
				
			||||||
 | 
							matching name is currently loaded in the kernel, the device will
 | 
				
			||||||
 | 
							not bind to any driver. This also allows devices to opt-out of
 | 
				
			||||||
 | 
							driver binding using a driver_override name such as "none".
 | 
				
			||||||
 | 
							Only a single driver may be specified in the override, there is
 | 
				
			||||||
 | 
							no support for parsing delimiters.
 | 
				
			||||||
| 
						 | 
					@ -18,6 +18,7 @@
 | 
				
			||||||
#include <linux/pm_domain.h>
 | 
					#include <linux/pm_domain.h>
 | 
				
			||||||
#include <linux/amba/bus.h>
 | 
					#include <linux/amba/bus.h>
 | 
				
			||||||
#include <linux/sizes.h>
 | 
					#include <linux/sizes.h>
 | 
				
			||||||
 | 
					#include <linux/limits.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/irq.h>
 | 
					#include <asm/irq.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv)
 | 
				
			||||||
	struct amba_device *pcdev = to_amba_device(dev);
 | 
						struct amba_device *pcdev = to_amba_device(dev);
 | 
				
			||||||
	struct amba_driver *pcdrv = to_amba_driver(drv);
 | 
						struct amba_driver *pcdrv = to_amba_driver(drv);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* When driver_override is set, only bind to the matching driver */
 | 
				
			||||||
 | 
						if (pcdev->driver_override)
 | 
				
			||||||
 | 
							return !strcmp(pcdev->driver_override, drv->name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return amba_lookup(pcdrv->id_table, pcdev) != NULL;
 | 
						return amba_lookup(pcdrv->id_table, pcdev) != NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
 | 
				
			||||||
	return retval;
 | 
						return retval;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t driver_override_show(struct device *_dev,
 | 
				
			||||||
 | 
									    struct device_attribute *attr, char *buf)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct amba_device *dev = to_amba_device(_dev);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!dev->driver_override)
 | 
				
			||||||
 | 
							return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return sprintf(buf, "%s\n", dev->driver_override);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static ssize_t driver_override_store(struct device *_dev,
 | 
				
			||||||
 | 
									     struct device_attribute *attr,
 | 
				
			||||||
 | 
									     const char *buf, size_t count)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						struct amba_device *dev = to_amba_device(_dev);
 | 
				
			||||||
 | 
						char *driver_override, *old = dev->driver_override, *cp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (count > PATH_MAX)
 | 
				
			||||||
 | 
							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)) {
 | 
				
			||||||
 | 
							dev->driver_override = driver_override;
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
						       kfree(driver_override);
 | 
				
			||||||
 | 
						       dev->driver_override = NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(old);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return count;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define amba_attr_func(name,fmt,arg...)					\
 | 
					#define amba_attr_func(name,fmt,arg...)					\
 | 
				
			||||||
static ssize_t name##_show(struct device *_dev,				\
 | 
					static ssize_t name##_show(struct device *_dev,				\
 | 
				
			||||||
			   struct device_attribute *attr, char *buf)	\
 | 
								   struct device_attribute *attr, char *buf)	\
 | 
				
			||||||
| 
						 | 
					@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
 | 
				
			||||||
static struct device_attribute amba_dev_attrs[] = {
 | 
					static struct device_attribute amba_dev_attrs[] = {
 | 
				
			||||||
	__ATTR_RO(id),
 | 
						__ATTR_RO(id),
 | 
				
			||||||
	__ATTR_RO(resource),
 | 
						__ATTR_RO(resource),
 | 
				
			||||||
 | 
						__ATTR_RW(driver_override),
 | 
				
			||||||
	__ATTR_NULL,
 | 
						__ATTR_NULL,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -33,6 +33,7 @@ struct amba_device {
 | 
				
			||||||
	struct clk		*pclk;
 | 
						struct clk		*pclk;
 | 
				
			||||||
	unsigned int		periphid;
 | 
						unsigned int		periphid;
 | 
				
			||||||
	unsigned int		irq[AMBA_NR_IRQS];
 | 
						unsigned int		irq[AMBA_NR_IRQS];
 | 
				
			||||||
 | 
						char			*driver_override;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct amba_driver {
 | 
					struct amba_driver {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue