Re: [PATCH] driver core: amba: add device binding path 'driver_override'

2014-10-13 Thread Kim Phillips
On Mon, 13 Oct 2014 15:07:34 +0200
Antonios Motakis  wrote:

> 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 
> ---

Reviewed-by: Kim Phillips 

Kim
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 18/18] vfio/platform: implement IRQ masking/unmasking via an eventfd

2014-10-13 Thread Antonios Motakis
With this patch the VFIO user will be able to set an eventfd that can be
used in order to mask and unmask IRQs of platform devices.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_irq.c | 46 ---
 drivers/vfio/platform/vfio_platform_private.h |  2 ++
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
b/drivers/vfio/platform/vfio_platform_irq.c
index 7620a17..6abb387 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -45,6 +45,15 @@ static void vfio_platform_mask(struct vfio_platform_irq 
*irq_ctx)
spin_unlock_irqrestore(&irq_ctx->lock, flags);
 }
 
+static int vfio_platform_mask_handler(void *opaque, void *unused)
+{
+   struct vfio_platform_irq *irq_ctx = opaque;
+
+   vfio_platform_mask(irq_ctx);
+
+   return 0;
+}
+
 static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
unsigned index, unsigned start,
unsigned count, uint32_t flags, void *data)
@@ -52,8 +61,18 @@ static int vfio_platform_set_irq_mask(struct 
vfio_platform_device *vdev,
if (start != 0 || count != 1)
return -EINVAL;
 
-   if (flags & VFIO_IRQ_SET_DATA_EVENTFD)
-   return -EINVAL; /* not implemented yet */
+   if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+   int32_t fd = *(int32_t *)data;
+
+   if (fd >= 0)
+   return virqfd_enable((void *) &vdev->irqs[index],
+vfio_platform_mask_handler,
+NULL, NULL,
+&vdev->irqs[index].mask, fd);
+
+   virqfd_disable(&vdev->irqs[index].mask);
+   return 0;
+   }
 
if (flags & VFIO_IRQ_SET_DATA_NONE) {
vfio_platform_mask(&vdev->irqs[index]);
@@ -82,6 +101,15 @@ static void vfio_platform_unmask(struct vfio_platform_irq 
*irq_ctx)
spin_unlock_irqrestore(&irq_ctx->lock, flags);
 }
 
+static int vfio_platform_unmask_handler(void *opaque, void *unused)
+{
+   struct vfio_platform_irq *irq_ctx = opaque;
+
+   vfio_platform_unmask(irq_ctx);
+
+   return 0;
+}
+
 static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
unsigned index, unsigned start,
unsigned count, uint32_t flags, void *data)
@@ -89,8 +117,18 @@ static int vfio_platform_set_irq_unmask(struct 
vfio_platform_device *vdev,
if (start != 0 || count != 1)
return -EINVAL;
 
-   if (flags & VFIO_IRQ_SET_DATA_EVENTFD)
-   return -EINVAL; /* not implemented yet */
+   if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+   int32_t fd = *(int32_t *)data;
+
+   if (fd >= 0)
+   return virqfd_enable((void *) &vdev->irqs[index],
+vfio_platform_unmask_handler,
+NULL, NULL,
+&vdev->irqs[index].unmask, fd);
+
+   virqfd_disable(&vdev->irqs[index].unmask);
+   return 0;
+   }
 
if (flags & VFIO_IRQ_SET_DATA_NONE) {
vfio_platform_unmask(&vdev->irqs[index]);
diff --git a/drivers/vfio/platform/vfio_platform_private.h 
b/drivers/vfio/platform/vfio_platform_private.h
index 65e80e7..23ef038 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -32,6 +32,8 @@ struct vfio_platform_irq {
struct eventfd_ctx  *trigger;
boolmasked;
spinlock_t  lock;
+   struct virqfd   *unmask;
+   struct virqfd   *mask;
 };
 
 struct vfio_platform_region {
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 13/18] vfio/platform: support for maskable and automasked interrupts

2014-10-13 Thread Antonios Motakis
Adds support to mask interrupts, and also for automasked interrupts.
Level sensitive interrupts are exposed as automasked interrupts and
are masked and disabled automatically when they fire.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_irq.c | 94 +--
 drivers/vfio/platform/vfio_platform_private.h |  2 +
 2 files changed, 91 insertions(+), 5 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
b/drivers/vfio/platform/vfio_platform_irq.c
index 4359b9c..7620a17 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -31,27 +31,103 @@
 
 #include "vfio_platform_private.h"
 
+static void vfio_platform_mask(struct vfio_platform_irq *irq_ctx)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&irq_ctx->lock, flags);
+
+   if (!irq_ctx->masked) {
+   disable_irq(irq_ctx->hwirq);
+   irq_ctx->masked = true;
+   }
+
+   spin_unlock_irqrestore(&irq_ctx->lock, flags);
+}
+
 static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
unsigned index, unsigned start,
unsigned count, uint32_t flags, void *data)
 {
-   return -EINVAL;
+   if (start != 0 || count != 1)
+   return -EINVAL;
+
+   if (flags & VFIO_IRQ_SET_DATA_EVENTFD)
+   return -EINVAL; /* not implemented yet */
+
+   if (flags & VFIO_IRQ_SET_DATA_NONE) {
+   vfio_platform_mask(&vdev->irqs[index]);
+
+   } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+   uint8_t mask = *(uint8_t *)data;
+
+   if (mask)
+   vfio_platform_mask(&vdev->irqs[index]);
+   }
+
+   return 0;
+}
+
+static void vfio_platform_unmask(struct vfio_platform_irq *irq_ctx)
+{
+   unsigned long flags;
+
+   spin_lock_irqsave(&irq_ctx->lock, flags);
+
+   if (irq_ctx->masked) {
+   enable_irq(irq_ctx->hwirq);
+   irq_ctx->masked = false;
+   }
+
+   spin_unlock_irqrestore(&irq_ctx->lock, flags);
 }
 
 static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
unsigned index, unsigned start,
unsigned count, uint32_t flags, void *data)
 {
-   return -EINVAL;
+   if (start != 0 || count != 1)
+   return -EINVAL;
+
+   if (flags & VFIO_IRQ_SET_DATA_EVENTFD)
+   return -EINVAL; /* not implemented yet */
+
+   if (flags & VFIO_IRQ_SET_DATA_NONE) {
+   vfio_platform_unmask(&vdev->irqs[index]);
+
+   } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+   uint8_t unmask = *(uint8_t *)data;
+
+   if (unmask)
+   vfio_platform_unmask(&vdev->irqs[index]);
+   }
+
+   return 0;
 }
 
 static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
 {
struct vfio_platform_irq *irq_ctx = dev_id;
+   unsigned long flags;
+   int ret = IRQ_NONE;
 
-   eventfd_signal(irq_ctx->trigger, 1);
+   spin_lock_irqsave(&irq_ctx->lock, flags);
+
+   if (!irq_ctx->masked) {
+   ret = IRQ_HANDLED;
+
+   if (irq_ctx->flags & VFIO_IRQ_INFO_AUTOMASKED) {
+   disable_irq_nosync(irq_ctx->hwirq);
+   irq_ctx->masked = true;
+   }
+   }
 
-   return IRQ_HANDLED;
+   spin_unlock_irqrestore(&irq_ctx->lock, flags);
+
+   if (ret == IRQ_HANDLED)
+   eventfd_signal(irq_ctx->trigger, 1);
+
+   return ret;
 }
 
 static int vfio_set_trigger(struct vfio_platform_device *vdev,
@@ -169,9 +245,17 @@ int vfio_platform_irq_init(struct vfio_platform_device 
*vdev)
if (hwirq < 0)
goto err;
 
-   vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
+   spin_lock_init(&vdev->irqs[i].lock);
+
+   vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD
+   | VFIO_IRQ_INFO_MASKABLE;
+
+   if (irq_get_trigger_type(hwirq) & IRQ_TYPE_LEVEL_MASK)
+   vdev->irqs[i].flags |= VFIO_IRQ_INFO_AUTOMASKED;
+
vdev->irqs[i].count = 1;
vdev->irqs[i].hwirq = hwirq;
+   vdev->irqs[i].masked = false;
}
 
vdev->num_irqs = cnt;
diff --git a/drivers/vfio/platform/vfio_platform_private.h 
b/drivers/vfio/platform/vfio_platform_private.h
index 47af6e0..65e80e7 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -30,6 +30,8 @@ struct vfio_platform_irq {
int hwirq;
char*name;
struct eventfd_ctx  *trigger;
+   boolmasked;
+   spinlock_t  lock;
 };
 
 struct vfio_platform_region {
-- 
2.1.1


[PATCH v8 11/18] vfio/platform: initial interrupts support code

2014-10-13 Thread Antonios Motakis
This patch is a skeleton for the VFIO_DEVICE_SET_IRQS IOCTL, around which
most IRQ functionality is implemented in VFIO.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c  | 52 +++--
 drivers/vfio/platform/vfio_platform_irq.c | 56 +++
 drivers/vfio/platform/vfio_platform_private.h |  6 +++
 3 files changed, 111 insertions(+), 3 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index c26a545..2a6c665 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -197,10 +197,54 @@ static long vfio_platform_ioctl(void *device_data,
 
return copy_to_user((void __user *)arg, &info, minsz);
 
-   } else if (cmd == VFIO_DEVICE_SET_IRQS)
-   return -EINVAL;
+   } else if (cmd == VFIO_DEVICE_SET_IRQS) {
+   struct vfio_irq_set hdr;
+   u8 *data = NULL;
+   int ret = 0;
+
+   minsz = offsetofend(struct vfio_irq_set, count);
+
+   if (copy_from_user(&hdr, (void __user *)arg, minsz))
+   return -EFAULT;
+
+   if (hdr.argsz < minsz)
+   return -EINVAL;
+
+   if (hdr.index >= vdev->num_irqs)
+   return -EINVAL;
+
+   if (hdr.flags & ~(VFIO_IRQ_SET_DATA_TYPE_MASK |
+ VFIO_IRQ_SET_ACTION_TYPE_MASK))
+   return -EINVAL;
 
-   else if (cmd == VFIO_DEVICE_RESET)
+   if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
+   size_t size;
+
+   if (hdr.flags & VFIO_IRQ_SET_DATA_BOOL)
+   size = sizeof(uint8_t);
+   else if (hdr.flags & VFIO_IRQ_SET_DATA_EVENTFD)
+   size = sizeof(int32_t);
+   else
+   return -EINVAL;
+
+   if (hdr.argsz - minsz < size)
+   return -EINVAL;
+
+   data = memdup_user((void __user *)(arg + minsz), size);
+   if (IS_ERR(data))
+   return PTR_ERR(data);
+   }
+
+   mutex_lock(&vdev->igate);
+
+   ret = vfio_platform_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
+  hdr.start, hdr.count, data);
+   mutex_unlock(&vdev->igate);
+   kfree(data);
+
+   return ret;
+
+   } else if (cmd == VFIO_DEVICE_RESET)
return -EINVAL;
 
return -ENOTTY;
@@ -442,6 +486,8 @@ int vfio_platform_probe_common(struct vfio_platform_device 
*vdev,
return ret;
}
 
+   mutex_init(&vdev->igate);
+
return 0;
 }
 EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
b/drivers/vfio/platform/vfio_platform_irq.c
index d99c71c..007b386 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -31,6 +31,53 @@
 
 #include "vfio_platform_private.h"
 
+static int vfio_platform_set_irq_mask(struct vfio_platform_device *vdev,
+   unsigned index, unsigned start,
+   unsigned count, uint32_t flags, void *data)
+{
+   return -EINVAL;
+}
+
+static int vfio_platform_set_irq_unmask(struct vfio_platform_device *vdev,
+   unsigned index, unsigned start,
+   unsigned count, uint32_t flags, void *data)
+{
+   return -EINVAL;
+}
+
+static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
+unsigned index, unsigned start,
+unsigned count, uint32_t flags, void *data)
+{
+   return -EINVAL;
+}
+
+int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
+uint32_t flags, unsigned index, unsigned start,
+unsigned count, void *data)
+{
+   int (*func)(struct vfio_platform_device *vdev, unsigned index,
+   unsigned start, unsigned count, uint32_t flags,
+   void *data) = NULL;
+
+   switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+   case VFIO_IRQ_SET_ACTION_MASK:
+   func = vfio_platform_set_irq_mask;
+   break;
+   case VFIO_IRQ_SET_ACTION_UNMASK:
+   func = vfio_platform_set_irq_unmask;
+   break;
+   case VFIO_IRQ_SET_ACTION_TRIGGER:
+   func = vfio_platform_set_irq_trigger;
+   break;
+   }
+
+   if (!func)
+   return -ENOTTY;
+
+   return func(vdev, index, start, count, flags, data);
+}
+
 int vfio_platform_irq_init(str

[PATCH v8 12/18] vfio/platform: trigger an interrupt via eventfd

2014-10-13 Thread Antonios Motakis
This patch allows to set an eventfd for a patform device's interrupt,
and also to trigger the interrupt eventfd from userspace for testing.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_irq.c | 83 ++-
 drivers/vfio/platform/vfio_platform_private.h |  2 +
 2 files changed, 83 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
b/drivers/vfio/platform/vfio_platform_irq.c
index 007b386..4359b9c 100644
--- a/drivers/vfio/platform/vfio_platform_irq.c
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -45,11 +45,85 @@ static int vfio_platform_set_irq_unmask(struct 
vfio_platform_device *vdev,
return -EINVAL;
 }
 
+static irqreturn_t vfio_irq_handler(int irq, void *dev_id)
+{
+   struct vfio_platform_irq *irq_ctx = dev_id;
+
+   eventfd_signal(irq_ctx->trigger, 1);
+
+   return IRQ_HANDLED;
+}
+
+static int vfio_set_trigger(struct vfio_platform_device *vdev,
+   int index, int fd)
+{
+   struct vfio_platform_irq *irq = &vdev->irqs[index];
+   struct eventfd_ctx *trigger;
+   int ret;
+
+   if (irq->trigger) {
+   free_irq(irq->hwirq, irq);
+   kfree(irq->name);
+   eventfd_ctx_put(irq->trigger);
+   irq->trigger = NULL;
+   }
+
+   if (fd < 0) /* Disable only */
+   return 0;
+
+   irq->name = kasprintf(GFP_KERNEL, "vfio-irq[%d](%s)",
+   irq->hwirq, vdev->name);
+   if (!irq->name)
+   return -ENOMEM;
+
+   trigger = eventfd_ctx_fdget(fd);
+   if (IS_ERR(trigger)) {
+   kfree(irq->name);
+   return PTR_ERR(trigger);
+   }
+
+   irq->trigger = trigger;
+
+   ret = request_irq(irq->hwirq, vfio_irq_handler, 0, irq->name, irq);
+   if (ret) {
+   kfree(irq->name);
+   eventfd_ctx_put(trigger);
+   irq->trigger = NULL;
+   return ret;
+   }
+
+   return 0;
+}
+
 static int vfio_platform_set_irq_trigger(struct vfio_platform_device *vdev,
 unsigned index, unsigned start,
 unsigned count, uint32_t flags, void *data)
 {
-   return -EINVAL;
+   struct vfio_platform_irq *irq = &vdev->irqs[index];
+
+   if (!count && (flags & VFIO_IRQ_SET_DATA_NONE))
+   return vfio_set_trigger(vdev, index, -1);
+
+   if (start != 0 || count != 1)
+   return -EINVAL;
+
+   if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
+   int32_t fd = *(int32_t *)data;
+
+   return vfio_set_trigger(vdev, index, fd);
+   }
+
+   if (flags & VFIO_IRQ_SET_DATA_NONE) {
+   vfio_irq_handler(irq->hwirq, irq);
+
+   } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
+   uint8_t trigger = *(uint8_t *)data;
+
+   if (trigger)
+   vfio_irq_handler(irq->hwirq, irq);
+   }
+
+   return 0;
 }
 
 int vfio_platform_set_irqs_ioctl(struct vfio_platform_device *vdev,
@@ -95,7 +169,7 @@ int vfio_platform_irq_init(struct vfio_platform_device *vdev)
if (hwirq < 0)
goto err;
 
-   vdev->irqs[i].flags = 0;
+   vdev->irqs[i].flags = VFIO_IRQ_INFO_EVENTFD;
vdev->irqs[i].count = 1;
vdev->irqs[i].hwirq = hwirq;
}
@@ -110,6 +184,11 @@ err:
 
 void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
 {
+   int i;
+
+   for (i = 0; i < vdev->num_irqs; i++)
+   vfio_set_trigger(vdev, i, -1);
+
vdev->num_irqs = 0;
kfree(vdev->irqs);
 }
