Re: [PATCH v3 1/2] acpica: iort: Update SMMUv3 header for proximity domain mapping

2017-06-19 Thread Ganapatrao Kulkarni
On Mon, Jun 19, 2017 at 11:24 PM, Robin Murphy  wrote:
> On 08/06/17 05:44, Ganapatrao Kulkarni wrote:
>> ARM IORT specification (rev. C) has added two new fields to define
>> proximity domain for the SMMUv3 node in the IORT table.
>>
>> Proximity Domain Valid:
>>   Set to 1 if the value provided in the Proximity Domain field is
>>   valid. Set to 0 otherwise.
>>
>> Proximity domain:
>>   If the Proximity Domain Valid flag is set to 1, this entry
>>   provides the proximity domain to which this SMMU
>>   instance belongs.
>>
>> Update header file to reflect this.
>>
>> Signed-off-by: Ganapatrao Kulkarni 
>> ---
>>  include/acpi/actbl2.h | 4 
>>  1 file changed, 4 insertions(+)
>>
>> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
>> index 4b306a6..389e91f 100644
>> --- a/include/acpi/actbl2.h
>> +++ b/include/acpi/actbl2.h
>> @@ -805,6 +805,9 @@ struct acpi_iort_smmu_v3 {
>>   u32 pri_gsiv;
>>   u32 gerr_gsiv;
>>   u32 sync_gsiv;
>> + u8 pxm;
>> + u8 reserved1;
>> + u16 reserved2;
>
> Why add the padding if you're not also adding the following field that
> it aligns? (side note: could it not just be a u8[3]?)

added to align as well to comply with  the spec.

>
> If the actual structure definition is changing, do there not need to be
> corresponding IASL changes too?

yes, it is been added and sent to acpica devel ML.
https://lists.acpica.org/pipermail/devel/2017-June/001243.html

>
>>  };
>>
>>  /* Values for Model field above */
>> @@ -817,6 +820,7 @@ struct acpi_iort_smmu_v3 {
>>
>>  #define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE   (1)
>>  #define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (1<<1)
>> +#define ACPI_IORT_SMMU_V3_PXM_VALID (1<<3)
>
> Maybe it's just me, but "PXM" seems incredibly cryptic.

PXM stands for proximity(refer ACPI spec)
it is widely used in spec and also in Linux kernel.

>
> Robin.
>
>>
>>  
>> /***
>>   *
>>
>

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


[patch 10/55] x86/msi: Provide new iommu irqdomain interface

2017-06-19 Thread Thomas Gleixner
Provide a new interface for creating the iommu remapping domains, so that
the caller can supply a name and a id in order to create named irqdomains.

Signed-off-by: Thomas Gleixner 
Cc: Joerg Roedel 
Cc: iommu@lists.linux-foundation.org
---
 arch/x86/include/asm/irq_remapping.h |2 ++
 arch/x86/kernel/apic/msi.c   |   15 +++
 2 files changed, 17 insertions(+)

--- a/arch/x86/include/asm/irq_remapping.h
+++ b/arch/x86/include/asm/irq_remapping.h
@@ -56,6 +56,8 @@ irq_remapping_get_irq_domain(struct irq_
 
 /* Create PCI MSI/MSIx irqdomain, use @parent as the parent irqdomain. */
 extern struct irq_domain *arch_create_msi_irq_domain(struct irq_domain 
*parent);
+extern struct irq_domain *
+arch_create_remap_msi_irq_domain(struct irq_domain *par, const char *n, int 
id);
 
 /* Get parent irqdomain for interrupt remapping irqdomain */
 static inline struct irq_domain *arch_get_ir_parent_domain(void)
--- a/arch/x86/kernel/apic/msi.c
+++ b/arch/x86/kernel/apic/msi.c
@@ -167,10 +167,25 @@ static struct msi_domain_info pci_msi_ir
.handler_name   = "edge",
 };
 
+struct irq_domain *arch_create_remap_msi_irq_domain(struct irq_domain *parent,
+   const char *name, int id)
+{
+   struct fwnode_handle *fn;
+   struct irq_domain *d;
+
+   fn = irq_domain_alloc_named_id_fwnode(name, id);
+   if (!fn)
+   return NULL;
+   d = pci_msi_create_irq_domain(fn, &pci_msi_ir_domain_info, parent);
+   kfree(fn);
+   return d;
+}
+
 struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent)
 {
return pci_msi_create_irq_domain(NULL, &pci_msi_ir_domain_info, parent);
 }
+
 #endif
 
 #ifdef CONFIG_DMAR_TABLE


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


[patch 03/55] iommu/vt-d: Add name to irq chip

2017-06-19 Thread Thomas Gleixner
Add the missing name, so debugging will work proper.

