diff -Naurp --exclude-from /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-02-24 01:09:21.000000000 +0200 +++ xen/xen/arch/x86/x86_64/entry.S 2006-03-07 13:05:03.000000000 +0200 @@ -549,6 +549,7 @@ ENTRY(hypercall_table) .quad do_mmuext_op .quad do_acm_op .quad do_nmi_op + .quad do_iommu_mapping .rept NR_hypercalls-((.-hypercall_table)/8) .quad do_ni_hypercall .endr @@ -583,6 +584,7 @@ ENTRY(hypercall_args_table) .byte 4 /* do_mmuext_op */ .byte 1 /* do_acm_op */ .byte 2 /* do_nmi_op */ + .byte 5 /* do_iommu_mapping */ .rept NR_hypercalls-(.-hypercall_args_table) .byte 0 /* do_ni_hypercall */ .endr diff -Naurp --exclude-from /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-07 17:23:10.000000000 +0200 @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2006 Muli Ben-Yehuda , IBM Corporation + */ + +#include +#include +#include +#include +#include +#include +#include + +#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) )); \ +}) + +static void tce_build(struct iommu_table* tbl, u64 index, u64 mfn, u32 access) +{ + union tce_entry *tp; + union tce_entry t; + + BUG_ON(!tbl); + + t.te_word = 0; + t.bits.read = access & 0x1; + t.bits.write = !!(access & 0x2); + t.bits.rpn = mfn; + + tp = ((union tce_entry *)tbl->ptr) + index; + tp->te_word = swab64(t.te_word); + + /* make sure HW sees it */ + mb(); +} + +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 * sizeof(union tce_entry); + + 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 * sizeof(union tce_entry); + + free_xenheap_pages(tbl->ptr, get_order_from_bytes(bytes)); + tbl->ptr = NULL; +} + +u64 calgary_establish_mapping(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; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -Naurp --exclude-from /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 #include #include +#include #include #include #include @@ -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 --exclude-from /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-07 17:22:21.000000000 +0200 @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2006 Muli Ben-Yehuda , IBM Corporation + */ + +#include +#include +#include + +#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; +} + +u64 do_iommu_mapping(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size) +{ + void* space; + u64 retaddr; + + space = (bdf == 0 ? iommu_space[0] : iommu_space[1]); + + retaddr = calgary_establish_mapping(space, ioaddr, mfn, access, bdf, size); + + return retaddr; +} + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff -Naurp --exclude-from /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 --exclude-from /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-07 19:54:46.000000000 +0200 +++ xen/xen/include/public/xen.h 2006-03-07 20:35:06.000000000 +0200 @@ -61,6 +61,7 @@ #define __HYPERVISOR_mmuext_op 26 #define __HYPERVISOR_acm_op 27 #define __HYPERVISOR_nmi_op 28 +#define __HYPERVISOR_iommu_mapping 29 /* * VIRTUAL INTERRUPTS diff -Naurp --exclude-from /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-07 16:00:50.000000000 +0200 @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2006 Muli Ben-Yehuda , IBM Corporation + */ + +#define TCE_MAX_TABLE_SIZE 7 + +struct iommu_table { + u32 size; /* in number of entries */ + void* ptr; +}; + +union tce_entry { + u64 te_word; + struct { + unsigned int read :1; /* read allowed */ + unsigned int write :1; /* write allowed */ + unsigned int hubid :6; /* hub id - unused */ + unsigned int rsvd :4; /* reserved */ + unsigned long rpn :36; /* Real page number */ + unsigned int unused :16; /* unused */ + } bits; +}; + +int calgary_create_io_space(u64 size, u32 bdf, void** space, u64* rootmfn); +void calgary_destroy_io_space(void* space); +u64 calgary_establish_mapping(void* space, u64 ioaddr, u64 mfn, + u32 access, 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 --exclude-from /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-07 15:35:50.000000000 +0200 @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2006 Muli Ben-Yehuda , IBM Corporation + */ + +#include +#include +#include + +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_mapping(u64 ioaddr, u64 mfn, u32 access, u32 bdf, u32 size); + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */