[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [RFC PATCH 1/2] Xen Calgary IOMMU support - Xen bits



On Sun, Mar 26, 2006 at 11:08:09PM +0200, Muli Ben-Yehuda wrote:

> The following two patches, against the xen-unstable and linux-2.6-xen
> repositories, introduce proof-of-concept IOMMU support in Xen.

Signed-off-by: Muli Ben-Yehuda <mulix@xxxxxxxxx>
Signed-off-by: Jon Mason <jdmason@xxxxxxxxxx>

diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/arch/x86/x86_64/entry.S 
xen/xen/arch/x86/x86_64/entry.S
--- vanilla.xen/xen/arch/x86/x86_64/entry.S     2006-03-16 09:53:07.000000000 
+0200
+++ xen/xen/arch/x86/x86_64/entry.S     2006-03-20 15:15:00.000000000 +0200
@@ -557,6 +557,8 @@ ENTRY(hypercall_table)
         .quad do_acm_op
         .quad do_nmi_op
         .quad do_arch_sched_op_new
+        .quad do_iommu_map          /* 30 */
+        .quad do_iommu_unmap
         .rept NR_hypercalls-((.-hypercall_table)/8)
         .quad do_ni_hypercall
         .endr
@@ -592,6 +594,8 @@ ENTRY(hypercall_args_table)
         .byte 1 /* do_acm_op            */
         .byte 2 /* do_nmi_op            */
         .byte 2 /* do_arch_sched_op_new */
+        .byte 5 /* do_iommu_map         */  /* 30 */
+        .byte 3 /* do_iommu_unmap       */
         .rept NR_hypercalls-(.-hypercall_args_table)
         .byte 0 /* do_ni_hypercall      */
         .endr
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/calgary.c 
xen/xen/common/calgary.c
--- vanilla.xen/xen/common/calgary.c    1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/common/calgary.c    2006-03-26 21:57:45.000000000 +0200
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <xen/lib.h>
+#include <xen/iommu.h>
+#include <xen/calgary.h>
+#include <xen/errno.h>
+#include <xen/mm.h>
+#include <asm/types.h>
+#include <asm/system.h>
+
+#define swab64(x) \
+({ \
+    u64 __x = (x); \
+    ((u64)( \
+        (u64)(((u64)(__x) & (u64)0x00000000000000ffULL) << 56) | \
+        (u64)(((u64)(__x) & (u64)0x000000000000ff00ULL) << 40) | \
+        (u64)(((u64)(__x) & (u64)0x0000000000ff0000ULL) << 24) | \
+        (u64)(((u64)(__x) & (u64)0x00000000ff000000ULL) <<  8) | \
+        (u64)(((u64)(__x) & (u64)0x000000ff00000000ULL) >>  8) | \
+        (u64)(((u64)(__x) & (u64)0x0000ff0000000000ULL) >> 24) | \
+        (u64)(((u64)(__x) & (u64)0x00ff000000000000ULL) >> 40) | \
+        (u64)(((u64)(__x) & (u64)0xff00000000000000ULL) >> 56) )); \
+})
+
+/* flush a tce at 'tceaddr' to main memory */
+static inline void flush_tce(void* tceaddr)
+{
+       /* a single tce can't cross a cache line */
+       if (cpu_has_clflush)
+               asm volatile("clflush (%0)" :: "r" (tceaddr));
+       else
+               asm volatile("wbinvd":::"memory");
+}
+
+static void tce_build(struct iommu_table* tbl, u64 index, u64 mfn, u32 access)
+{
+    u64* tp;
+    u64 t;
+
+    BUG_ON(!tbl);
+
+    t = (mfn << TCE_RPN_SHIFT) | access;
+
+    tp = ((u64*)tbl->ptr) + index;
+    *tp = swab64(t);
+
+    /* make sure HW sees it */
+    flush_tce(tp);
+}
+
+static inline u64 iospace_size_to_num_table_entries(u64 maxaddr)
+{
+    u64 ret;
+    u64 order;
+
+    order = get_order_from_bytes(maxaddr >> 13);
+
+    if (order > TCE_MAX_TABLE_SIZE)
+        order = TCE_MAX_TABLE_SIZE;
+
+    ret = (1 << order) * 0x2000;
+
+    return ret;
+}
+
+int calgary_create_io_space(u64 size, u32 bdf, void** space, u64* rootmfn)
+{
+    struct iommu_table* tbl;
+    int ret;
+    u64 bytes;
+
+    tbl = xmalloc(struct iommu_table);
+    if (!tbl) {
+        ret = -ENOMEM;
+        goto done;
+    }
+
+    tbl->size = iospace_size_to_num_table_entries(size); /* number of entries 
*/
+    bytes = tbl->size * TCE_ENTRY_SIZE;
+
+    tbl->ptr = alloc_xenheap_pages(get_order_from_bytes(bytes));
+    if (!tbl->ptr) {
+        ret = -ENODEV;
+        goto free_table;
+    }
+
+    *space = tbl;
+    *rootmfn = virt_to_maddr(tbl->ptr) >> PAGE_SHIFT;
+    return 0;
+
+free_table:
+    xfree(tbl);
+    *space = NULL;
+    *rootmfn = 0;
+done:
+    BUG_ON(ret);
+    return ret;
+}
+
+void calgary_destroy_io_space(void* space)
+{
+    struct iommu_table* tbl = space;
+    u64 bytes = tbl->size * TCE_ENTRY_SIZE;
+
+    free_xenheap_pages(tbl->ptr, get_order_from_bytes(bytes));
+    tbl->ptr = NULL;
+}
+
+u64 calgary_map(void* space, u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 
size)
+{
+    struct iommu_table* tbl = space;
+    u64 index = ioaddr >> PAGE_SHIFT;
+
+    BUG_ON(size != PAGE_SIZE);
+
+    tce_build(tbl, index, mfn, access);
+
+    return ioaddr;
+}
+
+int calgary_unmap(void* space, u64 ioaddr, u32 bdf, u32 size)
+{
+    struct iommu_table* tbl = space;
+    u64 index = ioaddr >> PAGE_SHIFT;
+
+    BUG_ON(size != PAGE_SIZE);
+
+    /* set the tce to all 0's */
+    tce_build(tbl, index, 0, 0);
+
+    return 0;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/dom0_ops.c 
xen/xen/common/dom0_ops.c
--- vanilla.xen/xen/common/dom0_ops.c   2006-03-05 13:44:48.000000000 +0200
+++ xen/xen/common/dom0_ops.c   2006-03-07 15:28:26.000000000 +0200
@@ -18,6 +18,7 @@
 #include <xen/console.h>
 #include <xen/iocap.h>
 #include <xen/guest_access.h>
+#include <xen/iommu.h>
 #include <asm/current.h>
 #include <public/dom0_ops.h>
 #include <public/sched_ctl.h>
@@ -682,6 +683,20 @@ long do_dom0_op(GUEST_HANDLE(dom0_op_t) 
     break;
 #endif
 
+    case DOM0_IOMMU_CREATE_IO_SPACE:
+    {
+        ret = iommu_create_io_space(u_dom0_op, op);
+    }
+    break;
+
+    case DOM0_IOMMU_DESTROY_IO_SPACE:
+    {
+        u32 bdf  = op->u.iommu_destroy_io_space.bdf;
+        
+        ret = iommu_destroy_io_space(bdf);
+    }
+    break;
+
     default:
         ret = arch_do_dom0_op(op, u_dom0_op);
         break;
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/iommu.c 
xen/xen/common/iommu.c
--- vanilla.xen/xen/common/iommu.c      1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/common/iommu.c      2006-03-26 15:15:12.000000000 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <xen/iommu.h>
+#include <xen/calgary.h>
+#include <xen/guest_access.h>
+
+/*
+ * TODOs:
+ * - use a tree sorted by BDF to hold IO spaces
+ * - add cache flushing interfaces - all entries, single entry, range of 
entries
+ * - TODO: add iommu_ops with dynamic registration, call iommu_ops->op for ops
+ */
+
+#define NUM_IOMMU_SPACES 2
+void* iommu_space[NUM_IOMMU_SPACES];
+
+int iommu_create_io_space(GUEST_HANDLE(dom0_op_t) u_dom0_op, struct dom0_op* 
op)
+{
+    void* space;
+    int ret;
+    u64 size = op->u.iommu_create_io_space.size;
+    u32 bdf = op->u.iommu_create_io_space.bdf;
+    u64* rootmfn = &op->u.iommu_create_io_space.rootmfn;
+
+    printk("%s called (size %"PRIu64" bdf 0x%x)!\n", __func__,
+           size, bdf);
+
+    ret = calgary_create_io_space(size, bdf, &space, rootmfn);
+    if (ret)
+        goto done;
+
+    printk("space %p rootmfn %"PRIx64"\n", space, *rootmfn);
+    if (bdf == 0)
+        iommu_space[0] = space;
+    else
+        iommu_space[1] = space;
+
+    ret = 0;
+
+    /* FIXME: cleanup if fails */
+    if ( copy_to_guest(u_dom0_op, op, 1) )
+        ret = -EFAULT;
+done:
+    return ret;
+}
+
+/* should this take BDF instead? */
+int iommu_destroy_io_space(u32 bdf)
+{
+    void** space;
+
+    if (bdf == 0)
+        space = &iommu_space[0];
+    else
+        space = &iommu_space[1];
+
+    calgary_destroy_io_space(*space);
+    *space = NULL;
+
+    return 0;
+}
+
+static inline void* find_io_space(u32 bdf)
+{
+    void* space;
+
+    space = (bdf == 0 ? iommu_space[0] : iommu_space[1]);
+
+    return space;
+}
+
+/* map takes a single "entry" - use hypercalls for batching */
+u64 do_iommu_map(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size)
+{
+    void* space;
+    u64 retaddr;
+
+    space = find_io_space(bdf);
+
+    retaddr = calgary_map(space, ioaddr, mfn, access, bdf, size);
+
+    /* the interface allows it but the current implementation doesn't */
+    BUG_ON(retaddr != ioaddr);
+
+    return retaddr;
+}
+
+/* unmap takes a single "entry" - use hypercalls for batching */
+int do_iommu_unmap(u64 ioaddr, u32 bdf, u32 size)
+{
+    void* space;
+    int ret;
+
+    space = find_io_space(bdf);
+
+    ret = calgary_unmap(space, ioaddr, bdf, size);
+
+    return ret;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/common/Makefile 
xen/xen/common/Makefile
--- vanilla.xen/xen/common/Makefile     2006-03-19 20:10:13.000000000 +0200
+++ xen/xen/common/Makefile     2006-03-20 12:28:54.000000000 +0200
@@ -2,11 +2,13 @@ include $(BASEDIR)/Rules.mk
 
 obj-y += acm_ops.o
 obj-y += bitmap.o
+obj-y += calgary.o
 obj-y += dom0_ops.o
 obj-y += domain.o
 obj-y += elf.o
 obj-y += event_channel.o
 obj-y += grant_table.o
+obj-y += iommu.o
 obj-y += kernel.o
 obj-y += keyhandler.o
 obj-y += lib.o
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/public/dom0_ops.h 
xen/xen/include/public/dom0_ops.h
--- vanilla.xen/xen/include/public/dom0_ops.h   2006-03-07 19:54:46.000000000 
+0200
+++ xen/xen/include/public/dom0_ops.h   2006-03-07 20:35:04.000000000 +0200
@@ -470,6 +470,20 @@ typedef struct dom0_hypercall_init {
     unsigned long mfn;        /* machine frame to be initialised */
 } dom0_hypercall_init_t;
 DEFINE_GUEST_HANDLE(dom0_hypercall_init_t);
+ 
+#define DOM0_IOMMU_CREATE_IO_SPACE 49
+typedef struct dom0_iommu_create_io_space {
+    u64 size;       /* size of the IO address space in bytes */
+    u32 bdf;        /* bus/dev/func this space translates for */
+    u64 rootmfn;    /* mfn of the root of the iommu table */
+} dom0_iommu_create_io_space_t;
+DEFINE_GUEST_HANDLE(dom0_iommu_create_io_space_t);
+
+#define DOM0_IOMMU_DESTROY_IO_SPACE 50
+typedef struct dom0_iommu_destroy_io_space {
+    u32 bdf;
+} dom0_iommu_destroy_io_space_t;
+DEFINE_GUEST_HANDLE(dom0_iommu_destroy_io_space_t);
 
 typedef struct dom0_op {
     uint32_t cmd;
@@ -512,6 +526,8 @@ typedef struct dom0_op {
         struct dom0_irq_permission    irq_permission;
         struct dom0_iomem_permission  iomem_permission;
         struct dom0_hypercall_init    hypercall_init;
+        struct dom0_iommu_create_io_space  iommu_create_io_space;
+        struct dom0_iommu_destroy_io_space iommu_destroy_io_space;
         uint8_t                       pad[128];
     } u;
 } dom0_op_t;
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/public/xen.h 
xen/xen/include/public/xen.h
--- vanilla.xen/xen/include/public/xen.h        2006-03-16 09:53:07.000000000 
+0200
+++ xen/xen/include/public/xen.h        2006-03-16 23:08:13.000000000 +0200
@@ -60,6 +60,8 @@
 #define __HYPERVISOR_acm_op               27
 #define __HYPERVISOR_nmi_op               28
 #define __HYPERVISOR_sched_op_new         29
+#define __HYPERVISOR_iommu_map            30
+#define __HYPERVISOR_iommu_unmap          31
 
 /* 
  * VIRTUAL INTERRUPTS
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/xen/calgary.h 
xen/xen/include/xen/calgary.h
--- vanilla.xen/xen/include/xen/calgary.h       1970-01-01 02:00:00.000000000 
+0200
+++ xen/xen/include/xen/calgary.h       2006-03-16 23:22:27.000000000 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#define TCE_MAX_TABLE_SIZE 7
+
+struct iommu_table {
+    u32 size; /* in number of entries */
+    void* ptr;
+};
+
+#define TCE_ENTRY_SIZE   8   /* in bytes */
+
+#define TCE_READ_SHIFT   0
+#define TCE_WRITE_SHIFT  1
+#define TCE_HUBID_SHIFT  2   /* unused */
+#define TCE_RSVD_SHIFT   8   /* unused */
+#define TCE_RPN_SHIFT    12
+#define TCE_UNUSED_SHIFT 48  /* unused */
+
+#define TCE_RPN_MASK     0x0000fffffffff000ULL
+
+int calgary_create_io_space(u64 size, u32 bdf, void** space, u64* rootmfn);
+void calgary_destroy_io_space(void* space);
+u64 calgary_map(void* space, u64 ioaddr, u64 mfn, u32 access, u32 bdf,
+        u32 size);
+int calgary_unmap(void* space, u64 ioaddr, u32 bdf, u32 size);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff -Naurp -X /home/muli/w/dontdiff vanilla.xen/xen/include/xen/iommu.h 
xen/xen/include/xen/iommu.h
--- vanilla.xen/xen/include/xen/iommu.h 1970-01-01 02:00:00.000000000 +0200
+++ xen/xen/include/xen/iommu.h 2006-03-20 15:17:11.000000000 +0200
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2006 Muli Ben-Yehuda <mulix@xxxxxxxxx>, IBM Corporation
+ */
+
+#include <asm/types.h>
+#include <asm/page.h>
+#include <public/dom0_ops.h>
+
+int iommu_create_io_space(GUEST_HANDLE(dom0_op_t) u_dom0_op,
+    struct dom0_op *op);
+int iommu_destroy_io_space(u32 bdf);
+u64 do_iommu_map(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size);
+int do_iommu_unmap(u64 ioaddr, u32 bdf, u32 size);
+
+/*
+ * Local variables:
+ * mode: C
+ * c-set-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */

-- 
Muli Ben-Yehuda
http://www.mulix.org | http://mulix.livejournal.com/


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.