]> xenbits.xensource.com Git - people/royger/xen.git/commitdiff
xen/passthrough: Introduce IOMMU ARM architecture
authorJulien Grall <julien.grall@linaro.org>
Tue, 13 May 2014 15:50:25 +0000 (16:50 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 14 May 2014 13:45:42 +0000 (14:45 +0100)
This patch contains the architecture to use IOMMUs on ARM. There is no
IOMMU drivers on this patch.

In this implementation, IOMMU page table will be shared with the P2M.

The code will run through the device tree and will initialize every IOMMU.
It's possible to have multiple IOMMUs on the same platform, but they must
be handled with the same driver. For now, there is no support for using
multiple iommu drivers at runtime.

Each new IOMMU drivers should contain:

static const char * const myiommu_dt_compat[] __initconst =
{
    /* list of device compatible with the drivers. Will be matched with
     * the "compatible" property on the device tree
     */
    NULL,
};

DT_DEVICE_START(myiommu, "MY IOMMU", DEVICE_IOMMU)
        .compatible = myiommu_compatible,
        .init = myiommu_init,
DT_DEVICE_END

Signed-off-by: Julien Grall <julien.grall@linaro.org>
Acked-by: Ian Campbell <ian.campbell@citrix.com>
Cc: Xiantao Zhang <xiantao.zhang@intel.com>
Cc: Jan Beulich <jbeulich@suse.com>
12 files changed:
xen/arch/arm/Rules.mk
xen/arch/arm/domain.c
xen/arch/arm/domain_build.c
xen/arch/arm/p2m.c
xen/arch/arm/setup.c
xen/drivers/passthrough/Makefile
xen/drivers/passthrough/arm/Makefile [new file with mode: 0644]
xen/drivers/passthrough/arm/iommu.c [new file with mode: 0644]
xen/include/asm-arm/device.h
xen/include/asm-arm/domain.h
xen/include/asm-arm/hvm/iommu.h [new file with mode: 0644]
xen/include/asm-arm/iommu.h [new file with mode: 0644]

index 8d5624b21cee13f9dae61fbdece068f372cfae66..76b35d9bf222dd4676204f7816288df34026a03d 100644 (file)
@@ -9,6 +9,7 @@
 HAS_DEVICE_TREE := y
 HAS_VIDEO := y
 HAS_ARM_HDLCD := y
+HAS_PASSTHROUGH := y
 
 CFLAGS += -I$(BASEDIR)/include
 
index 40f1c3a089c711abb331ed57d1622529f614b335..0b77c59df65d676414fc1b3ed04771de788a2c42 100644 (file)
@@ -533,6 +533,9 @@ int arch_domain_create(struct domain *d, unsigned int domcr_flags)
     if ( is_hardware_domain(d) && (rc = domain_vuart_init(d)) )
         goto fail;
 
+    if ( (rc = iommu_domain_init(d)) != 0 )
+        goto fail;
+
     return 0;
 
 fail:
@@ -544,6 +547,10 @@ fail:
 
 void arch_domain_destroy(struct domain *d)
 {
+    /* IOMMU page table is shared with P2M, always call
+     * iommu_domain_destroy() before p2m_teardown().
+     */
+    iommu_domain_destroy(d);
     p2m_teardown(d);
     domain_vgic_free(d);
     domain_vuart_free(d);
index af5cd6c60a8939362a332cead26a76fa418e5993..ff963816d29c236415b3b03645a480f7e5c6ddac 100644 (file)
@@ -679,7 +679,7 @@ static int make_timer_node(const struct domain *d, void *fdt,
 }
 
 /* Map the device in the domain */
-static int map_device(struct domain *d, const struct dt_device_node *dev)
+static int map_device(struct domain *d, struct dt_device_node *dev)
 {
     unsigned int nirq;
     unsigned int naddr;
@@ -694,6 +694,18 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
 
     DPRINT("%s nirq = %d naddr = %u\n", dt_node_full_name(dev), nirq, naddr);
 
+    if ( dt_device_is_protected(dev) )
+    {
+        DPRINT("%s setup iommu\n", dt_node_full_name(dev));
+        res = iommu_assign_dt_device(d, dev);
+        if ( res )
+        {
+            printk(XENLOG_ERR "Failed to setup the IOMMU for %s\n",
+                   dt_node_full_name(dev));
+            return res;
+        }
+    }
+
     /* Map IRQs */
     for ( i = 0; i < nirq; i++ )
     {
@@ -765,7 +777,7 @@ static int map_device(struct domain *d, const struct dt_device_node *dev)
 }
 
 static int handle_node(struct domain *d, struct kernel_info *kinfo,
-                       const struct dt_device_node *node)
+                       struct dt_device_node *node)
 {
     static const struct dt_device_match skip_matches[] __initconst =
     {
@@ -786,7 +798,7 @@ static int handle_node(struct domain *d, struct kernel_info *kinfo,
         DT_MATCH_TIMER,
         { /* sentinel */ },
     };
-    const struct dt_device_node *child;
+    struct dt_device_node *child;
     int res;
     const char *name;
     const char *path;
@@ -1014,6 +1026,8 @@ int construct_dom0(struct domain *d)
 
     printk("*** LOADING DOMAIN 0 ***\n");
 
+    iommu_hwdom_init(d);
+
     d->max_pages = ~0U;
 
     kinfo.unassigned_mem = dom0_mem;
index 61450cf86d60d91b4ff61a8ce958f9f3bef3a07f..816da21a30401886f7755e4e7bb0201b9ffa27c4 100644 (file)
@@ -465,7 +465,13 @@ static int apply_p2m_changes(struct domain *d,
     }
 
     if ( flush )
+    {
+        unsigned long sgfn = paddr_to_pfn(start_gpaddr);
+        unsigned long egfn = paddr_to_pfn(end_gpaddr);
+
         flush_tlb_domain(d);
+        iommu_iotlb_flush(d, sgfn, egfn - sgfn);
+    }
 
     if ( op == ALLOCATE || op == INSERT )
     {
index dec595063eca76759d1e70ba9835ecd224797a12..c983d955fd2f90c443bf19c12c400d4a926169d2 100644 (file)
@@ -735,6 +735,8 @@ void __init start_xen(unsigned long boot_phys_offset,
     local_irq_enable();
     local_abort_enable();
 
+    iommu_setup();
+
     smp_prepare_cpus(cpus);
 
     initialize_keytable();
index 5a0a35e816773202b95d772d5bc204e908db81ed..16e9027a32dd5d5b55b786f44a30351d307688fa 100644 (file)
@@ -1,6 +1,7 @@
 subdir-$(x86) += vtd
 subdir-$(x86) += amd
 subdir-$(x86_64) += x86
+subdir-$(arm) += arm
 
 obj-y += iommu.o
 obj-$(x86) += io.o
diff --git a/xen/drivers/passthrough/arm/Makefile b/xen/drivers/passthrough/arm/Makefile
new file mode 100644 (file)
index 0000000..0484b79
--- /dev/null
@@ -0,0 +1 @@
+obj-y += iommu.o
diff --git a/xen/drivers/passthrough/arm/iommu.c b/xen/drivers/passthrough/arm/iommu.c
new file mode 100644 (file)
index 0000000..3007b99
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Generic IOMMU framework via the device tree
+ *
+ * Julien Grall <julien.grall@linaro.org>
+ * Copyright (c) 2014 Linaro Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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 <xen/lib.h>
+#include <xen/iommu.h>
+#include <xen/device_tree.h>
+#include <asm/device.h>
+
+static const struct iommu_ops *iommu_ops;
+
+const struct iommu_ops *iommu_get_ops(void)
+{
+    return iommu_ops;
+}
+
+void __init iommu_set_ops(const struct iommu_ops *ops)
+{
+    BUG_ON(ops == NULL);
+
+    if ( iommu_ops && iommu_ops != ops )
+        printk("WARNING: Cannot set IOMMU ops, already set to a different value\n");
+
+    iommu_ops = ops;
+}
+
+int __init iommu_hardware_setup(void)
+{
+    struct dt_device_node *np;
+    int rc;
+    unsigned int num_iommus = 0;
+
+    dt_for_each_device_node(dt_host, np)
+    {
+        rc = device_init(np, DEVICE_IOMMU, NULL);
+        if ( !rc )
+            num_iommus++;
+    }
+
+    return ( num_iommus > 0 ) ? 0 : -ENODEV;
+}
+
+void __hwdom_init arch_iommu_check_autotranslated_hwdom(struct domain *d)
+{
+    /* ARM doesn't require specific check for hwdom */
+    return;
+}
+
+int arch_iommu_domain_init(struct domain *d)
+{
+    return iommu_dt_domain_init(d);
+}
+
+void arch_iommu_domain_destroy(struct domain *d)
+{
+    iommu_dt_domain_destroy(d);
+}
index 9e47ca636262c0e80709bccaec4eae3fc75f1736..ed043441cabda0da6648840813ce0af4c98d442d 100644 (file)
@@ -6,7 +6,8 @@
 
 enum device_type
 {
-    DEVICE_SERIAL
+    DEVICE_SERIAL,
+    DEVICE_IOMMU,
 };
 
 struct device_desc {
index aabeb51ae415967627be13b1f100fe424a293bbb..a42b292fc6aa5ccbb96cf1f0421d5bc8b7912215 100644 (file)
@@ -9,6 +9,7 @@
 #include <asm/vfp.h>
 #include <public/hvm/params.h>
 #include <xen/serial.h>
+#include <xen/hvm/iommu.h>
 
 /* Represents state corresponding to a block of 32 interrupts */
 struct vgic_irq_rank {
@@ -72,6 +73,7 @@ struct pending_irq
 struct hvm_domain
 {
     uint64_t              params[HVM_NR_PARAMS];
+    struct hvm_iommu      iommu;
 }  __cacheline_aligned;
 
 #ifdef CONFIG_ARM_64
diff --git a/xen/include/asm-arm/hvm/iommu.h b/xen/include/asm-arm/hvm/iommu.h
new file mode 100644 (file)
index 0000000..461c8cf
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef __ASM_ARM_HVM_IOMMU_H_
+#define __ASM_ARM_HVM_IOMMU_H_
+
+struct arch_hvm_iommu
+{
+    /* Private information for the IOMMU drivers */
+    void *priv;
+};
+
+#endif /* __ASM_ARM_HVM_IOMMU_H_ */
diff --git a/xen/include/asm-arm/iommu.h b/xen/include/asm-arm/iommu.h
new file mode 100644 (file)
index 0000000..9322f08
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+*/
+#ifndef __ARCH_ARM_IOMMU_H__
+#define __ARCH_ARM_IOMMU_H__
+
+/* Always share P2M Table between the CPU and the IOMMU */
+#define iommu_use_hap_pt(d) (1)
+#define domain_hvm_iommu(d) (&d->arch.hvm_domain.iommu)
+
+const struct iommu_ops *iommu_get_ops(void);
+void __init iommu_set_ops(const struct iommu_ops *ops);
+
+int __init iommu_hardware_setup(void);
+
+#endif /* __ARCH_ARM_IOMMU_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */