Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3cf38571 authored by Antonios Motakis's avatar Antonios Motakis Committed by Russell King
Browse files

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: default avatarAntonios Motakis <a.motakis@virtualopensystems.com>
Reviewed-by: default avatarKim Phillips <kim.phillips@freescale.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 8684014d
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
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.
+47 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/pm_domain.h>
#include <linux/amba/bus.h>
#include <linux/sizes.h>
#include <linux/limits.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_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;
}

@@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
	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...)					\
static ssize_t name##_show(struct device *_dev,				\
			   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[] = {
	__ATTR_RO(id),
	__ATTR_RO(resource),
	__ATTR_RW(driver_override),
	__ATTR_NULL,
};

+1 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ struct amba_device {
	struct clk		*pclk;
	unsigned int		periphid;
	unsigned int		irq[AMBA_NR_IRQS];
	char			*driver_override;
};

struct amba_driver {