Signed-off-by: Thomas Gleixner 
Cc: Joerg Roedel 
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/intel_irq_remapping.c |9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -1205,10 +1205,11 @@ static int intel_ir_set_vcpu_affinity(st
 }
 
 static struct irq_chip intel_ir_chip = {
-   .irq_ack = ir_ack_apic_edge,
-   .irq_set_affinity = intel_ir_set_affinity,
-   .irq_compose_msi_msg = intel_ir_compose_msi_msg,
-   .irq_set_vcpu_affinity = intel_ir_set_vcpu_affinity,
+   .name   = "INTEL-IR",
+   .irq_ack= ir_ack_apic_edge,
+   .irq_set_affinity   = intel_ir_set_affinity,
+   .irq_compose_msi_msg= intel_ir_compose_msi_msg,
+   .irq_set_vcpu_affinity  = intel_ir_set_vcpu_affinity,
 };
 
 static void intel_irq_remapping_prepare_irte(struct intel_ir_data *data,


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


[patch 12/55] iommu/amd: Use named irq domain interface

2017-06-19 Thread Thomas Gleixner
Signed-off-by: Thomas Gleixner 
Cc: Joerg Roedel 
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/amd_iommu.c |   13 ++---
 1 file changed, 10 insertions(+), 3 deletions(-)

--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4395,13 +4395,20 @@ static struct irq_chip amd_ir_chip = {
 
 int amd_iommu_create_irq_domain(struct amd_iommu *iommu)
 {
-   iommu->ir_domain = irq_domain_add_tree(NULL, &amd_ir_domain_ops, iommu);
+   struct fwnode_handle *fn;
+
+   fn = irq_domain_alloc_named_id_fwnode("AMD-IR", iommu->index);
+   if (!fn)
+   return -ENOMEM;
+   iommu->ir_domain = irq_domain_create_tree(fn, &amd_ir_domain_ops, 
iommu);
+   kfree(fn);
if (!iommu->ir_domain)
return -ENOMEM;
 
iommu->ir_domain->parent = arch_get_ir_parent_domain();
-   iommu->msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
-
+   iommu->msi_domain = arch_create_remap_msi_irq_domain(iommu->ir_domain,
+"AMD-IR-MSI",
+iommu->index);
return 0;
 }
 


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


[patch 11/55] iommu/vt-d: Use named irq domain interface

2017-06-19 Thread Thomas Gleixner
Signed-off-by: Thomas Gleixner 
Cc: Joerg Roedel 
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/intel_irq_remapping.c |   22 --
 1 file changed, 16 insertions(+), 6 deletions(-)

--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -500,8 +500,9 @@ static void iommu_enable_irq_remapping(s
 static int intel_setup_irq_remapping(struct intel_iommu *iommu)
 {
struct ir_table *ir_table;
-   struct page *pages;
+   struct fwnode_handle *fn;
unsigned long *bitmap;
+   struct page *pages;
 
if (iommu->ir_table)
return 0;
@@ -525,15 +526,24 @@ static int intel_setup_irq_remapping(str
goto out_free_pages;
}
 
-   iommu->ir_domain = irq_domain_add_hierarchy(arch_get_ir_parent_domain(),
-   0, INTR_REMAP_TABLE_ENTRIES,
-   NULL, &intel_ir_domain_ops,
-   iommu);
+   fn = irq_domain_alloc_named_id_fwnode("INTEL-IR", iommu->seq_id);
+   if (!fn)
+   goto out_free_bitmap;
+
+   iommu->ir_domain =
+   irq_domain_create_hierarchy(arch_get_ir_parent_domain(),
+   0, INTR_REMAP_TABLE_ENTRIES,
+   fn, &intel_ir_domain_ops,
+   iommu);
+   kfree(fn);
if (!iommu->ir_domain) {
pr_err("IR%d: failed to allocate irqdomain\n", iommu->seq_id);
goto out_free_bitmap;
}
-   iommu->ir_msi_domain = arch_create_msi_irq_domain(iommu->ir_domain);
+   iommu->ir_msi_domain =
+   arch_create_remap_msi_irq_domain(iommu->ir_domain,
+"INTEL-IR-MSI",
+iommu->seq_id);
 
ir_table->base = page_address(pages);
ir_table->bitmap = bitmap;


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


[patch 02/55] iommu/amd: Add name to irq chip

2017-06-19 Thread Thomas Gleixner
Add the missing name, so debugging will work proper.

Signed-off-by: Thomas Gleixner 
Cc: Joerg Roedel 
Cc: iommu@lists.linux-foundation.org
---
 drivers/iommu/amd_iommu.c |9 +
 1 file changed, 5 insertions(+), 4 deletions(-)

--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -4386,10 +4386,11 @@ static void ir_compose_msi_msg(struct ir
 }
 
 static struct irq_chip amd_ir_chip = {
-   .irq_ack = ir_ack_apic_edge,
-   .irq_set_affinity = amd_ir_set_affinity,
-   .irq_set_vcpu_affinity = amd_ir_set_vcpu_affinity,
-   .irq_compose_msi_msg = ir_compose_msi_msg,
+   .name   = "AMD-IR",
+   .irq_ack= ir_ack_apic_edge,
+   .irq_set_affinity   = amd_ir_set_affinity,
+   .irq_set_vcpu_affinity  = amd_ir_set_vcpu_affinity,
+   .irq_compose_msi_msg= ir_compose_msi_msg,
 };
 
 int amd_iommu_create_irq_domain(struct amd_iommu *iommu)


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


Re: [PATCH v3 1/2] acpica: iort: Update SMMUv3 header for proximity domain mapping

2017-06-19 Thread Robin Murphy
On 08/06/17 05:44, Ganapatrao Kulkarni wrote:
> ARM IORT specification (rev. C) has added two new fields to define
> proximity domain for the SMMUv3 node in the IORT table.
> 
> Proximity Domain Valid:
>   Set to 1 if the value provided in the Proximity Domain field is
>   valid. Set to 0 otherwise.
> 
> Proximity domain:
>   If the Proximity Domain Valid flag is set to 1, this entry
>   provides the proximity domain to which this SMMU
>   instance belongs.
> 
> Update header file to reflect this.
> 
> Signed-off-by: Ganapatrao Kulkarni 
> ---
>  include/acpi/actbl2.h | 4 
>  1 file changed, 4 insertions(+)
> 
> diff --git a/include/acpi/actbl2.h b/include/acpi/actbl2.h
> index 4b306a6..389e91f 100644
> --- a/include/acpi/actbl2.h
> +++ b/include/acpi/actbl2.h
> @@ -805,6 +805,9 @@ struct acpi_iort_smmu_v3 {
>   u32 pri_gsiv;
>   u32 gerr_gsiv;
>   u32 sync_gsiv;
> + u8 pxm;
> + u8 reserved1;
> + u16 reserved2;

Why add the padding if you're not also adding the following field that
it aligns? (side note: could it not just be a u8[3]?)

If the actual structure definition is changing, do there not need to be
corresponding IASL changes too?

>  };
>  
>  /* Values for Model field above */
> @@ -817,6 +820,7 @@ struct acpi_iort_smmu_v3 {
>  
>  #define ACPI_IORT_SMMU_V3_COHACC_OVERRIDE   (1)
>  #define ACPI_IORT_SMMU_V3_HTTU_OVERRIDE (1<<1)
> +#define ACPI_IORT_SMMU_V3_PXM_VALID (1<<3)

Maybe it's just me, but "PXM" seems incredibly cryptic.

Robin.

>  
>  
> /***
>   *
> 

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


Re: [PATCH v2 2/2] iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801

2017-06-19 Thread Robin Murphy
On 19/06/17 16:45, shameer wrote:
> The HiSilicon erratum 161010801 describes the limitation of HiSilicon
> platforms Hip06/Hip07 to support the SMMU mappings for MSI transactions.
> 
> On these platforms GICv3 ITS translator is presented with the deviceID
> by extending the MSI payload data to 64 bits to include the deviceID.
> Hence, the PCIe controller on this platforms has to differentiate the
> MSI payload against other DMA payload and has to modify the MSI payload.
> This basically makes it difficult for this platforms to have a SMMU
> translation for MSI.
> 
> This patch implements a ACPI table based quirk to reserve the hw msi
> regions in the smmu-v3 driver which means these address regions will
> not be translated and will be excluded from iova allocations.
> 
> Signed-off-by: shameer 
> ---
>  drivers/iommu/arm-smmu-v3.c | 29 -
>  1 file changed, 24 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
> index abe4b88..f03c63b 100644
> --- a/drivers/iommu/arm-smmu-v3.c
> +++ b/drivers/iommu/arm-smmu-v3.c
> @@ -597,6 +597,7 @@ struct arm_smmu_device {
>   u32 features;
>  
>  #define ARM_SMMU_OPT_SKIP_PREFETCH   (1 << 0)
> +#define ARM_SMMU_OPT_RESV_HW_MSI (1 << 1)
>   u32 options;
>  
>   struct arm_smmu_cmdqcmdq;
> @@ -1904,14 +1905,31 @@ static void arm_smmu_get_resv_regions(struct device 
> *dev,
> struct list_head *head)
>  {
>   struct iommu_resv_region *region;
> + struct arm_smmu_device *smmu;
> + struct iommu_fwspec *fwspec = dev->iommu_fwspec;
>   int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
>  
> - region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
> -  prot, IOMMU_RESV_SW_MSI);
> - if (!region)
> - return;
> + smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
> +
> + if (smmu && (smmu->options & ARM_SMMU_OPT_RESV_HW_MSI) &&

AFAICS, iommu_get_resv_regions is only ever called on devices which are
at least already part of an iommu_group, so smmu should never
legitimately be NULL. I'd say if you really want to be robust against
flagrant API misuse, at least WARN_ON and bail out immediately.

Robin.

> +   dev_is_pci(dev)) {
> + int ret = -EINVAL;
> +
> + if (!is_of_node(smmu->dev->fwnode))
> + ret = iort_iommu_its_get_resv_regions(dev, head);
>  
> - list_add_tail(®ion->list, head);
> + if (ret) {
> + dev_warn(dev, "HW MSI region resv failed: %d\n", ret);
> + return;
> + }
> + } else {
> + region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
> +  prot, IOMMU_RESV_SW_MSI);
> + if (!region)
> + return;
> +
> + list_add_tail(®ion->list, head);
> + }
>  
>   iommu_dma_get_resv_regions(dev, head);
>  }
> @@ -2611,6 +2629,7 @@ static void parse_driver_acpi_options(struct 
> acpi_iort_smmu_v3 *iort_smmu,
>   switch (iort_smmu->model) {
>   case ACPI_IORT_SMMU_HISILICON_HI161X:
>   smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH;
> + smmu->options |= ARM_SMMU_OPT_RESV_HW_MSI;
>   break;
>   default:
>   break;
> 

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


Re: [PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature

2017-06-19 Thread Robin Murphy
On 19/06/17 10:14, Magnus Damm wrote:
> From: Magnus Damm 
> 
> Add root device handling to the IPMMU driver by allowing certain
> DT compat strings to enable has_cache_leaf_nodes that in turn will
> support both root devices with interrupts and leaf devices that
> face the actual IPMMU consumer devices.
> 
> Signed-off-by: Magnus Damm 
> ---
> 
>  Changes since V3:
>  - Reworked root finding code to make it easier to follow, thanks Geert!
>  
>  Changes since V2:
>  - Fixed a bug in ipmmu_find_root() when only leaf devices are present
>  - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices
> 
>  Changes since V1:
>  - Moved patch to earlier in the series
>  - Updated code to work with recent changes in:
>[PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3
> 
>  drivers/iommu/ipmmu-vmsa.c |   95 
> 
>  1 file changed, 78 insertions(+), 17 deletions(-)
> 
> --- 0015/drivers/iommu/ipmmu-vmsa.c
> +++ work/drivers/iommu/ipmmu-vmsa.c   2017-06-19 13:59:41.050607110 +0900
> @@ -36,6 +36,7 @@
>  
>  struct ipmmu_features {
>   bool use_ns_alias_offset;
> + bool has_cache_leaf_nodes;
>  };
>  
>  struct ipmmu_vmsa_device {
> @@ -44,6 +45,7 @@ struct ipmmu_vmsa_device {
>   struct iommu_device iommu;
>   struct list_head list;
>   const struct ipmmu_features *features;
> + bool is_leaf;
>   unsigned int num_utlbs;
>   spinlock_t lock;/* Protects ctx and domains[] */
>   DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
> @@ -54,6 +56,7 @@ struct ipmmu_vmsa_device {
>  
>  struct ipmmu_vmsa_domain {
>   struct ipmmu_vmsa_device *mmu;
> + struct ipmmu_vmsa_device *root;

Would it not make more sense for this to be a property of the
ipmmu_device itself, rather than per ipmmu_domain? I may of course have
got the wrong idea of the topology here, but it seems as if mmu->is_leaf
could be expressed as mmu->root == mmu vs. mmu->root == some_other_mmu,
at which point there's one less thing to worry about in the domain.

>   struct iommu_domain io_domain;
>  
>   struct io_pgtable_cfg cfg;
> @@ -203,6 +206,44 @@ static struct ipmmu_vmsa_iommu_priv *to_
>  #define IMUASID_ASID0_SHIFT  0
>  
>  /* 
> -
> + * Root device handling
> + */
> +
> +static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu)
> +{
> + if (mmu->features->has_cache_leaf_nodes)
> + return mmu->is_leaf ? false : true> +   else
> + return true; /* older IPMMU hardware treated as single root */
> +}
> +
> +static struct ipmmu_vmsa_device *__ipmmu_find_root(void)
> +{
> + struct ipmmu_vmsa_device *mmu;
> + struct ipmmu_vmsa_device *root = NULL;
> +
> + spin_lock(&ipmmu_devices_lock);
> +
> + list_for_each_entry(mmu, &ipmmu_devices, list) {
> + if (ipmmu_is_root(mmu)) {
> + root = mmu;
> + break;
> + }
> + }
> +
> + spin_unlock(&ipmmu_devices_lock);
> + return root;
> +}

I wonder if it might be tidier to use driver_for_each_device() for this,
and remove the local list at the same time as its previous user.

Either way, what happens if things end up hapening in this order:

1: probe leaf IPMMU B
2: probe device X behind IPMMU B
3: create and attach default domain for device X
4: probe root IPMMU A

We know X will defer if B isn't ready, but it doesn't seem (at a glance,
admittedly) that there's anything to enforce the expected probe ordering
between A and B. This seems like another argument for moving the
root/leaf association up to the device level, such that B can look up A
once in its own probe routine, and defer itself if necessary.

> +
> +static struct ipmmu_vmsa_device *ipmmu_find_root(struct ipmmu_vmsa_device 
> *leaf)
> +{
> + if (ipmmu_is_root(leaf))
> + return leaf;
> + else
> + return __ipmmu_find_root();

Well actually, looking at that, I think what we have here is a very
long-winded way of implementing this:

static ipmmu_vmsa_device *root;

Yuck.

> +}
> +
> +/* 
> -
>   * Read/Write Access
>   */
>  
> @@ -219,13 +260,13 @@ static void ipmmu_write(struct ipmmu_vms
>  
>  static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg)
>  {
> - return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg);
> + return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg);
>  }
>  
>  static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int 
> reg,
>   u32 data)
>  {
> - ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data);
> + ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data);
>  }
>  
>  /* 
> -
> @@ 

Re: [PATCH v6 26/34] iommu/amd: Allow the AMD IOMMU to work with memory encryption

2017-06-19 Thread Borislav Petkov
On Thu, Jun 15, 2017 at 11:33:41AM -0500, Tom Lendacky wrote:
> Changing the signature back reverts to the original way, so this can be
> looked at separate from this patchset then.

Right, the patch which added the volatile thing was this one:

  4bf5beef578e ("iommu/amd: Don't put completion-wait semaphore on stack")

and the commit message doesn't say why the thing needs to be volatile at
all.

Joerg?

-- 
Regards/Gruss,
Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [PATCH 01/04] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister()

2017-06-19 Thread Robin Murphy
On 15/06/17 11:29, Magnus Damm wrote:
> From: Magnus Damm 
> 
> Extend the driver to make use of iommu_device_register()/unregister()
> functions together with iommu_device_set_ops() and iommu_set_fwnode().
> 
> These used to be part of the earlier posted 64-bit ARM (r8a7795) series but
> it turns out that these days they are required on 32-bit ARM as well.
> 
> Signed-off-by: Magnus Damm 
> ---
> 
>  drivers/iommu/ipmmu-vmsa.c |   10 ++
>  1 file changed, 10 insertions(+)
> 
> --- 0001/drivers/iommu/ipmmu-vmsa.c
> +++ work/drivers/iommu/ipmmu-vmsa.c   2017-06-15 16:57:21.890607110 +0900
> @@ -35,6 +35,7 @@
>  struct ipmmu_vmsa_device {
>   struct device *dev;
>   void __iomem *base;
> + struct iommu_device iommu;
>   struct list_head list;
>  
>   unsigned int num_utlbs;
> @@ -1054,6 +1055,13 @@ static int ipmmu_probe(struct platform_d
>  
>   ipmmu_device_reset(mmu);
>  
> + ret = iommu_device_register(&mmu->iommu);
> + if (ret)
> + return ret;
> +
> + iommu_device_set_ops(&mmu->iommu, &ipmmu_ops);
> + iommu_device_set_fwnode(&mmu->iommu, &pdev->dev.of_node->fwnode);

Nit: I guess it works out OK in practice, but it does look rather weird
to be initialising the iommu_device's members *after* registering it.

Robin.

> +
>   /*
>* We can't create the ARM mapping here as it requires the bus to have
>* an IOMMU, which only happens when bus_set_iommu() is called in
> @@ -1077,6 +1085,8 @@ static int ipmmu_remove(struct platform_
>   list_del(&mmu->list);
>   spin_unlock(&ipmmu_devices_lock);
>  
> + iommu_device_unregister(&mmu->iommu);
> +
>  #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA)
>   arm_iommu_release_mapping(mmu->mapping);
>  #endif
> 

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


Re: [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update

2017-06-19 Thread Robin Murphy
Hi Magnus,

On 15/06/17 11:29, Magnus Damm wrote:
> iommu/ipmmu-vmsa: 32-bit ARM update
> 
> [PATCH 01/04] iommu/ipmmu-vmsa: Use iommu_device_register()/unregister()
> [PATCH 02/04] iommu/ipmmu-vmsa: Consistent ->of_xlate() handling
> [PATCH 03/04] iommu/ipmmu-vmsa: Use fwspec on both 32 and 64-bit ARM
> [PATCH 04/04] iommu/ipmmu-vmsa: Replace local utlb code with fwspec ids
> 
> This series updates the IPMMU driver to make use of recent IOMMU framework
> changes and also improves code sharing in the driver between the 32-bit and
> 64-bit dma-mapping architecture glue code.

Nice! I did try rebasing my original patch myself but it quickly got
very messy. I also had the below beforehand as preliminary cleanup for
getting rid of the ipmmu_vmsa_iommu_priv structure altogether (i.e. so
fwspec->priv can just hold the ipmmu_vmsa_device pointer directly) - if
it does actually work as intended, feel free to take it ;)

Thanks,
Robin.

> Suggested-by: Robin Murphy  (Patch 2 and 4)
> Signed-off-by: Robin Murphy  (Patch 3)
> Signed-off-by: Magnus Damm 
> ---
> 
>  Developed on renesas-drivers-2017-06-13-v4.12-rc5 and rebased to 
> next-20170614
> 
>  drivers/iommu/ipmmu-vmsa.c |  186 
> +++-
>  1 file changed, 49 insertions(+), 137 deletions(-)
> 

>8-
From: Robin Murphy 
Subject: [PATCH] iommu/ipmmu-vmsa: Clean up group allocation

With the new IOMMU group support, we go through quite the merry dance
in order to find masters behind the same IPMMU instance, so that we can
ensure they are grouped together. None of which is really necessary,
since the master's private data already points to the particular IPMMU
it is associated with, and that IPMMU instance data is the perfect place
to keep track of a per-instance group.

Signed-off-by: Robin Murphy 
---
 drivers/iommu/ipmmu-vmsa.c | 53
+++---
 1 file changed, 8 insertions(+), 45 deletions(-)

diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 2a38aa15be17..9d75d7553e20 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -43,6 +43,7 @@ struct ipmmu_vmsa_device {
struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];

struct dma_iommu_mapping *mapping;
+   struct iommu_group *group;
 };

 struct ipmmu_vmsa_domain {
@@ -60,8 +61,6 @@ struct ipmmu_vmsa_iommu_priv {
struct ipmmu_vmsa_device *mmu;
unsigned int *utlbs;
unsigned int num_utlbs;
-   struct device *dev;
-   struct list_head list;
 };

 static DEFINE_SPINLOCK(ipmmu_devices_lock);
@@ -724,7 +723,6 @@ static int ipmmu_init_platform_device(struct device
*dev)
priv->mmu = mmu;
priv->utlbs = utlbs;
priv->num_utlbs = num_utlbs;
-   priv->dev = dev;
set_priv(dev, priv);
return 0;

@@ -854,9 +852,6 @@ static const struct iommu_ops ipmmu_ops = {

 #ifdef CONFIG_IOMMU_DMA

-static DEFINE_SPINLOCK(ipmmu_slave_devices_lock);
-static LIST_HEAD(ipmmu_slave_devices);
-
 static struct iommu_domain *ipmmu_domain_alloc_dma(unsigned type)
 {
struct iommu_domain *io_domain = NULL;
@@ -904,57 +899,25 @@ static int ipmmu_add_device_dma(struct device *dev)
if (IS_ERR(group))
return PTR_ERR(group);

-   spin_lock(&ipmmu_slave_devices_lock);
-   list_add(&to_priv(dev)->list, &ipmmu_slave_devices);
-   spin_unlock(&ipmmu_slave_devices_lock);
return 0;
 }

 static void ipmmu_remove_device_dma(struct device *dev)
 {
-   struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev);
-
-   spin_lock(&ipmmu_slave_devices_lock);
-   list_del(&priv->list);
-   spin_unlock(&ipmmu_slave_devices_lock);
-
iommu_group_remove_device(dev);
 }

-static struct device *ipmmu_find_sibling_device(struct device *dev)
-{
-   struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev);
-   struct ipmmu_vmsa_iommu_priv *sibling_priv = NULL;
-   bool found = false;
-
-   spin_lock(&ipmmu_slave_devices_lock);
-
-   list_for_each_entry(sibling_priv, &ipmmu_slave_devices, list) {
-   if (priv == sibling_priv)
-   continue;
-   if (sibling_priv->mmu == priv->mmu) {
-   found = true;
-   break;
-   }
-   }
-
-   spin_unlock(&ipmmu_slave_devices_lock);
-
-   return found ? sibling_priv->dev : NULL;
-}
-
 static struct iommu_group *ipmmu_find_group_dma(struct device *dev)
 {
-   struct iommu_group *group;
-   struct device *sibling;
+   struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev);
+   struct ipmmu_vmsa_device *mmu = priv->mmu;

-   sibling = ipmmu_find_sibling_device(dev);
-   if (sibling)
-   group = iommu_group_get(sibling);
-   if (!sibling || IS_ERR(group))
-   group = generic_device_group(dev);
+   if (mmu->group)
+   return iommu_group_ref_get(mmu->group);

-   return group;
+   mm

[PATCH v2 2/2] iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801

2017-06-19 Thread shameer
The HiSilicon erratum 161010801 describes the limitation of HiSilicon
platforms Hip06/Hip07 to support the SMMU mappings for MSI transactions.

On these platforms GICv3 ITS translator is presented with the deviceID
by extending the MSI payload data to 64 bits to include the deviceID.
Hence, the PCIe controller on this platforms has to differentiate the
MSI payload against other DMA payload and has to modify the MSI payload.
This basically makes it difficult for this platforms to have a SMMU
translation for MSI.

This patch implements a ACPI table based quirk to reserve the hw msi
regions in the smmu-v3 driver which means these address regions will
not be translated and will be excluded from iova allocations.

Signed-off-by: shameer 
---
 drivers/iommu/arm-smmu-v3.c | 29 -
 1 file changed, 24 insertions(+), 5 deletions(-)

diff --git a/drivers/iommu/arm-smmu-v3.c b/drivers/iommu/arm-smmu-v3.c
index abe4b88..f03c63b 100644
--- a/drivers/iommu/arm-smmu-v3.c
+++ b/drivers/iommu/arm-smmu-v3.c
@@ -597,6 +597,7 @@ struct arm_smmu_device {
u32 features;
 
 #define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
+#define ARM_SMMU_OPT_RESV_HW_MSI   (1 << 1)
u32 options;
 
struct arm_smmu_cmdqcmdq;
@@ -1904,14 +1905,31 @@ static void arm_smmu_get_resv_regions(struct device 
*dev,
  struct list_head *head)
 {
struct iommu_resv_region *region;
+   struct arm_smmu_device *smmu;
+   struct iommu_fwspec *fwspec = dev->iommu_fwspec;
int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
 
-   region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
-prot, IOMMU_RESV_SW_MSI);
-   if (!region)
-   return;
+   smmu = arm_smmu_get_by_fwnode(fwspec->iommu_fwnode);
+
+   if (smmu && (smmu->options & ARM_SMMU_OPT_RESV_HW_MSI) &&
+ dev_is_pci(dev)) {
+   int ret = -EINVAL;
+
+   if (!is_of_node(smmu->dev->fwnode))
+   ret = iort_iommu_its_get_resv_regions(dev, head);
 
-   list_add_tail(®ion->list, head);
+   if (ret) {
+   dev_warn(dev, "HW MSI region resv failed: %d\n", ret);
+   return;
+   }
+   } else {
+   region = iommu_alloc_resv_region(MSI_IOVA_BASE, MSI_IOVA_LENGTH,
+prot, IOMMU_RESV_SW_MSI);
+   if (!region)
+   return;
+
+   list_add_tail(®ion->list, head);
+   }
 
iommu_dma_get_resv_regions(dev, head);
 }
@@ -2611,6 +2629,7 @@ static void parse_driver_acpi_options(struct 
acpi_iort_smmu_v3 *iort_smmu,
switch (iort_smmu->model) {
case ACPI_IORT_SMMU_HISILICON_HI161X:
smmu->options |= ARM_SMMU_OPT_SKIP_PREFETCH;
+   smmu->options |= ARM_SMMU_OPT_RESV_HW_MSI;
break;
default:
break;
-- 
1.9.1


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


[PATCH v2 1/2] acpi:iort: Add an IORT helper function to reserve HW ITS address regions for IOMMU drivers

2017-06-19 Thread shameer
The helper function retrieves ITS address regions through IORT
device <-> ITS mappings and reserves it so that these regions
will not be translated by IOMMU and will be excluded from IOVA
allocations. IOMMU drivers can use this to implement their
.get_resv_regions callback.

Signed-off-by: shameer 
---
 drivers/acpi/arm64/iort.c| 91 ++--
 drivers/irqchip/irq-gic-v3-its.c |  3 +-
 include/linux/acpi_iort.h|  7 +++-
 3 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index c5fecf9..4810dbe 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -34,6 +34,7 @@
 struct iort_its_msi_chip {
struct list_headlist;
struct fwnode_handle*fw_node;
+   phys_addr_t base_addr;
u32 translation_id;
 };
 
@@ -131,14 +132,16 @@ typedef acpi_status (*iort_find_node_callback)
 static DEFINE_SPINLOCK(iort_msi_chip_lock);
 
 /**
- * iort_register_domain_token() - register domain token and related ITS ID
- * to the list from where we can get it back later on.
+ * iort_register_domain_token() - register domain token along with related
+ * ITS ID and base address to the list from where we can get it back later on.
  * @trans_id: ITS ID.
+ * @base: ITS base address.
  * @fw_node: Domain token.
  *
  * Returns: 0 on success, -ENOMEM if no memory when allocating list element
  */
-int iort_register_domain_token(int trans_id, struct fwnode_handle *fw_node)
+int iort_register_domain_token(int trans_id, phys_addr_t base,
+  struct fwnode_handle *fw_node)
 {
struct iort_its_msi_chip *its_msi_chip;
 
@@ -148,6 +151,7 @@ int iort_register_domain_token(int trans_id, struct 
fwnode_handle *fw_node)
 
its_msi_chip->fw_node = fw_node;
its_msi_chip->translation_id = trans_id;
+   its_msi_chip->base_addr = base;
 
spin_lock(&iort_msi_chip_lock);
list_add(&its_msi_chip->list, &iort_msi_chip_list);
@@ -491,6 +495,24 @@ int iort_pmsi_get_dev_id(struct device *dev, u32 *dev_id)
return -ENODEV;
 }
 
+static int iort_find_its_base(u32 its_id, phys_addr_t *base)
+{
+   struct iort_its_msi_chip *its_msi_chip;
+   bool match = false;
+
+   spin_lock(&iort_msi_chip_lock);
+   list_for_each_entry(its_msi_chip, &iort_msi_chip_list, list) {
+   if (its_msi_chip->translation_id == its_id) {
+   *base = its_msi_chip->base_addr;
+   match = true;
+   break;
+   }
+   }
+   spin_unlock(&iort_msi_chip_lock);
+
+   return match ? 0 : -ENODEV;
+}
+
 /**
  * iort_dev_find_its_id() - Find the ITS identifier for a device
  * @dev: The device.
@@ -649,6 +671,67 @@ int iort_add_device_replay(const struct iommu_ops *ops, 
struct device *dev)
 
return err;
 }
+
+/**
+ * iort_iommu_its_get_resv_regions - Reserved region driver helper
+ * @dev: Device from iommu_get_resv_regions()
+ * @list: Reserved region list from iommu_get_resv_regions()
+ *
+ * Returns: 0 on at least one ITS address region reservation,
+ *  appropriate error value otherwise.
+ *
+ * IOMMU drivers can use this to implement their .get_resv_regions callback
+ * for reserving the HW ITS address regions.
+ */
+int iort_iommu_its_get_resv_regions(struct device *dev, struct list_head *head)
+{
+   int i;
+   struct acpi_iort_its_group *its;
+   struct acpi_iort_node *node, *its_node = NULL;
+   bool resv = false;
+
+   node = iort_find_dev_node(dev);
+   if (!node)
+   return -ENODEV;
+
+   if (dev_is_pci(dev)) {
+   u32 rid;
+
+   pci_for_each_dma_alias(to_pci_dev(dev), __get_pci_rid, &rid);
+   its_node = iort_node_map_id(node, rid, NULL, IORT_MSI_TYPE);
+   } else {
+   for (i = 0; i < node->mapping_count; i++) {
+   its_node = iort_node_map_platform_id(node, NULL,
+IORT_MSI_TYPE, i);
+   if (its_node)
+   break;
+   }
+   }
+
+   if (!its_node)
+   return -ENODEV;
+
+   /* Move to ITS specific data */
+   its = (struct acpi_iort_its_group *)its_node->node_data;
+
+   for (i = 0; i < its->its_count; i++) {
+   phys_addr_t base;
+
+   if (!iort_find_its_base(its->identifiers[i], &base)) {
+   int prot = IOMMU_WRITE | IOMMU_NOEXEC | IOMMU_MMIO;
+   struct iommu_resv_region *region;
+
+   region = iommu_alloc_resv_region(base, SZ_128K, prot,
+IOMMU_RESV_MSI);
+   if (region) {
+   list_add_tail(®ion->list, head);
+   resv = true;
+   

[PATCH v2 0/2] iommu/smmu-v3: Workaround for hisilicon 161010801 erratum(reserve HW MSI)

2017-06-19 Thread shameer
On certain HiSilicon platforms (Hip06/Hip07) the GIC ITS and
PCIe RC deviates from the standard implementation and this breaks
PCIe MSI functionality when SMMU is enabled.

The HiSilicon erratum 161010801 describes this limitation of certain
HiSilicon platforms to support the SMMU mappings for MSI transactions.
On these platforms GICv3 ITS translator is presented with the deviceID
by extending the MSI payload data to 64 bits to include the deviceID.
Hence, the PCIe controller on this platforms has to differentiate the
MSI payload against other DMA payload and has to modify the MSI payload.
This basically makes it difficult for this platforms to have a SMMU
translation for MSI.

This patch implements a ACPI table based quirk to reserve the hw msi
regions in the smmu-v3 driver which means these address regions will
not be translated and will be excluded from iova allocations.

To implement this quirk, the following changes are incorporated:

1. Added a generic helper function to IORT code to retrieve and
   reserve the HW ITS address regions.
2. Added quirk to SMMUv3 to reserve HW ITS address regions based
   on IORT SMMUv3 model.

This is based on the following patches:
1. https://patchwork.kernel.org/patch/9740733/
2. https://patchwork.kernel.org/patch/9730491/

Thanks,
Shameer

Changelog:

v1 --> v2

-patch 2/2: Invoke iort helper fn based on fwnode type(acpi).

RFCv2 -->PATCH

-Incorporated Lorenzo's review comments.

RFC v1 --> RFC v2

Based on Robin's review comments,
-Removed  the generic erratum framework.
-Using IORT/MADT tables to retrieve the ITS base addr instead
 of vendor specific CSRT table.

shameer (2):
  acpi:iort: Add an IORT helper function to reserve HW ITS address
regions for IOMMU drivers
  iommu/arm-smmu-v3:Enable ACPI based HiSilicon erratum 161010801

 drivers/acpi/arm64/iort.c| 91 ++--
 drivers/iommu/arm-smmu-v3.c  | 29 ++---
 drivers/irqchip/irq-gic-v3-its.c |  3 +-
 include/linux/acpi_iort.h|  7 +++-
 4 files changed, 120 insertions(+), 10 deletions(-)

-- 
1.9.1


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


[PATCH v3] iommu/arm-smmu: Plumb in new ACPI identifiers

2017-06-19 Thread Robin Murphy
Revision C of IORT now allows us to identify ARM MMU-401 and the Cavium
ThunderX implementation. Wire them up so that we can probe these models
once firmware starts using the new codes in place of generic ones, and
so that the appropriate features and quirks get enabled when we do.

For the sake of backports and mitigating sychronisation problems with
the ACPICA headers, we'll carry a backup copy of the new definitions
locally for the short term to make life simpler.

CC: sta...@vger.kernel.org # 4.10
Acked-by: Robert Richter 
Tested-by: Robert Richter 
Signed-off-by: Robin Murphy 
---

v3: The patch that actually landed in ACPICA was slightly tweaked for
self-consistency, so s/CAVIUM_SMMUV2/CAVIUM_THUNDERX/ to match.

 drivers/iommu/arm-smmu.c | 16 
 1 file changed, 16 insertions(+)

diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 7ec30b08b3bd..7ecd1a0b8419 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -312,6 +312,14 @@ enum arm_smmu_implementation {
CAVIUM_SMMUV2,
 };
 
+/* Until ACPICA headers cover IORT rev. C */
+#ifndef ACPI_IORT_SMMU_CORELINK_MMU401
+#define ACPI_IORT_SMMU_CORELINK_MMU401 0x4
+#endif
+#ifndef ACPI_IORT_SMMU_CAVIUM_THUNDERX
+#define ACPI_IORT_SMMU_CAVIUM_THUNDERX 0x5
+#endif
+
 struct arm_smmu_s2cr {
struct iommu_group  *group;
int count;
@@ -2073,6 +2081,10 @@ static int acpi_smmu_get_data(u32 model, struct 
arm_smmu_device *smmu)
smmu->version = ARM_SMMU_V1;
smmu->model = GENERIC_SMMU;
break;
+   case ACPI_IORT_SMMU_CORELINK_MMU401:
+   smmu->version = ARM_SMMU_V1_64K;
+   smmu->model = GENERIC_SMMU;
+   break;
case ACPI_IORT_SMMU_V2:
smmu->version = ARM_SMMU_V2;
smmu->model = GENERIC_SMMU;
@@ -2081,6 +2093,10 @@ static int acpi_smmu_get_data(u32 model, struct 
arm_smmu_device *smmu)
smmu->version = ARM_SMMU_V2;
smmu->model = ARM_MMU500;
break;
+   case ACPI_IORT_SMMU_CAVIUM_THUNDERX:
+   smmu->version = ARM_SMMU_V2;
+   smmu->model = CAVIUM_SMMUV2;
+   break;
default:
ret = -ENODEV;
}
-- 
2.12.2.dirty

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


Re: [PATCH 06/44] iommu/dma: don't rely on DMA_ERROR_CODE

2017-06-19 Thread Robin Murphy
On 16/06/17 19:10, Christoph Hellwig wrote:
> DMA_ERROR_CODE is not a public API and will go away soon.  dma dma-iommu
> driver already implements a proper ->mapping_error method, so it's only
> using the value internally.  Add a new local define using the value
> that arm64 which is the only current user of dma-iommu.

I was angling at just open-coding 0/!dma_addr/etc. for simplicity rather
than having anything #defined at all - nothing except the 4th and final
hunks actually have any relevance to  dma_mapping_error(), and I reckon
it's plenty clear enough in context. The rest is just proactively
blatting address arguments with "arbitrary definitely-invalid value",
which is more paranoia than anything else (and arguably unnecessary).

It's not the biggest deal, though, so either way:

Reviewed-by: Robin Murphy 

> Signed-off-by: Christoph Hellwig 
> ---
>  drivers/iommu/dma-iommu.c | 18 ++
>  1 file changed, 10 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> index 62618e77bedc..9403336f1fa6 100644
> --- a/drivers/iommu/dma-iommu.c
> +++ b/drivers/iommu/dma-iommu.c
> @@ -31,6 +31,8 @@
>  #include 
>  #include 
>  
> +#define IOMMU_MAPPING_ERROR  0
> +
>  struct iommu_dma_msi_page {
>   struct list_headlist;
>   dma_addr_t  iova;
> @@ -500,7 +502,7 @@ void iommu_dma_free(struct device *dev, struct page 
> **pages, size_t size,
>  {
>   __iommu_dma_unmap(iommu_get_domain_for_dev(dev), *handle, size);
>   __iommu_dma_free_pages(pages, PAGE_ALIGN(size) >> PAGE_SHIFT);
> - *handle = DMA_ERROR_CODE;
> + *handle = IOMMU_MAPPING_ERROR;
>  }
>  
>  /**
> @@ -533,7 +535,7 @@ struct page **iommu_dma_alloc(struct device *dev, size_t 
> size, gfp_t gfp,
>   dma_addr_t iova;
>   unsigned int count, min_size, alloc_sizes = domain->pgsize_bitmap;
>  
> - *handle = DMA_ERROR_CODE;
> + *handle = IOMMU_MAPPING_ERROR;
>  
>   min_size = alloc_sizes & -alloc_sizes;
>   if (min_size < PAGE_SIZE) {
> @@ -627,11 +629,11 @@ static dma_addr_t __iommu_dma_map(struct device *dev, 
> phys_addr_t phys,
>  
>   iova = iommu_dma_alloc_iova(domain, size, dma_get_mask(dev), dev);
>   if (!iova)
> - return DMA_ERROR_CODE;
> + return IOMMU_MAPPING_ERROR;
>  
>   if (iommu_map(domain, iova, phys - iova_off, size, prot)) {
>   iommu_dma_free_iova(cookie, iova, size);
> - return DMA_ERROR_CODE;
> + return IOMMU_MAPPING_ERROR;
>   }
>   return iova + iova_off;
>  }
> @@ -671,7 +673,7 @@ static int __finalise_sg(struct device *dev, struct 
> scatterlist *sg, int nents,
>  
>   s->offset += s_iova_off;
>   s->length = s_length;
> - sg_dma_address(s) = DMA_ERROR_CODE;
> + sg_dma_address(s) = IOMMU_MAPPING_ERROR;
>   sg_dma_len(s) = 0;
>  
>   /*
> @@ -714,11 +716,11 @@ static void __invalidate_sg(struct scatterlist *sg, int 
> nents)
>   int i;
>  
>   for_each_sg(sg, s, nents, i) {
> - if (sg_dma_address(s) != DMA_ERROR_CODE)
> + if (sg_dma_address(s) != IOMMU_MAPPING_ERROR)
>   s->offset += sg_dma_address(s);
>   if (sg_dma_len(s))
>   s->length = sg_dma_len(s);
> - sg_dma_address(s) = DMA_ERROR_CODE;
> + sg_dma_address(s) = IOMMU_MAPPING_ERROR;
>   sg_dma_len(s) = 0;
>   }
>  }
> @@ -836,7 +838,7 @@ void iommu_dma_unmap_resource(struct device *dev, 
> dma_addr_t handle,
>  
>  int iommu_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
>  {
> - return dma_addr == DMA_ERROR_CODE;
> + return dma_addr == IOMMU_MAPPING_ERROR;
>  }
>  
>  static struct iommu_dma_msi_page *iommu_dma_get_msi_page(struct device *dev,
> 

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


Re: [PATCH 2/2] iommu/s390: Add support for iommu_device handling

2017-06-19 Thread Gerald Schaefer
On Thu, 15 Jun 2017 15:11:52 +0200
Joerg Roedel  wrote:

> From: Joerg Roedel 
> 
> Add support for the iommu_device_register interface to make
> the s390 hardware iommus visible to the iommu core and in
> sysfs.
> 
> Signed-off-by: Joerg Roedel 
> ---
>  arch/s390/include/asm/pci.h |  7 +++
>  arch/s390/pci/pci.c |  5 +
>  drivers/iommu/s390-iommu.c  | 35 +++
>  3 files changed, 47 insertions(+)
> 
> diff --git a/arch/s390/include/asm/pci.h b/arch/s390/include/asm/pci.h
> index 4e31866..a3f697e 100644
> --- a/arch/s390/include/asm/pci.h
> +++ b/arch/s390/include/asm/pci.h
> @@ -8,6 +8,7 @@
> 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -123,6 +124,8 @@ struct zpci_dev {
>   unsigned long   iommu_pages;
>   unsigned intnext_bit;
> 
> + struct iommu_device iommu_dev;  /* IOMMU core handle */
> +
>   char res_name[16];
>   struct zpci_bar_struct bars[PCI_BAR_COUNT];
> 
> @@ -173,6 +176,10 @@ int clp_add_pci_device(u32, u32, int);
>  int clp_enable_fh(struct zpci_dev *, u8);
>  int clp_disable_fh(struct zpci_dev *);
> 
> +/* IOMMU Interface */
> +int zpci_init_iommu(struct zpci_dev *zdev);
> +void zpci_destroy_iommu(struct zpci_dev *zdev);
> +
>  #ifdef CONFIG_PCI
>  /* Error handling and recovery */
>  void zpci_event_error(void *);
> diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
> index 8051df1..4c13da6 100644
> --- a/arch/s390/pci/pci.c
> +++ b/arch/s390/pci/pci.c
> @@ -749,6 +749,7 @@ void pcibios_remove_bus(struct pci_bus *bus)
> 
>   zpci_exit_slot(zdev);
>   zpci_cleanup_bus_resources(zdev);
> + zpci_destroy_iommu(zdev);
>   zpci_free_domain(zdev);
> 
>   spin_lock(&zpci_list_lock);
> @@ -820,6 +821,10 @@ int zpci_create_device(struct zpci_dev *zdev)
>   if (rc)
>   goto out;
> 
> + rc = zpci_init_iommu(zdev);
> + if (rc)
> + goto out_free;
> +

After this point, there are two options for failure (zpci_enable_device +
zpci_scan_bus), but missing error handling with an appropriate call to
zpci_destroy_iommu().

I must admit that I do not understand what these sysfs attributes are
used for, and by whom and when. Is it really necessary/correct to register
them (including the s390_iommu_ops) _before_ the zpci_dev is registered
to the bus (zpci_scan_bus -> pci_scan_root_bus/pci_bus_add_devices)?

What is the expected life cycle for the attributes, and are they already
needed when a device is still under DMA API access, or even before it is
added to the PCI bus?

>   mutex_init(&zdev->lock);
>   if (zdev->state == ZPCI_FN_STATE_CONFIGURED) {
>   rc = zpci_enable_device(zdev);
> diff --git a/drivers/iommu/s390-iommu.c b/drivers/iommu/s390-iommu.c
> index 8788640..85f3bc5 100644
> --- a/drivers/iommu/s390-iommu.c
> +++ b/drivers/iommu/s390-iommu.c
> @@ -18,6 +18,8 @@
>   */
>  #define S390_IOMMU_PGSIZES   (~0xFFFUL)
> 
> +static struct iommu_ops s390_iommu_ops;
> +
>  struct s390_domain {
>   struct iommu_domain domain;
>   struct list_headdevices;
> @@ -166,11 +168,13 @@ static void s390_iommu_detach_device(struct 
> iommu_domain *domain,
>  static int s390_iommu_add_device(struct device *dev)
>  {
>   struct iommu_group *group = iommu_group_get_for_dev(dev);
> + struct zpci_dev *zdev = to_pci_dev(dev)->sysdata;
> 
>   if (IS_ERR(group))
>   return PTR_ERR(group);
> 
>   iommu_group_put(group);
> + iommu_device_link(&zdev->iommu_dev, dev);
> 
>   return 0;
>  }
> @@ -197,6 +201,7 @@ static void s390_iommu_remove_device(struct device *dev)
>   s390_iommu_detach_device(domain, dev);
>   }
> 
> + iommu_device_unlink(&zdev->iommu_dev, dev);
>   iommu_group_remove_device(dev);
>  }
> 
> @@ -327,6 +332,36 @@ static size_t s390_iommu_unmap(struct iommu_domain 
> *domain,
>   return size;
>  }
> 
> +int zpci_init_iommu(struct zpci_dev *zdev)
> +{
> + int rc = 0;
> +
> + rc = iommu_device_sysfs_add(&zdev->iommu_dev, NULL, NULL,
> + "s390-iommu.%08x", zdev->fid);
> + if (rc)
> + goto out_err;
> +
> + iommu_device_set_ops(&zdev->iommu_dev, &s390_iommu_ops);
> +
> + rc = iommu_device_register(&zdev->iommu_dev);
> + if (rc)
> + goto out_sysfs;
> +
> + return 0;
> +
> +out_sysfs:
> + iommu_device_sysfs_remove(&zdev->iommu_dev);
> +
> +out_err:
> + return rc;
> +}
> +
> +void zpci_destroy_iommu(struct zpci_dev *zdev)
> +{
> + iommu_device_unregister(&zdev->iommu_dev);
> + iommu_device_sysfs_remove(&zdev->iommu_dev);
> +}
> +
>  static struct iommu_ops s390_iommu_ops = {
>   .capable = s390_iommu_capable,
>   .domain_alloc = s390_domain_alloc,

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


[PATCH v4 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Support the r8a7796 IPMMU by sharing feature flags between
r8a7795 and r8a7796. Also update IOMMU_OF_DECLARE to hook
up the updated compat string.

Signed-off-by: Magnus Damm 
Reviewed-by: Geert Uytterhoeven 
---

 Changes since V3:
 - Added Reviewed-by from Geert - thanks!

 Changes since V2:
 - Updated to include white list suppport

 Changes since V1:
 - None

 drivers/iommu/ipmmu-vmsa.c |   14 ++
 1 file changed, 10 insertions(+), 4 deletions(-)

--- 0016/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 19:48:27.430607110 +0900
@@ -755,8 +755,9 @@ static bool ipmmu_slave_whitelist(struct
return false;
 }
 
-static const struct soc_device_attribute soc_r8a7795[] = {
+static const struct soc_device_attribute soc_rcar_gen3[] = {
{ .soc_id = "r8a7795", },
+   { .soc_id = "r8a7796", },
{ /* sentinel */ }
 };
 
@@ -772,7 +773,7 @@ static int ipmmu_of_xlate(struct device
}
 
/* For R-Car Gen3 use a white list to opt-in slave devices */
-   if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev))
+   if (soc_device_match(soc_rcar_gen3) && !ipmmu_slave_whitelist(dev))
return -ENODEV;
 
iommu_fwspec_add_ids(dev, spec->args, 1);
@@ -1034,7 +1035,7 @@ static const struct ipmmu_features ipmmu
.twobit_imttbcr_sl0 = false,
 };
 
-static const struct ipmmu_features ipmmu_features_r8a7795 = {
+static const struct ipmmu_features ipmmu_features_rcar_gen3 = {
.use_ns_alias_offset = false,
.has_cache_leaf_nodes = true,
.number_of_contexts = 8,
@@ -1048,7 +1049,10 @@ static const struct of_device_id ipmmu_o
.data = &ipmmu_features_default,
}, {
.compatible = "renesas,ipmmu-r8a7795",
-   .data = &ipmmu_features_r8a7795,
+   .data = &ipmmu_features_rcar_gen3,
+   }, {
+   .compatible = "renesas,ipmmu-r8a7796",
+   .data = &ipmmu_features_rcar_gen3,
}, {
/* Terminator */
},
@@ -1229,6 +1233,8 @@ IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "r
 ipmmu_vmsa_iommu_of_setup);
 IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795",
 ipmmu_vmsa_iommu_of_setup);
+IOMMU_OF_DECLARE(ipmmu_r8a7796_iommu_of, "renesas,ipmmu-r8a7796",
+ipmmu_vmsa_iommu_of_setup);
 #endif
 
 MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU");
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 0/3] iommu/ipmmu-vmsa: r8a7796 support V4

2017-06-19 Thread Magnus Damm
iommu/ipmmu-vmsa: r8a7796 support V4

[PATCH v4 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding
[PATCH v4 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48
[PATCH v4 3/3] iommu/ipmmu-vmsa: Hook up r8a7796 DT matching code

This series adds r8a7796 support to the IPMMU driver. The DT binding
gets updated, maximum number of micro-TLBs are increased and the
driver is adjusted to match on the new DT binding.

Changes since V3:
 - Rebased on top of [PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4
 - Patch 3/3 updated with Reviewed-by - thanks Geert!

Changes since V2:
 - Patch 2/3 updated with an outer set of () - thanks Ramesh!
 - Patch 2/3 updated with Reviewed-by - thanks Geert!
 - Patch 3/3 updated to include white list support

Changes since V1:
 - Patch 1/3 updated with more Acked-by tags
 - Patch 2/3 updated with high I/O register range support

Patch 1/3 is ready for upstream merge and includes the following tags:
Signed-off-by: Magnus Damm 
Acked-by: Laurent Pinchart 
Acked-by: Rob Herring 
Acked-by: Simon Horman 
Acked-by: Geert Uytterhoeven 

Patch 2/3 and 3/3 are quite trivial but have no acked-by so far.

Signed-off-by: Magnus Damm 
---

 Developed on top of next-20170614 with the following series applied
 [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update
 [PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4

 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 
 drivers/iommu/ipmmu-vmsa.c |   24 
+++---
 2 files changed, 18 insertions(+), 7 deletions(-)
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 1/3] iommu/ipmmu-vmsa: Add r8a7796 DT binding

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Update the IPMMU DT binding documentation to include the r8a7796 compat
string for R-Car M3-W.

Signed-off-by: Magnus Damm 
Acked-by: Laurent Pinchart 
Acked-by: Rob Herring 
Acked-by: Simon Horman 
Acked-by: Geert Uytterhoeven 
---

 Changes since V3:
 - None

 Changes since V2:
 - None

 Changes since V1:
 - Included in series, added Acked-by from Geert - thanks!

 Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt |1 +
 1 file changed, 1 insertion(+)

--- 0001/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt
+++ work/Documentation/devicetree/bindings/iommu/renesas,ipmmu-vmsa.txt 
2017-06-19 19:51:13.990607110 +0900
@@ -16,6 +16,7 @@ Required Properties:
 - "renesas,ipmmu-r8a7793" for the R8A7793 (R-Car M2-N) IPMMU.
 - "renesas,ipmmu-r8a7794" for the R8A7794 (R-Car E2) IPMMU.
 - "renesas,ipmmu-r8a7795" for the R8A7795 (R-Car H3) IPMMU.
+- "renesas,ipmmu-r8a7796" for the R8A7796 (R-Car M3-W) IPMMU.
 - "renesas,ipmmu-vmsa" for generic R-Car Gen2 VMSA-compatible IPMMU.
 
   - reg: Base address and size of the IPMMU registers.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 2/3] iommu/ipmmu-vmsa: Increase maximum micro-TLBS to 48

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Bump up the maximum numbers of micro-TLBS to 48.

Each IPMMU device instance get micro-TLB assignment via
the "iommus" property in DT. Older SoCs tend to use a
maximum number of 32 micro-TLBs per IPMMU instance however
newer SoCs such as r8a7796 make use of up to 48 micro-TLBs.

At this point no SoC specific handling is done to validate
the maximum number of micro-TLBs, and because of that the
DT information is assumed to be within correct range for
each particular SoC.

If needed in the future SoC specific feature flags can be
added to handle the maximum number of micro-TLBs without
requiring DT changes, however at this point this does not
seem necessary.

Signed-off-by: Magnus Damm 
Reviewed-by: Geert Uytterhoeven 
---

 Changes since V3:
 - None

 Changes since V2:
 - Added outer set of () to IMUASID() and IMUCTR() - thanks Ramesh!
 - Added Reviewed-by from Geert - thanks!

 Changes since V1:
 - Added support for the second I/O range at 0x600.

 drivers/iommu/ipmmu-vmsa.c |   10 +++---
 1 file changed, 7 insertions(+), 3 deletions(-)

--- 0015/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 19:47:28.950607110 +0900
@@ -199,7 +199,9 @@ static struct ipmmu_vmsa_iommu_priv *to_
 #define IMPMBA(n)  (0x0280 + ((n) * 4))
 #define IMPMBD(n)  (0x02c0 + ((n) * 4))
 
-#define IMUCTR(n)  (0x0300 + ((n) * 16))
+#define IMUCTR(n)  ((n) < 32 ? IMUCTR0(n) : IMUCTR32(n))
+#define IMUCTR0(n) (0x0300 + ((n) * 16))
+#define IMUCTR32(n)(0x0600 + (((n) - 32) * 16))
 #define IMUCTR_FIXADDEN(1 << 31)
 #define IMUCTR_FIXADD_MASK (0xff << 16)
 #define IMUCTR_FIXADD_SHIFT16
@@ -209,7 +211,9 @@ static struct ipmmu_vmsa_iommu_priv *to_
 #define IMUCTR_FLUSH   (1 << 1)
 #define IMUCTR_MMUEN   (1 << 0)
 
-#define IMUASID(n) (0x0308 + ((n) * 16))
+#define IMUASID(n) ((n) < 32 ? IMUASID0(n) : IMUASID32(n))
+#define IMUASID0(n)(0x0308 + ((n) * 16))
+#define IMUASID32(n)   (0x0608 + (((n) - 32) * 16))
 #define IMUASID_ASID8_MASK (0xff << 8)
 #define IMUASID_ASID8_SHIFT8
 #define IMUASID_ASID0_MASK (0xff << 0)
@@ -1066,7 +1070,7 @@ static int ipmmu_probe(struct platform_d
}
 
mmu->dev = &pdev->dev;
-   mmu->num_utlbs = 32;
+   mmu->num_utlbs = 48;
spin_lock_init(&mmu->lock);
bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
mmu->features = of_device_get_match_data(&pdev->dev);
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Tie in r8a7795 features and update the IOMMU_OF_DECLARE
compat string to include the updated compat string.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Rebased code on top of
   [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update
   This includes support for iommu_fwspec_add_ids()
 - Use dev_err() instead of dev_info() - Thanks Geert!
 - Moved single-invokation check into of_xlate() - Thanks Geert!
 - Dropped TODO list
 
 Changes since V2:
 - Check for lack of root device in ->xlate()
   This fixed a bug when IPMMU-MM is disabled in DT the system hangs on boot
 - Added code to ipmmu_init_platform_device() to handle multiple ->xlate() calls
 - Include empty white list by default
 - Updated TODO list

 Changes since V1:
 - Enable multi context feature
 - Update TODO list

 drivers/iommu/ipmmu-vmsa.c |   48 
 1 file changed, 44 insertions(+), 4 deletions(-)

--- 0029/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:10:58.930607110 +0900
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA)
 #include 
@@ -730,10 +731,6 @@ static int ipmmu_init_platform_device(st
struct platform_device *ipmmu_pdev;
struct ipmmu_vmsa_iommu_priv *priv;
 
-   /* Initialize once - xlate() will call multiple times */
-   if (to_priv(dev))
-   return 0;
-
ipmmu_pdev = of_find_device_by_node(args->np);
if (!ipmmu_pdev)
return -ENODEV;
@@ -748,11 +745,41 @@ static int ipmmu_init_platform_device(st
return 0;
 }
 
+static bool ipmmu_slave_whitelist(struct device *dev)
+{
+   /* By default, do not allow use of IPMMU */
+   return false;
+}
+
+static const struct soc_device_attribute soc_r8a7795[] = {
+   { .soc_id = "r8a7795", },
+   { /* sentinel */ }
+};
+
 static int ipmmu_of_xlate(struct device *dev,
  struct of_phandle_args *spec)
 {
+   /* Failing in ->attach_device() results in a hang, so make
+* sure the root device is installed before going there
+*/
+   if (!__ipmmu_find_root()) {
+   dev_err(dev, "Unable to locate IPMMU root device\n");
+   return -ENODEV;
+   }
+
+   /* For R-Car Gen3 use a white list to opt-in slave devices */
+   if (soc_device_match(soc_r8a7795) && !ipmmu_slave_whitelist(dev))
+   return -ENODEV;
+
iommu_fwspec_add_ids(dev, spec->args, 1);
 
+   /*
+* Execute ipmmu_init_platform_device() once per device.
+* This xlate() callback will be invoked multiple times.
+*/
+   if (to_priv(dev))
+   return 0;
+
return ipmmu_init_platform_device(dev, spec);
 }
 
@@ -1003,11 +1030,22 @@ static const struct ipmmu_features ipmmu
.twobit_imttbcr_sl0 = false,
 };
 
+static const struct ipmmu_features ipmmu_features_r8a7795 = {
+   .use_ns_alias_offset = false,
+   .has_cache_leaf_nodes = true,
+   .number_of_contexts = 8,
+   .setup_imbuscr = false,
+   .twobit_imttbcr_sl0 = true,
+};
+
 static const struct of_device_id ipmmu_of_ids[] = {
{
.compatible = "renesas,ipmmu-vmsa",
.data = &ipmmu_features_default,
}, {
+   .compatible = "renesas,ipmmu-r8a7795",
+   .data = &ipmmu_features_r8a7795,
+   }, {
/* Terminator */
},
 };
@@ -1185,6 +1223,8 @@ static int __init ipmmu_vmsa_iommu_of_se
 
 IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa",
 ipmmu_vmsa_iommu_of_setup);
+IOMMU_OF_DECLARE(ipmmu_r8a7795_iommu_of, "renesas,ipmmu-r8a7795",
+ipmmu_vmsa_iommu_of_setup);
 #endif
 
 MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU");
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 08/09] iommu/ipmmu-vmsa: Allow two bit SL0

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Introduce support for two bit SL0 bitfield in IMTTBCR
by using a separate feature flag.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - None

 Changes since V2:
 - None

 Changes since V1:
 - None

 drivers/iommu/ipmmu-vmsa.c |   14 +-
 1 file changed, 13 insertions(+), 1 deletion(-)

--- 0027/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:08:26.100607110 +0900
@@ -40,6 +40,7 @@ struct ipmmu_features {
bool has_cache_leaf_nodes;
unsigned int number_of_contexts;
bool setup_imbuscr;
+   bool twobit_imttbcr_sl0;
 };
 
 struct ipmmu_vmsa_device {
@@ -149,6 +150,10 @@ static struct ipmmu_vmsa_iommu_priv *to_
 #define IMTTBCR_TSZ0_MASK  (7 << 0)
 #define IMTTBCR_TSZ0_SHIFT O
 
+#define IMTTBCR_SL0_TWOBIT_LVL_3   (0 << 6)
+#define IMTTBCR_SL0_TWOBIT_LVL_2   (1 << 6)
+#define IMTTBCR_SL0_TWOBIT_LVL_1   (2 << 6)
+
 #define IMBUSCR0x000c
 #define IMBUSCR_DVM(1 << 2)
 #define IMBUSCR_BUSSEL_SYS (0 << 0)
@@ -393,6 +398,7 @@ static int ipmmu_domain_allocate_context
 static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
 {
u64 ttbr;
+   u32 tmp;
int ret;
 
/*
@@ -445,9 +451,14 @@ static int ipmmu_domain_init_context(str
 * We use long descriptors with inner-shareable WBWA tables and allocate
 * the whole 32-bit VA space to TTBR0.
 */
+   if (domain->root->features->twobit_imttbcr_sl0)
+   tmp = IMTTBCR_SL0_TWOBIT_LVL_1;
+   else
+   tmp = IMTTBCR_SL0_LVL_1;
+
ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE |
 IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
-IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);
+IMTTBCR_IRGN0_WB_WA | tmp);
 
/* MAIR0 */
ipmmu_ctx_write_root(domain, IMMAIR0,
@@ -989,6 +1000,7 @@ static const struct ipmmu_features ipmmu
.has_cache_leaf_nodes = false,
.number_of_contexts = 1, /* software only tested with one context */
.setup_imbuscr = true,
+   .twobit_imttbcr_sl0 = false,
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 06/09] iommu/ipmmu-vmsa: Write IMCTR twice

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Write IMCTR both in the root device and the leaf node.

To allow access of IMCTR introduce the following function:
 - ipmmu_ctx_write_all()

While at it also rename context functions:
 - ipmmu_ctx_read() -> ipmmu_ctx_read_root()
 - ipmmu_ctx_write() -> ipmmu_ctx_write_root()

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Changed function names to improve code readability - Thanks Robin!

 Changes since V2:
 - None

 Changes since V1:
 - None

 drivers/iommu/ipmmu-vmsa.c |   55 +++-
 1 file changed, 34 insertions(+), 21 deletions(-)

--- 0023/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:06:16.770607110 +0900
@@ -261,17 +261,28 @@ static void ipmmu_write(struct ipmmu_vms
iowrite32(data, mmu->base + offset);
 }
 
-static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg)
+static u32 ipmmu_ctx_read_root(struct ipmmu_vmsa_domain *domain,
+  unsigned int reg)
 {
return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg);
 }
 
-static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg,
-   u32 data)
+static void ipmmu_ctx_write_root(struct ipmmu_vmsa_domain *domain,
+unsigned int reg, u32 data)
 {
ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data);
 }
 
+static void ipmmu_ctx_write_all(struct ipmmu_vmsa_domain *domain,
+   unsigned int reg, u32 data)
+{
+   if (domain->mmu != domain->root)
+   ipmmu_write(domain->mmu,
+   domain->context_id * IM_CTX_SIZE + reg, data);
+
+   ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data);
+}
+
 /* 
-
  * TLB and microTLB Management
  */
@@ -281,7 +292,7 @@ static void ipmmu_tlb_sync(struct ipmmu_
 {
unsigned int count = 0;
 
-   while (ipmmu_ctx_read(domain, IMCTR) & IMCTR_FLUSH) {
+   while (ipmmu_ctx_read_root(domain, IMCTR) & IMCTR_FLUSH) {
cpu_relax();
if (++count == TLB_LOOP_TIMEOUT) {
dev_err_ratelimited(domain->mmu->dev,
@@ -296,9 +307,9 @@ static void ipmmu_tlb_invalidate(struct
 {
u32 reg;
 
-   reg = ipmmu_ctx_read(domain, IMCTR);
+   reg = ipmmu_ctx_read_root(domain, IMCTR);
reg |= IMCTR_FLUSH;
-   ipmmu_ctx_write(domain, IMCTR, reg);
+   ipmmu_ctx_write_all(domain, IMCTR, reg);
 
ipmmu_tlb_sync(domain);
 }
@@ -425,31 +436,32 @@ static int ipmmu_domain_init_context(str
 
/* TTBR0 */
ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0];
-   ipmmu_ctx_write(domain, IMTTLBR0, ttbr);
-   ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32);
+   ipmmu_ctx_write_root(domain, IMTTLBR0, ttbr);
+   ipmmu_ctx_write_root(domain, IMTTUBR0, ttbr >> 32);
 
/*
 * TTBCR
 * We use long descriptors with inner-shareable WBWA tables and allocate
 * the whole 32-bit VA space to TTBR0.
 */
-   ipmmu_ctx_write(domain, IMTTBCR, IMTTBCR_EAE |
-   IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
-   IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);
+   ipmmu_ctx_write_root(domain, IMTTBCR, IMTTBCR_EAE |
+IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
+IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);
 
/* MAIR0 */
-   ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]);
+   ipmmu_ctx_write_root(domain, IMMAIR0,
+domain->cfg.arm_lpae_s1_cfg.mair[0]);
 
/* IMBUSCR */
-   ipmmu_ctx_write(domain, IMBUSCR,
-   ipmmu_ctx_read(domain, IMBUSCR) &
-   ~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
+   ipmmu_ctx_write_root(domain, IMBUSCR,
+ipmmu_ctx_read_root(domain, IMBUSCR) &
+~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
 
/*
 * IMSTR
 * Clear all interrupt flags.
 */
-   ipmmu_ctx_write(domain, IMSTR, ipmmu_ctx_read(domain, IMSTR));
+   ipmmu_ctx_write_root(domain, IMSTR, ipmmu_ctx_read_root(domain, IMSTR));
 
/*
 * IMCTR
@@ -458,7 +470,8 @@ static int ipmmu_domain_init_context(str
 * software management as we have no use for it. Flush the TLB as
 * required when modifying the context registers.
 */
-   ipmmu_ctx_write(domain, IMCTR, IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);
+   ipmmu_ctx_write_all(domain, IMCTR,
+   IMCTR_INTEN | IMCTR_FLUSH | IMCTR_MMUEN);
 
return 0;
 }
@@ -484,7 +497,7 @@ static void ipmmu_domain_destroy_context
 *
 * TODO: Is TLB flush really needed ?
 */
-   ipmmu_ct

[PATCH v4 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Introduce a feature to allow opt-out of setting up
IMBUSCR. The default case is unchanged.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - None

 Changes since V2:
 - None

 Changes since V1:
 - Updated the commit message
 - Reworked patch to coexist with the multi context feature

 drivers/iommu/ipmmu-vmsa.c |9 ++---
 1 file changed, 6 insertions(+), 3 deletions(-)

--- 0025/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:07:06.850607110 +0900
@@ -39,6 +39,7 @@ struct ipmmu_features {
bool use_ns_alias_offset;
bool has_cache_leaf_nodes;
unsigned int number_of_contexts;
+   bool setup_imbuscr;
 };
 
 struct ipmmu_vmsa_device {
@@ -453,9 +454,10 @@ static int ipmmu_domain_init_context(str
 domain->cfg.arm_lpae_s1_cfg.mair[0]);
 
/* IMBUSCR */
-   ipmmu_ctx_write_root(domain, IMBUSCR,
-ipmmu_ctx_read_root(domain, IMBUSCR) &
-~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
+   if (domain->root->features->setup_imbuscr)
+   ipmmu_ctx_write_root(domain, IMBUSCR,
+ipmmu_ctx_read_root(domain, IMBUSCR) &
+~(IMBUSCR_DVM | IMBUSCR_BUSSEL_MASK));
 
/*
 * IMSTR
@@ -986,6 +988,7 @@ static const struct ipmmu_features ipmmu
.use_ns_alias_offset = true,
.has_cache_leaf_nodes = false,
.number_of_contexts = 1, /* software only tested with one context */
+   .setup_imbuscr = true,
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 03/09] iommu/ipmmu-vmsa: Enable multi context support

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Add support for up to 8 contexts. Each context is mapped to one
domain. One domain is assigned one or more slave devices. Contexts
are allocated dynamically and slave devices are grouped together
based on which IPMMU device they are connected to. This makes slave
devices tied to the same IPMMU device share the same IOVA space.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Use number_of_contexts unsigned int, drop WARN_ON() - Thanks Robin!

 Changes since V2:
 - Updated patch description to reflect code included in:
   [PATCH v7 00/07] iommu/ipmmu-vmsa: IPMMU multi-arch update V7

 Changes since V1:
 - Support up to 8 contexts instead of 4
 - Use feature flag and runtime handling
 - Default to single context

 drivers/iommu/ipmmu-vmsa.c |   31 +++
 1 file changed, 23 insertions(+), 8 deletions(-)

--- 0017/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:00:59.880607110 +0900
@@ -32,11 +32,12 @@
 
 #include "io-pgtable.h"
 
-#define IPMMU_CTX_MAX 1
+#define IPMMU_CTX_MAX 8
 
 struct ipmmu_features {
bool use_ns_alias_offset;
bool has_cache_leaf_nodes;
+   unsigned int number_of_contexts;
 };
 
 struct ipmmu_vmsa_device {
@@ -47,6 +48,7 @@ struct ipmmu_vmsa_device {
const struct ipmmu_features *features;
bool is_leaf;
unsigned int num_utlbs;
+   unsigned int num_ctx;
spinlock_t lock;/* Protects ctx and domains[] */
DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
struct ipmmu_vmsa_domain *domains[IPMMU_CTX_MAX];
@@ -363,11 +365,12 @@ static int ipmmu_domain_allocate_context
 
spin_lock_irqsave(&mmu->lock, flags);
 
-   ret = find_first_zero_bit(mmu->ctx, IPMMU_CTX_MAX);
-   if (ret != IPMMU_CTX_MAX) {
+   ret = find_first_zero_bit(mmu->ctx, mmu->num_ctx);
+   if (ret != mmu->num_ctx) {
mmu->domains[ret] = domain;
set_bit(ret, mmu->ctx);
-   }
+   } else
+   ret = -EBUSY;
 
spin_unlock_irqrestore(&mmu->lock, flags);
 
@@ -412,9 +415,9 @@ static int ipmmu_domain_init_context(str
 * Find an unused context.
 */
ret = ipmmu_domain_allocate_context(domain->root, domain);
-   if (ret == IPMMU_CTX_MAX) {
+   if (ret < 0) {
free_io_pgtable_ops(domain->iop);
-   return -EBUSY;
+   return ret;
}
 
domain->context_id = ret;
@@ -549,7 +552,7 @@ static irqreturn_t ipmmu_irq(int irq, vo
/*
 * Check interrupts for all active contexts.
 */
-   for (i = 0; i < IPMMU_CTX_MAX; i++) {
+   for (i = 0; i < mmu->num_ctx; i++) {
if (!mmu->domains[i])
continue;
if (ipmmu_domain_irq(mmu->domains[i]) == IRQ_HANDLED)
@@ -620,6 +623,14 @@ static int ipmmu_attach_device(struct io
domain->mmu = mmu;
domain->root = root;
ret = ipmmu_domain_init_context(domain);
+   if (ret < 0) {
+   dev_err(dev, "Unable to initialize IPMMU context\n");
+   domain->mmu = NULL;
+   domain->root = NULL;
+   } else {
+   dev_info(dev, "Using IPMMU context %u\n",
+domain->context_id);
+   }
} else if (domain->mmu != mmu) {
/*
 * Something is wrong, we can't attach two devices using
@@ -953,13 +964,14 @@ static void ipmmu_device_reset(struct ip
unsigned int i;
 
/* Disable all contexts. */
-   for (i = 0; i < 4; ++i)
+   for (i = 0; i < mmu->num_ctx; ++i)
ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0);
 }
 
 static const struct ipmmu_features ipmmu_features_default = {
.use_ns_alias_offset = true,
.has_cache_leaf_nodes = false,
+   .number_of_contexts = 1, /* software only tested with one context */
 };
 
 static const struct of_device_id ipmmu_of_ids[] = {
@@ -1013,6 +1025,9 @@ static int ipmmu_probe(struct platform_d
if (mmu->features->use_ns_alias_offset)
mmu->base += IM_NS_ALIAS_OFFSET;
 
+   mmu->num_ctx = min_t(unsigned int, IPMMU_CTX_MAX,
+mmu->features->number_of_contexts);
+
irq = platform_get_irq(pdev, 0);
 
/*
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

The r8a7795 IPMMU supports 40-bit bus mastering. Both
the coherent DMA mask and the streaming DMA mask are
set to unlock the 40-bit address space for coherent
allocations and streaming operations.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - None

 Changes since V2:
 - Updated the code and commit message to use 40 bits instead of 64 bits

 Changes since V1:
 - Updated the commit message

 drivers/iommu/ipmmu-vmsa.c |1 +
 1 file changed, 1 insertion(+)

--- 0021/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:05:33.720607110 +0900
@@ -1004,6 +1004,7 @@ static int ipmmu_probe(struct platform_d
spin_lock_init(&mmu->lock);
bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
mmu->features = of_device_get_match_data(&pdev->dev);
+   dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(40));
 
/* Map I/O memory and request IRQ. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Hook up IOMMU_OF_DECLARE() support in case CONFIG_IOMMU_DMA
is enabled. The only current supported case for 32-bit ARM
is disabled, however for 64-bit ARM usage of OF is required.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Reworked to fit on top of
   [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update

 Changes since V2:
 - Reworked registration code to make use of recently introduced:
 iommu_device_register()
 iommu_device_set_ops()
 iommu_device_set_fwnode()

 Changes since V1:
 - Reworked slightly to fit updated patch order and
   [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3

 drivers/iommu/ipmmu-vmsa.c |   43 +--
 1 file changed, 37 insertions(+), 6 deletions(-)

--- 0019/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 14:03:53.140607110 +0900
@@ -20,6 +20,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -1055,13 +1056,25 @@ static int ipmmu_probe(struct platform_d
ipmmu_device_reset(mmu);
}
 
-   ret = iommu_device_register(&mmu->iommu);
-   if (ret)
-   return ret;
-
-   iommu_device_set_ops(&mmu->iommu, &ipmmu_ops);
-   iommu_device_set_fwnode(&mmu->iommu, &pdev->dev.of_node->fwnode);
+   /*
+* Register the IPMMU to the IOMMU subsystem in the following cases:
+* - R-Car Gen2 IPMMU (all devices registered)
+* - R-Car Gen3 IPMMU (leaf devices only - skip root IPMMU-MM device)
+*/
+   if (!mmu->features->has_cache_leaf_nodes || mmu->is_leaf) {
+   ret = iommu_device_register(&mmu->iommu);
+   if (ret)
+   return ret;
 
+   iommu_device_set_ops(&mmu->iommu, &ipmmu_ops);
+   iommu_device_set_fwnode(&mmu->iommu,
+   &pdev->dev.of_node->fwnode);
+
+#if defined(CONFIG_IOMMU_DMA)
+   if (!iommu_present(&platform_bus_type))
+   bus_set_iommu(&platform_bus_type, &ipmmu_ops);
+#endif
+   }
/*
 * We can't create the ARM mapping here as it requires the bus to have
 * an IOMMU, which only happens when bus_set_iommu() is called in
@@ -1107,15 +1120,22 @@ static struct platform_driver ipmmu_driv
 
 static int __init ipmmu_init(void)
 {
+   static bool setup_done;
int ret;
 
+   if (setup_done)
+   return 0;
+
ret = platform_driver_register(&ipmmu_driver);
if (ret < 0)
return ret;
 
+#if defined(CONFIG_ARM) && !defined(CONFIG_IOMMU_DMA)
if (!iommu_present(&platform_bus_type))
bus_set_iommu(&platform_bus_type, &ipmmu_ops);
+#endif
 
+   setup_done = true;
return 0;
 }
 
@@ -1127,6 +1147,17 @@ static void __exit ipmmu_exit(void)
 subsys_initcall(ipmmu_init);
 module_exit(ipmmu_exit);
 
+#ifdef CONFIG_IOMMU_DMA
+static int __init ipmmu_vmsa_iommu_of_setup(struct device_node *np)
+{
+   ipmmu_init();
+   return 0;
+}
+
+IOMMU_OF_DECLARE(ipmmu_vmsa_iommu_of, "renesas,ipmmu-vmsa",
+ipmmu_vmsa_iommu_of_setup);
+#endif
+
 MODULE_DESCRIPTION("IOMMU API for Renesas VMSA-compatible IPMMU");
 MODULE_AUTHOR("Laurent Pinchart ");
 MODULE_LICENSE("GPL v2");
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 00/09] iommu/ipmmu-vmsa: r8a7795 support V4

2017-06-19 Thread Magnus Damm
iommu/ipmmu-vmsa: r8a7795 support V4

[PATCH v4 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias
[PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature
[PATCH v4 03/09] iommu/ipmmu-vmsa: Enable multi context support
[PATCH v4 04/09] iommu/ipmmu-vmsa: Make use of IOMMU_OF_DECLARE()
[PATCH v4 05/09] iommu/ipmmu-vmsa: IPMMU device is 40-bit bus master
[PATCH v4 06/09] iommu/ipmmu-vmsa: Write IMCTR twice
[PATCH v4 07/09] iommu/ipmmu-vmsa: Make IMBUSCTR setup optional
[PATCH v4 08/09] iommu/ipmmu-vmsa: Allow two bit SL0
[PATCH v4 09/09] iommu/ipmmu-vmsa: Hook up r8a7795 DT matching code

Here's an updated series for r8a7795 IPMMU support. The patches adjust
the code based on feedback from Geert and Robin together with a rebase
to include changes from the recently posted series:

[PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update

The DT binding for r8a7795 has been accepted for upstream merge
and this series implements support following such format:

d4e42e7 iommu/ipmmu-vmsa: Add r8a7795 DT binding

The r8a7795 IPMMU is almost register compatible with earlier devices
like r8a7790-r8a7794, however some bitfields have been shifted
slightly. On a grander scale topology has been added and interrupts
have been reworked. So now there are several "cache" IPMMU units
without interrupt that somehow communicate with IPMMU-MM that
is the only instance that supports interrupts. The code refers to
IPMMU-MM as a "root" device and the other ones as "leaf" nodes.

Changes since V3:
 - Rebased on top of [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update
 - Patch 1/9 has been updated to use of_device_get_match_data(), thanks Robin!
 - Patch 2/9 has been reworked to make it easier to follow, thanks Geert!
 - Patch 3/9 now uses unsigned int for context counts - thanks Robin!
 - Patch 6/9 now includes function name changes - thanks Robin! 
 - Patch 9/9 now uses dev_err() instead of dev_info() - thanks Geert!

Changes since V2:
 - Patch 2/9 has been updated with a bug fix and to supply __ipmmu_find_root()
 - Patch 4/9 now makes use of iommu_device_* functions
 - Patch 5/9 sets the mask to 40 bits instead of 64 bits
 - Patch 9/9 implements white list handling via ->xlate() and fixes a bug

Signed-off-by: Magnus Damm 
---

 Developed on top of next-20170614 with the following series applied
 [PATCH 00/04] iommu/ipmmu-vmsa: 32-bit ARM update

 drivers/iommu/ipmmu-vmsa.c |  327 ++--
 1 file changed, 260 insertions(+), 67 deletions(-)
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 01/09] iommu/ipmmu-vmsa: Introduce features, break out alias

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Introduce struct ipmmu_features to track various hardware
and software implementation changes inside the driver for
different kinds of IPMMU hardware. Add use_ns_alias_offset
as a first example of a feature to control if the secure
register bank offset should be used or not.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Use of_device_get_match_data(), thanks Robin!

 Changes since V2:
 - None

 Changes since V1:
 - Moved patch to front of the series

 drivers/iommu/ipmmu-vmsa.c |   31 ---
 1 file changed, 24 insertions(+), 7 deletions(-)

--- 0014/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 13:57:36.300607110 +0900
@@ -19,6 +19,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -33,12 +34,16 @@
 
 #define IPMMU_CTX_MAX 1
 
+struct ipmmu_features {
+   bool use_ns_alias_offset;
+};
+
 struct ipmmu_vmsa_device {
struct device *dev;
void __iomem *base;
struct iommu_device iommu;
struct list_head list;
-
+   const struct ipmmu_features *features;
unsigned int num_utlbs;
spinlock_t lock;/* Protects ctx and domains[] */
DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
@@ -904,6 +909,21 @@ static void ipmmu_device_reset(struct ip
ipmmu_write(mmu, i * IM_CTX_SIZE + IMCTR, 0);
 }
 
+static const struct ipmmu_features ipmmu_features_default = {
+   .use_ns_alias_offset = true,
+};
+
+static const struct of_device_id ipmmu_of_ids[] = {
+   {
+   .compatible = "renesas,ipmmu-vmsa",
+   .data = &ipmmu_features_default,
+   }, {
+   /* Terminator */
+   },
+};
+
+MODULE_DEVICE_TABLE(of, ipmmu_of_ids);
+
 static int ipmmu_probe(struct platform_device *pdev)
 {
struct ipmmu_vmsa_device *mmu;
@@ -921,6 +941,7 @@ static int ipmmu_probe(struct platform_d
mmu->num_utlbs = 32;
spin_lock_init(&mmu->lock);
bitmap_zero(mmu->ctx, IPMMU_CTX_MAX);
+   mmu->features = of_device_get_match_data(&pdev->dev);
 
/* Map I/O memory and request IRQ. */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -940,7 +961,8 @@ static int ipmmu_probe(struct platform_d
 * Offset the registers base unconditionally to point to the non-secure
 * alias space for now.
 */
-   mmu->base += IM_NS_ALIAS_OFFSET;
+   if (mmu->features->use_ns_alias_offset)
+   mmu->base += IM_NS_ALIAS_OFFSET;
 
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -998,11 +1020,6 @@ static int ipmmu_remove(struct platform_
return 0;
 }
 
-static const struct of_device_id ipmmu_of_ids[] = {
-   { .compatible = "renesas,ipmmu-vmsa", },
-   { }
-};
-
 static struct platform_driver ipmmu_driver = {
.driver = {
.name = "ipmmu-vmsa",
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


[PATCH v4 02/09] iommu/ipmmu-vmsa: Add optional root device feature

2017-06-19 Thread Magnus Damm
From: Magnus Damm 

Add root device handling to the IPMMU driver by allowing certain
DT compat strings to enable has_cache_leaf_nodes that in turn will
support both root devices with interrupts and leaf devices that
face the actual IPMMU consumer devices.

Signed-off-by: Magnus Damm 
---

 Changes since V3:
 - Reworked root finding code to make it easier to follow, thanks Geert!
 
 Changes since V2:
 - Fixed a bug in ipmmu_find_root() when only leaf devices are present
 - Broke out __ipmmu_find_root() to allow ->xlate() check for root devices

 Changes since V1:
 - Moved patch to earlier in the series
 - Updated code to work with recent changes in:
   [PATCH v3 00/06] iommu/ipmmu-vmsa: IPMMU multi-arch update V3

 drivers/iommu/ipmmu-vmsa.c |   95 
 1 file changed, 78 insertions(+), 17 deletions(-)

--- 0015/drivers/iommu/ipmmu-vmsa.c
+++ work/drivers/iommu/ipmmu-vmsa.c 2017-06-19 13:59:41.050607110 +0900
@@ -36,6 +36,7 @@
 
 struct ipmmu_features {
bool use_ns_alias_offset;
+   bool has_cache_leaf_nodes;
 };
 
 struct ipmmu_vmsa_device {
@@ -44,6 +45,7 @@ struct ipmmu_vmsa_device {
struct iommu_device iommu;
struct list_head list;
const struct ipmmu_features *features;
+   bool is_leaf;
unsigned int num_utlbs;
spinlock_t lock;/* Protects ctx and domains[] */
DECLARE_BITMAP(ctx, IPMMU_CTX_MAX);
@@ -54,6 +56,7 @@ struct ipmmu_vmsa_device {
 
 struct ipmmu_vmsa_domain {
struct ipmmu_vmsa_device *mmu;
+   struct ipmmu_vmsa_device *root;
struct iommu_domain io_domain;
 
struct io_pgtable_cfg cfg;
@@ -203,6 +206,44 @@ static struct ipmmu_vmsa_iommu_priv *to_
 #define IMUASID_ASID0_SHIFT0
 
 /* 
-
+ * Root device handling
+ */
+
+static bool ipmmu_is_root(struct ipmmu_vmsa_device *mmu)
+{
+   if (mmu->features->has_cache_leaf_nodes)
+   return mmu->is_leaf ? false : true;
+   else
+   return true; /* older IPMMU hardware treated as single root */
+}
+
+static struct ipmmu_vmsa_device *__ipmmu_find_root(void)
+{
+   struct ipmmu_vmsa_device *mmu;
+   struct ipmmu_vmsa_device *root = NULL;
+
+   spin_lock(&ipmmu_devices_lock);
+
+   list_for_each_entry(mmu, &ipmmu_devices, list) {
+   if (ipmmu_is_root(mmu)) {
+   root = mmu;
+   break;
+   }
+   }
+
+   spin_unlock(&ipmmu_devices_lock);
+   return root;
+}
+
+static struct ipmmu_vmsa_device *ipmmu_find_root(struct ipmmu_vmsa_device 
*leaf)
+{
+   if (ipmmu_is_root(leaf))
+   return leaf;
+   else
+   return __ipmmu_find_root();
+}
+
+/* 
-
  * Read/Write Access
  */
 
@@ -219,13 +260,13 @@ static void ipmmu_write(struct ipmmu_vms
 
 static u32 ipmmu_ctx_read(struct ipmmu_vmsa_domain *domain, unsigned int reg)
 {
-   return ipmmu_read(domain->mmu, domain->context_id * IM_CTX_SIZE + reg);
+   return ipmmu_read(domain->root, domain->context_id * IM_CTX_SIZE + reg);
 }
 
 static void ipmmu_ctx_write(struct ipmmu_vmsa_domain *domain, unsigned int reg,
u32 data)
 {
-   ipmmu_write(domain->mmu, domain->context_id * IM_CTX_SIZE + reg, data);
+   ipmmu_write(domain->root, domain->context_id * IM_CTX_SIZE + reg, data);
 }
 
 /* 
-
@@ -360,7 +401,7 @@ static int ipmmu_domain_init_context(str
 * TODO: Add support for coherent walk through CCI with DVM and remove
 * cache handling. For now, delegate it to the io-pgtable code.
 */
-   domain->cfg.iommu_dev = domain->mmu->dev;
+   domain->cfg.iommu_dev = domain->root->dev;
 
domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg,
   domain);
@@ -370,7 +411,7 @@ static int ipmmu_domain_init_context(str
/*
 * Find an unused context.
 */
-   ret = ipmmu_domain_allocate_context(domain->mmu, domain);
+   ret = ipmmu_domain_allocate_context(domain->root, domain);
if (ret == IPMMU_CTX_MAX) {
free_io_pgtable_ops(domain->iop);
return -EBUSY;
@@ -441,7 +482,7 @@ static void ipmmu_domain_destroy_context
 */
ipmmu_ctx_write(domain, IMCTR, IMCTR_FLUSH);
ipmmu_tlb_sync(domain);
-   ipmmu_domain_free_context(domain->mmu, domain->context_id);
+   ipmmu_domain_free_context(domain->root, domain->context_id);
 }
 
 /* 
-
@@ -555,7 +596,7 @@ static int ipmmu_attach_device(struct io
 {
struct ipmmu_vmsa_iommu_priv *priv = to_priv(dev);
struct iommu_fwspec *fwspec = dev->iommu_