diff --git a/drivers/vfio/platform/vfio_platform_private.h 
b/drivers/vfio/platform/vfio_platform_private.h
index 11ad1bb..47af6e0 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -28,6 +28,8 @@ struct vfio_platform_irq {
u32 flags;
u32 count;
int hwirq;
+   char*name;
+   struct eventfd_ctx  *trigger;
 };
 
 struct vfio_platform_region {
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 17/18] vfio: initialize the virqfd workqueue in VFIO generic code

2014-10-13 Thread Antonios Motakis
Now we have finally completely decoupled virqfd from VFIO_PCI. We can
initialize it from the VFIO generic code, in order to safely use it from
multiple independent VFIO bus drivers.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/pci/vfio_pci.c | 8 
 drivers/vfio/vfio.c | 8 
 drivers/vfio/virqfd.c   | 4 ++--
 include/linux/vfio.h| 4 ++--
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index f782533..40e176d 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -1034,7 +1034,6 @@ static void vfio_pci_try_bus_reset(struct vfio_pci_device 
*vdev)
 static void __exit vfio_pci_cleanup(void)
 {
pci_unregister_driver(&vfio_pci_driver);
-   vfio_pci_virqfd_exit();
vfio_pci_uninit_perm_bits();
 }
 
@@ -1047,11 +1046,6 @@ static int __init vfio_pci_init(void)
if (ret)
return ret;
 
-   /* Start the virqfd cleanup handler */
-   ret = vfio_pci_virqfd_init();
-   if (ret)
-   goto out_virqfd;
-
/* Register and scan for devices */
ret = pci_register_driver(&vfio_pci_driver);
if (ret)
@@ -1060,8 +1054,6 @@ static int __init vfio_pci_init(void)
return 0;
 
 out_driver:
-   vfio_pci_virqfd_exit();
-out_virqfd:
vfio_pci_uninit_perm_bits();
return ret;
 }
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index f018d8d..8e84471 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -1464,6 +1464,11 @@ static int __init vfio_init(void)
if (ret)
goto err_cdev_add;
 
+   /* Start the virqfd cleanup handler used by some VFIO bus drivers */
+   ret = vfio_virqfd_init();
+   if (ret)
+   goto err_virqfd;
+
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
 
/*
@@ -1476,6 +1481,8 @@ static int __init vfio_init(void)
 
return 0;
 
+err_virqfd:
+   cdev_del(&vfio.group_cdev);
 err_cdev_add:
unregister_chrdev_region(vfio.group_devt, MINORMASK);
 err_alloc_chrdev:
@@ -1490,6 +1497,7 @@ static void __exit vfio_cleanup(void)
 {
WARN_ON(!list_empty(&vfio.group_list));
 
+   vfio_virqfd_exit();
idr_destroy(&vfio.group_idr);
cdev_del(&vfio.group_cdev);
unregister_chrdev_region(vfio.group_devt, MINORMASK);
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
index ac63ec0..c28882f 100644
--- a/drivers/vfio/virqfd.c
+++ b/drivers/vfio/virqfd.c
@@ -18,7 +18,7 @@
 static struct workqueue_struct *vfio_irqfd_cleanup_wq;
 static spinlock_t lock;
 
-int __init vfio_pci_virqfd_init(void)
+int __init vfio_virqfd_init(void)
 {
vfio_irqfd_cleanup_wq =
create_singlethread_workqueue("vfio-irqfd-cleanup");
@@ -30,7 +30,7 @@ int __init vfio_pci_virqfd_init(void)
return 0;
 }
 
-void vfio_pci_virqfd_exit(void)
+void vfio_virqfd_exit(void)
 {
destroy_workqueue(vfio_irqfd_cleanup_wq);
 }
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index ce23a42..9fa02c8 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -140,8 +140,8 @@ struct virqfd {
struct virqfd   **pvirqfd;
 };
 
-extern int vfio_pci_virqfd_init(void);
-extern void vfio_pci_virqfd_exit(void);
+extern int vfio_virqfd_init(void);
+extern void vfio_virqfd_exit(void);
 extern int virqfd_enable(void *opaque,
 int (*handler)(void *, void *),
 void (*thread)(void *, void *),
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 15/18] vfio: add local lock in virqfd instead of depending on VFIO PCI

2014-10-13 Thread Antonios Motakis
Virqfd just needs to keep accesses to any struct *virqfd safe, but this
comes into play only when creating or destroying eventfds, so sharing
the same spinlock with the VFIO bus driver is not necessary.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/pci/vfio_pci_intrs.c | 10 +-
 drivers/vfio/virqfd.c | 24 +---
 include/linux/vfio.h  |  3 +--
 3 files changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/vfio/pci/vfio_pci_intrs.c 
b/drivers/vfio/pci/vfio_pci_intrs.c
index 3f909bb..e56c814 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -226,8 +226,8 @@ static int vfio_intx_set_signal(struct vfio_pci_device 
*vdev, int fd)
 static void vfio_intx_disable(struct vfio_pci_device *vdev)
 {
vfio_intx_set_signal(vdev, -1);
-   virqfd_disable(vdev, &vdev->ctx[0].unmask);
-   virqfd_disable(vdev, &vdev->ctx[0].mask);
+   virqfd_disable(&vdev->ctx[0].unmask);
+   virqfd_disable(&vdev->ctx[0].mask);
vdev->irq_type = VFIO_PCI_NUM_IRQS;
vdev->num_ctx = 0;
kfree(vdev->ctx);
@@ -377,8 +377,8 @@ static void vfio_msi_disable(struct vfio_pci_device *vdev, 
bool msix)
vfio_msi_set_block(vdev, 0, vdev->num_ctx, NULL, msix);
 
for (i = 0; i < vdev->num_ctx; i++) {
-   virqfd_disable(vdev, &vdev->ctx[i].unmask);
-   virqfd_disable(vdev, &vdev->ctx[i].mask);
+   virqfd_disable(&vdev->ctx[i].unmask);
+   virqfd_disable(&vdev->ctx[i].mask);
}
 
if (msix) {
@@ -415,7 +415,7 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_device 
*vdev,
 vfio_send_intx_eventfd, NULL,
 &vdev->ctx[0].unmask, fd);
 
-   virqfd_disable(vdev, &vdev->ctx[0].unmask);
+   virqfd_disable(&vdev->ctx[0].unmask);
}
 
return 0;
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
index 243eb61..27fa2f0 100644
--- a/drivers/vfio/virqfd.c
+++ b/drivers/vfio/virqfd.c
@@ -17,6 +17,7 @@
 #include "pci/vfio_pci_private.h"
 
 static struct workqueue_struct *vfio_irqfd_cleanup_wq;
+static spinlock_t lock;
 
 int __init vfio_pci_virqfd_init(void)
 {
@@ -25,6 +26,8 @@ int __init vfio_pci_virqfd_init(void)
if (!vfio_irqfd_cleanup_wq)
return -ENOMEM;
 
+   spin_lock_init(&lock);
+
return 0;
 }
 
@@ -53,21 +56,21 @@ static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, 
int sync, void *key)
 
if (flags & POLLHUP) {
unsigned long flags;
-   spin_lock_irqsave(&virqfd->vdev->irqlock, flags);
+   spin_lock_irqsave(&lock, flags);
 
/*
 * The eventfd is closing, if the virqfd has not yet been
 * queued for release, as determined by testing whether the
-* vdev pointer to it is still valid, queue it now.  As
+* virqfd pointer to it is still valid, queue it now.  As
 * with kvm irqfds, we know we won't race against the virqfd
-* going away because we hold wqh->lock to get here.
+* going away because we hold the lock to get here.
 */
if (*(virqfd->pvirqfd) == virqfd) {
*(virqfd->pvirqfd) = NULL;
virqfd_deactivate(virqfd);
}
 
-   spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags);
+   spin_unlock_irqrestore(&lock, flags);
}
 
