debuggers.hg
changeset 22738:66e806289464
EPT/VT-d: bug fix for EPT/VT-d table sharing
This patch makes following changes: 1) Moves EPT/VT-d sharing
initialization back to when it is actually needed to make sure
vmx_ept_vpid_cap has been initialized. 2) added page order parameter
to iommu_pte_flush() to tell VT-d what size of page to flush. 3)
added hap_2mb flag to ease performance studies between base 4KB EPT
size and when 2MB and 1GB page size support are enabled.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
This patch makes following changes: 1) Moves EPT/VT-d sharing
initialization back to when it is actually needed to make sure
vmx_ept_vpid_cap has been initialized. 2) added page order parameter
to iommu_pte_flush() to tell VT-d what size of page to flush. 3)
added hap_2mb flag to ease performance studies between base 4KB EPT
size and when 2MB and 1GB page size support are enabled.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author | Keir Fraser <keir@xen.org> |
---|---|
date | Mon Jan 10 08:40:32 2011 +0000 (2011-01-10) |
parents | 946d84529a07 |
children | 08bb0eefe871 |
files | xen/arch/x86/mm/hap/p2m-ept.c xen/arch/x86/mm/p2m.c xen/drivers/passthrough/vtd/iommu.c xen/include/xen/iommu.h |
line diff
1.1 --- a/xen/arch/x86/mm/hap/p2m-ept.c Sat Jan 08 11:07:18 2011 +0000 1.2 +++ b/xen/arch/x86/mm/hap/p2m-ept.c Mon Jan 10 08:40:32 2011 +0000 1.3 @@ -451,12 +451,12 @@ out: 1.4 if ( rv && iommu_enabled && need_iommu(p2m->domain) && need_modify_vtd_table ) 1.5 { 1.6 if ( iommu_hap_pt_share ) 1.7 - iommu_pte_flush(d, gfn, (u64*)ept_entry, vtd_pte_present); 1.8 + iommu_pte_flush(d, gfn, (u64*)ept_entry, order, vtd_pte_present); 1.9 else 1.10 { 1.11 if ( p2mt == p2m_ram_rw ) 1.12 { 1.13 - if ( order == EPT_TABLE_ORDER ) 1.14 + if ( order > 0 ) 1.15 { 1.16 for ( i = 0; i < (1 << order); i++ ) 1.17 iommu_map_page( 1.18 @@ -469,7 +469,7 @@ out: 1.19 } 1.20 else 1.21 { 1.22 - if ( order == EPT_TABLE_ORDER ) 1.23 + if ( order > 0 ) 1.24 { 1.25 for ( i = 0; i < (1 << order); i++ ) 1.26 iommu_unmap_page(p2m->domain, gfn - offset + i);
2.1 --- a/xen/arch/x86/mm/p2m.c Sat Jan 08 11:07:18 2011 +0000 2.2 +++ b/xen/arch/x86/mm/p2m.c Mon Jan 10 08:40:32 2011 +0000 2.3 @@ -43,6 +43,9 @@ 2.4 static bool_t __read_mostly opt_hap_1gb = 1; 2.5 boolean_param("hap_1gb", opt_hap_1gb); 2.6 2.7 +static bool_t __read_mostly opt_hap_2mb = 1; 2.8 +boolean_param("hap_2mb", opt_hap_2mb); 2.9 + 2.10 /* Printouts */ 2.11 #define P2M_PRINTK(_f, _a...) \ 2.12 debugtrace_printk("p2m: %s(): " _f, __func__, ##_a) 2.13 @@ -1779,7 +1782,7 @@ int set_p2m_entry(struct p2m_domain *p2m 2.14 order = ( (((gfn | mfn_x(mfn) | todo) & ((1ul << 18) - 1)) == 0) && 2.15 hvm_hap_has_1gb(d) && opt_hap_1gb ) ? 18 : 2.16 ((((gfn | mfn_x(mfn) | todo) & ((1ul << 9) - 1)) == 0) && 2.17 - hvm_hap_has_2mb(d)) ? 9 : 0; 2.18 + hvm_hap_has_2mb(d) && opt_hap_2mb) ? 9 : 0; 2.19 else 2.20 order = 0; 2.21
3.1 --- a/xen/drivers/passthrough/vtd/iommu.c Sat Jan 08 11:07:18 2011 +0000 3.2 +++ b/xen/drivers/passthrough/vtd/iommu.c Mon Jan 10 08:40:32 2011 +0000 3.3 @@ -518,24 +518,9 @@ static int inline iommu_flush_iotlb_dsi( 3.4 return status; 3.5 } 3.6 3.7 -static int inline get_alignment(u64 base, unsigned int size) 3.8 -{ 3.9 - int t = 0; 3.10 - u64 end; 3.11 - 3.12 - end = base + size - 1; 3.13 - while ( base != end ) 3.14 - { 3.15 - t++; 3.16 - base >>= 1; 3.17 - end >>= 1; 3.18 - } 3.19 - return t; 3.20 -} 3.21 - 3.22 static int inline iommu_flush_iotlb_psi( 3.23 struct iommu *iommu, u16 did, u64 addr, unsigned int pages, 3.24 - int flush_non_present_entry, int flush_dev_iotlb) 3.25 + int order, int flush_non_present_entry, int flush_dev_iotlb) 3.26 { 3.27 unsigned int align; 3.28 struct iommu_flush *flush = iommu_get_flush(iommu); 3.29 @@ -548,17 +533,12 @@ static int inline iommu_flush_iotlb_psi( 3.30 if ( !cap_pgsel_inv(iommu->cap) ) 3.31 return iommu_flush_iotlb_dsi(iommu, did, flush_non_present_entry, flush_dev_iotlb); 3.32 3.33 - /* 3.34 - * PSI requires page size is 2 ^ x, and the base address is naturally 3.35 - * aligned to the size 3.36 - */ 3.37 - align = get_alignment(addr >> PAGE_SHIFT_4K, pages); 3.38 /* Fallback to domain selective flush if size is too big */ 3.39 - if ( align > cap_max_amask_val(iommu->cap) ) 3.40 + if ( order > cap_max_amask_val(iommu->cap) ) 3.41 return iommu_flush_iotlb_dsi(iommu, did, flush_non_present_entry, flush_dev_iotlb); 3.42 3.43 - addr >>= PAGE_SHIFT_4K + align; 3.44 - addr <<= PAGE_SHIFT_4K + align; 3.45 + addr >>= PAGE_SHIFT_4K + order; 3.46 + addr <<= PAGE_SHIFT_4K + order; 3.47 3.48 /* apply platform specific errata workarounds */ 3.49 vtd_ops_preamble_quirk(iommu); 3.50 @@ -634,8 +614,8 @@ static void dma_pte_clear_one(struct dom 3.51 iommu_domid= domain_iommu_domid(domain, iommu); 3.52 if ( iommu_domid == -1 ) 3.53 continue; 3.54 - if ( iommu_flush_iotlb_psi(iommu, iommu_domid, 3.55 - addr, 1, 0, flush_dev_iotlb) ) 3.56 + if ( iommu_flush_iotlb_psi(iommu, iommu_domid, addr, 3.57 + 1, 0, 0, flush_dev_iotlb) ) 3.58 iommu_flush_write_buffer(iommu); 3.59 } 3.60 } 3.61 @@ -1710,7 +1690,7 @@ static int intel_iommu_map_page( 3.62 if ( iommu_domid == -1 ) 3.63 continue; 3.64 if ( iommu_flush_iotlb_psi(iommu, iommu_domid, 3.65 - (paddr_t)gfn << PAGE_SHIFT_4K, 1, 3.66 + (paddr_t)gfn << PAGE_SHIFT_4K, 1, 0, 3.67 !dma_pte_present(old), flush_dev_iotlb) ) 3.68 iommu_flush_write_buffer(iommu); 3.69 } 3.70 @@ -1729,7 +1709,8 @@ static int intel_iommu_unmap_page(struct 3.71 return 0; 3.72 } 3.73 3.74 -void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int present) 3.75 +void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, 3.76 + int order, int present) 3.77 { 3.78 struct acpi_drhd_unit *drhd; 3.79 struct iommu *iommu = NULL; 3.80 @@ -1751,7 +1732,7 @@ void iommu_pte_flush(struct domain *d, u 3.81 continue; 3.82 if ( iommu_flush_iotlb_psi(iommu, iommu_domid, 3.83 (paddr_t)gfn << PAGE_SHIFT_4K, 1, 3.84 - !present, flush_dev_iotlb) ) 3.85 + order, !present, flush_dev_iotlb) ) 3.86 iommu_flush_write_buffer(iommu); 3.87 } 3.88 } 3.89 @@ -1769,6 +1750,28 @@ static int vtd_ept_page_compatible(struc 3.90 return 1; 3.91 } 3.92 3.93 +static bool_t vtd_ept_share(void) 3.94 +{ 3.95 + struct acpi_drhd_unit *drhd; 3.96 + struct iommu *iommu; 3.97 + bool_t share = TRUE; 3.98 + 3.99 + /* sharept defaults to 0 for now, default to 1 when feature matures */ 3.100 + if ( !sharept ) 3.101 + share = FALSE; 3.102 + 3.103 + /* 3.104 + * Determine whether EPT and VT-d page tables can be shared or not. 3.105 + */ 3.106 + for_each_drhd_unit ( drhd ) 3.107 + { 3.108 + iommu = drhd->iommu; 3.109 + if ( !vtd_ept_page_compatible(drhd->iommu) ) 3.110 + share = FALSE; 3.111 + } 3.112 + return share; 3.113 +} 3.114 + 3.115 /* 3.116 * set VT-d page table directory to EPT table if allowed 3.117 */ 3.118 @@ -1779,11 +1782,13 @@ void iommu_set_pgd(struct domain *d) 3.119 3.120 ASSERT( is_hvm_domain(d) && d->arch.hvm_domain.hap_enabled ); 3.121 3.122 - if ( !iommu_hap_pt_share ) 3.123 - return; 3.124 - 3.125 + iommu_hap_pt_share = vtd_ept_share(); 3.126 pgd_mfn = pagetable_get_mfn(p2m_get_pagetable(p2m_get_hostp2m(d))); 3.127 hd->pgd_maddr = pagetable_get_paddr(pagetable_from_mfn(pgd_mfn)); 3.128 + 3.129 + dprintk(XENLOG_INFO VTDPREFIX, 3.130 + "VT-d page table %s with EPT table\n", 3.131 + iommu_hap_pt_share ? "shares" : "not sharing"); 3.132 } 3.133 3.134 static int domain_rmrr_mapped(struct domain *d, 3.135 @@ -2036,27 +2041,6 @@ static int init_vtd_hw(void) 3.136 } 3.137 } 3.138 iommu_flush_all(); 3.139 - 3.140 - /* 3.141 - * Determine whether EPT and VT-d page tables can be shared or not. 3.142 - */ 3.143 - iommu_hap_pt_share = TRUE; 3.144 - for_each_drhd_unit ( drhd ) 3.145 - { 3.146 - iommu = drhd->iommu; 3.147 - if ( (drhd->iommu->nr_pt_levels != VTD_PAGE_TABLE_LEVEL_4) || 3.148 - !vtd_ept_page_compatible(drhd->iommu) ) 3.149 - iommu_hap_pt_share = FALSE; 3.150 - } 3.151 - 3.152 - /* keep boot flag sharept as safe fallback. remove after feature matures */ 3.153 - if ( !sharept ) 3.154 - iommu_hap_pt_share = FALSE; 3.155 - 3.156 - dprintk(XENLOG_INFO VTDPREFIX, 3.157 - "VT-d page table %sshared with EPT table\n", 3.158 - iommu_hap_pt_share ? "" : "not "); 3.159 - 3.160 return 0; 3.161 } 3.162
4.1 --- a/xen/include/xen/iommu.h Sat Jan 08 11:07:18 2011 +0000 4.2 +++ b/xen/include/xen/iommu.h Mon Jan 10 08:40:32 2011 +0000 4.3 @@ -85,7 +85,7 @@ int iommu_get_device_group(struct domain 4.4 int iommu_map_page(struct domain *d, unsigned long gfn, unsigned long mfn, 4.5 unsigned int flags); 4.6 int iommu_unmap_page(struct domain *d, unsigned long gfn); 4.7 -void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int present); 4.8 +void iommu_pte_flush(struct domain *d, u64 gfn, u64 *pte, int order, int present); 4.9 void iommu_set_pgd(struct domain *d); 4.10 void iommu_domain_teardown(struct domain *d); 4.11 int hvm_do_IRQ_dpci(struct domain *d, unsigned int irq);