Re: [PATCH] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704

2016-03-01 Thread Chalamarla, Tirumalesh





On 3/1/16, 7:07 PM, "Will Deacon"  wrote:

>On Wed, Feb 24, 2016 at 01:13:53PM -0800, Tirumalesh Chalamarla wrote:
>> Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID and VMID
>> namespaces; specifically within a given node SMMU0 and SMMU1 share,
>> as does SMMU2 and SMMU3.
>> 
>> This patch address these issuee by supplying asid and vmid
>> while calculating ASID and VMID for Thunder SMMUv2.
>> 
>> NOTE: resending with commit message fix.
>> 
>> changes from V2:
>>  - removed *_base from DT, and replaced with compatible string
>> 
>> changes from V1:
>>  - rebased on top of 16 bit VMID patch
>>  - removed redundent options from DT
>>  - insted of transform, DT now supplies starting ASID/VMID
>> 
>> Signed-off-by: Tirumalesh Chalamarla 
>> Signed-off-by: Akula Geethasowjanya 
>> ---
>>  .../devicetree/bindings/iommu/arm,smmu.txt |  1 +
>>  drivers/iommu/arm-smmu.c   | 48 
>> +-
>>  2 files changed, 38 insertions(+), 11 deletions(-)
>> 
>> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt 
>> b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> index 7180745..19fe6f2 100644
>> --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
>> @@ -16,6 +16,7 @@ conditions.
>>  "arm,mmu-400"
>>  "arm,mmu-401"
>>  "arm,mmu-500"
>> +"cavium,smmu-v2"
>>  
>>depending on the particular implementation and/or the
>>version of the architecture implemented.
>> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
>> index 247a469..c704f88 100644
>> --- a/drivers/iommu/arm-smmu.c
>> +++ b/drivers/iommu/arm-smmu.c
>> @@ -326,6 +326,12 @@ struct arm_smmu_device {
>>  
>>  struct list_headlist;
>>  struct rb_root  masters;
>> +/*
>> + *The following fields are specific to Cavium, Thunder
>> + */
>> +u32 cavium_smmu_id;
>
>Why do you need this field as well as the base?
Will be removed. 
>
>> +u32 cavium_id_base;
>> +
>>  };
>>  
>>  struct arm_smmu_cfg {
>> @@ -335,8 +341,8 @@ struct arm_smmu_cfg {
>>  };
>>  #define INVALID_IRPTNDX 0xff
>>  
>> -#define ARM_SMMU_CB_ASID(cfg)   ((cfg)->cbndx)
>> -#define ARM_SMMU_CB_VMID(cfg)   ((cfg)->cbndx + 1)
>> +#define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base + 
>> (cfg)->cbndx)
>> +#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + 
>> (cfg)->cbndx + 1)
>>  
>>  enum arm_smmu_domain_stage {
>>  ARM_SMMU_DOMAIN_S1 = 0,
>> @@ -364,6 +370,8 @@ struct arm_smmu_option_prop {
>>  const char *prop;
>>  };
>>  
>> +static int cavium_smmu_count;
>
>I'd be more comfortable if this was an atomic_t.

Sure.
>
>> +/*
>> + * Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID and VMID
>> + * namespaces; specifically within a given node SMMU0 and SMMU1 share,
>> + * as does SMMU2 and SMMU3. see if this is a Cavium SMMU, if so
>> + * set asid and vmid base such that each SMMU gets unique
>> + * asid/vmid space.
>> + */
>> +if (!strcasecmp(of_id->compatible, "cavium,smmu-v2")) {
>
>of_device_is_compatible
Sure.
>
>> +/* VMID16 must be present on Cavium SMMUv2*/
>> +if (!(smmu->features & ARM_SMMU_FEAT_VMID16))
>> +goto out_free_irqs;
>
>This check seems a bit overkill. I think you can remove it.
I don’t think it is possible to support unique ASID space with out 16 bit VMID.
But I can remove this check if that’s implicit. 
>
>> +smmu->cavium_smmu_id = cavium_smmu_count;
>> +cavium_smmu_count++;
>> +smmu->cavium_id_base =
>> +(smmu->cavium_smmu_id * ARM_SMMU_MAX_CBS);
>
>Can you not use num_context_banks here, instead of the constant?
We need total context banks so far, so ARM_SMMU_MAX_CBS is best option.
For Thunder both are same anyway.  
>
>Will
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

Re: [PATCH] iommu/arm-smmu-v2: Workaround for ThunderX errata#27704

2016-03-01 Thread Will Deacon
On Wed, Feb 24, 2016 at 01:13:53PM -0800, Tirumalesh Chalamarla wrote:
> Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID and VMID
> namespaces; specifically within a given node SMMU0 and SMMU1 share,
> as does SMMU2 and SMMU3.
> 
> This patch address these issuee by supplying asid and vmid
> while calculating ASID and VMID for Thunder SMMUv2.
> 
> NOTE: resending with commit message fix.
> 
> changes from V2:
>   - removed *_base from DT, and replaced with compatible string
> 
> changes from V1:
>   - rebased on top of 16 bit VMID patch
>   - removed redundent options from DT
>   - insted of transform, DT now supplies starting ASID/VMID
> 
> Signed-off-by: Tirumalesh Chalamarla 
> Signed-off-by: Akula Geethasowjanya 
> ---
>  .../devicetree/bindings/iommu/arm,smmu.txt |  1 +
>  drivers/iommu/arm-smmu.c   | 48 
> +-
>  2 files changed, 38 insertions(+), 11 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.txt 
> b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> index 7180745..19fe6f2 100644
> --- a/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> +++ b/Documentation/devicetree/bindings/iommu/arm,smmu.txt
> @@ -16,6 +16,7 @@ conditions.
>  "arm,mmu-400"
>  "arm,mmu-401"
>  "arm,mmu-500"
> +"cavium,smmu-v2"
>  
>depending on the particular implementation and/or the
>version of the architecture implemented.
> diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
> index 247a469..c704f88 100644
> --- a/drivers/iommu/arm-smmu.c
> +++ b/drivers/iommu/arm-smmu.c
> @@ -326,6 +326,12 @@ struct arm_smmu_device {
>  
>   struct list_headlist;
>   struct rb_root  masters;
> + /*
> +  *The following fields are specific to Cavium, Thunder
> +  */
> + u32 cavium_smmu_id;

Why do you need this field as well as the base?

> + u32 cavium_id_base;
> +
>  };
>  
>  struct arm_smmu_cfg {
> @@ -335,8 +341,8 @@ struct arm_smmu_cfg {
>  };
>  #define INVALID_IRPTNDX  0xff
>  
> -#define ARM_SMMU_CB_ASID(cfg)((cfg)->cbndx)
> -#define ARM_SMMU_CB_VMID(cfg)((cfg)->cbndx + 1)
> +#define ARM_SMMU_CB_ASID(smmu, cfg) ((u16)(smmu)->cavium_id_base + 
> (cfg)->cbndx)
> +#define ARM_SMMU_CB_VMID(smmu, cfg) ((u16)(smmu)->cavium_id_base + 
> (cfg)->cbndx + 1)
>  
>  enum arm_smmu_domain_stage {
>   ARM_SMMU_DOMAIN_S1 = 0,
> @@ -364,6 +370,8 @@ struct arm_smmu_option_prop {
>   const char *prop;
>  };
>  
> +static int cavium_smmu_count;

I'd be more comfortable if this was an atomic_t.

> + /*
> +  * Due to Errata#27704 CN88xx SMMUv2,supports  only shared ASID and VMID
> +  * namespaces; specifically within a given node SMMU0 and SMMU1 share,
> +  * as does SMMU2 and SMMU3. see if this is a Cavium SMMU, if so
> +  * set asid and vmid base such that each SMMU gets unique
> +  * asid/vmid space.
> +  */
> + if (!strcasecmp(of_id->compatible, "cavium,smmu-v2")) {

of_device_is_compatible

> + /* VMID16 must be present on Cavium SMMUv2*/
> + if (!(smmu->features & ARM_SMMU_FEAT_VMID16))
> + goto out_free_irqs;

This check seems a bit overkill. I think you can remove it.

> + smmu->cavium_smmu_id = cavium_smmu_count;
> + cavium_smmu_count++;
> + smmu->cavium_id_base =
> + (smmu->cavium_smmu_id * ARM_SMMU_MAX_CBS);

Can you not use num_context_banks here, instead of the constant?

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


Re: [PATCH] iommu/mtk: fix handling of of_count_phandle_with_args result

2016-03-01 Thread Yong Wu
On Tue, 2016-03-01 at 12:34 +0100, Joerg Roedel wrote:
> On Tue, Mar 01, 2016 at 10:36:23AM +0100, Andrzej Hajda wrote:
> > The function can return negative value so it should be assigned to signed
> > variable. The patch changes also type of related i variable to make code
> > more compact and coherent.
> > 
> > The problem has been detected using patch
> > scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci.
> > 
> > Signed-off-by: Andrzej Hajda 
> > ---
> >  drivers/iommu/mtk_iommu.c | 3 +--
> >  1 file changed, 1 insertion(+), 2 deletions(-)
> 
> Applied, thanks.

Thanks.

nit: It would be better to use iommu/mediatek.

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


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


Bug: Freeing dma regions

2016-03-01 Thread David Kiarie
Hello,

This patch seems to have introduced a bug -
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=4eeca8c5e72fad752eba9efc293c924d65faa86e

As the commit message says, it should check for regions behind the
next_bit but it checks for regions beyond.

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


[PATCH] iommu/mtk: fix handling of of_count_phandle_with_args result

2016-03-01 Thread Andrzej Hajda
The function can return negative value so it should be assigned to signed
variable. The patch changes also type of related i variable to make code
more compact and coherent.

The problem has been detected using patch
scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci.

Signed-off-by: Andrzej Hajda 
---
 drivers/iommu/mtk_iommu.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c
index 721ffdb..de9241b 100644
--- a/drivers/iommu/mtk_iommu.c
+++ b/drivers/iommu/mtk_iommu.c
@@ -578,8 +578,7 @@ static int mtk_iommu_probe(struct platform_device *pdev)
struct resource *res;
struct component_match  *match = NULL;
void*protect;
-   unsigned inti, larb_nr;
-   int ret;
+   int i, larb_nr, ret;
 
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
-- 
1.9.1

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


[PATCH v2] iommu/io-pgtable-armv7s: Fix kmem_cache_alloc() flags

2016-03-01 Thread Robin Murphy
Whilst the default SLUB allocator happily just merges the original
allocation flags from kmem_cache_create() with those passed through
kmem_cache_alloc(), there is a code path in the SLAB allocator which
will aggressively BUG_ON() if the cache was created with SLAB_CACHE_DMA
but GFP_DMA is not specified for an allocation:

  kernel BUG at mm/slab.c:2536!
  Internal error: Oops - BUG: 0 [#1] SMP ARM
  Modules linked in:[1.299311] Modules linked in:

  CPU: 1 PID: 1 Comm: swapper/0 Not tainted
  4.5.0-rc6-koelsch-05892-ge7e45ad53ab6795e #2270
  Hardware name: Generic R8A7791 (Flattened Device Tree)
  task: ef422040 ti: ef442000 task.ti: ef442000
  PC is at cache_alloc_refill+0x2a0/0x530
  LR is at _raw_spin_unlock+0x8/0xc
...
  [] (cache_alloc_refill) from [] 
(kmem_cache_alloc+0x7c/0xd4)
  [] (kmem_cache_alloc) from []
  (__arm_v7s_alloc_table+0x5c/0x278)
  [] (__arm_v7s_alloc_table) from []
  (__arm_v7s_map.constprop.6+0x68/0x25c)
  [] (__arm_v7s_map.constprop.6) from []
  (arm_v7s_map+0x34/0xa4)
  [] (arm_v7s_map) from [] 
(arm_v7s_do_selftests+0x140/0x418)
  [] (arm_v7s_do_selftests) from []
  (do_one_initcall+0x100/0x1b4)
  [] (do_one_initcall) from []
  (kernel_init_freeable+0x120/0x1e8)
  [] (kernel_init_freeable) from [] (kernel_init+0x8/0xec)
  [] (kernel_init) from [] (ret_from_fork+0x14/0x2c)
  Code: 1a03 e7f001f2 e3130001 0a00 (e7f001f2)
  ---[ end trace 190f6f6b84352efd ]---

Keep the peace by adding GFP_DMA when allocating a table.

Reported-by: Geert Uytterhoeven 
Acked-by: Will Deacon 
Signed-off-by: Robin Murphy 
---

v2: Add the backtrace to the commit log, add Will's ack.
 
 drivers/iommu/io-pgtable-arm-v7s.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/io-pgtable-arm-v7s.c 
b/drivers/iommu/io-pgtable-arm-v7s.c
index 9fcceb1..9488e3c 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -192,7 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
if (lvl == 1)
table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size));
else if (lvl == 2)
-   table = kmem_cache_zalloc(data->l2_tables, gfp);
+   table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA);
if (table && !selftest_running) {
dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
-- 
2.7.2.333.g70bd996.dirty

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


Re: [PATCH] iommu/io-pgtable-armv7s: Fix kmem_cache_alloc() flags

2016-03-01 Thread Will Deacon
On Tue, Mar 01, 2016 at 06:17:38PM +, Robin Murphy wrote:
> Whilst the default SLUB allocator happily just merges the original
> allocation flags from kmem_cache_create() with those passed through
> kmem_cache_alloc(), there is a code path in the SLAB allocator which
> will aggressively BUG_ON() if the cache was created with SLAB_CACHE_DMA
> but GFP_DMA is not specified for an allocation.

It would be nice to include the backtrace here.

> Keep the peace by adding GFP_DMA when allocating a table.
> 
> Reported-by: Geert Uytterhoeven 
> Signed-off-by: Robin Murphy 
> ---
>  drivers/iommu/io-pgtable-arm-v7s.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/io-pgtable-arm-v7s.c 
> b/drivers/iommu/io-pgtable-arm-v7s.c
> index 9fcceb1..9488e3c 100644
> --- a/drivers/iommu/io-pgtable-arm-v7s.c
> +++ b/drivers/iommu/io-pgtable-arm-v7s.c
> @@ -192,7 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
>   if (lvl == 1)
>   table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size));
>   else if (lvl == 2)
> - table = kmem_cache_zalloc(data->l2_tables, gfp);
> + table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA);
>   if (table && !selftest_running) {
>   dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
>   if (dma_mapping_error(dev, dma))

Acked-by: Will Deacon 

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


[RFC v5 15/17] vfio/type1: also check IRQ remapping capability at msi domain

2016-03-01 Thread Eric Auger
On x86 IRQ remapping is abstracted by the IOMMU. On ARM this is abstracted
by the msi controller. vfio_safe_irq_domain allows to check whether
interrupts are "safe" for a given device. They are if the device does
not use MSI or if the device uses MSI and the msi-parent controller
supports IRQ remapping.

Then we check at group level if all devices have safe interrupts: if not,
we only allow the group to be attached if allow_unsafe_interrupts is set.

At this point ARM sMMU still advertises IOMMU_CAP_INTR_REMAP. This is
changed in next patch.

Signed-off-by: Eric Auger 

---
v3 -> v4:
- rename vfio_msi_parent_irq_remapping_capable into vfio_safe_irq_domain
  and irq_remapping into safe_irq_domains

v2 -> v3:
- protect vfio_msi_parent_irq_remapping_capable with
  CONFIG_GENERIC_MSI_IRQ_DOMAIN
---
 drivers/vfio/vfio_iommu_type1.c | 44 +++--
 1 file changed, 42 insertions(+), 2 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 4e01ebe..88a40f1 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -37,6 +37,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #define DRIVER_VERSION  "0.2"
 #define DRIVER_AUTHOR   "Alex Williamson "
@@ -788,6 +790,33 @@ static int vfio_bus_type(struct device *dev, void *data)
return 0;
 }
 