return 0;
@@ -143,16 +146,16 @@ int virqfd_enable(struct vfio_pci_device *vdev,
 * we update the pointer to the virqfd under lock to avoid
 * pushing multiple jobs to release the same virqfd.
 */
-   spin_lock_irq(&vdev->irqlock);
+   spin_lock_irq(&lock);
 
if (*pvirqfd) {
-   spin_unlock_irq(&vdev->irqlock);
+   spin_unlock_irq(&lock);
ret = -EBUSY;
goto err_busy;
}
*pvirqfd = virqfd;
 
-   spin_unlock_irq(&vdev->irqlock);
+   spin_unlock_irq(&lock);
 
/*
 * Install our own custom wake-up handling so we are notified via
@@ -190,19 +193,18 @@ err_fd:
 }
 EXPORT_SYMBOL_GPL(virqfd_enable);
 
-void virqfd_disable(struct vfio_pci_device *vdev,
-  struct virqfd **pvirqfd)
+void virqfd_disable(struct virqfd **pvirqfd)
 {
unsigned long flags;
 
-   spin_lock_irqsave(&vdev->irqlock, flags);
+   spin_lock_irqsave(&lock, flags);
 
if (*pvirqfd) {
virqfd_deactivate(*pvirqfd);
*pvirqfd = NULL;
}
 
-   spin_unlock_irqrestore(&vdev->irqlock, flags);
+   spin_unlock_irqrestore(&lock, flags);
 
/*
 * Block until we know all outstanding shutdown jobs have completed.
diff --git a/include/linux/vfio.h b/include/linux

[PATCH v8 14/18] vfio: move eventfd support code for VFIO_PCI to a separate file

2014-10-13 Thread Antonios Motakis
The virqfd functionality that is used by VFIO_PCI to implement interrupt
masking and unmasking via an eventfd, is generic enough and can be reused
by another driver. Move it to a separate file in order to allow the code
to be shared.

Also properly export virqfd_enable and virqfd_disable in the process.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/Makefile   |   4 +-
 drivers/vfio/pci/vfio_pci_intrs.c   | 213 ---
 drivers/vfio/pci/vfio_pci_private.h |   3 -
 drivers/vfio/virqfd.c   | 214 
 include/linux/vfio.h|  28 +
 5 files changed, 245 insertions(+), 217 deletions(-)
 create mode 100644 drivers/vfio/virqfd.c

diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index dadf0ca..d798b09 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -1,4 +1,6 @@
-obj-$(CONFIG_VFIO) += vfio.o
+vfio_core-y := vfio.o virqfd.o
+
+obj-$(CONFIG_VFIO) += vfio_core.o
 obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
 obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
 obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c 
b/drivers/vfio/pci/vfio_pci_intrs.c
index 9dd49c9..3f909bb 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -18,226 +18,13 @@
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
-#include 
 #include 
 
 #include "vfio_pci_private.h"
 
 /*
- * IRQfd - generic
- */
-struct virqfd {
-   struct vfio_pci_device  *vdev;
-   struct eventfd_ctx  *eventfd;
-   int (*handler)(struct vfio_pci_device *, void *);
-   void(*thread)(struct vfio_pci_device *, void *);
-   void*data;
-   struct work_struct  inject;
-   wait_queue_twait;
-   poll_table  pt;
-   struct work_struct  shutdown;
-   struct virqfd   **pvirqfd;
-};
-
-static struct workqueue_struct *vfio_irqfd_cleanup_wq;
-
-int __init vfio_pci_virqfd_init(void)
-{
-   vfio_irqfd_cleanup_wq =
-   create_singlethread_workqueue("vfio-irqfd-cleanup");
-   if (!vfio_irqfd_cleanup_wq)
-   return -ENOMEM;
-
-   return 0;
-}
-
-void vfio_pci_virqfd_exit(void)
-{
-   destroy_workqueue(vfio_irqfd_cleanup_wq);
-}
-
-static void virqfd_deactivate(struct virqfd *virqfd)
-{
-   queue_work(vfio_irqfd_cleanup_wq, &virqfd->shutdown);
-}
-
-static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, int sync, void 
*key)
-{
-   struct virqfd *virqfd = container_of(wait, struct virqfd, wait);
-   unsigned long flags = (unsigned long)key;
-
-   if (flags & POLLIN) {
-   /* An event has been signaled, call function */
-   if ((!virqfd->handler ||
-virqfd->handler(virqfd->vdev, virqfd->data)) &&
-   virqfd->thread)
-   schedule_work(&virqfd->inject);
-   }
-
-   if (flags & POLLHUP) {
-   unsigned long flags;
-   spin_lock_irqsave(&virqfd->vdev->irqlock, flags);
-
-   /*
-* The eventfd is closing, if the virqfd has not yet been
-* queued for release, as determined by testing whether the
-* vdev pointer to it is still valid, queue it now.  As
-* with kvm irqfds, we know we won't race against the virqfd
-* going away because we hold wqh->lock to get here.
-*/
-   if (*(virqfd->pvirqfd) == virqfd) {
-   *(virqfd->pvirqfd) = NULL;
-   virqfd_deactivate(virqfd);
-   }
-
-   spin_unlock_irqrestore(&virqfd->vdev->irqlock, flags);
-   }
-
-   return 0;
-}
-
-static void virqfd_ptable_queue_proc(struct file *file,
-wait_queue_head_t *wqh, poll_table *pt)
-{
-   struct virqfd *virqfd = container_of(pt, struct virqfd, pt);
-   add_wait_queue(wqh, &virqfd->wait);
-}
-
-static void virqfd_shutdown(struct work_struct *work)
-{
-   struct virqfd *virqfd = container_of(work, struct virqfd, shutdown);
-   u64 cnt;
-
-   eventfd_ctx_remove_wait_queue(virqfd->eventfd, &virqfd->wait, &cnt);
-   flush_work(&virqfd->inject);
-   eventfd_ctx_put(virqfd->eventfd);
-
-   kfree(virqfd);
-}
-
-static void virqfd_inject(struct work_struct *work)
-{
-   struct virqfd *virqfd = container_of(work, struct virqfd, inject);
-   if (virqfd->thread)
-   virqfd->thread(virqfd->vdev, virqfd->data);
-}
-
-static int virqfd_enable(struct vfio_pci_device *vdev,
-int (*handler)(struct vfio_pci_device *, void *),
-void (*thread)(struct vfio_pci_device *, void *),
-void *data, struct virqfd **pvirqfd, int fd)
-{
-   struct fd irq

[PATCH v8 16/18] vfio: pass an opaque pointer on virqfd initialization

2014-10-13 Thread Antonios Motakis
VFIO_PCI passes the VFIO device structure *vdev via eventfd to the handler
that implements masking/unmasking of IRQs via an eventfd. We can replace
it in the virqfd infrastructure with an opaque type so we can make use
of the mechanism from other VFIO bus drivers.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/pci/vfio_pci_intrs.c | 11 +++
 drivers/vfio/virqfd.c | 17 -
 include/linux/vfio.h  | 12 ++--
 3 files changed, 21 insertions(+), 19 deletions(-)

diff --git a/drivers/vfio/pci/vfio_pci_intrs.c 
b/drivers/vfio/pci/vfio_pci_intrs.c
index e56c814..6ca22a8 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -27,8 +27,10 @@
 /*
  * INTx
  */
-static void vfio_send_intx_eventfd(struct vfio_pci_device *vdev, void *unused)
+static void vfio_send_intx_eventfd(void *opaque, void *unused)
 {
+   struct vfio_pci_device *vdev = opaque;
+
if (likely(is_intx(vdev) && !vdev->virq_disabled))
eventfd_signal(vdev->ctx[0].trigger, 1);
 }
@@ -71,9 +73,9 @@ void vfio_pci_intx_mask(struct vfio_pci_device *vdev)
  * a signal is necessary, which can then be handled via a work queue
  * or directly depending on the caller.
  */
-static int vfio_pci_intx_unmask_handler(struct vfio_pci_device *vdev,
-   void *unused)
+static int vfio_pci_intx_unmask_handler(void *opaque, void *unused)
 {
+   struct vfio_pci_device *vdev = opaque;
struct pci_dev *pdev = vdev->pdev;
unsigned long flags;
int ret = 0;
@@ -411,7 +413,8 @@ static int vfio_pci_set_intx_unmask(struct vfio_pci_device 
*vdev,
} else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
int32_t fd = *(int32_t *)data;
if (fd >= 0)
-   return virqfd_enable(vdev, vfio_pci_intx_unmask_handler,
+   return virqfd_enable((void *) vdev,
+vfio_pci_intx_unmask_handler,
 vfio_send_intx_eventfd, NULL,
 &vdev->ctx[0].unmask, fd);
 
diff --git a/drivers/vfio/virqfd.c b/drivers/vfio/virqfd.c
index 27fa2f0..ac63ec0 100644
--- a/drivers/vfio/virqfd.c
+++ b/drivers/vfio/virqfd.c
@@ -14,7 +14,6 @@
 #include 
 #include 
 #include 
-#include "pci/vfio_pci_private.h"
 
 static struct workqueue_struct *vfio_irqfd_cleanup_wq;
 static spinlock_t lock;
@@ -49,7 +48,7 @@ static int virqfd_wakeup(wait_queue_t *wait, unsigned mode, 
int sync, void *key)
if (flags & POLLIN) {
/* An event has been signaled, call function */
if ((!virqfd->handler ||
-virqfd->handler(virqfd->vdev, virqfd->data)) &&
+virqfd->handler(virqfd->opaque, virqfd->data)) &&
virqfd->thread)
schedule_work(&virqfd->inject);
}
@@ -99,13 +98,13 @@ static void virqfd_inject(struct work_struct *work)
 {
struct virqfd *virqfd = container_of(work, struct virqfd, inject);
if (virqfd->thread)
-   virqfd->thread(virqfd->vdev, virqfd->data);
+   virqfd->thread(virqfd->opaque, virqfd->data);
 }
 
-int virqfd_enable(struct vfio_pci_device *vdev,
-int (*handler)(struct vfio_pci_device *, void *),
-void (*thread)(struct vfio_pci_device *, void *),
-void *data, struct virqfd **pvirqfd, int fd)
+int virqfd_enable(void *opaque,
+ int (*handler)(void *, void *),
+ void (*thread)(void *, void *),
+ void *data, struct virqfd **pvirqfd, int fd)
 {
struct fd irqfd;
struct eventfd_ctx *ctx;
@@ -118,7 +117,7 @@ int virqfd_enable(struct vfio_pci_device *vdev,
return -ENOMEM;
 
virqfd->pvirqfd = pvirqfd;
-   virqfd->vdev = vdev;
+   virqfd->opaque = opaque;
virqfd->handler = handler;
virqfd->thread = thread;
virqfd->data = data;
@@ -171,7 +170,7 @@ int virqfd_enable(struct vfio_pci_device *vdev,
 * before we registered and trigger it as if we didn't miss it.
 */
if (events & POLLIN) {
-   if ((!handler || handler(vdev, data)) && thread)
+   if ((!handler || handler(opaque, data)) && thread)
schedule_work(&virqfd->inject);
}
 
diff --git a/include/linux/vfio.h b/include/linux/vfio.h
index fb6037b..ce23a42 100644
--- a/include/linux/vfio.h
+++ b/include/linux/vfio.h
@@ -128,10 +128,10 @@ static inline long vfio_spapr_iommu_eeh_ioctl(struct 
iommu_group *group,
  * IRQFD support
  */
 struct virqfd {
-   struct vfio_pci_device  *vdev;
+   void*opaque;
struct eventfd_ctx  *eventfd;
-   int (*handler)(struct vfio_pci_device *, void *);
-   void(*thread)(struc

[PATCH v8 10/18] vfio/platform: return IRQ info

2014-10-13 Thread Antonios Motakis
Return information for the interrupts exposed by the device.
This patch extends VFIO_DEVICE_GET_INFO with the number of IRQs
and enables VFIO_DEVICE_GET_IRQ_INFO.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/Makefile|  2 +-
 drivers/vfio/platform/vfio_platform_common.c  | 34 ---
 drivers/vfio/platform/vfio_platform_irq.c | 59 +++
 drivers/vfio/platform/vfio_platform_private.h | 10 +
 4 files changed, 99 insertions(+), 6 deletions(-)
 create mode 100644 drivers/vfio/platform/vfio_platform_irq.c

diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
index 1957170..81de144 100644
--- a/drivers/vfio/platform/Makefile
+++ b/drivers/vfio/platform/Makefile
@@ -1,5 +1,5 @@
 
-vfio-platform-y := vfio_platform.o vfio_platform_common.o
+vfio-platform-y := vfio_platform.o vfio_platform_common.o vfio_platform_irq.o
 
 obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
 
diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index 4db7187..c26a545 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -99,8 +99,10 @@ static void vfio_platform_release(void *device_data)
 {
struct vfio_platform_device *vdev = device_data;
 
-   if (atomic_dec_and_test(&vdev->refcnt))
+   if (atomic_dec_and_test(&vdev->refcnt)) {
vfio_platform_regions_cleanup(vdev);
+   vfio_platform_irq_cleanup(vdev);
+   }
 
module_put(THIS_MODULE);
 }
@@ -117,10 +119,16 @@ static int vfio_platform_open(void *device_data)
ret = vfio_platform_regions_init(vdev);
if (ret)
goto err_reg;
+
+   ret = vfio_platform_irq_init(vdev);
+   if (ret)
+   goto err_irq;
}
 
return 0;
 
+err_irq:
+   vfio_platform_regions_cleanup(vdev);
 err_reg:
module_put(THIS_MODULE);
return ret;
@@ -145,7 +153,7 @@ static long vfio_platform_ioctl(void *device_data,
 
info.flags = vdev->flags;
info.num_regions = vdev->num_regions;
-   info.num_irqs = 0;
+   info.num_irqs = vdev->num_irqs;
 
return copy_to_user((void __user *)arg, &info, minsz);
 
@@ -170,10 +178,26 @@ static long vfio_platform_ioctl(void *device_data,
 
return copy_to_user((void __user *)arg, &info, minsz);
 
-   } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
-   return -EINVAL;
+   } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
+   struct vfio_irq_info info;
+
+   minsz = offsetofend(struct vfio_irq_info, count);
+
+   if (copy_from_user(&info, (void __user *)arg, minsz))
+   return -EFAULT;
+
+   if (info.argsz < minsz)
+   return -EINVAL;
+
+   if (info.index >= vdev->num_irqs)
+   return -EINVAL;
+
+   info.flags = vdev->irqs[info.index].flags;
+   info.count = vdev->irqs[info.index].count;
+
+   return copy_to_user((void __user *)arg, &info, minsz);
 
-   else if (cmd == VFIO_DEVICE_SET_IRQS)
+   } else if (cmd == VFIO_DEVICE_SET_IRQS)
return -EINVAL;
 
else if (cmd == VFIO_DEVICE_RESET)
diff --git a/drivers/vfio/platform/vfio_platform_irq.c 
b/drivers/vfio/platform/vfio_platform_irq.c
new file mode 100644
index 000..d99c71c
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_irq.c
@@ -0,0 +1,59 @@
+/*
+ * VFIO platform devices interrupt handling
+ *
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "vfio_platform_private.h"
+
+int vfio_platform_irq_init(struct vfio_platform_device *vdev)
+{
+   int cnt = 0, i;
+
+   while (vdev->get_irq(vdev, cnt) > 0)
+   cnt++;
+
+   vdev->irqs = kcalloc(cnt, sizeof(struct vfio_platform_irq), GFP_KERNEL);
+   if (!vdev->irqs)
+   return -ENOMEM;
+
+   for (i = 0; i < cnt; i++) {
+   vdev->irqs[i].flags = 0;
+   vdev->irqs[i].count = 1;
+   }
+
+   vdev->num_irqs = cnt;
+
+   return 0;
+}
+
+void vfio_platform_irq_cleanup(struct vfio_platform_device *vdev)
+{
+   vdev->num_irq

[PATCH v8 09/18] vfio/platform: support MMAP of MMIO regions

2014-10-13 Thread Antonios Motakis
Allow to memory map the MMIO regions of the device so userspace can
directly access them. PIO regions are not being handled at this point.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c | 57 
 1 file changed, 57 insertions(+)

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index ac74710..4db7187 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -57,6 +57,16 @@ static int vfio_platform_regions_init(struct 
vfio_platform_device *vdev)
if (!(res->flags & IORESOURCE_READONLY))
vdev->regions[i].flags |=
VFIO_REGION_INFO_FLAG_WRITE;
+
+   /*
+* Only regions addressed with PAGE granularity may be
+* MMAPed securely.
+*/
+   if (!(vdev->regions[i].addr & ~PAGE_MASK) &&
+   !(vdev->regions[i].size & ~PAGE_MASK))
+   vdev->regions[i].flags |=
+   VFIO_REGION_INFO_FLAG_MMAP;
+
break;
case IORESOURCE_IO:
vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
@@ -325,8 +335,55 @@ static ssize_t vfio_platform_write(void *device_data, 
const char __user *buf,
return -EINVAL;
 }
 
+static int vfio_platform_mmap_mmio(struct vfio_platform_region region,
+  struct vm_area_struct *vma)
+{
+   u64 req_len, pgoff, req_start;
+
+   req_len = vma->vm_end - vma->vm_start;
+   pgoff = vma->vm_pgoff &
+   ((1U << (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
+   req_start = pgoff << PAGE_SHIFT;
+
+   if (region.size < PAGE_SIZE || req_start + req_len > region.size)
+   return -EINVAL;
+
+   vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+   vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
+
+   return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
+  req_len, vma->vm_page_prot);
+}
+
 static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
 {
+   struct vfio_platform_device *vdev = device_data;
+   unsigned int index;
+
+   index = vma->vm_pgoff >> (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT);
+
+   if (vma->vm_end < vma->vm_start)
+   return -EINVAL;
+   if ((vma->vm_flags & VM_SHARED) == 0)
+   return -EINVAL;
+   if (index >= vdev->num_regions)
+   return -EINVAL;
+   if (vma->vm_start & ~PAGE_MASK)
+   return -EINVAL;
+   if (vma->vm_end & ~PAGE_MASK)
+   return -EINVAL;
+
+   if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
+   return -EINVAL;
+
+   vma->vm_private_data = vdev;
+
+   if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
+   return vfio_platform_mmap_mmio(vdev->regions[index], vma);
+
+   else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
+   return -EINVAL; /* not implemented */
+
return -EINVAL;
 }
 
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 05/18] vfio: amba: add the VFIO for AMBA devices module to Kconfig

2014-10-13 Thread Antonios Motakis
Enable building the VFIO AMBA driver. VFIO_AMBA depends on VFIO_PLATFORM,
since it is sharing a portion of the code, and it is essentially implemented
as a platform device whose resources are discovered via AMBA specific APIs
in the kernel.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/Kconfig  | 10 ++
 drivers/vfio/platform/Makefile |  4 
 2 files changed, 14 insertions(+)

diff --git a/drivers/vfio/platform/Kconfig b/drivers/vfio/platform/Kconfig
index c51af17..c0a3bff 100644
--- a/drivers/vfio/platform/Kconfig
+++ b/drivers/vfio/platform/Kconfig
@@ -7,3 +7,13 @@ config VFIO_PLATFORM
  framework.
 
  If you don't know what to do here, say N.
+
+config VFIO_AMBA
+   tristate "VFIO support for AMBA devices"
+   depends on VFIO_PLATFORM && ARM_AMBA
+   help
+ Support for ARM AMBA devices with VFIO. This is required to make
+ use of ARM AMBA devices present on the system using the VFIO
+ framework.
+
+ If you don't know what to do here, say N.
diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
index 279862b..1957170 100644
--- a/drivers/vfio/platform/Makefile
+++ b/drivers/vfio/platform/Makefile
@@ -2,3 +2,7 @@
 vfio-platform-y := vfio_platform.o vfio_platform_common.o
 
 obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
+
+vfio-amba-y := vfio_amba.o
+
+obj-$(CONFIG_VFIO_AMBA) += vfio-amba.o
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 08/18] vfio/platform: read and write support for the device fd

2014-10-13 Thread Antonios Motakis
VFIO returns a file descriptor which we can use to manipulate the memory
regions of the device. Usually, the user will mmap memory regions that are
addressable on page boundaries, however for memory regions where this is
not the case we cannot provide mmap functionality due to security concerns.
For this reason we also need allow to read and write to the memory regions
via the file descriptor. Implement this funcionality only for MMIO regions
of platform devices; PIO regions are not being handled at this point.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c  | 150 ++
 drivers/vfio/platform/vfio_platform_private.h |   1 +
 2 files changed, 151 insertions(+)

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index 8a7e474..ac74710 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -53,6 +53,10 @@ static int vfio_platform_regions_init(struct 
vfio_platform_device *vdev)
switch (resource_type(res)) {
case IORESOURCE_MEM:
vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;
+   vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
+   if (!(res->flags & IORESOURCE_READONLY))
+   vdev->regions[i].flags |=
+   VFIO_REGION_INFO_FLAG_WRITE;
break;
case IORESOURCE_IO:
vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
@@ -72,6 +76,11 @@ err:
 
 static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
 {
+   int i;
+
+   for (i = 0; i < vdev->num_regions; i++)
+   iounmap(vdev->regions[i].ioaddr);
+
vdev->num_regions = 0;
kfree(vdev->regions);
 }
@@ -163,15 +172,156 @@ static long vfio_platform_ioctl(void *device_data,
return -ENOTTY;
 }
 
+static ssize_t vfio_platform_read_mmio(struct vfio_platform_region reg,
+  char __user *buf, size_t count,
+  loff_t off)
+{
+   unsigned int done = 0;
+
+   if (!reg.ioaddr) {
+   reg.ioaddr =
+   ioremap_nocache(reg.addr, reg.size);
+
+   if (!reg.ioaddr)
+   return -ENOMEM;
+   }
+
+   while (count) {
+   size_t filled;
+
+   if (count >= 4 && !(off % 4)) {
+   u32 val;
+
+   val = ioread32(reg.ioaddr + off);
+   if (copy_to_user(buf, &val, 4))
+   goto err;
+
+   filled = 4;
+   } else if (count >= 2 && !(off % 2)) {
+   u16 val;
+
+   val = ioread16(reg.ioaddr + off);
+   if (copy_to_user(buf, &val, 2))
+   goto err;
+
+   filled = 2;
+   } else {
+   u8 val;
+
+   val = ioread8(reg.ioaddr + off);
+   if (copy_to_user(buf, &val, 1))
+   goto err;
+
+   filled = 1;
+   }
+
+
+   count -= filled;
+   done += filled;
+   off += filled;
+   buf += filled;
+   }
+
+   return done;
+err:
+   return -EFAULT;
+}
+
 static ssize_t vfio_platform_read(void *device_data, char __user *buf,
  size_t count, loff_t *ppos)
 {
+   struct vfio_platform_device *vdev = device_data;
+   unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
+   loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
+
+   if (index >= vdev->num_regions)
+   return -EINVAL;
+
+   if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ))
+   return -EINVAL;
+
+   if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
+   return vfio_platform_read_mmio(vdev->regions[index],
+   buf, count, off);
+   else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
+   return -EINVAL; /* not implemented */
+
return -EINVAL;
 }
 
+static ssize_t vfio_platform_write_mmio(struct vfio_platform_region reg,
+   const char __user *buf, size_t count,
+   loff_t off)
+{
+   unsigned int done = 0;
+
+   if (!reg.ioaddr) {
+   reg.ioaddr =
+   ioremap_nocache(reg.addr, reg.size);
+
+   if (!reg.ioaddr)
+   return -ENOMEM;
+   }
+
+   while (count) {
+   size_t filled;
+
+   if (count >= 4 && !(off % 4)) {
+   u

[PATCH v8 06/18] vfio/platform: return info for bound device

2014-10-13 Thread Antonios Motakis
A VFIO userspace driver will start by opening the VFIO device
that corresponds to an IOMMU group, and will use the ioctl interface
to get the basic device info, such as number of memory regions and
interrupts, and their properties. This patch enables the
VFIO_DEVICE_GET_INFO ioctl call.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c | 23 ---
 1 file changed, 20 insertions(+), 3 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index 13808d0..1e4073f 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -43,10 +43,27 @@ static int vfio_platform_open(void *device_data)
 static long vfio_platform_ioctl(void *device_data,
   unsigned int cmd, unsigned long arg)
 {
-   if (cmd == VFIO_DEVICE_GET_INFO)
-   return -EINVAL;
+   struct vfio_platform_device *vdev = device_data;
+   unsigned long minsz;
+
+   if (cmd == VFIO_DEVICE_GET_INFO) {
+   struct vfio_device_info info;
+
+   minsz = offsetofend(struct vfio_device_info, num_irqs);
+
+   if (copy_from_user(&info, (void __user *)arg, minsz))
+   return -EFAULT;
+
+   if (info.argsz < minsz)
+   return -EINVAL;
+
+   info.flags = vdev->flags;
+   info.num_regions = 0;
+   info.num_irqs = 0;
+
+   return copy_to_user((void __user *)arg, &info, minsz);
 
-   else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
+   } else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
return -EINVAL;
 
else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 07/18] vfio/platform: return info for device memory mapped IO regions

2014-10-13 Thread Antonios Motakis
This patch enables the IOCTLs VFIO_DEVICE_GET_REGION_INFO ioctl call,
which allows the user to learn about the available MMIO resources of
a device.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c  | 93 +--
 drivers/vfio/platform/vfio_platform_private.h | 22 +++
 2 files changed, 111 insertions(+), 4 deletions(-)

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
index 1e4073f..8a7e474 100644
--- a/drivers/vfio/platform/vfio_platform_common.c
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -27,17 +27,84 @@
 
 #include "vfio_platform_private.h"
 
+static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
+{
+   int cnt = 0, i;
+
+   while (vdev->get_resource(vdev, cnt))
+   cnt++;
+
+   vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),
+   GFP_KERNEL);
+   if (!vdev->regions)
+   return -ENOMEM;
+
+   for (i = 0; i < cnt;  i++) {
+   struct resource *res =
+   vdev->get_resource(vdev, i);
+
+   if (!res)
+   goto err;
+
+   vdev->regions[i].addr = res->start;
+   vdev->regions[i].size = resource_size(res);
+   vdev->regions[i].flags = 0;
+
+   switch (resource_type(res)) {
+   case IORESOURCE_MEM:
+   vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;
+   break;
+   case IORESOURCE_IO:
+   vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
+   break;
+   default:
+   goto err;
+   }
+   }
+
+   vdev->num_regions = cnt;
+
+   return 0;
+err:
+   kfree(vdev->regions);
+   return -EINVAL;
+}
+
+static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
+{
+   vdev->num_regions = 0;
+   kfree(vdev->regions);
+}
+
 static void vfio_platform_release(void *device_data)
 {
+   struct vfio_platform_device *vdev = device_data;
+
+   if (atomic_dec_and_test(&vdev->refcnt))
+   vfio_platform_regions_cleanup(vdev);
+
module_put(THIS_MODULE);
 }
 
 static int vfio_platform_open(void *device_data)
 {
+   struct vfio_platform_device *vdev = device_data;
+   int ret;
+
if (!try_module_get(THIS_MODULE))
return -ENODEV;
 
+   if (atomic_inc_return(&vdev->refcnt) == 1) {
+   ret = vfio_platform_regions_init(vdev);
+   if (ret)
+   goto err_reg;
+   }
+
return 0;
+
+err_reg:
+   module_put(THIS_MODULE);
+   return ret;
 }
 
 static long vfio_platform_ioctl(void *device_data,
@@ -58,15 +125,33 @@ static long vfio_platform_ioctl(void *device_data,
return -EINVAL;
 
info.flags = vdev->flags;
-   info.num_regions = 0;
+   info.num_regions = vdev->num_regions;
info.num_irqs = 0;
 
return copy_to_user((void __user *)arg, &info, minsz);
 
-   } else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
-   return -EINVAL;
+   } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
+   struct vfio_region_info info;
+
+   minsz = offsetofend(struct vfio_region_info, offset);
+
+   if (copy_from_user(&info, (void __user *)arg, minsz))
+   return -EFAULT;
+
+   if (info.argsz < minsz)
+   return -EINVAL;
+
+   if (info.index >= vdev->num_regions)
+   return -EINVAL;
+
+   /* map offset to the physical address  */
+   info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index);
+   info.size = vdev->regions[info.index].size;
+   info.flags = vdev->regions[info.index].flags;
+
+   return copy_to_user((void __user *)arg, &info, minsz);
 
-   else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
+   } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
return -EINVAL;
 
else if (cmd == VFIO_DEVICE_SET_IRQS)
diff --git a/drivers/vfio/platform/vfio_platform_private.h 
b/drivers/vfio/platform/vfio_platform_private.h
index ef76737..2a06035 100644
--- a/drivers/vfio/platform/vfio_platform_private.h
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -15,7 +15,29 @@
 #ifndef VFIO_PLATFORM_PRIVATE_H
 #define VFIO_PLATFORM_PRIVATE_H
 
+#define VFIO_PLATFORM_OFFSET_SHIFT   40
+#define VFIO_PLATFORM_OFFSET_MASK (((u64)(1) << VFIO_PLATFORM_OFFSET_SHIFT) - 
1)
+
+#define VFIO_PLATFORM_OFFSET_TO_INDEX(off) \
+   (off >> VFIO_PLATFORM_OFFSET_SHIFT)
+
+#define VFIO_PLATFORM_INDEX_TO_OFFSET(index)   \
+   ((u64)(index) << VFIO_PLATFORM_OFFSET_SHIFT)
+
+struct vfio_platform_region {
+   u64

[PATCH v8 02/18] vfio: platform: probe to devices on the platform bus

2014-10-13 Thread Antonios Motakis
Driver to bind to Linux platform devices, and callbacks to discover their
resources to be used by the main VFIO PLATFORM code.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform.c | 107 ++
 include/uapi/linux/vfio.h |   1 +
 2 files changed, 108 insertions(+)
 create mode 100644 drivers/vfio/platform/vfio_platform.c

diff --git a/drivers/vfio/platform/vfio_platform.c 
b/drivers/vfio/platform/vfio_platform.c
new file mode 100644
index 000..baeb7da
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "vfio_platform_private.h"
+
+#define DRIVER_VERSION  "0.8"
+#define DRIVER_AUTHOR   "Antonios Motakis "
+#define DRIVER_DESC "VFIO for platform devices - User Level meta-driver"
+
+/* probing devices from the linux platform bus */
+
+static struct resource *get_platform_resource(struct vfio_platform_device 
*vdev,
+   int num)
+{
+   struct platform_device *dev = (struct platform_device *) vdev->opaque;
+   int i;
+
+   for (i = 0; i < dev->num_resources; i++) {
+   struct resource *r = &dev->resource[i];
+
+   if (resource_type(r) & (IORESOURCE_MEM|IORESOURCE_IO)) {
+   num--;
+
+   if (!num)
+   return r;
+   }
+   }
+   return NULL;
+}
+
+static int get_platform_irq(struct vfio_platform_device *vdev, int i)
+{
+   struct platform_device *pdev = (struct platform_device *) vdev->opaque;
+
+   return platform_get_irq(pdev, i);
+}
+
+
+static int vfio_platform_probe(struct platform_device *pdev)
+{
+   struct vfio_platform_device *vdev;
+   int ret;
+
+   vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+   if (!vdev)
+   return -ENOMEM;
+
+   vdev->opaque = (void *) pdev;
+   vdev->name = pdev->name;
+   vdev->flags = VFIO_DEVICE_FLAGS_PLATFORM;
+   vdev->get_resource = get_platform_resource;
+   vdev->get_irq = get_platform_irq;
+
+   ret = vfio_platform_probe_common(vdev, &pdev->dev);
+   if (ret)
+   kfree(vdev);
+
+   return ret;
+}
+
+static int vfio_platform_remove(struct platform_device *pdev)
+{
+   return vfio_platform_remove_common(&pdev->dev);
+}
+
+static struct platform_driver vfio_platform_driver = {
+   .probe  = vfio_platform_probe,
+   .remove = vfio_platform_remove,
+   .driver = {
+   .name   = "vfio-platform",
+   .owner  = THIS_MODULE,
+   },
+};
+
+module_platform_driver(vfio_platform_driver);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 111b5e8..aca6d3e 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -158,6 +158,7 @@ struct vfio_device_info {
__u32   flags;
 #define VFIO_DEVICE_FLAGS_RESET(1 << 0)/* Device supports 
reset */
 #define VFIO_DEVICE_FLAGS_PCI  (1 << 1)/* vfio-pci device */
+#define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2)/* vfio-platform device */
__u32   num_regions;/* Max region index + 1 */
__u32   num_irqs;   /* Max IRQ index + 1 */
 };
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 01/18] vfio/platform: initial skeleton of VFIO support for platform devices

2014-10-13 Thread Antonios Motakis
This patch forms the common skeleton code for platform devices support
with VFIO. This will include the core functionality of VFIO_PLATFORM,
however binding to the device and discovering the device resources will
be done with the help of a separate file where any Linux platform bus
specific code will reside.

This will allow us to implement support for also discovering AMBA devices
and their resources, but still reuse a large part of the VFIO_PLATFORM
implementation.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_platform_common.c  | 129 ++
 drivers/vfio/platform/vfio_platform_private.h |  35 +++
 2 files changed, 164 insertions(+)
 create mode 100644 drivers/vfio/platform/vfio_platform_common.c
 create mode 100644 drivers/vfio/platform/vfio_platform_private.h

diff --git a/drivers/vfio/platform/vfio_platform_common.c 
b/drivers/vfio/platform/vfio_platform_common.c
new file mode 100644
index 000..13808d0
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_common.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "vfio_platform_private.h"
+
+static void vfio_platform_release(void *device_data)
+{
+   module_put(THIS_MODULE);
+}
+
+static int vfio_platform_open(void *device_data)
+{
+   if (!try_module_get(THIS_MODULE))
+   return -ENODEV;
+
+   return 0;
+}
+
+static long vfio_platform_ioctl(void *device_data,
+  unsigned int cmd, unsigned long arg)
+{
+   if (cmd == VFIO_DEVICE_GET_INFO)
+   return -EINVAL;
+
+   else if (cmd == VFIO_DEVICE_GET_REGION_INFO)
+   return -EINVAL;
+
+   else if (cmd == VFIO_DEVICE_GET_IRQ_INFO)
+   return -EINVAL;
+
+   else if (cmd == VFIO_DEVICE_SET_IRQS)
+   return -EINVAL;
+
+   else if (cmd == VFIO_DEVICE_RESET)
+   return -EINVAL;
+
+   return -ENOTTY;
+}
+
+static ssize_t vfio_platform_read(void *device_data, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+   return -EINVAL;
+}
+
+static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
+  size_t count, loff_t *ppos)
+{
+   return -EINVAL;
+}
+
+static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
+{
+   return -EINVAL;
+}
+
+static const struct vfio_device_ops vfio_platform_ops = {
+   .name   = "vfio-platform",
+   .open   = vfio_platform_open,
+   .release= vfio_platform_release,
+   .ioctl  = vfio_platform_ioctl,
+   .read   = vfio_platform_read,
+   .write  = vfio_platform_write,
+   .mmap   = vfio_platform_mmap,
+};
+
+int vfio_platform_probe_common(struct vfio_platform_device *vdev,
+  struct device *dev)
+{
+   struct iommu_group *group;
+   int ret;
+
+   if (!vdev)
+   return -EINVAL;
+
+   group = iommu_group_get(dev);
+   if (!group) {
+   pr_err("VFIO: No IOMMU group for device %s\n", vdev->name);
+   return -EINVAL;
+   }
+
+   ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
+   if (ret) {
+   iommu_group_put(group);
+   return ret;
+   }
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
+
+int vfio_platform_remove_common(struct device *dev)
+{
+   struct vfio_platform_device *vdev;
+
+   vdev = vfio_del_group_dev(dev);
+   if (!vdev)
+   return -EINVAL;
+
+   iommu_group_put(dev->iommu_group);
+   kfree(vdev);
+
+   return 0;
+}
+EXPORT_SYMBOL_GPL(vfio_platform_remove_common);
diff --git a/drivers/vfio/platform/vfio_platform_private.h 
b/drivers/vfio/platform/vfio_platform_private.h
new file mode 100644
index 000..ef76737
--- /dev/null
+++ b/drivers/vfio/platform/vfio_platform_private.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even th

[PATCH v8 04/18] vfio: amba: VFIO support for AMBA devices

2014-10-13 Thread Antonios Motakis
Add support for discovering AMBA devices with VFIO and handle them
similarly to Linux platform devices.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/platform/vfio_amba.c | 108 ++
 include/uapi/linux/vfio.h |   1 +
 2 files changed, 109 insertions(+)
 create mode 100644 drivers/vfio/platform/vfio_amba.c

diff --git a/drivers/vfio/platform/vfio_amba.c 
b/drivers/vfio/platform/vfio_amba.c
new file mode 100644
index 000..b16a40d
--- /dev/null
+++ b/drivers/vfio/platform/vfio_amba.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2013 - Virtual Open Systems
+ * Author: Antonios Motakis 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "vfio_platform_private.h"
+
+#define DRIVER_VERSION  "0.8"
+#define DRIVER_AUTHOR   "Antonios Motakis "
+#define DRIVER_DESC "VFIO for AMBA devices - User Level meta-driver"
+
+/* probing devices from the AMBA bus */
+
+static struct resource *get_amba_resource(struct vfio_platform_device *vdev,
+   int i)
+{
+   struct amba_device *adev = (struct amba_device *) vdev->opaque;
+
+   if (i == 0)
+   return &adev->res;
+
+   return NULL;
+}
+
+static int get_amba_irq(struct vfio_platform_device *vdev, int i)
+{
+   struct amba_device *adev = (struct amba_device *) vdev->opaque;
+
+   if (i < AMBA_NR_IRQS)
+   return adev->irq[i];
+
+   return 0;
+}
+
+static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
+{
+
+   struct vfio_platform_device *vdev;
+   int ret;
+
+   vdev = kzalloc(sizeof(*vdev), GFP_KERNEL);
+   if (!vdev)
+   return -ENOMEM;
+
+   vdev->opaque = (void *) adev;
+   vdev->name = "vfio-amba-dev";
+   vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
+   vdev->get_resource = get_amba_resource;
+   vdev->get_irq = get_amba_irq;
+
+   ret = vfio_platform_probe_common(vdev, &adev->dev);
+   if (ret)
+   kfree(vdev);
+
+   return ret;
+}
+
+static int vfio_amba_remove(struct amba_device *adev)
+{
+   return vfio_platform_remove_common(&adev->dev);
+}
+
+static struct amba_id pl330_ids[] = {
+   { 0, 0 },
+};
+
+MODULE_DEVICE_TABLE(amba, pl330_ids);
+
+static struct amba_driver vfio_amba_driver = {
+   .probe = vfio_amba_probe,
+   .remove = vfio_amba_remove,
+   .id_table = pl330_ids,
+   .drv = {
+   .name = "vfio-amba",
+   .owner = THIS_MODULE,
+   },
+};
+
+module_amba_driver(vfio_amba_driver);
+
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index aca6d3e..1a5986c 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -159,6 +159,7 @@ struct vfio_device_info {
 #define VFIO_DEVICE_FLAGS_RESET(1 << 0)/* Device supports 
reset */
 #define VFIO_DEVICE_FLAGS_PCI  (1 << 1)/* vfio-pci device */
 #define VFIO_DEVICE_FLAGS_PLATFORM (1 << 2)/* vfio-platform device */
+#define VFIO_DEVICE_FLAGS_AMBA  (1 << 3)   /* vfio-amba device */
__u32   num_regions;/* Max region index + 1 */
__u32   num_irqs;   /* Max IRQ index + 1 */
 };
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 03/18] vfio: platform: add the VFIO PLATFORM module to Kconfig

2014-10-13 Thread Antonios Motakis
Enable building the VFIO PLATFORM driver that allows to use Linux platform
devices with VFIO.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/Kconfig   | 1 +
 drivers/vfio/Makefile  | 1 +
 drivers/vfio/platform/Kconfig  | 9 +
 drivers/vfio/platform/Makefile | 4 
 4 files changed, 15 insertions(+)
 create mode 100644 drivers/vfio/platform/Kconfig
 create mode 100644 drivers/vfio/platform/Makefile

diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index a0abe04..962fb80 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -27,3 +27,4 @@ menuconfig VFIO
  If you don't know what to do here, say N.
 
 source "drivers/vfio/pci/Kconfig"
+source "drivers/vfio/platform/Kconfig"
diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile
index 0b035b1..dadf0ca 100644
--- a/drivers/vfio/Makefile
+++ b/drivers/vfio/Makefile
@@ -3,3 +3,4 @@ obj-$(CONFIG_VFIO_IOMMU_TYPE1) += vfio_iommu_type1.o
 obj-$(CONFIG_VFIO_IOMMU_SPAPR_TCE) += vfio_iommu_spapr_tce.o
 obj-$(CONFIG_VFIO_SPAPR_EEH) += vfio_spapr_eeh.o
 obj-$(CONFIG_VFIO_PCI) += pci/
+obj-$(CONFIG_VFIO_PLATFORM) += platform/
diff --git a/drivers/vfio/platform/Kconfig b/drivers/vfio/platform/Kconfig
new file mode 100644
index 000..c51af17
--- /dev/null
+++ b/drivers/vfio/platform/Kconfig
@@ -0,0 +1,9 @@
+config VFIO_PLATFORM
+   tristate "VFIO support for platform devices"
+   depends on VFIO && EVENTFD && ARM
+   help
+ Support for platform devices with VFIO. This is required to make
+ use of platform devices present on the system using the VFIO
+ framework.
+
+ If you don't know what to do here, say N.
diff --git a/drivers/vfio/platform/Makefile b/drivers/vfio/platform/Makefile
new file mode 100644
index 000..279862b
--- /dev/null
+++ b/drivers/vfio/platform/Makefile
@@ -0,0 +1,4 @@
+
+vfio-platform-y := vfio_platform.o vfio_platform_common.o
+
+obj-$(CONFIG_VFIO_PLATFORM) += vfio-platform.o
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 5/5] vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag

2014-10-13 Thread Antonios Motakis
Some IOMMU drivers, such as the ARM SMMU driver, make available the
IOMMU_NOEXEC flag, to set the page tables for a device as XN (execute never).
This affects devices such as the ARM PL330 DMA Controller, which respects
this flag and will refuse to fetch DMA instructions from memory where the
XN flag has been set.

The flag can be used only if all IOMMU domains behind the container support
the IOMMU_NOEXEC flag. Also, if any mappings are created with the flag, any
new domains with devices will have to support it as well.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/vfio_iommu_type1.c | 25 -
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 8b4202a..e225e8f 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -569,6 +569,12 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
if (map->flags & VFIO_DMA_MAP_FLAG_READ)
prot |= IOMMU_READ;
 
+   if (map->flags & VFIO_DMA_MAP_FLAG_NOEXEC) {
+   if (!vfio_domains_have_iommu_cap(iommu, IOMMU_CAP_NOEXEC))
+   return -EINVAL;
+   prot |= IOMMU_NOEXEC;
+   }
+
if (!prot || !size || (size | iova | vaddr) & mask)
return -EINVAL;
 
@@ -662,6 +668,14 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
dma = rb_entry(n, struct vfio_dma, node);
iova = dma->iova;
 
+   /*
+* if any of the mappings to be replayed has the NOEXEC flag
+* set, then the new iommu domain must support it
+*/
+   if ((dma->prot | IOMMU_NOEXEC) &&
+   !(domain->caps & IOMMU_CAP_NOEXEC))
+   return -EINVAL;
+
while (iova < dma->iova + dma->size) {
phys_addr_t phys = iommu_iova_to_phys(d->domain, iova);
size_t size;
@@ -749,6 +763,9 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
 
+   if (iommu_capable(bus, IOMMU_CAP_NOEXEC))
+   domain->caps |= IOMMU_CAP_NOEXEC;
+
/*
 * Try to match an existing compatible domain.  We don't want to
 * preclude an IOMMU driver supporting multiple bus_types and being
@@ -900,6 +917,11 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
return 0;
return vfio_domains_have_iommu_cap(iommu,
  IOMMU_CAP_CACHE_COHERENCY);
+   case VFIO_DMA_NOEXEC_IOMMU:
+   if (!iommu)
+   return 0;
+   return vfio_domains_have_iommu_cap(iommu,
+  IOMMU_CAP_NOEXEC);
default:
return 0;
}
@@ -923,7 +945,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
} else if (cmd == VFIO_IOMMU_MAP_DMA) {
struct vfio_iommu_type1_dma_map map;
uint32_t mask = VFIO_DMA_MAP_FLAG_READ |
-   VFIO_DMA_MAP_FLAG_WRITE;
+   VFIO_DMA_MAP_FLAG_WRITE |
+   VFIO_DMA_MAP_FLAG_NOEXEC;
 
minsz = offsetofend(struct vfio_iommu_type1_dma_map, size);
 
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v8 00/18] VFIO support for platform and AMBA devices on ARM

2014-10-13 Thread Antonios Motakis
This patch series aims to implement VFIO support for platform devices that
reside behind an IOMMU. Examples of such devices are devices behind an ARM
SMMU, or behind a Samsung Exynos System MMU.

The API used is based on the existing VFIO API that is also used with PCI
devices. Only devices that include a basic set of IRQs and memory regions are
targeted; devices with complex relationships with other devices on a device
tree are not taken into account at this stage.

This patch series should be applied at least on the following series/patches:
 - [PATCH 0/3] iommu: replace IOMMU_EXEC with IOMMU_EXEC and update ARM SMMU 
driver
 - [PATCH] driver core: amba: add device binding path 'driver_override'
 - [PATCH 0/5] vfio: type1: support for ARM SMMUS with VFIO_IOMMU_TYPE1

A copy can be cloned from the branch vfio-platform-v8 at:
g...@github.com:virtualopensystems/linux-kvm-arm.git

Changes since v7:
 - Some initial placeholder functionality for PIO resources
 - Cleaned up code for IRQ triggering, masking and unmasking
 - Some functionality has been removed from this series and posted separately:
   - VFIO_IOMMU_TYPE1 support for ARM SMMUs
   - IOMMU NOEXEC patches
   - driver_override functionality for AMBA devices
 - Several fixes
Changes since v6:
 - Integrated support for AMBA devices
 - Numerous cleanups and fixes
Changes since v5:
 - Full eventfd support for IRQ masking and unmasking.
 - Changed IOMMU_EXEC to IOMMU_NOEXEC, along with related flags in VFIO.
 - Other fixes based on reviewer comments.
Changes since v4:
 - Use static offsets for each region in the VFIO device fd
 - Include patch in the series for the ARM SMMU to expose IOMMU_EXEC
   availability via IOMMU_CAP_DMA_EXEC
 - Rebased on VFIO multi domain support:
   - IOMMU_EXEC is now available if at least one IOMMU in the container
 supports it
   - Expose IOMMU_EXEC if available via the capability VFIO_IOMMU_PROT_EXEC
 - Some bug fixes
Changes since v3:
 - Use Kim Phillips' driver_probe_device()
Changes since v2:
 - Fixed Read/Write and MMAP on device regions
 - Removed dependency on Device Tree
 - Interrupts support
 - Interrupt masking/unmasking
 - Automask level sensitive interrupts
 - Introduced VFIO_DMA_MAP_FLAG_EXEC
 - Code clean ups

Antonios Motakis (18):
  vfio/platform: initial skeleton of VFIO support for platform devices
  vfio: platform: probe to devices on the platform bus
  vfio: platform: add the VFIO PLATFORM module to Kconfig
  vfio: amba: VFIO support for AMBA devices
  vfio: amba: add the VFIO for AMBA devices module to Kconfig
  vfio/platform: return info for bound device
  vfio/platform: return info for device memory mapped IO regions
  vfio/platform: read and write support for the device fd
  vfio/platform: support MMAP of MMIO regions
  vfio/platform: return IRQ info
  vfio/platform: initial interrupts support code
  vfio/platform: trigger an interrupt via eventfd
  vfio/platform: support for maskable and automasked interrupts
  vfio: move eventfd support code for VFIO_PCI to a separate file
  vfio: add local lock in virqfd instead of depending on VFIO PCI
  vfio: pass an opaque pointer on virqfd initialization
  vfio: initialize the virqfd workqueue in VFIO generic code
  vfio/platform: implement IRQ masking/unmasking via an eventfd

 drivers/vfio/Kconfig  |   1 +
 drivers/vfio/Makefile |   5 +-
 drivers/vfio/pci/vfio_pci.c   |   8 -
 drivers/vfio/pci/vfio_pci_intrs.c | 234 +---
 drivers/vfio/pci/vfio_pci_private.h   |   3 -
 drivers/vfio/platform/Kconfig |  19 +
 drivers/vfio/platform/Makefile|   8 +
 drivers/vfio/platform/vfio_amba.c | 108 ++
 drivers/vfio/platform/vfio_platform.c | 107 ++
 drivers/vfio/platform/vfio_platform_common.c  | 508 ++
 drivers/vfio/platform/vfio_platform_irq.c | 316 
 drivers/vfio/platform/vfio_platform_private.h |  80 
 drivers/vfio/vfio.c   |   8 +
 drivers/vfio/virqfd.c | 215 +++
 include/linux/vfio.h  |  27 ++
 include/uapi/linux/vfio.h |   2 +
 16 files changed, 1415 insertions(+), 234 deletions(-)
 create mode 100644 drivers/vfio/platform/Kconfig
 create mode 100644 drivers/vfio/platform/Makefile
 create mode 100644 drivers/vfio/platform/vfio_amba.c
 create mode 100644 drivers/vfio/platform/vfio_platform.c
 create mode 100644 drivers/vfio/platform/vfio_platform_common.c
 create mode 100644 drivers/vfio/platform/vfio_platform_irq.c
 create mode 100644 drivers/vfio/platform/vfio_platform_private.h
 create mode 100644 drivers/vfio/virqfd.c

-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 2/5] vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag

2014-10-13 Thread Antonios Motakis
We introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag to the VFIO dma map call,
and expose its availability via the capability VFIO_DMA_NOEXEC_IOMMU.
This way the user can control whether the XN flag will be set on the
requested mappings. The IOMMU_NOEXEC flag needs to be available for all
the IOMMUs of the container used.

Signed-off-by: Antonios Motakis 
---
 include/uapi/linux/vfio.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 6612974..111b5e8 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -29,6 +29,7 @@
  * capability is subject to change as groups are added or removed.
  */
 #define VFIO_DMA_CC_IOMMU  4
+#define VFIO_DMA_NOEXEC_IOMMU  5
 
 /* Check if EEH is supported */
 #define VFIO_EEH   5
@@ -401,6 +402,7 @@ struct vfio_iommu_type1_dma_map {
__u32   flags;
 #define VFIO_DMA_MAP_FLAG_READ (1 << 0)/* readable from device 
*/
 #define VFIO_DMA_MAP_FLAG_WRITE (1 << 1)   /* writable from device */
+#define VFIO_DMA_MAP_FLAG_NOEXEC (1 << 2)  /* not executable from device */
__u64   vaddr;  /* Process virtual address */
__u64   iova;   /* IO virtual address */
__u64   size;   /* Size of mapping (bytes) */
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 1/5] vfio/iommu_type1: support for platform bus devices on ARM

2014-10-13 Thread Antonios Motakis
This allows to make use of the VFIO_IOMMU_TYPE1 driver with platform
devices on ARM. The driver can then be used with an Exynos SMMU, or
ARM SMMU driver.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig
index d8c5763..a0abe04 100644
--- a/drivers/vfio/Kconfig
+++ b/drivers/vfio/Kconfig
@@ -16,7 +16,7 @@ config VFIO_SPAPR_EEH
 menuconfig VFIO
tristate "VFIO Non-Privileged userspace driver framework"
depends on IOMMU_API
-   select VFIO_IOMMU_TYPE1 if X86
+   select VFIO_IOMMU_TYPE1 if X86 || ARM
select VFIO_IOMMU_SPAPR_TCE if (PPC_POWERNV || PPC_PSERIES)
select VFIO_SPAPR_EEH if (PPC_POWERNV || PPC_PSERIES)
select ANON_INODES
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 3/5] vfio: type1: replace domain wide protection flags with supported capabilities

2014-10-13 Thread Antonios Motakis
VFIO_IOMMU_TYPE1 keeps track for each domain it knows a list of protection
flags it always applies to all mappings in the domain. This is used for
domains that support IOMMU_CAP_CACHE_COHERENCY.

Refactor this slightly, by keeping track instead that a given domain
supports the capability, and applying the IOMMU_CACHE protection flag when
doing the actual DMA mappings.

This will allow us to reuse the behavior for IOMMU_CAP_NOEXEC, which we
also want to keep track of, but without applying it to all domains that
support it unless the user explicitly requests it.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/vfio_iommu_type1.c | 25 +
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 562f686..62a8b4d 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -64,7 +64,7 @@ struct vfio_domain {
struct iommu_domain *domain;
struct list_headnext;
struct list_headgroup_list;
-   int prot;   /* IOMMU_CACHE */
+   int caps;
 };
 
 struct vfio_dma {
@@ -485,7 +485,7 @@ static int map_try_harder(struct vfio_domain *domain, 
dma_addr_t iova,
for (i = 0; i < npage; i++, pfn++, iova += PAGE_SIZE) {
ret = iommu_map(domain->domain, iova,
(phys_addr_t)pfn << PAGE_SHIFT,
-   PAGE_SIZE, prot | domain->prot);
+   PAGE_SIZE, prot);
if (ret)
break;
}
@@ -503,11 +503,16 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, 
dma_addr_t iova,
int ret;
 
list_for_each_entry(d, &iommu->domain_list, next) {
+   int dprot = prot;
+
+   if (d->caps | IOMMU_CAP_CACHE_COHERENCY)
+   dprot |= IOMMU_CACHE;
+
ret = iommu_map(d->domain, iova, (phys_addr_t)pfn << PAGE_SHIFT,
-   npage << PAGE_SHIFT, prot | d->prot);
+   npage << PAGE_SHIFT, dprot);
if (ret) {
if (ret != -EBUSY ||
-   map_try_harder(d, iova, pfn, npage, prot))
+   map_try_harder(d, iova, pfn, npage, dprot))
goto unwind;
}
}
@@ -620,6 +625,10 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
struct vfio_domain *d;
struct rb_node *n;
int ret;
+   int dprot = 0;
+
+   if (domain->caps | IOMMU_CAP_CACHE_COHERENCY)
+   dprot |= IOMMU_CACHE;
 
/* Arbitrarily pick the first domain in the list for lookups */
d = list_first_entry(&iommu->domain_list, struct vfio_domain, next);
@@ -653,7 +662,7 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
size += PAGE_SIZE;
 
ret = iommu_map(domain->domain, iova, phys,
-   size, dma->prot | domain->prot);
+   size, dma->prot | dprot);
if (ret)
return ret;
 
@@ -721,7 +730,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
}
 
if (iommu_capable(bus, IOMMU_CAP_CACHE_COHERENCY))
-   domain->prot |= IOMMU_CACHE;
+   domain->caps |= IOMMU_CAP_CACHE_COHERENCY;
 
/*
 * Try to match an existing compatible domain.  We don't want to
@@ -732,7 +741,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
 */
list_for_each_entry(d, &iommu->domain_list, next) {
if (d->domain->ops == domain->domain->ops &&
-   d->prot == domain->prot) {
+   d->caps == domain->caps) {
iommu_detach_group(domain->domain, iommu_group);
if (!iommu_attach_group(d->domain, iommu_group)) {
list_add(&group->next, &d->group_list);
@@ -865,7 +874,7 @@ static int vfio_domains_have_iommu_cache(struct vfio_iommu 
*iommu)
 
mutex_lock(&iommu->lock);
list_for_each_entry(domain, &iommu->domain_list, next) {
-   if (!(domain->prot & IOMMU_CACHE)) {
+   if (!(domain->caps & IOMMU_CAP_CACHE_COHERENCY)) {
ret = 0;
break;
}
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 4/5] vfio: type1: replace vfio_domains_have_iommu_cache with generic function

2014-10-13 Thread Antonios Motakis
Replace the function vfio_domains_have_iommu_cache() with a more generic
function vfio_domains_have_iommu_cap() which allows to check all domains
of an vfio_iommu structure for a given cached capability.

Signed-off-by: Antonios Motakis 
---
 drivers/vfio/vfio_iommu_type1.c | 37 +++--
 1 file changed, 19 insertions(+), 18 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 62a8b4d..8b4202a 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -80,6 +80,23 @@ struct vfio_group {
struct list_headnext;
 };
 
+static int vfio_domains_have_iommu_cap(struct vfio_iommu *iommu, int cap)
+{
+   struct vfio_domain *domain;
+   int ret = 1;
+
+   mutex_lock(&iommu->lock);
+   list_for_each_entry(domain, &iommu->domain_list, next) {
+   if (!(domain->caps & cap)) {
+   ret = 0;
+   break;
+   }
+   }
+   mutex_unlock(&iommu->lock);
+
+   return ret;
+}
+
 /*
  * This code handles mapping and unmapping of user data buffers
  * into DMA'ble space using the IOMMU
@@ -867,23 +884,6 @@ static void vfio_iommu_type1_release(void *iommu_data)
kfree(iommu);
 }
 
-static int vfio_domains_have_iommu_cache(struct vfio_iommu *iommu)
-{
-   struct vfio_domain *domain;
-   int ret = 1;
-
-   mutex_lock(&iommu->lock);
-   list_for_each_entry(domain, &iommu->domain_list, next) {
-   if (!(domain->caps & IOMMU_CAP_CACHE_COHERENCY)) {
-   ret = 0;
-   break;
-   }
-   }
-   mutex_unlock(&iommu->lock);
-
-   return ret;
-}
-
 static long vfio_iommu_type1_ioctl(void *iommu_data,
   unsigned int cmd, unsigned long arg)
 {
@@ -898,7 +898,8 @@ static long vfio_iommu_type1_ioctl(void *iommu_data,
case VFIO_DMA_CC_IOMMU:
if (!iommu)
return 0;
-   return vfio_domains_have_iommu_cache(iommu);
+   return vfio_domains_have_iommu_cap(iommu,
+ IOMMU_CAP_CACHE_COHERENCY);
default:
return 0;
}
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 0/5] vfio: type1: support for ARM SMMUS with VFIO_IOMMU_TYPE1

2014-10-13 Thread Antonios Motakis
This patch series makes the VFIO_IOMMU_TYPE1 driver buildable on ARM, so it
may be used with ARM SMMUs. It also adds support for the IOMMU_NOEXEC flag
supported by SMMUs adhering to the ARM SMMU specification so the VFIO user can
specify whether the target memory can be executed by the device behind the
SMMU.

Antonios Motakis (5):
  vfio/iommu_type1: support for platform bus devices on ARM
  vfio: introduce the VFIO_DMA_MAP_FLAG_NOEXEC flag
  vfio: type1: replace domain wide protection flags with supported
capabilities
  vfio: type1: replace vfio_domains_have_iommu_cache with generic
function
  vfio/iommu_type1: implement the VFIO_DMA_MAP_FLAG_NOEXEC flag

 drivers/vfio/Kconfig|  2 +-
 drivers/vfio/vfio_iommu_type1.c | 85 -
 include/uapi/linux/vfio.h   |  2 +
 3 files changed, 62 insertions(+), 27 deletions(-)

-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH] driver core: amba: add device binding path 'driver_override'

2014-10-13 Thread Antonios Motakis
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 
---
 Documentation/ABI/testing/sysfs-bus-amba | 20 ++
 drivers/amba/bus.c   | 47 
 include/linux/amba/bus.h |  1 +
 3 files changed, 68 insertions(+)
 create mode 100644 Documentation/ABI/testing/sysfs-bus-amba

diff --git a/Documentation/ABI/testing/sysfs-bus-amba 
b/Documentation/ABI/testing/sysfs-bus-amba
new file mode 100644
index 000..e7b5467
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-bus-amba
@@ -0,0 +1,20 @@
+What:  /sys/bus/amba/devices/.../driver_override
+Date:  September 2014
+Contact:   Antonios Motakis 
+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.
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 3cf61a1..c7aa448 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -17,6 +17,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
@@ -42,6 +43,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;
 }
 
@@ -58,6 +63,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)\
@@ -80,6 +126,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,
 };
 
diff --git a/include/linux/amba/bus.h b/include/linux/amba/bus.h
index fdd7e1b..7c011e7 100644
--- a/include/linux/amba/bus.h
+++ b/include/linux/amba/bus.h
@@ -32,6 +32,7 @@ struct amba_device {
struct clk 

[PATCH 2/3] iommu: add capability IOMMU_CAP_NOEXEC

2014-10-13 Thread Antonios Motakis
Some IOMMUs accept an IOMMU_NOEXEC protection flag in addition to
IOMMU_READ and IOMMU_WRITE. Expose this as an IOMMU capability.

Signed-off-by: Antonios Motakis 
Acked-by: Joerg Roedel 
---
 include/linux/iommu.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 5f6f71c..ba026f1 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -61,6 +61,7 @@ enum iommu_cap {
IOMMU_CAP_CACHE_COHERENCY,  /* IOMMU can enforce cache coherent DMA
   transactions */
IOMMU_CAP_INTR_REMAP,   /* IOMMU supports interrupt isolation */
+   IOMMU_CAP_NOEXEC,   /* IOMMU_NOEXEC flag */
 };
 
 /*
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 3/3] iommu/arm-smmu: add IOMMU_CAP_NOEXEC to the ARM SMMU driver

2014-10-13 Thread Antonios Motakis
The ARM SMMU supports the IOMMU_NOEXEC protection flag. Add the
corresponding IOMMU capability.

Signed-off-by: Antonios Motakis 
---
 drivers/iommu/arm-smmu.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 566c176..c8fc02f 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1569,6 +1569,8 @@ static bool arm_smmu_capable(enum iommu_cap cap)
return true;
case IOMMU_CAP_INTR_REMAP:
return true; /* MSIs are just memory writes */
+   case IOMMU_CAP_NOEXEC:
+   return true;
default:
return false;
}
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 1/3] iommu/arm-smmu: change IOMMU_EXEC to IOMMU_NOEXEC

2014-10-13 Thread Antonios Motakis
Exposing the XN flag of the SMMU driver as IOMMU_NOEXEC instead of
IOMMU_EXEC makes it enforceable, since for IOMMUs that don't support
the XN flag pages will always be executable.

Signed-off-by: Antonios Motakis 
Acked-by: Joerg Roedel 
---
 drivers/iommu/arm-smmu.c | 9 +
 include/linux/iommu.h| 2 +-
 2 files changed, 6 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 60558f7..566c176 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1281,7 +1281,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device 
*smmu, pmd_t *pmd,
   unsigned long pfn, int prot, int stage)
 {
pte_t *pte, *start;
-   pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN;
+   pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
 
if (pmd_none(*pmd)) {
/* Allocate a new set of tables */
@@ -1315,10 +1315,11 @@ static int arm_smmu_alloc_init_pte(struct 
arm_smmu_device *smmu, pmd_t *pmd,
pteval |= ARM_SMMU_PTE_MEMATTR_NC;
}
 
+   if (prot & IOMMU_NOEXEC)
+   pteval |= ARM_SMMU_PTE_XN;
+
/* If no access, create a faulting entry to avoid TLB fills */
-   if (prot & IOMMU_EXEC)
-   pteval &= ~ARM_SMMU_PTE_XN;
-   else if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
+   if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
pteval &= ~ARM_SMMU_PTE_PAGE;
 
pteval |= ARM_SMMU_PTE_SH_IS;
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index 379a617..5f6f71c 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -27,7 +27,7 @@
 #define IOMMU_READ (1 << 0)
 #define IOMMU_WRITE(1 << 1)
 #define IOMMU_CACHE(1 << 2) /* DMA cache coherency */
-#define IOMMU_EXEC (1 << 3)
+#define IOMMU_NOEXEC   (1 << 3)
 
 struct iommu_ops;
 struct iommu_group;
-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 0/3] iommu: replace IOMMU_EXEC with IOMMU_EXEC and update ARM SMMU driver

2014-10-13 Thread Antonios Motakis
This patch series applies to Joerg Roedel's iommu/next branch, commit 09b5269a.
It replaces the IOMMU_EXEC flag used by the ARM SMMU driver to IOMMU_NOEXEC.
This is more enforceable, since the lack of the flag on hardware that doesn't
support it implies that the target memory will be executable.

Antonios Motakis (3):
  iommu/arm-smmu: change IOMMU_EXEC to IOMMU_NOEXEC
  iommu: add capability IOMMU_CAP_NOEXEC
  iommu/arm-smmu: add IOMMU_CAP_NOEXEC to the ARM SMMU driver

 drivers/iommu/arm-smmu.c | 11 +++
 include/linux/iommu.h|  3 ++-
 2 files changed, 9 insertions(+), 5 deletions(-)

-- 
2.1.1

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 12/12] ARM: tegra: Enable IOMMU for display controllers on Tegra124

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Add iommus properties to the device tree nodes for the two display
controllers found on Tegra124. This will allow the display controllers
to map physically non-contiguous buffers to I/O virtual contiguous
address spaces so that they can be used for scan-out.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra124.dtsi | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index afe9c6a34709..652f595784e1 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -1,5 +1,6 @@
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -102,6 +103,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DC>;
+
nvidia,head = <0>;
};
 
