diff -r a583f3a7eafc xen/arch/x86/hvm/vmx/vtd/intel-iommu.c --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue Dec 04 22:54:58 2007 +0000 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Wed Dec 05 14:59:23 2007 +0800 @@ -40,6 +40,52 @@ extern void print_vtd_entries(struct dom extern void print_vtd_entries(struct domain *d, int bus, int devfn, unsigned long gmfn); +static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */ +static int domid_bitmap_size; /* domain id bitmap size in bit */ +static void *domid_bitmap; /* iommu domain id bitmap */ + +#define DID_FIELD_WIDTH 16 +#define DID_HIGH_OFFSET 8 +static void context_set_domain_id(struct context_entry *context, + struct domain *d) +{ + unsigned int idx; + unsigned long flags; + domid_t iommu_domid = domain_iommu_domid(d); + + if ( iommu_domid != 0 ) + { + context->hi &= (1 << DID_HIGH_OFFSET) - 1; + context->hi |= iommu_domid << DID_HIGH_OFFSET; + return; + } + + idx = find_first_zero_bit(domid_bitmap, domid_bitmap_size); + iommu_domid = idx & ((1 << DID_FIELD_WIDTH) - 1); + context->hi &= (1 << DID_HIGH_OFFSET) - 1; + context->hi |= iommu_domid << DID_HIGH_OFFSET; + + domain_set_iommu_domid(d, iommu_domid); + + spin_lock_irqsave(&domid_bitmap_lock, flags); + set_bit(iommu_domid, domid_bitmap); + spin_unlock_irqrestore(&domid_bitmap_lock, flags); +} + +static void iommu_domid_release(struct domain *d) +{ + unsigned long flags; + domid_t iommu_domid = domain_iommu_domid(d); + + if ( iommu_domid != 0 ) + { + domain_set_iommu_domid(d, 0); + spin_lock_irqsave(&domid_bitmap_lock, flags); + clear_bit(iommu_domid, domid_bitmap); + spin_unlock_irqrestore(&domid_bitmap_lock, flags); + } +} + unsigned int x86_clflush_size; void clflush_cache_range(void *adr, int size) { @@ -276,9 +322,6 @@ static int __iommu_flush_context( unsigned long flag; unsigned long start_time; - /* Domain id in context is 1 based */ - did++; - /* * In the non-present entry flush case, if hardware doesn't cache * non-present entry we do nothing and if hardware cache non-present @@ -362,9 +405,6 @@ static int __iommu_flush_iotlb(struct io u64 val = 0, val_iva = 0; unsigned long flag; unsigned long start_time; - - /* Domain id in context is 1 based */ - did++; /* * In the non-present entry flush case, if hardware doesn't cache @@ -534,7 +574,8 @@ static void dma_pte_clear_one(struct dom { iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) - iommu_flush_iotlb_psi(iommu, domain->domain_id, addr, 1, 0); + iommu_flush_iotlb_psi(iommu, domain_iommu_domid(domain), + addr, 1, 0); else if (cap_rwbf(iommu->cap)) iommu_flush_write_buffer(iommu); } @@ -1036,7 +1077,7 @@ static int domain_context_mapping_one( * domain_id 0 is not valid on Intel's IOMMU, force domain_id to * be 1 based as required by intel's iommu hw. */ - context_set_domain_id(*context, domain->domain_id); + context_set_domain_id(context, domain); context_set_address_width(*context, hd->agaw); if ( ecap_pass_thru(iommu->ecap) ) @@ -1069,12 +1110,12 @@ static int domain_context_mapping_one( bus, PCI_SLOT(devfn), PCI_FUNC(devfn), context->hi, context->lo, hd->pgd); - if ( iommu_flush_context_device(iommu, domain->domain_id, + if ( iommu_flush_context_device(iommu, domain_iommu_domid(domain), (((u16)bus) << 8) | devfn, DMA_CCMD_MASK_NOBIT, 1) ) iommu_flush_write_buffer(iommu); else - iommu_flush_iotlb_dsi(iommu, domain->domain_id, 0); + iommu_flush_iotlb_dsi(iommu, domain_iommu_domid(domain), 0); spin_unlock_irqrestore(&iommu->lock, flags); return ret; } @@ -1414,6 +1455,8 @@ void iommu_domain_teardown(struct domain if ( list_empty(&acpi_drhd_units) ) return; + iommu_domid_release(d); + #if CONFIG_PAGING_LEVELS == 3 { struct hvm_iommu *hd = domain_hvm_iommu(d); @@ -1492,7 +1535,7 @@ int iommu_map_page(struct domain *d, pad { iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) - iommu_flush_iotlb_psi(iommu, d->domain_id, + iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d), gfn << PAGE_SHIFT_4K, 1, 0); else if ( cap_rwbf(iommu->cap) ) iommu_flush_write_buffer(iommu); @@ -1556,7 +1599,8 @@ int iommu_page_mapping(struct domain *do { iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) - iommu_flush_iotlb_psi(iommu, domain->domain_id, iova, index, 0); + iommu_flush_iotlb_psi(iommu, domain_iommu_domid(domain), + iova, index, 0); else if ( cap_rwbf(iommu->cap) ) iommu_flush_write_buffer(iommu); } @@ -1581,7 +1625,7 @@ void iommu_flush(struct domain *d, dma_a { iommu = drhd->iommu; if ( cap_caching_mode(iommu->cap) ) - iommu_flush_iotlb_psi(iommu, d->domain_id, + iommu_flush_iotlb_psi(iommu, domain_iommu_domid(d), gfn << PAGE_SHIFT_4K, 1, 0); else if ( cap_rwbf(iommu->cap) ) iommu_flush_write_buffer(iommu); @@ -1755,11 +1799,12 @@ int iommu_setup(void) struct hvm_iommu *hd = domain_hvm_iommu(dom0); struct acpi_drhd_unit *drhd; struct iommu *iommu; - unsigned long i; + unsigned long i, flags; if ( !vtd_enabled ) return 0; + spin_lock_init(&domid_bitmap_lock); INIT_LIST_HEAD(&hd->pdev_list); /* start from scratch */ @@ -1773,6 +1818,20 @@ int iommu_setup(void) */ drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list); iommu = drhd->iommu; + + /* Allocate domain id bitmap, and set bit 0 as reserved */ + spin_lock_irqsave(&domid_bitmap_lock, flags); + domid_bitmap_size = cap_ndoms(iommu->cap); + domid_bitmap = xmalloc_bytes(domid_bitmap_size / 8); + if ( domid_bitmap == NULL ) + { + spin_unlock_irqrestore(&domid_bitmap_lock, flags); + goto error; + } + else + memset(domid_bitmap, 0, domid_bitmap_size / 8); + set_bit(0, domid_bitmap); + spin_unlock_irqrestore(&domid_bitmap_lock, flags); /* setup 1:1 page table for dom0 */ for ( i = 0; i < max_page; i++ ) diff -r a583f3a7eafc xen/include/asm-x86/hvm/iommu.h --- a/xen/include/asm-x86/hvm/iommu.h Tue Dec 04 22:54:58 2007 +0000 +++ b/xen/include/asm-x86/hvm/iommu.h Wed Dec 05 13:18:27 2007 +0800 @@ -28,6 +28,10 @@ #include #include +#define domain_iommu_domid(d) (d->arch.hvm_domain.hvm_iommu.iommu_domid) +#define domain_set_iommu_domid(d, iommu_did) \ + do {d->arch.hvm_domain.hvm_iommu.iommu_domid = iommu_did;} while(0) + struct g2m_ioport { struct list_head list; unsigned int gport; @@ -42,6 +46,7 @@ struct hvm_iommu { spinlock_t mapping_lock; /* io page table lock */ int agaw; /* adjusted guest address width, 0 is level 2 30-bit */ struct list_head g2m_ioport_list; /* guest to machine ioport mapping */ + domid_t iommu_domid; /* domain id stored in iommu */ /* amd iommu support */ int domain_id; diff -r a583f3a7eafc xen/include/asm-x86/hvm/vmx/intel-iommu.h --- a/xen/include/asm-x86/hvm/vmx/intel-iommu.h Tue Dec 04 22:54:58 2007 +0000 +++ b/xen/include/asm-x86/hvm/vmx/intel-iommu.h Wed Dec 05 09:36:51 2007 +0800 @@ -227,8 +227,6 @@ struct context_entry { do {(c).lo &= 0xfff; (c).lo |= (val) & PAGE_MASK_4K ;} while(0) #define context_set_address_width(c, val) \ do {(c).hi &= 0xfffffff8; (c).hi |= (val) & 7;} while(0) -#define context_set_domain_id(c, val) \ - do {(c).hi &= 0xff; (c).hi |= ((val + 1) & ((1 << 16) - 1)) << 8;} while(0) #define context_clear_entry(c) do {(c).lo = 0; (c).hi = 0;} while(0) /* page table handling */