+/**
+ * vfio_safe_irq_domain: returns whether the irq domain
+ * the device is attached to is safe with respect to MSI isolation.
+ * If the irq domain is not an MSI domain, we return it is safe.
+ *
+ * @dev: device handle
+ * @data: unused
+ * returns 0 if the irq domain is safe, -1 if not.
+ */
+static int vfio_safe_irq_domain(struct device *dev, void *data)
+{
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+   struct irq_domain *domain;
+   struct msi_domain_info *info;
+
+   domain = dev_get_msi_domain(dev);
+   if (!domain)
+   return 0;
+
+   info = msi_get_domain_info(domain);
+
+   if (!(info->flags & MSI_FLAG_IRQ_REMAPPING))
+   return -1;
+#endif
+   return 0;
+}
+
 static int vfio_iommu_replay(struct vfio_iommu *iommu,
 struct vfio_domain *domain)
 {
@@ -882,7 +911,7 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
struct vfio_group *group, *g;
struct vfio_domain *domain, *d;
struct bus_type *bus = NULL;
-   int ret;
+   int ret, safe_irq_domains;
 
mutex_lock(>lock);
 
@@ -905,6 +934,13 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
 
group->iommu_group = iommu_group;
 
+   /*
+* Determine if all the devices of the group have a safe irq domain
+* with respect to MSI isolation
+*/
+   safe_irq_domains = !iommu_group_for_each_dev(iommu_group, ,
+  vfio_safe_irq_domain);
+
/* Determine bus_type in order to allocate a domain */
ret = iommu_group_for_each_dev(iommu_group, , vfio_bus_type);
if (ret)
@@ -932,8 +968,12 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
INIT_LIST_HEAD(>group_list);
list_add(>next, >group_list);
 
+   /*
+* to advertise safe interrupts either the IOMMU or the MSI controllers
+* must support IRQ remapping/interrupt translation
+*/
if (!allow_unsafe_interrupts &&
-   !iommu_capable(bus, IOMMU_CAP_INTR_REMAP)) {
+   (!iommu_capable(bus, IOMMU_CAP_INTR_REMAP) && !safe_irq_domains)) {
pr_warn("%s: No interrupt remapping support.  Use the module 
param \"allow_unsafe_interrupts\" to enable VFIO IOMMU support on this 
platform\n",
   __func__);
ret = -EPERM;
-- 
1.9.1

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


[RFC v5 13/17] vfio: introduce VFIO_IOVA_RESERVED vfio_dma type

2016-03-01 Thread Eric Auger
We introduce a vfio_dma type since we will need to discriminate
legacy vfio_dma's from new reserved ones. Since those latter are
not mapped at registration, some treatments need to be reworked:
removal, replay. Currently they are unplugged. In subsequent patches
they will be reworked.

Signed-off-by: Eric Auger 
---
 drivers/vfio/vfio_iommu_type1.c | 17 -
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 6f1ea3d..692e9a2 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -53,6 +53,15 @@ module_param_named(disable_hugepages,
 MODULE_PARM_DESC(disable_hugepages,
 "Disable VFIO IOMMU support for IOMMU hugepages.");
 
+enum vfio_iova_type {
+   VFIO_IOVA_USER = 0, /* standard IOVA used to map user vaddr */
+   /*
+* IOVA reserved to map special host physical addresses,
+* MSI frames for instance
+*/
+   VFIO_IOVA_RESERVED,
+};
+
 struct vfio_iommu {
struct list_headdomain_list;
struct mutexlock;
@@ -75,6 +84,7 @@ struct vfio_dma {
unsigned long   vaddr;  /* Process virtual addr */
size_t  size;   /* Map size (bytes) */
int prot;   /* IOMMU_READ/WRITE */
+   enum vfio_iova_type type;   /* type of IOVA */
 };
 
 struct vfio_group {
@@ -395,7 +405,8 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
struct vfio_dma *dma)
 
 static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
 {
-   vfio_unmap_unpin(iommu, dma);
+   if (likely(dma->type != VFIO_IOVA_RESERVED))
+   vfio_unmap_unpin(iommu, dma);
vfio_unlink_dma(iommu, dma);
kfree(dma);
 }
@@ -671,6 +682,10 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
dma_addr_t iova;
 
dma = rb_entry(n, struct vfio_dma, node);
+
+   if (unlikely(dma->type == VFIO_IOVA_RESERVED))
+   continue;
+
iova = dma->iova;
 
while (iova < dma->iova + dma->size) {
-- 
1.9.1

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


[RFC v5 16/17] iommu/arm-smmu: do not advertise IOMMU_CAP_INTR_REMAP

2016-03-01 Thread Eric Auger
Do not advertise IOMMU_CAP_INTR_REMAP for arm-smmu. Indeed the
irq_remapping capability is abstracted on irqchip side for ARM as
opposed to Intel IOMMU featuring IRQ remapping HW.

So to check IRQ remapping capability, the msi domain needs to be
checked instead.

This commit needs to be applied after "vfio/type1: also check IRQ
remapping capability at msi domain" else the legacy interrupt
assignment gets broken with arm-smmu.

Signed-off-by: Eric Auger 
---
 drivers/iommu/arm-smmu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index c8b7e71..ce988fb 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1284,7 +1284,7 @@ static bool arm_smmu_capable(enum iommu_cap cap)
 */
return true;
case IOMMU_CAP_INTR_REMAP:
-   return true; /* MSIs are just memory writes */
+   return false; /* interrupt translation handled at MSI 
controller level */
case IOMMU_CAP_NOEXEC:
return true;
default:
-- 
1.9.1

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


[RFC v5 10/17] msi: export msi_get_domain_info

2016-03-01 Thread Eric Auger
We plan to use msi_get_domain_info in VFIO module so let's export it.

Signed-off-by: Eric Auger 

---

v2 -> v3:
- remove static implementation in case CONFIG_PCI_MSI_IRQ_DOMAIN is not set
---
 kernel/irq/msi.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 38e89ce..9b0ba4a 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -400,5 +400,6 @@ struct msi_domain_info *msi_get_domain_info(struct 
irq_domain *domain)
 {
return (struct msi_domain_info *)domain->host_data;
 }
+EXPORT_SYMBOL_GPL(msi_get_domain_info);
 
 #endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
-- 
1.9.1

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


[RFC v5 07/17] dma-reserved-iommu: iommu_unmap_reserved

2016-03-01 Thread Eric Auger
Introduce a new function whose role is to unmap all allocated
reserved IOVAs and free the reserved iova domain

Signed-off-by: Eric Auger 

---

v3 -> v4:
- previously "iommu/arm-smmu: relinquish reserved resources on
  domain deletion"
---
 drivers/iommu/dma-reserved-iommu.c | 27 ---
 include/linux/dma-reserved-iommu.h |  7 +++
 2 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/dma-reserved-iommu.c 
b/drivers/iommu/dma-reserved-iommu.c
index 537c83e..7217bb7 100644
--- a/drivers/iommu/dma-reserved-iommu.c
+++ b/drivers/iommu/dma-reserved-iommu.c
@@ -116,7 +116,7 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(iommu_alloc_reserved_iova_domain);
 
-void iommu_free_reserved_iova_domain(struct iommu_domain *domain)
+void __iommu_free_reserved_iova_domain(struct iommu_domain *domain)
 {
struct iova_domain *iovad =
(struct iova_domain *)domain->reserved_iova_cookie;
@@ -124,11 +124,14 @@ void iommu_free_reserved_iova_domain(struct iommu_domain 
*domain)
if (!iovad)
return;
 
-   mutex_lock(>reserved_mutex);
-
put_iova_domain(iovad);
kfree(iovad);
+}
 
+void iommu_free_reserved_iova_domain(struct iommu_domain *domain)
+{
+   mutex_lock(>reserved_mutex);
+   __iommu_free_reserved_iova_domain(domain);
mutex_unlock(>reserved_mutex);
 }
 EXPORT_SYMBOL_GPL(iommu_free_reserved_iova_domain);
@@ -245,5 +248,23 @@ unlock:
 }
 EXPORT_SYMBOL_GPL(iommu_put_single_reserved);
 
+void iommu_unmap_reserved(struct iommu_domain *domain)
+{
+   struct rb_node *node;
+
+   mutex_lock(>reserved_mutex);
+   while ((node = rb_first(>reserved_binding_list))) {
+   struct iommu_reserved_binding *b =
+   rb_entry(node, struct iommu_reserved_binding, node);
+
+   while (!kref_put(>kref, reserved_binding_release))
+   ;
+   }
+   domain->reserved_binding_list = RB_ROOT;
+   __iommu_free_reserved_iova_domain(domain);
+   mutex_unlock(>reserved_mutex);
+}
+EXPORT_SYMBOL_GPL(iommu_unmap_reserved);
+
 
 
diff --git a/include/linux/dma-reserved-iommu.h 
b/include/linux/dma-reserved-iommu.h
index 71ec800..766c58c 100644
--- a/include/linux/dma-reserved-iommu.h
+++ b/include/linux/dma-reserved-iommu.h
@@ -66,6 +66,13 @@ int iommu_get_single_reserved(struct iommu_domain *domain,
  */
 void iommu_put_single_reserved(struct iommu_domain *domain, dma_addr_t iova);
 
+/**
+ * iommu_unmap_reserved: unmap & destroy the reserved iova bindings
+ *
+ * @domain: iommu domain handle
+ */
+void iommu_unmap_reserved(struct iommu_domain *domain);
+
 #endif /* CONFIG_IOMMU_DMA_RESERVED */
 #endif /* __KERNEL__ */
 #endif /* __DMA_RESERVED_IOMMU_H */
-- 
1.9.1

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


[RFC v5 14/17] vfio: allow the user to register reserved iova range for MSI mapping

2016-03-01 Thread Eric Auger
The user is allowed to [un]register a reserved IOVA range by using the
DMA MAP API and setting the new flag: VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA.
It provides the base address and the size. This region is stored in the
vfio_dma rb tree. At that point the iova range is not mapped to any target
address yet. The host kernel will use those iova when needed, typically
when the VFIO-PCI device allocates its MSIs.

This patch also handles the destruction of the reserved binding RB-tree and
domain's iova_domains.

Signed-off-by: Eric Auger 
Signed-off-by: Bharat Bhushan 

---
v3 -> v4:
- use iommu_alloc/free_reserved_iova_domain exported by dma-reserved-iommu
- protect vfio_register_reserved_iova_range implementation with
  CONFIG_IOMMU_DMA_RESERVED
- handle unregistration by user-space and on vfio_iommu_type1 release

v1 -> v2:
- set returned value according to alloc_reserved_iova_domain result
- free the iova domains in case any error occurs

RFC v1 -> v1:
- takes into account Alex comments, based on
  [RFC PATCH 1/6] vfio: Add interface for add/del reserved iova region:
- use the existing dma map/unmap ioctl interface with a flag to register
  a reserved IOVA range. A single reserved iova region is allowed.
---
 drivers/vfio/vfio_iommu_type1.c | 141 +++-
 include/uapi/linux/vfio.h   |  12 +++-
 2 files changed, 150 insertions(+), 3 deletions(-)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 692e9a2..4e01ebe 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -36,6 +36,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_VERSION  "0.2"
 #define DRIVER_AUTHOR   "Alex Williamson "
@@ -403,10 +404,22 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, 
struct vfio_dma *dma)
vfio_lock_acct(-unlocked);
 }
 
+static void vfio_unmap_reserved(struct vfio_iommu *iommu)
+{
+#ifdef CONFIG_IOMMU_DMA_RESERVED
+   struct vfio_domain *d;
+
+   list_for_each_entry(d, >domain_list, next)
+   iommu_unmap_reserved(d->domain);
+#endif
+}
+
 static void vfio_remove_dma(struct vfio_iommu *iommu, struct vfio_dma *dma)
 {
if (likely(dma->type != VFIO_IOVA_RESERVED))
vfio_unmap_unpin(iommu, dma);
+   else
+   vfio_unmap_reserved(iommu);
vfio_unlink_dma(iommu, dma);
kfree(dma);
 }
@@ -489,7 +502,8 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
 */
if (iommu->v2) {
dma = vfio_find_dma(iommu, unmap->iova, 0);
-   if (dma && dma->iova != unmap->iova) {
+   if (dma && (dma->iova != unmap->iova ||
+  (dma->type == VFIO_IOVA_RESERVED))) {
ret = -EINVAL;
goto unlock;
}
@@ -501,6 +515,10 @@ static int vfio_dma_do_unmap(struct vfio_iommu *iommu,
}
 
while ((dma = vfio_find_dma(iommu, unmap->iova, unmap->size))) {
+   if (dma->type == VFIO_IOVA_RESERVED) {
+   ret = -EINVAL;
+   goto unlock;
+   }
if (!iommu->v2 && unmap->iova > dma->iova)
break;
unmapped += dma->size;
@@ -650,6 +668,114 @@ static int vfio_dma_do_map(struct vfio_iommu *iommu,
return ret;
 }
 
+static int vfio_register_reserved_iova_range(struct vfio_iommu *iommu,
+  struct vfio_iommu_type1_dma_map *map)
+{
+#ifdef CONFIG_IOMMU_DMA_RESERVED
+   dma_addr_t iova = map->iova;
+   size_t size = map->size;
+   uint64_t mask;
+   struct vfio_dma *dma;
+   int ret = 0;
+   struct vfio_domain *d;
+   unsigned long order;
+
+   /* Verify that none of our __u64 fields overflow */
+   if (map->size != size || map->iova != iova)
+   return -EINVAL;
+
+   order =  __ffs(vfio_pgsize_bitmap(iommu));
+   mask = ((uint64_t)1 << order) - 1;
+
+   WARN_ON(mask & PAGE_MASK);
+
+   if (!size || (size | iova) & mask)
+   return -EINVAL;
+
+   /* Don't allow IOVA address wrap */
+   if (iova + size - 1 < iova)
+   return -EINVAL;
+
+   mutex_lock(>lock);
+
+   if (vfio_find_dma(iommu, iova, size)) {
+   ret =  -EEXIST;
+   goto out;
+   }
+
+   dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+   if (!dma) {
+   ret = -ENOMEM;
+   goto out;
+   }
+
+   dma->iova = iova;
+   dma->size = size;
+   dma->type = VFIO_IOVA_RESERVED;
+
+   list_for_each_entry(d, >domain_list, next)
+   ret |= iommu_alloc_reserved_iova_domain(d->domain, iova,
+   size, order);
+
+   if (ret) {
+   list_for_each_entry(d, >domain_list, next)
+   

[RFC v5 17/17] vfio/type1: return MSI mapping requirements with VFIO_IOMMU_GET_INFO

2016-03-01 Thread Eric Auger
This patch allows the user-space to know whether MSI addresses need to
be mapped in the IOMMU. The user-space uses VFIO_IOMMU_GET_INFO ioctl and
IOMMU_INFO_REQUIRE_MSI_MAP gets set if they need to.

Also the number of IOMMU pages requested to map those is returned in
msi_iova_pages field. User-space must use this information to allocate an
IOVA contiguous region of size msi_iova_pages * ffs(iova_pgsizes) and pass
it with VFIO_IOMMU_MAP_DMA iotcl (VFIO_DMA_MAP_FLAG_MSI_RESERVED_IOVA set).

Signed-off-by: Eric Auger 

---

Currently it is assumed a single doorbell page is used per MSI controller.
This is the case for known ARM MSI controllers (GICv2M, GICv3 ITS, ...).
If an MSI controller were to expose more doorbells it could implement a
new callback at irq_chip interface.

v4 -> v5:
- move msi_info and ret declaration within the conditional code

v3 -> v4:
- replace former vfio_domains_require_msi_mapping by
  more complex computation of MSI mapping requirements, especially the
  number of pages to be provided by the user-space.
- reword patch title

RFC v1 -> v1:
- derived from
  [RFC PATCH 3/6] vfio: Extend iommu-info to return MSIs automap state
- renamed allow_msi_reconfig into require_msi_mapping
- fixed VFIO_IOMMU_GET_INFO
---
 drivers/vfio/vfio_iommu_type1.c | 149 
 include/uapi/linux/vfio.h   |   2 +
 2 files changed, 151 insertions(+)

diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 88a40f1..17a941c 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -39,6 +39,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #define DRIVER_VERSION  "0.2"
 #define DRIVER_AUTHOR   "Alex Williamson "
@@ -95,6 +96,18 @@ struct vfio_group {
struct list_headnext;
 };
 
+struct vfio_irq_chip {
+   struct list_head next;
+   struct irq_chip *chip;
+};
+
+struct vfio_msi_map_info {
+   bool mapping_required;
+   size_t page_size;
+   unsigned int iova_pages;
+   struct list_head irq_chip_list;
+};
+
 /*
  * This code handles mapping and unmapping of user data buffers
  * into DMA'ble space using the IOMMU
@@ -267,6 +280,128 @@ static int vaddr_get_pfn(unsigned long vaddr, int prot, 
unsigned long *pfn)
return ret;
 }
 
+#if defined(CONFIG_GENERIC_MSI_IRQ_DOMAIN) && 
defined(CONFIG_IOMMU_DMA_RESERVED)
+/**
+ * vfio_dev_compute_msi_map_info: augment MSI mapping info (@data) with
+ * the @dev device requirements.
+ *
+ * @dev: device handle
+ * @data: opaque pointing to a struct vfio_msi_map_info
+ *
+ * returns 0 upon success or -ENOMEM
+ */
+static int vfio_dev_compute_msi_map_info(struct device *dev, void *data)
+{
+   struct irq_domain *domain;
+   struct msi_domain_info *info;
+   struct vfio_msi_map_info *msi_info = (struct vfio_msi_map_info *)data;
+   struct irq_chip *chip;
+   struct vfio_irq_chip *iter, *new;
+
+   domain = dev_get_msi_domain(dev);
+   if (!domain)
+   return 0;
+
+   /* Let's compute the needs for the MSI domain */
+   info = msi_get_domain_info(domain);
+   chip = info->chip;
+   list_for_each_entry(iter, _info->irq_chip_list, next) {
+   if (iter->chip == chip)
+   return 0;
+   }
+
+   new = kzalloc(sizeof(*new), GFP_KERNEL);
+   if (!new)
+   return -ENOMEM;
+
+   new->chip = chip;
+
+   list_add(>next, _info->irq_chip_list);
+
+   /*
+* new irq_chip to be taken into account; we currently assume
+* a single iova doorbell by irq chip requesting MSI mapping
+*/
+   msi_info->iova_pages += 1;
+   return 0;
+}
+
+/**
+ * vfio_domain_compute_msi_map_info: compute MSI mapping requirements (@data)
+ * for vfio_domain @d
+ *
+ * @d: vfio domain handle
+ * @data: opaque pointing to a struct vfio_msi_map_info
+ *
+ * returns 0 upon success or -ENOMEM
+ */
+static int vfio_domain_compute_msi_map_info(struct vfio_domain *d, void *data)
+{
+   int ret = 0;
+   struct vfio_msi_map_info *msi_info = (struct vfio_msi_map_info *)data;
+   struct vfio_irq_chip *iter, *tmp;
+   struct vfio_group *g;
+
+   msi_info->iova_pages = 0;
+   INIT_LIST_HEAD(_info->irq_chip_list);
+
+   if (iommu_domain_get_attr(d->domain,
+  DOMAIN_ATTR_MSI_MAPPING, NULL))
+   return 0;
+   msi_info->mapping_required = true;
+   list_for_each_entry(g, >group_list, next) {
+   ret = iommu_group_for_each_dev(g->iommu_group, msi_info,
+  vfio_dev_compute_msi_map_info);
+   if (ret)
+   goto out;
+   }
+out:
+   list_for_each_entry_safe(iter, tmp, _info->irq_chip_list, next) {
+   list_del(>next);
+   kfree(iter);
+   }
+   return ret;
+}
+
+/**
+ * vfio_compute_msi_map_info: compute MSI 

[RFC v5 06/17] dma-reserved-iommu: iommu_get/put_single_reserved

2016-03-01 Thread Eric Auger
This patch introduces iommu_get/put_single_reserved.

iommu_get_single_reserved allows to allocate a new reserved iova page
and map it onto the physical page that contains a given physical address.
Page size is the IOMMU page one. It is the responsability of the
system integrator to make sure the in use IOMMU page size corresponds
to the granularity of the MSI frame.

It returns the iova that is mapped onto the provided physical address.
Hence the physical address passed in argument does not need to be aligned.

In case a mapping already exists between both pages, the IOVA mapped
to the PA is directly returned.

Each time an iova is successfully returned a binding ref count is
incremented.

iommu_put_single_reserved decrements the ref count and when this latter
is null, the mapping is destroyed and the iova is released.

Signed-off-by: Eric Auger 
Signed-off-by: Ankit Jindal 
Signed-off-by: Pranavkumar Sawargaonkar 
Signed-off-by: Bharat Bhushan 

---

v3 -> v4:
- formerly in iommu: iommu_get/put_single_reserved &
  iommu/arm-smmu: implement iommu_get/put_single_reserved
- Attempted to address Marc's doubts about missing size/alignment
  at VFIO level (user-space knows the IOMMU page size and the number
  of IOVA pages to provision)

v2 -> v3:
- remove static implementation of iommu_get_single_reserved &
  iommu_put_single_reserved when CONFIG_IOMMU_API is not set

v1 -> v2:
- previously a VFIO API, named vfio_alloc_map/unmap_free_reserved_iova
---
 drivers/iommu/dma-reserved-iommu.c | 115 +
 include/linux/dma-reserved-iommu.h |  26 +
 2 files changed, 141 insertions(+)

diff --git a/drivers/iommu/dma-reserved-iommu.c 
b/drivers/iommu/dma-reserved-iommu.c
index 30d54d0..537c83e 100644
--- a/drivers/iommu/dma-reserved-iommu.c
+++ b/drivers/iommu/dma-reserved-iommu.c
@@ -132,3 +132,118 @@ void iommu_free_reserved_iova_domain(struct iommu_domain 
*domain)
mutex_unlock(>reserved_mutex);
 }
 EXPORT_SYMBOL_GPL(iommu_free_reserved_iova_domain);
+
+int iommu_get_single_reserved(struct iommu_domain *domain,
+ phys_addr_t addr, int prot,
+ dma_addr_t *iova)
+{
+   unsigned long order = __ffs(domain->ops->pgsize_bitmap);
+   size_t page_size = 1 << order;
+   phys_addr_t mask = page_size - 1;
+   phys_addr_t aligned_addr = addr & ~mask;
+   phys_addr_t offset  = addr - aligned_addr;
+   struct iommu_reserved_binding *b;
+   struct iova *p_iova;
+   struct iova_domain *iovad =
+   (struct iova_domain *)domain->reserved_iova_cookie;
+   int ret;
+
+   if (!iovad)
+   return -EINVAL;
+
+   mutex_lock(>reserved_mutex);
+
+   b = find_reserved_binding(domain, aligned_addr, page_size);
+   if (b) {
+   *iova = b->iova + offset;
+   kref_get(>kref);
+   ret = 0;
+   goto unlock;
+   }
+
+   /* there is no existing reserved iova for this pa */
+   p_iova = alloc_iova(iovad, 1, iovad->dma_32bit_pfn, true);
+   if (!p_iova) {
+   ret = -ENOMEM;
+   goto unlock;
+   }
+   *iova = p_iova->pfn_lo << order;
+
+   b = kzalloc(sizeof(*b), GFP_KERNEL);
+   if (!b) {
+   ret = -ENOMEM;
+   goto free_iova_unlock;
+   }
+
+   ret = iommu_map(domain, *iova, aligned_addr, page_size, prot);
+   if (ret)
+   goto free_binding_iova_unlock;
+
+   kref_init(>kref);
+   kref_get(>kref);
+   b->domain = domain;
+   b->addr = aligned_addr;
+   b->iova = *iova;
+   b->size = page_size;
+
+   link_reserved_binding(domain, b);
+
+   *iova += offset;
+   goto unlock;
+
+free_binding_iova_unlock:
+   kfree(b);
+free_iova_unlock:
+   free_iova(iovad, *iova >> order);
+unlock:
+   mutex_unlock(>reserved_mutex);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_get_single_reserved);
+
+/* called with reserved_mutex locked */
+static void reserved_binding_release(struct kref *kref)
+{
+   struct iommu_reserved_binding *b =
+   container_of(kref, struct iommu_reserved_binding, kref);
+   struct iommu_domain *d = b->domain;
+   struct iova_domain *iovad =
+   (struct iova_domain *)d->reserved_iova_cookie;
+   unsigned long order = __ffs(b->size);
+
+   iommu_unmap(d, b->iova, b->size);
+   free_iova(iovad, b->iova >> order);
+   unlink_reserved_binding(d, b);
+   kfree(b);
+}
+
+void iommu_put_single_reserved(struct iommu_domain *domain, dma_addr_t iova)
+{
+   unsigned long order;
+   phys_addr_t aligned_addr;
+   dma_addr_t aligned_iova, page_size, mask, offset;
+   struct iommu_reserved_binding *b;
+
+   order = __ffs(domain->ops->pgsize_bitmap);
+   page_size = (uint64_t)1 << order;
+   mask = page_size 

[RFC v5 12/17] msi: IOMMU map the doorbell address when needed

2016-03-01 Thread Eric Auger
In case the msi is emitted by a device attached to an iommu
domain and this iommu domain requires MSI mapping, the msi
address (aka doorbell) must be mapped in the IOMMU. Else
MSI write transaction will cause a fault.

We perform this action at msi message composition time. On any
MSI address change and MSI message erasure we decrement the reference
counter to the IOMMU binding.

In case the mapping fails we just WARN_ON.

Signed-off-by: Eric Auger 

---

v5:
- use macros to increase the readability
- add comments
- fix a typo that caused a compilation error if CONFIG_IOMMU_API
  is not set
---
 include/linux/msi.h |  15 +++
 kernel/irq/msi.c| 119 
 2 files changed, 134 insertions(+)

diff --git a/include/linux/msi.h b/include/linux/msi.h
index 03eda72..b920cac 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -10,6 +10,21 @@ struct msi_msg {
u32 data;   /* 16 bits of msi message data */
 };
 
+/* Helpers to convert the msi message address to a an iova/physical address */
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+#define msg_to_dma_addr(msg) \
+   (((dma_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
+#else
+#define msg_to_dma_addr(msg) ((msg)->address_lo)
+#endif
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+#define msg_to_phys_addr(msg) \
+   (((phys_addr_t)((msg)->address_hi) << 32) | (msg)->address_lo)
+#else
+#define msg_to_phys_addr(msg)  ((msg)->address_lo)
+#endif
+
 extern int pci_msi_ignore_mask;
 /* Helper functions */
 struct irq_data;
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 72bf4d6..8ddbe57 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -17,6 +17,8 @@
 
 /* Temparory solution for building, will be removed later */
 #include 
+#include 
+#include 
 
 struct msi_desc *alloc_msi_entry(struct device *dev)
 {
@@ -55,16 +57,133 @@ static inline void irq_chip_write_msi_msg(struct irq_data 
*data,
data->chip->irq_write_msi_msg(data, msg);
 }
 
+/**
+ * msi_map_doorbell: make sure an IOMMU mapping exists on domain @d
+ * for the message physical address (aka. doorbell)
+ *
+ * Either allocate an IOVA and create a mapping or simply increment
+ * a reference count on the existing IOMMU mapping
+ * @d: iommu domain handle the mapping belongs to
+ * @msg: msi message handle
+ */
+static int msi_map_doorbell(struct iommu_domain *d, struct msi_msg *msg)
+{
+#ifdef CONFIG_IOMMU_DMA_RESERVED
+   phys_addr_t addr;
+   dma_addr_t iova;
+   int ret;
+
+   addr = msg_to_phys_addr(msg);
+   ret = iommu_get_single_reserved(d, addr, IOMMU_WRITE, );
+   if (!ret) {
+   msg->address_lo = lower_32_bits(iova);
+   msg->address_hi = upper_32_bits(iova);
+   }
+   return ret;
+#else
+   return -ENODEV;
+#endif
+}
+
+/**
+ * msi_unmap_doorbell: decrements the reference count on an existing
+ * doorbell IOMMU mapping
+ *
+ * @d: iommu domain the mapping is attached to
+ * @msg: msi message containing the doorbell IOVA to unbind
+ */
+static void msi_unmap_doorbell(struct iommu_domain *d, struct msi_msg *msg)
+{
+#ifdef CONFIG_IOMMU_DMA_RESERVED
+   dma_addr_t iova;
+
+   iova = msg_to_dma_addr(msg);
+   iommu_put_single_reserved(d, iova);
+#endif
+}
+
+#ifdef CONFIG_IOMMU_API
+/**
+ * irq_data_to_msi_mapping_domain: checks if an irq corresponds to
+ * an MSI whose write address must be mapped in an IOMMU domain
+ *
+ * determine whether the irq corresponds to an MSI emitted by a device,
+ * upstream to an IOMMU, and if this IOMMU requires a binding of the
+ * MSI address
+ *
+ * @irq_data: irq data handle
+ */
+static struct iommu_domain *
+irq_data_to_msi_mapping_domain(struct irq_data *irq_data)
+{
+   struct iommu_domain *d;
+   struct msi_desc *desc;
+   struct device *dev;
+   int ret;
+
+   desc = irq_data_get_msi_desc(irq_data);
+   if (!desc)
+   return NULL;
+
+   dev = msi_desc_to_dev(desc);
+
+   d = iommu_get_domain_for_dev(dev);
+   if (!d)
+   return NULL;
+
+   ret = iommu_domain_get_attr(d, DOMAIN_ATTR_MSI_MAPPING, NULL);
+   if (!ret)
+   return d;
+   else
+   return NULL;
+}
+#else
+static inline struct iommu_domain *
+irq_data_to_msi_mapping_domain(struct irq_data *irq_data)
+{
+   return NULL;
+}
+#endif /* CONFIG_IOMMU_API */
+
 static int msi_compose(struct irq_data *irq_data,
   struct msi_msg *msg, bool erase)
 {
+   struct msi_msg old_msg;
+   struct iommu_domain *d;
int ret = 0;
 
+   /*
+* Does this IRQ require an MSI address mapping in an IOMMU?
+* If it does, read the existing cached message. This will allow
+* to check if the IOMMU mapping needs an update
+*/
+   d = irq_data_to_msi_mapping_domain(irq_data);
+   if (unlikely(d))
+   get_cached_msi_msg(irq_data->irq, _msg);
+
if 

[RFC v5 03/17] iommu: introduce a reserved iova cookie

2016-03-01 Thread Eric Auger
This patch introduces some new fields in the iommu_domain struct,
dedicated to reserved iova management.

In a similar way as DMA mapping IOVA window, we need to store
information related to a reserved IOVA window.

The reserved_iova_cookie will store the reserved iova_domain
handle. An RB tree indexed by physical address is introduced to
store the host physical addresses bound to reserved IOVAs.

Those physical addresses will correspond to MSI frame base
addresses, also referred to as doorbells. Their number should be
quite limited per domain.

Also a mutex is introduced to protect accesses to the iova_domain
and RB tree.

Signed-off-by: Eric Auger 
---
 drivers/iommu/iommu.c | 1 +
 include/linux/iommu.h | 5 +
 2 files changed, 6 insertions(+)

diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index 0e3b009..7b2bb94 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1072,6 +1072,7 @@ static struct iommu_domain *__iommu_domain_alloc(struct 
bus_type *bus,
 
domain->ops  = bus->iommu_ops;
domain->type = type;
+   mutex_init(>reserved_mutex);
 
return domain;
 }
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a4fe04a..0189144 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -82,6 +82,11 @@ struct iommu_domain {
void *handler_token;
struct iommu_domain_geometry geometry;
void *iova_cookie;
+   void *reserved_iova_cookie;
+   /* rb tree indexed by PA, for reserved bindings only */
+   struct rb_root reserved_binding_list;
+   /* protects reserved cookie and rbtree manipulation */
+   struct mutex reserved_mutex;
 };
 
 enum iommu_cap {
-- 
1.9.1

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


[RFC v5 01/17] iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute

2016-03-01 Thread Eric Auger
Introduce a new DOMAIN_ATTR_MSI_MAPPING domain attribute. If supported,
this means the MSI addresses need to be mapped in the IOMMU.

x86 IOMMUs typically don't expose the attribute since on x86, MSI write
transaction addresses always are within the 1MB PA region [FEE0_h -
FEF0_000h] window which directly targets the APIC configuration space and
hence bypass the sMMU. On ARM and PowerPC however MSI transactions are
conveyed through the IOMMU.

Signed-off-by: Bharat Bhushan 
Signed-off-by: Eric Auger 

---

v4 -> v5:
- introduce the user in the next patch

RFC v1 -> v1:
- the data field is not used
- for this attribute domain_get_attr simply returns 0 if the MSI_MAPPING
  capability if needed or <0 if not.
- removed struct iommu_domain_msi_maps
---
 include/linux/iommu.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index a5c539f..a4fe04a 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -112,6 +112,7 @@ enum iommu_attr {
DOMAIN_ATTR_FSL_PAMU_ENABLE,
DOMAIN_ATTR_FSL_PAMUV1,
DOMAIN_ATTR_NESTING,/* two stages of translation */
+   DOMAIN_ATTR_MSI_MAPPING, /* Require MSIs mapping in iommu */
DOMAIN_ATTR_MAX,
 };
 
-- 
1.9.1

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


[RFC v5 00/17] KVM PCIe/MSI passthrough on ARM/ARM64

2016-03-01 Thread Eric Auger
This series addresses KVM PCIe passthrough with MSI enabled on ARM/ARM64.
It pursues the efforts done on [1], [2], [3]. It also aims at covering the
same need on PowerPC platforms although the same kind of integration
should be carried out.

On x86 all accesses to the 1MB PA region [FEE0_h - FEF0_000h] are directed
as interrupt messages: accesses to this special PA window directly target the
APIC configuration space and not DRAM, meaning the downstream IOMMU is bypassed.

This is not the case on above mentionned platforms where MSI messages emitted
by devices are conveyed through the IOMMU. This means an IOVA/host PA mapping
must exist for the MSI to reach the MSI controller. Normal way to create
IOVA bindings consists in using VFIO DMA MAP API. However in this case
the MSI IOVA is not mapped onto guest RAM but on host physical page (the MSI
controller frame).

In a nutshell, this series does:
- introduce a new DMA-RESERVED-IOMMU API to register a IOVA window usable for
  reserved mapping and allocate/bind IOVA to host physical addresses
- reuse VFIO DMA MAP ioctl with a new flag to plug onto that new API
- check if the MSI mapping is safe when attaching the vfio group to the
  container (allow_unsafe_interrupts modality)
- allow the MSI subsystem to map/unmap the doorbell on MSI message composition
- allow the user-space to know how many IOVA pages are requested

Best Regards

Eric

Testing:
- functional on ARM64 AMD Overdrive HW (single GICv2m frame) with
  x Intel e1000e PCIe card
  x Intel X540-T2 (SR-IOV capable)
- Not tested: ARM GICv3 ITS

References:
[1] [RFC 0/2] VFIO: Add virtual MSI doorbell support
(https://lkml.org/lkml/2015/7/24/135)
[2] [RFC PATCH 0/6] vfio: Add interface to map MSI pages
(https://lists.cs.columbia.edu/pipermail/kvmarm/2015-September/016607.html)
[3] [PATCH v2 0/3] Introduce MSI hardware mapping for VFIO
(http://permalink.gmane.org/gmane.comp.emulators.kvm.arm.devel/3858)

Git:
https://git.linaro.org/people/eric.auger/linux.git/shortlog/refs/heads/v4.5-rc6-pcie-passthrough-rfcv5

previous version at
v3: 
https://git.linaro.org/people/eric.auger/linux.git/shortlog/refs/heads/v4.5-rc5-pcie-passthrough-rfcv4

QEMU Integration:
[RFC v2 0/8] KVM PCI/MSI passthrough with mach-virt
(http://lists.gnu.org/archive/html/qemu-arm/2016-01/msg00444.html)
https://git.linaro.org/people/eric.auger/qemu.git/shortlog/refs/heads/v2.5.0-pci-passthrough-rfc-v2

User Hints:
To allow PCI/MSI passthrough with GICv2M, compile VFIO as a module and
load the vfio_iommu_type1 module with allow_unsafe_interrupts param:
sudo modprobe -v vfio-pci
sudo modprobe -r vfio_iommu_type1
sudo modprobe -v vfio_iommu_type1 allow_unsafe_interrupts=1

History:

RFC v4 -> RFC v5:
- take into account Thomas' comments on MSI related patches
  - split "msi: IOMMU map the doorbell address when needed"
  - increase readability and add comments
  - fix style issues
 - split "iommu: Add DOMAIN_ATTR_MSI_MAPPING attribute"
 - platform ITS now advertises IOMMU_CAP_INTR_REMAP
 - fix compilation issue with CONFIG_IOMMU API unset
 - arm-smmu-v3 now advertises DOMAIN_ATTR_MSI_MAPPING

RFC v3 -> v4:
- Move doorbell mapping/unmapping in msi.c
- fix ref count issue on set_affinity: in case of a change in the address
  the previous address is decremented
- doorbell map/unmap now is done on msi composition. Should allow the use
  case for platform MSI controllers
- create dma-reserved-iommu.h/c exposing/implementing a new API dedicated
  to reserved IOVA management (looking like dma-iommu glue)
- series reordering to ease the review:
  - first part is related to IOMMU
  - second related to MSI sub-system
  - third related to VFIO (except arm-smmu IOMMU_CAP_INTR_REMAP removal)
- expose the number of requested IOVA pages through VFIO_IOMMU_GET_INFO
  [this partially addresses Marc's comments on iommu_get/put_single_reserved
   size/alignment problematic - which I did not ignore - but I don't know
   how much I can do at the moment]

RFC v2 -> RFC v3:
- should fix wrong handling of some CONFIG combinations:
  CONFIG_IOVA, CONFIG_IOMMU_API, CONFIG_PCI_MSI_IRQ_DOMAIN
- fix MSI_FLAG_IRQ_REMAPPING setting in GICv3 ITS (although not tested)

PATCH v1 -> RFC v2:
- reverted to RFC since it looks more reasonable ;-) the code is split
  between VFIO, IOMMU, MSI controller and I am not sure I did the right
  choices. Also API need to be further discussed.
- iova API usage in arm-smmu.c.
- MSI controller natively programs the MSI addr with either the PA or IOVA.
  This is not done anymore in vfio-pci driver as suggested by Alex.
- check irq remapping capability of the group

RFC v1 [2] -> PATCH v1:
- use the existing dma map/unmap ioctl interface with a flag to register a
  reserved IOVA range. Use the legacy Rb to store this special vfio_dma.
- a single reserved IOVA contiguous region now is allowed
- use of an RB tree indexed by PA to store allocated reserved slots
- use of a vfio_domain iova_domain to manage iova allocation within 

[RFC v5 11/17] msi: msi_compose wrapper

2016-03-01 Thread Eric Auger
Currently the MSI message is composed by directly calling
irq_chip_compose_msi_msg and erased by setting the memory to zero.

On some platforms, we will need to complexify this composition to
properly handle MSI emission through IOMMU. Also we will need to track
when the MSI message is erased.

We propose to introduce a common wrapper for actual composition and
erasure, msi_compose.

Signed-off-by: Eric Auger 

---
v4 -> v5:
- just introduce the msi-compose wrapper without adding new
  functionalities

v3 -> v4:
- that code was formely in irq-gic-common.c
  "irqchip/gicv2m/v3-its-pci-msi: IOMMU map the MSI frame when needed"
  also the [un]mapping was done in irq_write_msi_msg; now done on compose

v2 -> v3:
- protect iova/addr manipulation with CONFIG_ARCH_DMA_ADDR_T_64BIT and
  CONFIG_PHYS_ADDR_T_64BIT
- only expose gic_pci_msi_domain_write_msg in case CONFIG_IOMMU_API &
  CONFIG_PCI_MSI_IRQ_DOMAIN are set.
- gic_set/unset_msi_addr duly become static
---
 kernel/irq/msi.c | 19 ---
 1 file changed, 16 insertions(+), 3 deletions(-)

diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 9b0ba4a..72bf4d6 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -55,6 +55,19 @@ static inline void irq_chip_write_msi_msg(struct irq_data 
*data,
data->chip->irq_write_msi_msg(data, msg);
 }
 
+static int msi_compose(struct irq_data *irq_data,
+  struct msi_msg *msg, bool erase)
+{
+   int ret = 0;
+
+   if (erase)
+   memset(msg, 0, sizeof(*msg));
+   else
+   ret = irq_chip_compose_msi_msg(irq_data, msg);
+
+   return ret;
+}
+
 /**
  * msi_domain_set_affinity - Generic affinity setter function for MSI domains
  * @irq_data:  The irq data associated to the interrupt
@@ -73,7 +86,7 @@ int msi_domain_set_affinity(struct irq_data *irq_data,
 
ret = parent->chip->irq_set_affinity(parent, mask, force);
if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
-   BUG_ON(irq_chip_compose_msi_msg(irq_data, ));
+   BUG_ON(msi_compose(irq_data, , false));
irq_chip_write_msi_msg(irq_data, );
}
 
@@ -85,7 +98,7 @@ static void msi_domain_activate(struct irq_domain *domain,
 {
struct msi_msg msg;
 
-   BUG_ON(irq_chip_compose_msi_msg(irq_data, ));
+   BUG_ON(msi_compose(irq_data, , false));
irq_chip_write_msi_msg(irq_data, );
 }
 
@@ -94,7 +107,7 @@ static void msi_domain_deactivate(struct irq_domain *domain,
 {
struct msi_msg msg;
 
-   memset(, 0, sizeof(msg));
+   msi_compose(irq_data, , true);
irq_chip_write_msi_msg(irq_data, );
 }
 
-- 
1.9.1

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


[RFC v5 04/17] dma-reserved-iommu: alloc/free_reserved_iova_domain

2016-03-01 Thread Eric Auger
Introduce alloc/free_reserved_iova_domain in the IOMMU API.
alloc_reserved_iova_domain initializes an iova domain at a given
iova base address and with a given size. This iova domain will
be used to allocate iova within that window. Those IOVAs will be reserved
for special purpose, typically MSI frame binding. Allocation function
within the reserved iova domain will be introduced in subsequent patches.

Those functions are implemented and exposed if CONFIG_IOMMU_DMA_RESERVED
is seta.

Signed-off-by: Eric Auger 

---

v3 -> v4:
- formerly in "iommu/arm-smmu: implement alloc/free_reserved_iova_domain" &
  "iommu: add alloc/free_reserved_iova_domain"

v2 -> v3:
- remove iommu_alloc_reserved_iova_domain & iommu_free_reserved_iova_domain
  static implementation in case CONFIG_IOMMU_API is not set

v1 -> v2:
- moved from vfio API to IOMMU API
---
 drivers/iommu/Kconfig  |  8 +
 drivers/iommu/Makefile |  1 +
 drivers/iommu/dma-reserved-iommu.c | 74 ++
 include/linux/dma-reserved-iommu.h | 45 +++
 4 files changed, 128 insertions(+)
 create mode 100644 drivers/iommu/dma-reserved-iommu.c
 create mode 100644 include/linux/dma-reserved-iommu.h

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index a1e75cb..0775143 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -55,6 +55,12 @@ config IOMMU_DMA
select IOMMU_API
select IOMMU_IOVA
 
+# IOMMU reserved IOVA mapping (MSI doorbell)
+config IOMMU_DMA_RESERVED
+   bool
+   select IOMMU_API
+   select IOMMU_IOVA
+
 config FSL_PAMU
bool "Freescale IOMMU support"
depends on PPC32
@@ -288,6 +294,7 @@ config SPAPR_TCE_IOMMU
 config ARM_SMMU
bool "ARM Ltd. System MMU (SMMU) Support"
depends on (ARM64 || ARM) && MMU
+   select IOMMU_DMA_RESERVED
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
@@ -301,6 +308,7 @@ config ARM_SMMU
 config ARM_SMMU_V3
bool "ARM Ltd. System MMU Version 3 (SMMUv3) Support"
depends on ARM64 && PCI
+   select IOMMU_DMA_RESERVED
select IOMMU_API
select IOMMU_IO_PGTABLE_LPAE
select GENERIC_MSI_IRQ_DOMAIN
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 42fc0c2..ea68d23 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -2,6 +2,7 @@ obj-$(CONFIG_IOMMU_API) += iommu.o
 obj-$(CONFIG_IOMMU_API) += iommu-traces.o
 obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
 obj-$(CONFIG_IOMMU_DMA) += dma-iommu.o
+obj-$(CONFIG_IOMMU_DMA_RESERVED) += dma-reserved-iommu.o
 obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
 obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
 obj-$(CONFIG_IOMMU_IOVA) += iova.o
diff --git a/drivers/iommu/dma-reserved-iommu.c 
b/drivers/iommu/dma-reserved-iommu.c
new file mode 100644
index 000..41a1add
--- /dev/null
+++ b/drivers/iommu/dma-reserved-iommu.c
@@ -0,0 +1,74 @@
+/*
+ * Reserved IOVA Management
+ *
+ * Copyright (c) 2015 Linaro Ltd.
+ *  www.linaro.org
+ *
+ * Copyright (C) 2000-2004 Russell King
+ *
+ * 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 
+
+int iommu_alloc_reserved_iova_domain(struct iommu_domain *domain,
+dma_addr_t iova, size_t size,
+unsigned long order)
+{
+   unsigned long granule, mask;
+   struct iova_domain *iovad;
+   int ret = 0;
+
+   granule = 1UL << order;
+   mask = granule - 1;
+   if (iova & mask || (!size) || (size & mask))
+   return -EINVAL;
+
+   mutex_lock(>reserved_mutex);
+
+   if (domain->reserved_iova_cookie) {
+   ret = -EEXIST;
+   goto unlock;
+   }
+
+   iovad = kzalloc(sizeof(struct iova_domain), GFP_KERNEL);
+   if (!iovad) {
+   ret = -ENOMEM;
+   goto unlock;
+   }
+
+   init_iova_domain(iovad, granule,
+iova >> order, (iova + size - 1) >> order);
+   domain->reserved_iova_cookie = iovad;
+
+unlock:
+   mutex_unlock(>reserved_mutex);
+   return ret;
+}
+EXPORT_SYMBOL_GPL(iommu_alloc_reserved_iova_domain);
+
+void iommu_free_reserved_iova_domain(struct iommu_domain *domain)
+{
+   struct iova_domain *iovad =
+   (struct iova_domain *)domain->reserved_iova_cookie;
+
+   if (!iovad)
+   return;
+
+   mutex_lock(>reserved_mutex);
+
+   put_iova_domain(iovad);
+   kfree(iovad);
+
+

[RFC v5 02/17] iommu/arm-smmu: advertise DOMAIN_ATTR_MSI_MAPPING attribute

2016-03-01 Thread Eric Auger
On ARM, MSI write transactions from device upstream to the smmu
are conveyed through the iommu. Therefore target physical addresses
must be mapped and DOMAIN_ATTR_MSI_MAPPING is set to advertise
this requirement on arm-smmu and arm-smmu-v3.

Signed-off-by: Eric Auger 
Signed-off-by: Bharat Bhushan 

---

v4 -> v5:
- don't handle fsl_pamu_domain anymore
- handle arm-smmu-v3
---
 drivers/iommu/arm-smmu-v3.c | 2 ++
 drivers/iommu/arm-smmu.c| 2 ++
 2 files changed, 4 insertions(+)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index 2087534..1d7b506 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -1895,6 +1895,8 @@ static int arm_smmu_domain_get_attr(struct iommu_domain 
*domain,
case DOMAIN_ATTR_NESTING:
*(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
return 0;
+   case DOMAIN_ATTR_MSI_MAPPING:
+   return 0;
default:
return -ENODEV;
}
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 59ee4b8..c8b7e71 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1409,6 +1409,8 @@ static int arm_smmu_domain_get_attr(struct iommu_domain 
*domain,
case DOMAIN_ATTR_NESTING:
*(int *)data = (smmu_domain->stage == ARM_SMMU_DOMAIN_NESTED);
return 0;
+   case DOMAIN_ATTR_MSI_MAPPING:
+   return 0;
default:
return -ENODEV;
}
-- 
1.9.1

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


[PATCH] iommu/io-pgtable-armv7s: Fix kmem_cache_alloc() flags

2016-03-01 Thread Robin Murphy
Whilst the default SLUB allocator happily just merges the original
allocation flags from kmem_cache_create() with those passed through
kmem_cache_alloc(), there is a code path in the SLAB allocator which
will aggressively BUG_ON() if the cache was created with SLAB_CACHE_DMA
but GFP_DMA is not specified for an allocation.

Keep the peace by adding GFP_DMA when allocating a table.

Reported-by: Geert Uytterhoeven 
Signed-off-by: Robin Murphy 
---
 drivers/iommu/io-pgtable-arm-v7s.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/io-pgtable-arm-v7s.c 
b/drivers/iommu/io-pgtable-arm-v7s.c
index 9fcceb1..9488e3c 100644
--- a/drivers/iommu/io-pgtable-arm-v7s.c
+++ b/drivers/iommu/io-pgtable-arm-v7s.c
@@ -192,7 +192,7 @@ static void *__arm_v7s_alloc_table(int lvl, gfp_t gfp,
if (lvl == 1)
table = (void *)__get_dma_pages(__GFP_ZERO, get_order(size));
else if (lvl == 2)
-   table = kmem_cache_zalloc(data->l2_tables, gfp);
+   table = kmem_cache_zalloc(data->l2_tables, gfp | GFP_DMA);
if (table && !selftest_running) {
dma = dma_map_single(dev, table, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma))
-- 
2.7.2.333.g70bd996.dirty

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


Re: [PATCH v3 1/3] iommu/io-pgtable: Add ARMv7 short descriptor support

2016-03-01 Thread Robin Murphy

Hi Geert,

On 01/03/16 12:01, Geert Uytterhoeven wrote:

Hi Robin,

On Tue, Jan 26, 2016 at 6:13 PM, Robin Murphy  wrote:

Add a nearly-complete ARMv7 short descriptor implementation, omitting
only a few legacy and CPU-centric aspects which shouldn't be necessary
for IOMMU API use anyway.

Signed-off-by: Yong Wu 
Signed-off-by: Robin Murphy 
---
  drivers/iommu/Kconfig  |  19 +
  drivers/iommu/Makefile |   1 +
  drivers/iommu/io-pgtable-arm-v7s.c | 849 +
  drivers/iommu/io-pgtable.c |   3 +
  drivers/iommu/io-pgtable.h |  14 +-
  5 files changed, 885 insertions(+), 1 deletion(-)
  create mode 100644 drivers/iommu/io-pgtable-arm-v7s.c

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index a1e75cb..dc1aaa5 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -39,6 +39,25 @@ config IOMMU_IO_PGTABLE_LPAE_SELFTEST

   If unsure, say N here.

+config IOMMU_IO_PGTABLE_ARMV7S
+   bool "ARMv7/v8 Short Descriptor Format"
+   select IOMMU_IO_PGTABLE
+   depends on HAS_DMA && (ARM || ARM64 || COMPILE_TEST)
+   help
+ Enable support for the ARM Short-descriptor pagetable format.
+ This supports 32-bit virtual and physical addresses mapped using
+ 2-level tables with 4KB pages/1MB sections, and contiguous entries
+ for 64KB pages/16MB supersections if indicated by the IOMMU driver.
+
+config IOMMU_IO_PGTABLE_ARMV7S_SELFTEST
+   bool "ARMv7s selftests"
+   depends on IOMMU_IO_PGTABLE_ARMV7S
+   help
+ Enable self-tests for ARMv7s page table allocator. This performs
+ a series of page-table consistency checks during boot.
+
+ If unsure, say N here.
+


When enabling IOMMU_IO_PGTABLE_ARMV7S_SELFTEST on r8a7791 (dual Cortex A15),
the kernel crashes with:

kernel BUG at mm/slab.c:2536!
Internal error: Oops - BUG: 0 [#1] SMP ARM
Modules linked in:[1.299311] Modules linked in:

CPU: 1 PID: 1 Comm: swapper/0 Not tainted
4.5.0-rc6-koelsch-05892-ge7e45ad53ab6795e #2270
Hardware name: Generic R8A7791 (Flattened Device Tree)
task: ef422040 ti: ef442000 task.ti: ef442000
PC is at cache_alloc_refill+0x2a0/0x530
LR is at _raw_spin_unlock+0x8/0xc
pc : []lr : []psr: 0093
sp : ef443d88  ip : d0a7b1f0  fp : 0220
r10: 0010  r9 :   r8 : 02088020
r7 :   r6 : ef5172c0  r5 :   r4 : ef5d7f40
r3 : 4001  r2 : 0001  r1 : 00020001  r0 : ef5172c0
Flags: nzcv  IRQs off  FIQs on  Mode SVC_32  ISA ARM  Segment kernel
Control: 30c5387d  Table: 40003000  DAC: 
Process swapper/0 (pid: 1, stack limit = 0xef442210)
Stack: (0xef443d88 to 0xef444000)
3d80:   ef48b4c0  ef5172d0 c0e38280  1000
3da0: 02088020 6013 ef5d7f40 c0445010  ef517340 1000 c02c6630
3dc0: 0008 1000  0400 0002 c0bc  
3de0: 024000c0 ef517340  4000 0001 0001 c0e3b000 ef517340
3e00:  1000  ef5f8000 ef517340 c0445010  000f
3e20: 1000 c0444e1c   ef517350  ef520f15 ef517340
3e40: ef443ea0 ef517390   1000 c0445010  ef517390
3e60: 1000 c0445044 1000 000f ef5f8000 ef443ea0 c0e92a00 c0e92a00
3e80:   000c c0c18ee4 1000 000f 0001 0014
3ea0: 0001 0000 0020 0020 c0e25bc8  6f5f806a 
3ec0: 0020 40004000 800b8204     
3ee0: c0c3ce94 ef520f00 c0c18da4  c0e05550 c0e05550 c0e3b000 c0c2d848
3f00:  c0201760 ef5036c0 c0804b44 c0e5fdd0  c0e0be00 c0e0be7c
3f20:  6013  efffec51 efffec59 c023893c c09dc204 0004
3f40: 0004 c09dce98 00a0 c09dce98 c0e09e78 0004 c0c2d834 0004
3f60: c0c2d838 00a1 c0c3ce94 c0e3b000 c0e3b000 c0c00d4c 0004 0004
3f80:  c0c0058c  c067a35c    
3fa0:  c067a364  c0206b68    
3fc0:        
3fe0:     0013  ef443ff4 
[] (cache_alloc_refill) from [] (kmem_cache_alloc+0x7c/0xd4)
[] (kmem_cache_alloc) from []
(__arm_v7s_alloc_table+0x5c/0x278)
[] (__arm_v7s_alloc_table) from []
(__arm_v7s_map.constprop.6+0x68/0x25c)
[] (__arm_v7s_map.constprop.6) from []
(arm_v7s_map+0x34/0xa4)
[] (arm_v7s_map) from [] (arm_v7s_do_selftests+0x140/0x418)
[] (arm_v7s_do_selftests) from []
(do_one_initcall+0x100/0x1b4)
[] (do_one_initcall) from []
(kernel_init_freeable+0x120/0x1e8)
[] (kernel_init_freeable) from [] (kernel_init+0x8/0xec)
[] (kernel_init) from [] (ret_from_fork+0x14/0x2c)
Code: 1a03 e7f001f2 e3130001 0a00 (e7f001f2)
---[ end trace 190f6f6b84352efd ]---
Kernel panic - not