@@ -115,6 +118,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DCB>;
+
nvidia,head = <1>;
};
 
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 08/12] ARM: tegra: Add memory controller support for Tegra114

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Add the device tree node for the memory controller found on Tegra114
SoCs. The memory controller integrates an IOMMU (called SMMU) as well as
various knobs to tweak memory accesses by the various clients.

The old IOMMU device tree node is collapsed into the memory controller
node to more accurately describe the hardware. While this change is
incompatible, the IOMMU driver has never had any users so the change is
not going to cause any breakage.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra114.dtsi | 18 +-
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 2ca9c1807f72..2c26b07c11ed 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -505,15 +505,15 @@
reset-names = "fuse";
};
 
-   iommu@70019010 {
-   compatible = "nvidia,tegra114-smmu", "nvidia,tegra30-smmu";
-   reg = <0x70019010 0x02c
-  0x700191f0 0x010
-  0x70019228 0x074>;
-   nvidia,#asids = <4>;
-   dma-window = <0 0x4000>;
-   nvidia,swgroups = <0x18659fe>;
-   nvidia,ahb = <&ahb>;
+   mc: memory-controller@70019000 {
+   compatible = "nvidia,tegra114-mc";
+   reg = <0x70019000 0x1000>;
+   clocks = <&tegra_car TEGRA114_CLK_MC>;
+   clock-names = "mc";
+
+   interrupts = ;
+
+   #iommu-cells = <1>;
};
 
ahub@7008 {
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 10/12] ARM: tegra: Enable IOMMU for display controllers on Tegra30

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Add iommus properties to the device tree nodes for the two display
controllers found on Tegra30. This will allow the display controllers to
map physically non-contiguous buffers to I/O virtual contiguous address
spaces so that they can be used for scan-out.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra30.dtsi | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index fa7e5b642434..976eb9ba8659 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -1,5 +1,6 @@
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -174,6 +175,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DC>;
+
nvidia,head = <0>;
 
rgb {
@@ -191,6 +194,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DCB>;
+
nvidia,head = <1>;
 
rgb {
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 04/12] of: Add NVIDIA Tegra memory controller binding

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

The memory controller on NVIDIA Tegra exposes various knobs that can be
used to tune the behaviour of the clients attached to it.

In addition, the memory controller implements an SMMU (IOMMU) which can
translate I/O virtual addresses to physical addresses for clients. This
is useful for scatter-gather operation on devices that don't support it
natively and for virtualization or process separation.

Signed-off-by: Thierry Reding 
---
Changes in v3:
- add missing clocks and clock-names properties
- add example

 .../memory-controllers/nvidia,tegra-mc.txt | 36 ++
 1 file changed, 36 insertions(+)
 create mode 100644 
Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt

diff --git 
a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt 
b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
new file mode 100644
index ..f3db93c85eea
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
@@ -0,0 +1,36 @@
+NVIDIA Tegra Memory Controller device tree bindings
+===
+
+Required properties:
+- compatible: Should be "nvidia,tegra-mc"
+- reg: Physical base address and length of the controller's registers.
+- clocks: Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+  - mc: the module's clock input
+- interrupts: The interrupt outputs from the controller.
+- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines
+  the SWGROUP of the master.
+
+This device implements an IOMMU that complies with the generic IOMMU binding.
+See ../iommu/iommu.txt for details.
+
+Example:
+
+
+   mc: memory-controller@0,70019000 {
+   compatible = "nvidia,tegra124-mc";
+   reg = <0x0 0x70019000 0x0 0x1000>;
+   clocks = <&tegra_car TEGRA124_CLK_MC>;
+   clock-names = "mc";
+
+   interrupts = ;
+
+   #iommu-cells = <1>;
+   };
+
+   sdhci@0,700b {
+   compatible = "nvidia,tegra124-sdhci";
+   ...
+   iommus = <&mc TEGRA_SWGROUP_SDMMC1A>;
+   };
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 09/12] ARM: tegra: Add memory controller support for Tegra124

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Add the memory controller and wire up the interrupt that is used to
report errors. Provide a reference to the memory controller clock and
mark the device as being an IOMMU by adding an #iommu-cells property.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra124.dtsi | 11 +++
 1 file changed, 11 insertions(+)

diff --git a/arch/arm/boot/dts/tegra124.dtsi b/arch/arm/boot/dts/tegra124.dtsi
index 478c555ebd96..afe9c6a34709 100644
--- a/arch/arm/boot/dts/tegra124.dtsi
+++ b/arch/arm/boot/dts/tegra124.dtsi
@@ -551,6 +551,17 @@
reset-names = "fuse";
};
 
