debuggers.hg
changeset 16813:cc5bb500df5f
vtd: Enable queued invalidation method if such HW support is
detected. Otherwise, register invalidation method is used.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
detected. Otherwise, register invalidation method is used.
Signed-off-by: Allen Kay <allen.m.kay@intel.com>
author | Keir Fraser <keir.fraser@citrix.com> |
---|---|
date | Tue Jan 22 09:48:51 2008 +0000 (2008-01-22) |
parents | 80e177b12fd2 |
children | 2af5fb3e34e5 |
files | xen/arch/x86/hvm/vmx/vtd/Makefile xen/arch/x86/hvm/vmx/vtd/extern.h xen/arch/x86/hvm/vmx/vtd/intel-iommu.c xen/arch/x86/hvm/vmx/vtd/qinval.c xen/arch/x86/hvm/vmx/vtd/vtd.h xen/include/asm-x86/iommu.h |
line diff
1.1 --- a/xen/arch/x86/hvm/vmx/vtd/Makefile Tue Jan 22 09:46:33 2008 +0000 1.2 +++ b/xen/arch/x86/hvm/vmx/vtd/Makefile Tue Jan 22 09:48:51 2008 +0000 1.3 @@ -2,3 +2,4 @@ obj-y += intel-iommu.o 1.4 obj-y += dmar.o 1.5 obj-y += utils.o 1.6 obj-y += io.o 1.7 +obj-y += qinval.o
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/xen/arch/x86/hvm/vmx/vtd/extern.h Tue Jan 22 09:48:51 2008 +0000 2.3 @@ -0,0 +1,55 @@ 2.4 +/* 2.5 + * Copyright (c) 2006, Intel Corporation. 2.6 + * 2.7 + * This program is free software; you can redistribute it and/or modify it 2.8 + * under the terms and conditions of the GNU General Public License, 2.9 + * version 2, as published by the Free Software Foundation. 2.10 + * 2.11 + * This program is distributed in the hope it will be useful, but WITHOUT 2.12 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 2.13 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 2.14 + * more details. 2.15 + * 2.16 + * You should have received a copy of the GNU General Public License along with 2.17 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 2.18 + * Place - Suite 330, Boston, MA 02111-1307 USA. 2.19 + * 2.20 + * Copyright (C) Allen Kay <allen.m.kay@intel.com> 2.21 + * Copyright (C) Weidong Han <weidong.han@intel.com> 2.22 + */ 2.23 + 2.24 +#ifndef _VTD_EXTERN_H_ 2.25 +#define _VTD_EXTERN_H_ 2.26 + 2.27 +#include "dmar.h" 2.28 + 2.29 +extern int iommu_setup_done; 2.30 +extern int vtd2_thurley_enabled; 2.31 +extern int vtd2_qinval_enabled; 2.32 + 2.33 +extern spinlock_t ioapic_lock; 2.34 +extern struct qi_ctrl *qi_ctrl; 2.35 +extern struct ir_ctrl *ir_ctrl; 2.36 + 2.37 +void print_iommu_regs(struct acpi_drhd_unit *drhd); 2.38 +void print_vtd_entries(struct domain *d, struct iommu *iommu, 2.39 + int bus, int devfn, unsigned long gmfn); 2.40 + 2.41 +int qinval_setup(struct iommu *iommu); 2.42 +int queue_invalidate_context(struct iommu *iommu, 2.43 + u16 did, u16 source_id, u8 function_mask, u8 granu); 2.44 +int queue_invalidate_iotlb(struct iommu *iommu, 2.45 + u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr); 2.46 +int queue_invalidate_iec(struct iommu *iommu, 2.47 + u8 granu, u8 im, u16 iidx); 2.48 +int invalidate_sync(struct iommu *iommu); 2.49 +int iommu_flush_iec_global(struct iommu *iommu); 2.50 +int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx); 2.51 +void gsi_remapping(unsigned int gsi); 2.52 +void print_iommu_regs(struct acpi_drhd_unit *drhd); 2.53 +int vtd_hw_check(void); 2.54 +struct iommu * ioapic_to_iommu(unsigned int apic_id); 2.55 +struct acpi_drhd_unit * ioapic_to_drhd(unsigned int apic_id); 2.56 +void clear_fault_bits(struct iommu *iommu); 2.57 + 2.58 +#endif // _VTD_EXTERN_H_
3.1 --- a/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue Jan 22 09:46:33 2008 +0000 3.2 +++ b/xen/arch/x86/hvm/vmx/vtd/intel-iommu.c Tue Jan 22 09:48:51 2008 +0000 3.3 @@ -34,13 +34,10 @@ 3.4 #include "pci-direct.h" 3.5 #include "pci_regs.h" 3.6 #include "msi.h" 3.7 +#include "extern.h" 3.8 3.9 #define domain_iommu_domid(d) ((d)->arch.hvm_domain.hvm_iommu.iommu_domid) 3.10 3.11 -extern void print_iommu_regs(struct acpi_drhd_unit *drhd); 3.12 -extern void print_vtd_entries(struct domain *d, int bus, int devfn, 3.13 - unsigned long gmfn); 3.14 - 3.15 static spinlock_t domid_bitmap_lock; /* protect domain id bitmap */ 3.16 static int domid_bitmap_size; /* domain id bitmap size in bit */ 3.17 static void *domid_bitmap; /* iommu domain id bitmap */ 3.18 @@ -304,11 +301,12 @@ static void iommu_flush_write_buffer(str 3.19 } 3.20 3.21 /* return value determine if we need a write buffer flush */ 3.22 -static int __iommu_flush_context( 3.23 - struct iommu *iommu, 3.24 +static int flush_context_reg( 3.25 + void *_iommu, 3.26 u16 did, u16 source_id, u8 function_mask, u64 type, 3.27 int non_present_entry_flush) 3.28 { 3.29 + struct iommu *iommu = (struct iommu *) _iommu; 3.30 u64 val = 0; 3.31 unsigned long flag; 3.32 unsigned long start_time; 3.33 @@ -367,14 +365,16 @@ static int __iommu_flush_context( 3.34 static int inline iommu_flush_context_global( 3.35 struct iommu *iommu, int non_present_entry_flush) 3.36 { 3.37 - return __iommu_flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL, 3.38 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.39 + return flush->context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL, 3.40 non_present_entry_flush); 3.41 } 3.42 3.43 static int inline iommu_flush_context_domain( 3.44 struct iommu *iommu, u16 did, int non_present_entry_flush) 3.45 { 3.46 - return __iommu_flush_context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL, 3.47 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.48 + return flush->context(iommu, did, 0, 0, DMA_CCMD_DOMAIN_INVL, 3.49 non_present_entry_flush); 3.50 } 3.51 3.52 @@ -382,16 +382,18 @@ static int inline iommu_flush_context_de 3.53 struct iommu *iommu, u16 did, u16 source_id, 3.54 u8 function_mask, int non_present_entry_flush) 3.55 { 3.56 - return __iommu_flush_context(iommu, did, source_id, function_mask, 3.57 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.58 + return flush->context(iommu, did, source_id, function_mask, 3.59 DMA_CCMD_DEVICE_INVL, 3.60 non_present_entry_flush); 3.61 } 3.62 3.63 /* return value determine if we need a write buffer flush */ 3.64 -static int __iommu_flush_iotlb(struct iommu *iommu, u16 did, 3.65 +static int flush_iotlb_reg(void *_iommu, u16 did, 3.66 u64 addr, unsigned int size_order, u64 type, 3.67 int non_present_entry_flush) 3.68 { 3.69 + struct iommu *iommu = (struct iommu *) _iommu; 3.70 int tlb_offset = ecap_iotlb_offset(iommu->ecap); 3.71 u64 val = 0, val_iva = 0; 3.72 unsigned long flag; 3.73 @@ -467,14 +469,16 @@ static int __iommu_flush_iotlb(struct io 3.74 static int inline iommu_flush_iotlb_global(struct iommu *iommu, 3.75 int non_present_entry_flush) 3.76 { 3.77 - return __iommu_flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH, 3.78 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.79 + return flush->iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH, 3.80 non_present_entry_flush); 3.81 } 3.82 3.83 static int inline iommu_flush_iotlb_dsi(struct iommu *iommu, u16 did, 3.84 int non_present_entry_flush) 3.85 { 3.86 - return __iommu_flush_iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH, 3.87 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.88 + return flush->iotlb(iommu, did, 0, 0, DMA_TLB_DSI_FLUSH, 3.89 non_present_entry_flush); 3.90 } 3.91 3.92 @@ -498,6 +502,7 @@ static int inline iommu_flush_iotlb_psi( 3.93 u64 addr, unsigned int pages, int non_present_entry_flush) 3.94 { 3.95 unsigned int align; 3.96 + struct iommu_flush *flush = iommu_get_flush(iommu); 3.97 3.98 BUG_ON(addr & (~PAGE_MASK_4K)); 3.99 BUG_ON(pages == 0); 3.100 @@ -520,7 +525,7 @@ static int inline iommu_flush_iotlb_psi( 3.101 addr >>= PAGE_SHIFT_4K + align; 3.102 addr <<= PAGE_SHIFT_4K + align; 3.103 3.104 - return __iommu_flush_iotlb(iommu, did, addr, align, 3.105 + return flush->iotlb(iommu, did, addr, align, 3.106 DMA_TLB_PSI_FLUSH, non_present_entry_flush); 3.107 } 3.108 3.109 @@ -701,7 +706,7 @@ static int iommu_enable_translation(stru 3.110 unsigned long flags; 3.111 3.112 dprintk(XENLOG_INFO VTDPREFIX, 3.113 - "iommu_enable_translation: enabling vt-d translation\n"); 3.114 + "iommu_enable_translation: iommu->reg = %p\n", iommu->reg); 3.115 spin_lock_irqsave(&iommu->register_lock, flags); 3.116 iommu->gcmd |= DMA_GCMD_TE; 3.117 dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); 3.118 @@ -746,14 +751,47 @@ static int iommu_page_fault_do_one(struc 3.119 u8 fault_reason, u16 source_id, u32 addr) 3.120 { 3.121 dprintk(XENLOG_WARNING VTDPREFIX, 3.122 - "iommu_page_fault:%s: DEVICE %x:%x.%x addr %x REASON %x\n", 3.123 - (type ? "DMA Read" : "DMA Write"), 3.124 - (source_id >> 8), PCI_SLOT(source_id & 0xFF), 3.125 - PCI_FUNC(source_id & 0xFF), addr, fault_reason); 3.126 + "iommu_fault:%s: %x:%x.%x addr %x REASON %x iommu->reg = %p\n", 3.127 + (type ? "DMA Read" : "DMA Write"), (source_id >> 8), 3.128 + PCI_SLOT(source_id & 0xFF), PCI_FUNC(source_id & 0xFF), addr, 3.129 + fault_reason, iommu->reg); 3.130 + 3.131 + if (fault_reason < 0x20) 3.132 + print_vtd_entries(current->domain, iommu, (source_id >> 8), 3.133 + (source_id & 0xff), (addr >> PAGE_SHIFT)); 3.134 + 3.135 + return 0; 3.136 +} 3.137 3.138 - print_vtd_entries(current->domain, (source_id >> 8),(source_id & 0xff), 3.139 - (addr >> PAGE_SHIFT)); 3.140 - return 0; 3.141 +static void iommu_fault_status(u32 fault_status) 3.142 +{ 3.143 + if (fault_status & DMA_FSTS_PFO) 3.144 + dprintk(XENLOG_ERR VTDPREFIX, 3.145 + "iommu_fault_status: Fault Overflow\n"); 3.146 + else 3.147 + if (fault_status & DMA_FSTS_PPF) 3.148 + dprintk(XENLOG_ERR VTDPREFIX, 3.149 + "iommu_fault_status: Primary Pending Fault\n"); 3.150 + else 3.151 + if (fault_status & DMA_FSTS_AFO) 3.152 + dprintk(XENLOG_ERR VTDPREFIX, 3.153 + "iommu_fault_status: Advanced Fault Overflow\n"); 3.154 + else 3.155 + if (fault_status & DMA_FSTS_APF) 3.156 + dprintk(XENLOG_ERR VTDPREFIX, 3.157 + "iommu_fault_status: Advanced Pending Fault\n"); 3.158 + else 3.159 + if (fault_status & DMA_FSTS_IQE) 3.160 + dprintk(XENLOG_ERR VTDPREFIX, 3.161 + "iommu_fault_status: Invalidation Queue Error\n"); 3.162 + else 3.163 + if (fault_status & DMA_FSTS_ICE) 3.164 + dprintk(XENLOG_ERR VTDPREFIX, 3.165 + "iommu_fault_status: Invalidation Completion Error\n"); 3.166 + else 3.167 + if (fault_status & DMA_FSTS_ITE) 3.168 + dprintk(XENLOG_ERR VTDPREFIX, 3.169 + "iommu_fault_status: Invalidation Time-out Error\n"); 3.170 } 3.171 3.172 #define PRIMARY_FAULT_REG_LEN (16) 3.173 @@ -772,6 +810,8 @@ static void iommu_page_fault(int vector, 3.174 fault_status = dmar_readl(iommu->reg, DMAR_FSTS_REG); 3.175 spin_unlock_irqrestore(&iommu->register_lock, flags); 3.176 3.177 + iommu_fault_status(fault_status); 3.178 + 3.179 /* FIXME: ignore advanced fault log */ 3.180 if ( !(fault_status & DMA_FSTS_PPF) ) 3.181 return; 3.182 @@ -936,6 +976,8 @@ struct iommu *iommu_alloc(void *hw_data) 3.183 { 3.184 struct acpi_drhd_unit *drhd = (struct acpi_drhd_unit *) hw_data; 3.185 struct iommu *iommu; 3.186 + struct qi_ctrl *qi_ctrl; 3.187 + struct ir_ctrl *ir_ctrl; 3.188 3.189 if ( nr_iommus > MAX_IOMMUS ) 3.190 { 3.191 @@ -951,9 +993,10 @@ struct iommu *iommu_alloc(void *hw_data) 3.192 3.193 set_fixmap_nocache(FIX_IOMMU_REGS_BASE_0 + nr_iommus, drhd->address); 3.194 iommu->reg = (void *) fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus); 3.195 - dprintk(XENLOG_INFO VTDPREFIX, 3.196 - "iommu_alloc: iommu->reg = %p drhd->address = %lx\n", 3.197 - iommu->reg, drhd->address); 3.198 + 3.199 + printk("iommu_alloc: iommu->reg = %p drhd->address = %lx\n", 3.200 + iommu->reg, drhd->address); 3.201 + 3.202 nr_iommus++; 3.203 3.204 if ( !iommu->reg ) 3.205 @@ -965,9 +1008,19 @@ struct iommu *iommu_alloc(void *hw_data) 3.206 iommu->cap = dmar_readq(iommu->reg, DMAR_CAP_REG); 3.207 iommu->ecap = dmar_readq(iommu->reg, DMAR_ECAP_REG); 3.208 3.209 + printk("iommu_alloc: cap = %"PRIx64"\n",iommu->cap); 3.210 + printk("iommu_alloc: ecap = %"PRIx64"\n", iommu->ecap); 3.211 + 3.212 spin_lock_init(&iommu->lock); 3.213 spin_lock_init(&iommu->register_lock); 3.214 3.215 + qi_ctrl = iommu_qi_ctrl(iommu); 3.216 + spin_lock_init(&qi_ctrl->qinval_lock); 3.217 + spin_lock_init(&qi_ctrl->qinval_poll_lock); 3.218 + 3.219 + ir_ctrl = iommu_ir_ctrl(iommu); 3.220 + spin_lock_init(&ir_ctrl->iremap_lock); 3.221 + 3.222 drhd->iommu = iommu; 3.223 return iommu; 3.224 error: 3.225 @@ -1071,8 +1124,10 @@ static int domain_context_mapping_one( 3.226 3.227 if ( ecap_pass_thru(iommu->ecap) ) 3.228 context_set_translation_type(*context, CONTEXT_TT_PASS_THRU); 3.229 +#ifdef CONTEXT_PASSTHRU 3.230 else 3.231 { 3.232 +#endif 3.233 if ( !hd->pgd ) 3.234 { 3.235 struct dma_pte *pgd = (struct dma_pte *)alloc_xenheap_page(); 3.236 @@ -1087,7 +1142,9 @@ static int domain_context_mapping_one( 3.237 3.238 context_set_address_root(*context, virt_to_maddr(hd->pgd)); 3.239 context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL); 3.240 +#ifdef CONTEXT_PASSTHRU 3.241 } 3.242 +#endif 3.243 3.244 context_set_fault_enable(*context); 3.245 context_set_present(*context); 3.246 @@ -1462,7 +1519,6 @@ void iommu_domain_teardown(struct domain 3.247 if ( pgd[0].val != 0 ) 3.248 free_xenheap_page((void*)maddr_to_virt( 3.249 dma_pte_addr(pgd[0]))); 3.250 - 3.251 free_xenheap_page((void *)hd->pgd); 3.252 } 3.253 break; 3.254 @@ -1503,9 +1559,11 @@ int iommu_map_page(struct domain *d, pad 3.255 drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list); 3.256 iommu = drhd->iommu; 3.257 3.258 +#ifdef CONTEXT_PASSTHRU 3.259 /* do nothing if dom0 and iommu supports pass thru */ 3.260 if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) ) 3.261 return 0; 3.262 +#endif 3.263 3.264 pg = addr_to_dma_page(d, gfn << PAGE_SHIFT_4K); 3.265 if ( !pg ) 3.266 @@ -1538,9 +1596,11 @@ int iommu_unmap_page(struct domain *d, d 3.267 drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list); 3.268 iommu = drhd->iommu; 3.269 3.270 +#ifdef CONTEXT_PASSTHRU 3.271 /* do nothing if dom0 and iommu supports pass thru */ 3.272 if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) ) 3.273 return 0; 3.274 +#endif 3.275 3.276 dma_pte_clear_one(d, gfn << PAGE_SHIFT_4K); 3.277 3.278 @@ -1711,7 +1771,7 @@ void __init setup_dom0_devices(void) 3.279 pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); 3.280 } 3.281 3.282 -void clear_fault_bit(struct iommu *iommu) 3.283 +void clear_fault_bits(struct iommu *iommu) 3.284 { 3.285 u64 val; 3.286 3.287 @@ -1722,13 +1782,15 @@ void clear_fault_bit(struct iommu *iommu 3.288 iommu->reg, 3.289 cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+8, 3.290 val); 3.291 - dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_PFO); 3.292 + dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_FAULTS); 3.293 } 3.294 3.295 static int init_vtd_hw(void) 3.296 { 3.297 struct acpi_drhd_unit *drhd; 3.298 struct iommu *iommu; 3.299 + struct iommu_flush *flush = NULL; 3.300 + int vector; 3.301 int ret; 3.302 3.303 for_each_drhd_unit ( drhd ) 3.304 @@ -1740,8 +1802,23 @@ static int init_vtd_hw(void) 3.305 gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: set root entry failed\n"); 3.306 return -EIO; 3.307 } 3.308 + 3.309 + vector = iommu_set_interrupt(iommu); 3.310 + dma_msi_data_init(iommu, vector); 3.311 + dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map))); 3.312 + iommu->vector = vector; 3.313 + clear_fault_bits(iommu); 3.314 + dmar_writel(iommu->reg, DMAR_FECTL_REG, 0); 3.315 + 3.316 + /* initialize flush functions */ 3.317 + flush = iommu_get_flush(iommu); 3.318 + flush->context = flush_context_reg; 3.319 + flush->iotlb = flush_iotlb_reg; 3.320 + 3.321 + if ( qinval_setup(iommu) != 0); 3.322 + dprintk(XENLOG_ERR VTDPREFIX, 3.323 + "Queued Invalidation hardware not found\n"); 3.324 } 3.325 - 3.326 return 0; 3.327 } 3.328 3.329 @@ -1749,20 +1826,13 @@ static int enable_vtd_translation(void) 3.330 { 3.331 struct acpi_drhd_unit *drhd; 3.332 struct iommu *iommu; 3.333 - int vector = 0; 3.334 3.335 for_each_drhd_unit ( drhd ) 3.336 { 3.337 iommu = drhd->iommu; 3.338 - vector = iommu_set_interrupt(iommu); 3.339 - dma_msi_data_init(iommu, vector); 3.340 - dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map))); 3.341 - iommu->vector = vector; 3.342 - clear_fault_bit(iommu); 3.343 if ( iommu_enable_translation(iommu) ) 3.344 return -EIO; 3.345 } 3.346 - 3.347 return 0; 3.348 } 3.349 3.350 @@ -1793,9 +1863,6 @@ int iommu_setup(void) 3.351 spin_lock_init(&domid_bitmap_lock); 3.352 INIT_LIST_HEAD(&hd->pdev_list); 3.353 3.354 - /* start from scratch */ 3.355 - iommu_flush_all(); 3.356 - 3.357 /* setup clflush size */ 3.358 x86_clflush_size = ((cpuid_ebx(1) >> 8) & 0xff) * 8; 3.359 3.360 @@ -1815,12 +1882,12 @@ int iommu_setup(void) 3.361 for ( i = 0; i < max_page; i++ ) 3.362 iommu_map_page(dom0, i, i); 3.363 3.364 + enable_vtd_translation(); 3.365 if ( init_vtd_hw() ) 3.366 goto error; 3.367 setup_dom0_devices(); 3.368 setup_dom0_rmrr(); 3.369 - if ( enable_vtd_translation() ) 3.370 - goto error; 3.371 + iommu_flush_all(); 3.372 3.373 return 0; 3.374
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/xen/arch/x86/hvm/vmx/vtd/qinval.c Tue Jan 22 09:48:51 2008 +0000 4.3 @@ -0,0 +1,456 @@ 4.4 +/* 4.5 + * Copyright (c) 2006, Intel Corporation. 4.6 + * 4.7 + * This program is free software; you can redistribute it and/or modify it 4.8 + * under the terms and conditions of the GNU General Public License, 4.9 + * version 2, as published by the Free Software Foundation. 4.10 + * 4.11 + * This program is distributed in the hope it will be useful, but WITHOUT 4.12 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 4.13 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 4.14 + * more details. 4.15 + * 4.16 + * You should have received a copy of the GNU General Public License along with 4.17 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 4.18 + * Place - Suite 330, Boston, MA 02111-1307 USA. 4.19 + * 4.20 + * Copyright (C) Allen Kay <allen.m.kay@intel.com> 4.21 + * Copyright (C) Xiaohui Xin <xiaohui.xin@intel.com> 4.22 + */ 4.23 + 4.24 + 4.25 +#include <xen/init.h> 4.26 +#include <xen/irq.h> 4.27 +#include <xen/spinlock.h> 4.28 +#include <xen/sched.h> 4.29 +#include <xen/xmalloc.h> 4.30 +#include <xen/domain_page.h> 4.31 +#include <asm/delay.h> 4.32 +#include <asm/string.h> 4.33 +#include <asm/iommu.h> 4.34 +#include <asm/hvm/vmx/intel-iommu.h> 4.35 +#include "dmar.h" 4.36 +#include "vtd.h" 4.37 +#include "pci-direct.h" 4.38 +#include "pci_regs.h" 4.39 +#include "msi.h" 4.40 +#include "extern.h" 4.41 + 4.42 +static void print_qi_regs(struct iommu *iommu) 4.43 +{ 4.44 + u64 val; 4.45 + 4.46 + val = dmar_readq(iommu->reg, DMAR_IQA_REG); 4.47 + printk("DMAR_IAQ_REG = %"PRIx64"\n", val); 4.48 + 4.49 + val = dmar_readq(iommu->reg, DMAR_IQH_REG); 4.50 + printk("DMAR_IAH_REG = %"PRIx64"\n", val); 4.51 + 4.52 + val = dmar_readq(iommu->reg, DMAR_IQT_REG); 4.53 + printk("DMAR_IAT_REG = %"PRIx64"\n", val); 4.54 +} 4.55 + 4.56 +static int qinval_next_index(struct iommu *iommu) 4.57 +{ 4.58 + u64 val; 4.59 + val = dmar_readq(iommu->reg, DMAR_IQT_REG); 4.60 + return (val >> 4); 4.61 +} 4.62 + 4.63 +static int qinval_update_qtail(struct iommu *iommu, int index) 4.64 +{ 4.65 + u64 val; 4.66 + 4.67 + /* Need an ASSERT to insure that we have got register lock */ 4.68 + val = (index < (QINVAL_ENTRY_NR-1)) ? (index + 1) : 0; 4.69 + dmar_writeq(iommu->reg, DMAR_IQT_REG, (val << 4)); 4.70 + return 0; 4.71 +} 4.72 + 4.73 +static int gen_cc_inv_dsc(struct iommu *iommu, int index, 4.74 + u16 did, u16 source_id, u8 function_mask, u8 granu) 4.75 +{ 4.76 + u64 *ptr64; 4.77 + unsigned long flags; 4.78 + struct qinval_entry * qinval_entry = NULL; 4.79 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.80 + 4.81 + spin_lock_irqsave(&qi_ctrl->qinval_lock, flags); 4.82 + qinval_entry = &qi_ctrl->qinval[index]; 4.83 + qinval_entry->q.cc_inv_dsc.lo.type = TYPE_INVAL_CONTEXT; 4.84 + qinval_entry->q.cc_inv_dsc.lo.granu = granu; 4.85 + qinval_entry->q.cc_inv_dsc.lo.res_1 = 0; 4.86 + qinval_entry->q.cc_inv_dsc.lo.did = did; 4.87 + qinval_entry->q.cc_inv_dsc.lo.sid = source_id; 4.88 + qinval_entry->q.cc_inv_dsc.lo.fm = function_mask; 4.89 + qinval_entry->q.cc_inv_dsc.lo.res_2 = 0; 4.90 + qinval_entry->q.cc_inv_dsc.hi.res = 0; 4.91 + spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags); 4.92 + 4.93 + ptr64 = (u64 *)qinval_entry; 4.94 + return 0; 4.95 +} 4.96 + 4.97 +int queue_invalidate_context(struct iommu *iommu, 4.98 + u16 did, u16 source_id, u8 function_mask, u8 granu) 4.99 +{ 4.100 + int ret = -1; 4.101 + unsigned long flags; 4.102 + int index = -1; 4.103 + 4.104 + spin_lock_irqsave(&iommu->register_lock, flags); 4.105 + index = qinval_next_index(iommu); 4.106 + if (index == -1) 4.107 + return -EBUSY; 4.108 + ret = gen_cc_inv_dsc(iommu, index, did, source_id, 4.109 + function_mask, granu); 4.110 + ret |= qinval_update_qtail(iommu, index); 4.111 + spin_unlock_irqrestore(&iommu->register_lock, flags); 4.112 + return ret; 4.113 +} 4.114 + 4.115 +static int gen_iotlb_inv_dsc(struct iommu *iommu, int index, 4.116 + u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr) 4.117 +{ 4.118 + unsigned long flags; 4.119 + struct qinval_entry * qinval_entry = NULL; 4.120 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.121 + 4.122 + if ( index == -1 ) 4.123 + return -1; 4.124 + spin_lock_irqsave(&qi_ctrl->qinval_lock, flags); 4.125 + 4.126 + qinval_entry = &qi_ctrl->qinval[index]; 4.127 + qinval_entry->q.iotlb_inv_dsc.lo.type = TYPE_INVAL_IOTLB; 4.128 + qinval_entry->q.iotlb_inv_dsc.lo.granu = granu; 4.129 + qinval_entry->q.iotlb_inv_dsc.lo.dr = 0; 4.130 + qinval_entry->q.iotlb_inv_dsc.lo.dw = 0; 4.131 + qinval_entry->q.iotlb_inv_dsc.lo.res_1 = 0; 4.132 + qinval_entry->q.iotlb_inv_dsc.lo.did = did; 4.133 + qinval_entry->q.iotlb_inv_dsc.lo.res_2 = 0; 4.134 + 4.135 + qinval_entry->q.iotlb_inv_dsc.hi.am = am; 4.136 + qinval_entry->q.iotlb_inv_dsc.hi.ih = ih; 4.137 + qinval_entry->q.iotlb_inv_dsc.hi.res_1 = 0; 4.138 + qinval_entry->q.iotlb_inv_dsc.hi.addr = addr; 4.139 + 4.140 + spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags); 4.141 + return 0; 4.142 +} 4.143 + 4.144 +int queue_invalidate_iotlb(struct iommu *iommu, 4.145 + u8 granu, u8 dr, u8 dw, u16 did, u8 am, u8 ih, u64 addr) 4.146 +{ 4.147 + int ret = -1; 4.148 + unsigned long flags; 4.149 + int index = -1; 4.150 + 4.151 + spin_lock_irqsave(&iommu->register_lock, flags); 4.152 + 4.153 + index = qinval_next_index(iommu); 4.154 + ret = gen_iotlb_inv_dsc(iommu, index, granu, dr, dw, did, 4.155 + am, ih, addr); 4.156 + ret |= qinval_update_qtail(iommu, index); 4.157 + spin_unlock_irqrestore(&iommu->register_lock, flags); 4.158 + return ret; 4.159 +} 4.160 + 4.161 +static int gen_wait_dsc(struct iommu *iommu, int index, 4.162 + u8 iflag, u8 sw, u8 fn, u32 sdata, volatile u32 *saddr) 4.163 +{ 4.164 + u64 *ptr64; 4.165 + unsigned long flags; 4.166 + struct qinval_entry * qinval_entry = NULL; 4.167 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.168 + 4.169 + if ( index == -1 ) 4.170 + return -1; 4.171 + spin_lock_irqsave(&qi_ctrl->qinval_lock, flags); 4.172 + qinval_entry = &qi_ctrl->qinval[index]; 4.173 + qinval_entry->q.inv_wait_dsc.lo.type = TYPE_INVAL_WAIT; 4.174 + qinval_entry->q.inv_wait_dsc.lo.iflag = iflag; 4.175 + qinval_entry->q.inv_wait_dsc.lo.sw = sw; 4.176 + qinval_entry->q.inv_wait_dsc.lo.fn = fn; 4.177 + qinval_entry->q.inv_wait_dsc.lo.res_1 = 0; 4.178 + qinval_entry->q.inv_wait_dsc.lo.sdata = sdata; 4.179 + qinval_entry->q.inv_wait_dsc.hi.res_1 = 0; 4.180 + qinval_entry->q.inv_wait_dsc.hi.saddr = virt_to_maddr(saddr) >> 2; 4.181 + spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags); 4.182 + ptr64 = (u64 *)qinval_entry; 4.183 + return 0; 4.184 +} 4.185 + 4.186 +static int queue_invalidate_wait(struct iommu *iommu, 4.187 + u8 iflag, u8 sw, u8 fn, u32 sdata, volatile u32 *saddr) 4.188 +{ 4.189 + unsigned long flags; 4.190 + unsigned long start_time; 4.191 + int index = -1; 4.192 + int ret = -1; 4.193 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.194 + 4.195 + spin_lock_irqsave(&qi_ctrl->qinval_poll_lock, flags); 4.196 + spin_lock_irqsave(&iommu->register_lock, flags); 4.197 + index = qinval_next_index(iommu); 4.198 + if (*saddr == 1) 4.199 + *saddr = 0; 4.200 + ret = gen_wait_dsc(iommu, index, iflag, sw, fn, sdata, saddr); 4.201 + ret |= qinval_update_qtail(iommu, index); 4.202 + spin_unlock_irqrestore(&iommu->register_lock, flags); 4.203 + 4.204 + /* Now we don't support interrupt method */ 4.205 + if ( sw ) 4.206 + { 4.207 + /* In case all wait descriptor writes to same addr with same data */ 4.208 + start_time = jiffies; 4.209 + while ( *saddr != 1 ) { 4.210 + if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT)) { 4.211 + print_qi_regs(iommu); 4.212 + panic("queue invalidate wait descriptor was not executed\n"); 4.213 + } 4.214 + cpu_relax(); 4.215 + } 4.216 + } 4.217 + spin_unlock_irqrestore(&qi_ctrl->qinval_poll_lock, flags); 4.218 + return ret; 4.219 +} 4.220 + 4.221 +int invalidate_sync(struct iommu *iommu) 4.222 +{ 4.223 + int ret = -1; 4.224 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.225 + 4.226 + if (qi_ctrl->qinval) 4.227 + { 4.228 + ret = queue_invalidate_wait(iommu, 4.229 + 0, 1, 1, 1, &qi_ctrl->qinval_poll_status); 4.230 + return ret; 4.231 + } 4.232 + return 0; 4.233 +} 4.234 + 4.235 +static int gen_dev_iotlb_inv_dsc(struct iommu *iommu, int index, 4.236 + u32 max_invs_pend, u16 sid, u16 size, u64 addr) 4.237 +{ 4.238 + unsigned long flags; 4.239 + struct qinval_entry * qinval_entry = NULL; 4.240 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.241 + 4.242 + if ( index == -1 ) 4.243 + return -1; 4.244 + spin_lock_irqsave(&qi_ctrl->qinval_lock, flags); 4.245 + 4.246 + qinval_entry = &qi_ctrl->qinval[index]; 4.247 + qinval_entry->q.dev_iotlb_inv_dsc.lo.type = TYPE_INVAL_DEVICE_IOTLB; 4.248 + qinval_entry->q.dev_iotlb_inv_dsc.lo.res_1 = 0; 4.249 + qinval_entry->q.dev_iotlb_inv_dsc.lo.max_invs_pend = max_invs_pend; 4.250 + qinval_entry->q.dev_iotlb_inv_dsc.lo.res_2 = 0; 4.251 + qinval_entry->q.dev_iotlb_inv_dsc.lo.sid = sid; 4.252 + qinval_entry->q.dev_iotlb_inv_dsc.lo.res_3 = 0; 4.253 + 4.254 + qinval_entry->q.dev_iotlb_inv_dsc.hi.size = size; 4.255 + qinval_entry->q.dev_iotlb_inv_dsc.hi.addr = addr; 4.256 + 4.257 + spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags); 4.258 + return 0; 4.259 +} 4.260 + 4.261 +int queue_invalidate_device_iotlb(struct iommu *iommu, 4.262 + u32 max_invs_pend, u16 sid, u16 size, u64 addr) 4.263 +{ 4.264 + int ret = -1; 4.265 + unsigned long flags; 4.266 + int index = -1; 4.267 + 4.268 + spin_lock_irqsave(&iommu->register_lock, flags); 4.269 + index = qinval_next_index(iommu); 4.270 + ret = gen_dev_iotlb_inv_dsc(iommu, index, max_invs_pend, 4.271 + sid, size, addr); 4.272 + ret |= qinval_update_qtail(iommu, index); 4.273 + spin_unlock_irqrestore(&iommu->register_lock, flags); 4.274 + return ret; 4.275 +} 4.276 + 4.277 +static int gen_iec_inv_dsc(struct iommu *iommu, int index, 4.278 + u8 granu, u8 im, u16 iidx) 4.279 +{ 4.280 + unsigned long flags; 4.281 + struct qinval_entry * qinval_entry = NULL; 4.282 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.283 + 4.284 + if ( index == -1 ) 4.285 + return -1; 4.286 + spin_lock_irqsave(&qi_ctrl->qinval_lock, flags); 4.287 + 4.288 + qinval_entry = &qi_ctrl->qinval[index]; 4.289 + qinval_entry->q.iec_inv_dsc.lo.type = TYPE_INVAL_IEC; 4.290 + qinval_entry->q.iec_inv_dsc.lo.granu = granu; 4.291 + qinval_entry->q.iec_inv_dsc.lo.res_1 = 0; 4.292 + qinval_entry->q.iec_inv_dsc.lo.im = im; 4.293 + qinval_entry->q.iec_inv_dsc.lo.iidx = iidx; 4.294 + qinval_entry->q.iec_inv_dsc.lo.res_2 = 0; 4.295 + qinval_entry->q.iec_inv_dsc.hi.res = 0; 4.296 + 4.297 + spin_unlock_irqrestore(&qi_ctrl->qinval_lock, flags); 4.298 + return 0; 4.299 +} 4.300 + 4.301 +int queue_invalidate_iec(struct iommu *iommu, u8 granu, u8 im, u16 iidx) 4.302 +{ 4.303 + int ret; 4.304 + unsigned long flags; 4.305 + int index = -1; 4.306 + 4.307 + spin_lock_irqsave(&iommu->register_lock, flags); 4.308 + index = qinval_next_index(iommu); 4.309 + ret = gen_iec_inv_dsc(iommu, index, granu, im, iidx); 4.310 + ret |= qinval_update_qtail(iommu, index); 4.311 + spin_unlock_irqrestore(&iommu->register_lock, flags); 4.312 + return ret; 4.313 +} 4.314 + 4.315 +u64 iec_cap; 4.316 +int __iommu_flush_iec(struct iommu *iommu, u8 granu, u8 im, u16 iidx) 4.317 +{ 4.318 + int ret; 4.319 + ret = queue_invalidate_iec(iommu, granu, im, iidx); 4.320 + ret |= invalidate_sync(iommu); 4.321 + 4.322 + /* 4.323 + * reading vt-d architecture register will ensure 4.324 + * draining happens in implementation independent way. 4.325 + */ 4.326 + iec_cap = dmar_readq(iommu->reg, DMAR_CAP_REG); 4.327 + return ret; 4.328 +} 4.329 + 4.330 +int iommu_flush_iec_global(struct iommu *iommu) 4.331 +{ 4.332 + return __iommu_flush_iec(iommu, IEC_GLOBAL_INVL, 0, 0); 4.333 +} 4.334 + 4.335 +int iommu_flush_iec_index(struct iommu *iommu, u8 im, u16 iidx) 4.336 +{ 4.337 + return __iommu_flush_iec(iommu, IEC_INDEX_INVL, im, iidx); 4.338 +} 4.339 + 4.340 +static int flush_context_qi( 4.341 + void *_iommu, u16 did, u16 sid, u8 fm, u64 type, 4.342 + int non_present_entry_flush) 4.343 +{ 4.344 + int ret = 0; 4.345 + struct iommu *iommu = (struct iommu *)_iommu; 4.346 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.347 + 4.348 + /* 4.349 + * In the non-present entry flush case, if hardware doesn't cache 4.350 + * non-present entry we do nothing and if hardware cache non-present 4.351 + * entry, we flush entries of domain 0 (the domain id is used to cache 4.352 + * any non-present entries) 4.353 + */ 4.354 + if ( non_present_entry_flush ) 4.355 + { 4.356 + if ( !cap_caching_mode(iommu->cap) ) 4.357 + return 1; 4.358 + else 4.359 + did = 0; 4.360 + } 4.361 + 4.362 + if (qi_ctrl->qinval) 4.363 + { 4.364 + ret = queue_invalidate_context(iommu, did, sid, fm, 4.365 + type >> DMA_CCMD_INVL_GRANU_OFFSET); 4.366 + ret |= invalidate_sync(iommu); 4.367 + } 4.368 + return ret; 4.369 +} 4.370 + 4.371 +static int flush_iotlb_qi( 4.372 + void *_iommu, u16 did, 4.373 + u64 addr, unsigned int size_order, u64 type, 4.374 + int non_present_entry_flush) 4.375 +{ 4.376 + u8 dr = 0, dw = 0; 4.377 + int ret = 0; 4.378 + struct iommu *iommu = (struct iommu *)_iommu; 4.379 + struct qi_ctrl *qi_ctrl = iommu_qi_ctrl(iommu); 4.380 + 4.381 + /* 4.382 + * In the non-present entry flush case, if hardware doesn't cache 4.383 + * non-present entry we do nothing and if hardware cache non-present 4.384 + * entry, we flush entries of domain 0 (the domain id is used to cache 4.385 + * any non-present entries) 4.386 + */ 4.387 + if ( non_present_entry_flush ) 4.388 + { 4.389 + if ( !cap_caching_mode(iommu->cap) ) 4.390 + return 1; 4.391 + else 4.392 + did = 0; 4.393 + } 4.394 + 4.395 + if (qi_ctrl->qinval) { 4.396 + /* use queued invalidation */ 4.397 + if (cap_write_drain(iommu->cap)) 4.398 + dw = 1; 4.399 + if (cap_read_drain(iommu->cap)) 4.400 + dr = 1; 4.401 + /* Need to conside the ih bit later */ 4.402 + ret = queue_invalidate_iotlb(iommu, 4.403 + (type >> DMA_TLB_FLUSH_GRANU_OFFSET), dr, 4.404 + dw, did, (u8)size_order, 0, addr); 4.405 + ret |= invalidate_sync(iommu); 4.406 + } 4.407 + return ret; 4.408 +} 4.409 + 4.410 +int qinval_setup(struct iommu *iommu) 4.411 +{ 4.412 + unsigned long start_time; 4.413 + u64 paddr; 4.414 + u32 status = 0; 4.415 + struct qi_ctrl *qi_ctrl; 4.416 + struct iommu_flush *flush; 4.417 + 4.418 + qi_ctrl = iommu_qi_ctrl(iommu); 4.419 + flush = iommu_get_flush(iommu); 4.420 + 4.421 + if ( !ecap_queued_inval(iommu->ecap) ) 4.422 + return -ENODEV; 4.423 + 4.424 + if (qi_ctrl->qinval == NULL) { 4.425 + qi_ctrl->qinval = alloc_xenheap_page(); 4.426 + if (qi_ctrl->qinval == NULL) 4.427 + panic("Cannot allocate memory for qi_ctrl->qinval\n"); 4.428 + memset((u8*)qi_ctrl->qinval, 0, PAGE_SIZE_4K); 4.429 + flush->context = flush_context_qi; 4.430 + flush->iotlb = flush_iotlb_qi; 4.431 + } 4.432 + paddr = virt_to_maddr(qi_ctrl->qinval); 4.433 + 4.434 + /* Setup Invalidation Queue Address(IQA) register with the 4.435 + * address of the page we just allocated. QS field at 4.436 + * bits[2:0] to indicate size of queue is one 4KB page. 4.437 + * That's 256 entries. Queued Head (IQH) and Queue Tail (IQT) 4.438 + * registers are automatically reset to 0 with write 4.439 + * to IQA register. 4.440 + */ 4.441 + dmar_writeq(iommu->reg, DMAR_IQA_REG, paddr); 4.442 + 4.443 + /* enable queued invalidation hardware */ 4.444 + iommu->gcmd |= DMA_GCMD_QIE; 4.445 + dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd); 4.446 + 4.447 + /* Make sure hardware complete it */ 4.448 + start_time = jiffies; 4.449 + while (1) { 4.450 + status = dmar_readl(iommu->reg, DMAR_GSTS_REG); 4.451 + if (status & DMA_GSTS_QIES) 4.452 + break; 4.453 + if (time_after(jiffies, start_time + DMAR_OPERATION_TIMEOUT)) 4.454 + panic("Cannot set QIE field for queue invalidation\n"); 4.455 + cpu_relax(); 4.456 + } 4.457 + status = 0; 4.458 + return status; 4.459 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/xen/arch/x86/hvm/vmx/vtd/vtd.h Tue Jan 22 09:48:51 2008 +0000 5.3 @@ -0,0 +1,54 @@ 5.4 +/* 5.5 + * Copyright (c) 2006, Intel Corporation. 5.6 + * 5.7 + * This program is free software; you can redistribute it and/or modify it 5.8 + * under the terms and conditions of the GNU General Public License, 5.9 + * version 2, as published by the Free Software Foundation. 5.10 + * 5.11 + * This program is distributed in the hope it will be useful, but WITHOUT 5.12 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.13 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for 5.14 + * more details. 5.15 + * 5.16 + * You should have received a copy of the GNU General Public License along with 5.17 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple 5.18 + * Place - Suite 330, Boston, MA 02111-1307 USA. 5.19 + * 5.20 + * Copyright (C) Allen Kay <allen.m.kay@intel.com> 5.21 + * Copyright (C) Weidong Han <weidong.han@intel.com> 5.22 + */ 5.23 + 5.24 +#ifndef _VTD_H_ 5.25 +#define _VTD_H_ 5.26 + 5.27 +#include <xen/list.h> 5.28 +#include <asm/iommu.h> 5.29 + 5.30 +#define VTDPREFIX "[VT-D]" 5.31 + 5.32 +#define DMAR_OPERATION_TIMEOUT (HZ*60) /* 1m */ 5.33 +#define time_after(a,b) \ 5.34 + (typecheck(unsigned long, a) && \ 5.35 + typecheck(unsigned long, b) && \ 5.36 + ((long)(b) - (long)(a) < 0)) 5.37 + 5.38 +struct IO_APIC_route_remap_entry { 5.39 + union { 5.40 + u64 val; 5.41 + struct { 5.42 + u64 vector:8, 5.43 + delivery_mode:3, 5.44 + index_15:1, 5.45 + delivery_status:1, 5.46 + polarity:1, 5.47 + irr:1, 5.48 + trigger:1, 5.49 + mask:1, 5.50 + reserved:31, 5.51 + format:1, 5.52 + index_0_14:15; 5.53 + }; 5.54 + }; 5.55 +}; 5.56 + 5.57 +#endif // _VTD_H_
6.1 --- a/xen/include/asm-x86/iommu.h Tue Jan 22 09:46:33 2008 +0000 6.2 +++ b/xen/include/asm-x86/iommu.h Tue Jan 22 09:48:51 2008 +0000 6.3 @@ -31,6 +31,9 @@ extern int vtd_enabled; 6.4 6.5 #define domain_hvm_iommu(d) (&d->arch.hvm_domain.hvm_iommu) 6.6 #define domain_vmx_iommu(d) (&d->arch.hvm_domain.hvm_iommu.vmx_iommu) 6.7 +#define iommu_qi_ctrl(iommu) (&(iommu->intel.qi_ctrl)); 6.8 +#define iommu_ir_ctrl(iommu) (&(iommu->intel.ir_ctrl)); 6.9 +#define iommu_get_flush(iommu) (&(iommu->intel.flush)); 6.10 6.11 /* 6.12 * The PCI interface treats multi-function devices as independent 6.13 @@ -61,6 +64,7 @@ struct iommu { 6.14 spinlock_t register_lock; /* protect iommu register handling */ 6.15 struct root_entry *root_entry; /* virtual address */ 6.16 unsigned int vector; 6.17 + struct intel_iommu intel; 6.18 }; 6.19 6.20 int iommu_setup(void);