+   mc: memory-controller@0,70019000 {
+   compatible = "nvidia,tegra124-mc";
+   reg = <0x0 0x70019000 0x0 0x1000>;
+   clocks = <&tegra_car TEGRA124_CLK_MC>;
+   clock-names = "mc";
+
+   interrupts = ;
+
+   #iommu-cells = <1>;
+   };
+
sata@0,7002 {
compatible = "nvidia,tegra124-ahci";
 
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 05/12] memory: Add NVIDIA Tegra memory controller support

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

The memory controller on NVIDIA Tegra exposes various knobs that can be
used to tune the behaviour of the clients attached to it.

Currently this driver sets up the latency allowance registers to the HW
defaults. Eventually an API should be exported by this driver (via a
custom API or a generic subsystem) to allow clients to register latency
requirements.

This driver also registers an IOMMU (SMMU) that's implemented by the
memory controller. It is supported on Tegra30, Tegra114 and Tegra124
currently. Tegra20 has a GART instead.

Signed-off-by: Thierry Reding 
---
Changes in v4:
- remove DMA/IOMMU integration glue
- don't initialize linear SMMU mapping
- fail attachment for non-masters
- free empty page tables

Changes in v3:
- drop changes related to probe ordering that were rejected
- remove old SMMU driver

 drivers/iommu/Makefile   |1 -
 drivers/iommu/tegra-smmu.c   | 1295 --
 drivers/memory/Makefile  |3 +-
 drivers/memory/tegra/Makefile|5 +
 drivers/memory/tegra/tegra-mc.c  | 1061 
 drivers/memory/tegra/tegra-mc.h  |   90 +++
 drivers/memory/tegra/tegra114-mc.c   |  948 ++
 drivers/memory/tegra/tegra124-mc.c   | 1028 
 drivers/memory/tegra/tegra30-mc.c|  970 ++
 drivers/memory/tegra30-mc.c  |  378 -
 include/dt-bindings/memory/tegra114-mc.h |   25 +
 include/dt-bindings/memory/tegra124-mc.h |   31 +
 include/dt-bindings/memory/tegra30-mc.h  |   24 +
 13 files changed, 4184 insertions(+), 1675 deletions(-)
 delete mode 100644 drivers/iommu/tegra-smmu.c
 create mode 100644 drivers/memory/tegra/Makefile
 create mode 100644 drivers/memory/tegra/tegra-mc.c
 create mode 100644 drivers/memory/tegra/tegra-mc.h
 create mode 100644 drivers/memory/tegra/tegra114-mc.c
 create mode 100644 drivers/memory/tegra/tegra124-mc.c
 create mode 100644 drivers/memory/tegra/tegra30-mc.c
 delete mode 100644 drivers/memory/tegra30-mc.c
 create mode 100644 include/dt-bindings/memory/tegra114-mc.h
 create mode 100644 include/dt-bindings/memory/tegra124-mc.h
 create mode 100644 include/dt-bindings/memory/tegra30-mc.h

diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 16edef74b8ee..fe926ac4290d 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -14,7 +14,6 @@ obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
 obj-$(CONFIG_OMAP_IOMMU) += omap-iommu2.o
 obj-$(CONFIG_OMAP_IOMMU_DEBUG) += omap-iommu-debug.o
 obj-$(CONFIG_TEGRA_IOMMU_GART) += tegra-gart.o
-obj-$(CONFIG_TEGRA_IOMMU_SMMU) += tegra-smmu.o
 obj-$(CONFIG_EXYNOS_IOMMU) += exynos-iommu.o
 obj-$(CONFIG_SHMOBILE_IOMMU) += shmobile-iommu.o
 obj-$(CONFIG_SHMOBILE_IPMMU) += shmobile-ipmmu.o
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
deleted file mode 100644
index 3afdf43f732a..
--- a/drivers/iommu/tegra-smmu.c
+++ /dev/null
@@ -1,1295 +0,0 @@
-/*
- * IOMMU API for SMMU in Tegra30
- *
- * Copyright (c) 2011-2013, NVIDIA CORPORATION.  All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#define pr_fmt(fmt)"%s(): " fmt, __func__
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-#include 
-#include 
-
-enum smmu_hwgrp {
-   HWGRP_AFI,
-   HWGRP_AVPC,
-   HWGRP_DC,
-   HWGRP_DCB,
-   HWGRP_EPP,
-   HWGRP_G2,
-   HWGRP_HC,
-   HWGRP_HDA,
-   HWGRP_ISP,
-   HWGRP_MPE,
-   HWGRP_NV,
-   HWGRP_NV2,
-   HWGRP_PPCS,
-   HWGRP_SATA,
-   HWGRP_VDE,
-   HWGRP_VI,
-
-   HWGRP_COUNT,
-
-   HWGRP_END = ~0,
-};
-
-#define HWG_AFI(1 << HWGRP_AFI)
-#define HWG_AVPC   (1 << HWGRP_AVPC)
-#define HWG_DC (1 << HWGRP_DC)
-#define HWG_DCB(1 << HWGRP_DCB)
-#define HWG_EPP(1 << HWGRP_EPP)
-#define HWG_G2 (1 << HWGRP_G2)
-#define HWG_HC (1 << HWGRP_HC)
-#define HWG_HDA(1 << HWGRP_HDA)
-#define HWG_ISP(1 << HWGRP_ISP)
-#define HWG_MPE(1 << HWGRP_MPE)
-#define HWG_NV (1 << HWGRP_NV)
-#define HWG_NV2  

[PATCH 06/12] ARM: tegra: Add memory controller support for Tegra20

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Collapses the old memory-controller and IOMMU device tree nodes into a
single node to more accurately describe the hardware.

Note that this is an incompatible change, but while a GART driver has
existed for a few years it has never been used to do any translations.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra20.dtsi | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/arch/arm/boot/dts/tegra20.dtsi b/arch/arm/boot/dts/tegra20.dtsi
index 3b374c49d04d..a195c1975f3c 100644
--- a/arch/arm/boot/dts/tegra20.dtsi
+++ b/arch/arm/boot/dts/tegra20.dtsi
@@ -538,15 +538,14 @@
 
memory-controller@7000f000 {
compatible = "nvidia,tegra20-mc";
-   reg = <0x7000f000 0x024
-  0x7000f03c 0x3c4>;
+   reg = <0x7000f000 0x0400   /* controller registers */
+  0x5800 0x0200>; /* GART aperture */
+   clocks = <&tegra_car TEGRA20_CLK_MC>;
+   clock-names = "mc";
+
interrupts = ;
-   };
 
-   iommu@7000f024 {
-   compatible = "nvidia,tegra20-gart";
-   reg = <0x7000f024 0x0018/* controller registers */
-  0x5800 0x0200>;  /* GART aperture */
+   #iommu-cells = <1>;
};
 
memory-controller@7000f400 {
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 11/12] ARM: tegra: Enable IOMMU for display controllers on Tegra114

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Add iommus properties to the device tree nodes for the two display
controllers found on Tegra114. This will allow the display controllers
to map physically non-contiguous buffers to I/O virtual contiguous
address spaces so that they can be used for scan-out.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra114.dtsi | 5 +
 1 file changed, 5 insertions(+)

diff --git a/arch/arm/boot/dts/tegra114.dtsi b/arch/arm/boot/dts/tegra114.dtsi
index 2c26b07c11ed..c8c3b6438b4d 100644
--- a/arch/arm/boot/dts/tegra114.dtsi
+++ b/arch/arm/boot/dts/tegra114.dtsi
@@ -1,5 +1,6 @@
 #include 
 #include 
+#include 
 #include 
 #include 
 
@@ -57,6 +58,8 @@
resets = <&tegra_car 27>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DC>;
+
nvidia,head = <0>;
 
rgb {
@@ -74,6 +77,8 @@
resets = <&tegra_car 26>;
reset-names = "dc";
 
+   iommus = <&mc TEGRA_SWGROUP_DCB>;
+
nvidia,head = <1>;
 
rgb {
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 02/12] amba: Add Kconfig file

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Rather than duplicate the ARM_AMBA Kconfig symbol in both 32-bit and
64-bit ARM architectures, move the common definition to drivers/amba
where dependent drivers will be located.

Signed-off-by: Thierry Reding 
---
 arch/arm/Kconfig | 3 ---
 arch/arm64/Kconfig   | 3 ---
 drivers/amba/Kconfig | 2 ++
 3 files changed, 2 insertions(+), 6 deletions(-)
 create mode 100644 drivers/amba/Kconfig

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 89c4b5ccc68d..77f8ca5cc3e6 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1259,9 +1259,6 @@ source "arch/arm/common/Kconfig"
 
 menu "Bus support"
 
-config ARM_AMBA
-   bool
-
 config ISA
bool
help
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index ac9afde76dea..9442ff1209d5 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -165,9 +165,6 @@ endmenu
 
 menu "Bus support"
 
-config ARM_AMBA
-   bool
-
 config PCI
bool "PCI support"
help
diff --git a/drivers/amba/Kconfig b/drivers/amba/Kconfig
new file mode 100644
index ..d1cba6a9b3b8
--- /dev/null
+++ b/drivers/amba/Kconfig
@@ -0,0 +1,2 @@
+config ARM_AMBA
+   bool
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 03/12] ARM: tegra: Move AHB Kconfig to drivers/amba

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

This will allow the Kconfig option to be shared among 32-bit and 64-bit
ARM.

Signed-off-by: Thierry Reding 
---
Changes in v4:
- add precursory patch introducing drivers/amba/Kconfig, rebase on top

Changes in v3:
- select ARM_AMBA from ARCH_TEGRA to enable the TEGRA_AHB driver

 arch/arm/mach-tegra/Kconfig |  9 +
 drivers/Kconfig |  2 ++
 drivers/amba/Kconfig| 12 
 3 files changed, 15 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 095399618ca5..d0be9a1ef6b8 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -2,6 +2,7 @@ menuconfig ARCH_TEGRA
bool "NVIDIA Tegra" if ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
+   select ARM_AMBA
select ARM_GIC
select CLKSRC_MMIO
select HAVE_ARM_SCU if SMP
@@ -59,12 +60,4 @@ config ARCH_TEGRA_124_SOC
  Support for NVIDIA Tegra T124 processor family, based on the
  ARM CortexA15MP CPU
 
-config TEGRA_AHB
-   bool "Enable AHB driver for NVIDIA Tegra SoCs"
-   default y
-   help
- Adds AHB configuration functionality for NVIDIA Tegra SoCs,
- which controls AHB bus master arbitration and some
- performance parameters(priority, prefech size).
-
 endif
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1a693d3f9d51..af02a8a8ec4a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
 menu "Device Drivers"
 
+source "drivers/amba/Kconfig"
+
 source "drivers/base/Kconfig"
 
 source "drivers/bus/Kconfig"
diff --git a/drivers/amba/Kconfig b/drivers/amba/Kconfig
index d1cba6a9b3b8..4a5c9d279059 100644
--- a/drivers/amba/Kconfig
+++ b/drivers/amba/Kconfig
@@ -1,2 +1,14 @@
 config ARM_AMBA
bool
+
+if ARM_AMBA
+
+config TEGRA_AHB
+   bool "Enable AHB driver for NVIDIA Tegra SoCs"
+   default y if ARCH_TEGRA
+   help
+ Adds AHB configuration functionality for NVIDIA Tegra SoCs,
+ which controls AHB bus master arbitration and some performance
+ parameters (priority, prefetch size).
+
+endif
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH 07/12] ARM: tegra: Add memory controller support for Tegra30

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

Collapses the old memory-controller and IOMMU device tree nodes into a
single node to more accurately describe the hardware.

While this is an incompatible change there are no users of the IOMMU on
Tegra, even though a driver has existed for some time.

Signed-off-by: Thierry Reding 
---
 arch/arm/boot/dts/tegra30.dtsi | 20 ++--
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/arch/arm/boot/dts/tegra30.dtsi b/arch/arm/boot/dts/tegra30.dtsi
index aa6ccea13d30..fa7e5b642434 100644
--- a/arch/arm/boot/dts/tegra30.dtsi
+++ b/arch/arm/boot/dts/tegra30.dtsi
@@ -623,23 +623,15 @@
clock-names = "pclk", "clk32k_in";
};
 
-   memory-controller@7000f000 {
+   mc: memory-controller@7000f000 {
compatible = "nvidia,tegra30-mc";
-   reg = <0x7000f000 0x010
-  0x7000f03c 0x1b4
-  0x7000f200 0x028
-  0x7000f284 0x17c>;
+   reg = <0x7000f000 0x400>;
+   clocks = <&tegra_car TEGRA30_CLK_MC>;
+   clock-names = "mc";
+
interrupts = ;
-   };
 
-   iommu@7000f010 {
-   compatible = "nvidia,tegra30-smmu";
-   reg = <0x7000f010 0x02c
-  0x7000f1f0 0x010
-  0x7000f228 0x05c>;
-   nvidia,#asids = <4>;/* # of ASIDs */
-   dma-window = <0 0x4000>;/* IOVA start & length */
-   nvidia,ahb = <&ahb>;
+   #iommu-cells = <1>;
};
 
fuse@7000f800 {
-- 
2.1.2

___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v3 01/12] clk: tegra: Implement memory-controller clock

2014-10-13 Thread Thierry Reding
From: Thierry Reding 

The memory controller clock runs either at half or the same frequency as
the EMC clock.

Signed-off-by: Thierry Reding 
---
Changes in v3:
- split registration into a separate function that can be reused for all
  SoC generations, but pass in the name and parent parameters for
  clarity as well as the register address (in case it ever changes) and
  the EMC spin-lock since it isn't globally available

 drivers/clk/tegra/clk-divider.c  | 13 +
 drivers/clk/tegra/clk-tegra114.c |  7 ++-
 drivers/clk/tegra/clk-tegra124.c |  7 ++-
 drivers/clk/tegra/clk-tegra20.c  |  8 +++-
 drivers/clk/tegra/clk-tegra30.c  |  7 ++-
 drivers/clk/tegra/clk.h  |  2 ++
 include/dt-bindings/clock/tegra114-car.h |  2 +-
 include/dt-bindings/clock/tegra124-car.h |  2 +-
 include/dt-bindings/clock/tegra20-car.h  |  2 +-
 9 files changed, 43 insertions(+), 7 deletions(-)

diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 290f9c1a3749..84e1b3c1fb2a 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -185,3 +185,16 @@ struct clk *tegra_clk_register_divider(const char *name,
 
return clk;
 }
+
+static const struct clk_div_table mc_div_table[] = {
+   { .val = 0, .div = 2 },
+   { .val = 1, .div = 1 },
+   { .val = 0, .div = 0 },
+};
+
+struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
+ void __iomem *reg, spinlock_t *lock)
+{
+   return clk_register_divider_table(NULL, "mc", "emc_mux", 0, reg,
+ 16, 1, 0, mc_div_table, lock);
+}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index f760f31d05c4..0b03d2cf7264 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -173,6 +173,7 @@ static DEFINE_SPINLOCK(pll_d_lock);
 static DEFINE_SPINLOCK(pll_d2_lock);
 static DEFINE_SPINLOCK(pll_u_lock);
 static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(emc_lock);
 
 static struct div_nmp pllxc_nmp = {
.divm_shift = 0,
@@ -1228,7 +1229,11 @@ static __init void tegra114_periph_clk_init(void __iomem 
*clk_base,
   ARRAY_SIZE(mux_pllmcp_clkm),
   CLK_SET_RATE_NO_REPARENT,
   clk_base + CLK_SOURCE_EMC,
-  29, 3, 0, NULL);
+  29, 3, 0, &emc_lock);
+
+   clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+   &emc_lock);
+   clks[TEGRA114_CLK_MC] = clk;
 
for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
data = &tegra_periph_clk_list[i];
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index e3a85842ce0c..f5f9baca7bb6 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -132,6 +132,7 @@ static DEFINE_SPINLOCK(pll_d2_lock);
 static DEFINE_SPINLOCK(pll_e_lock);
 static DEFINE_SPINLOCK(pll_re_lock);
 static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(emc_lock);
 
 /* possible OSC frequencies in Hz */
 static unsigned long tegra124_input_freq[] = {
@@ -1127,7 +1128,11 @@ static __init void tegra124_periph_clk_init(void __iomem 
*clk_base,
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
   ARRAY_SIZE(mux_pllmcp_clkm), 0,
   clk_base + CLK_SOURCE_EMC,
-  29, 3, 0, NULL);
+  29, 3, 0, &emc_lock);
+
+   clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+   &emc_lock);
+   clks[TEGRA124_CLK_MC] = clk;
 
/* cml0 */
clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index dace2b1b5ae6..41272dcc9e22 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -140,6 +140,8 @@ static struct cpu_clk_suspend_context {
 static void __iomem *clk_base;
 static void __iomem *pmc_base;
 
+static DEFINE_SPINLOCK(emc_lock);
+
 #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,  \
_clk_num, _gate_flags, _clk_id) \
TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset,   \
@@ -819,11 +821,15 @@ static void __init tegra20_periph_clk_init(void)
   ARRAY_SIZE(mux_pllmcp_clkm),
   CLK_SET_RATE_NO_REPARENT,
   clk_base + CLK_SOURCE_EMC,
-  30, 2, 0, NULL);
+  30, 2, 0, &emc_lock);
clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
57, periph_cl