ia64/xen-unstable

changeset 16830: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>
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,16 +751,49 @@ 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 -    print_vtd_entries(current->domain, (source_id >> 8),(source_id & 0xff),
   3.132 -                      (addr >> PAGE_SHIFT)); 
   3.133 +    if (fault_reason < 0x20) 
   3.134 +        print_vtd_entries(current->domain, iommu, (source_id >> 8),
   3.135 +                          (source_id & 0xff), (addr >> PAGE_SHIFT)); 
   3.136 +
   3.137      return 0;
   3.138  }
   3.139  
   3.140 +static void iommu_fault_status(u32 fault_status)
   3.141 +{
   3.142 +    if (fault_status & DMA_FSTS_PFO)
   3.143 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.144 +            "iommu_fault_status: Fault Overflow\n");
   3.145 +    else
   3.146 +    if (fault_status & DMA_FSTS_PPF)
   3.147 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.148 +            "iommu_fault_status: Primary Pending Fault\n");
   3.149 +    else
   3.150 +    if (fault_status & DMA_FSTS_AFO)
   3.151 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.152 +            "iommu_fault_status: Advanced Fault Overflow\n");
   3.153 +    else
   3.154 +    if (fault_status & DMA_FSTS_APF)
   3.155 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.156 +            "iommu_fault_status: Advanced Pending Fault\n");
   3.157 +    else
   3.158 +    if (fault_status & DMA_FSTS_IQE)
   3.159 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.160 +            "iommu_fault_status: Invalidation Queue Error\n");
   3.161 +    else
   3.162 +    if (fault_status & DMA_FSTS_ICE)
   3.163 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.164 +            "iommu_fault_status: Invalidation Completion Error\n");
   3.165 +    else
   3.166 +    if (fault_status & DMA_FSTS_ITE)
   3.167 +        dprintk(XENLOG_ERR VTDPREFIX,
   3.168 +            "iommu_fault_status: Invalidation Time-out Error\n");
   3.169 +}
   3.170 +
   3.171  #define PRIMARY_FAULT_REG_LEN (16)
   3.172  static void iommu_page_fault(int vector, void *dev_id,
   3.173                               struct cpu_user_regs *regs)
   3.174 @@ -772,6 +810,8 @@ static void iommu_page_fault(int vector,
   3.175      fault_status = dmar_readl(iommu->reg, DMAR_FSTS_REG);
   3.176      spin_unlock_irqrestore(&iommu->register_lock, flags);
   3.177  
   3.178 +    iommu_fault_status(fault_status);
   3.179 +
   3.180      /* FIXME: ignore advanced fault log */
   3.181      if ( !(fault_status & DMA_FSTS_PPF) )
   3.182          return;
   3.183 @@ -936,6 +976,8 @@ struct iommu *iommu_alloc(void *hw_data)
   3.184  {
   3.185      struct acpi_drhd_unit *drhd = (struct acpi_drhd_unit *) hw_data;
   3.186      struct iommu *iommu;
   3.187 +    struct qi_ctrl *qi_ctrl;
   3.188 +    struct ir_ctrl *ir_ctrl;
   3.189  
   3.190      if ( nr_iommus > MAX_IOMMUS )
   3.191      {
   3.192 @@ -951,9 +993,10 @@ struct iommu *iommu_alloc(void *hw_data)
   3.193  
   3.194      set_fixmap_nocache(FIX_IOMMU_REGS_BASE_0 + nr_iommus, drhd->address);
   3.195      iommu->reg = (void *) fix_to_virt(FIX_IOMMU_REGS_BASE_0 + nr_iommus);
   3.196 -    dprintk(XENLOG_INFO VTDPREFIX,
   3.197 -            "iommu_alloc: iommu->reg = %p drhd->address = %lx\n",
   3.198 -            iommu->reg, drhd->address);
   3.199 +
   3.200 +    printk("iommu_alloc: iommu->reg = %p drhd->address = %lx\n",
   3.201 +           iommu->reg, drhd->address);
   3.202 +
   3.203      nr_iommus++;
   3.204  
   3.205      if ( !iommu->reg )
   3.206 @@ -965,9 +1008,19 @@ struct iommu *iommu_alloc(void *hw_data)
   3.207      iommu->cap = dmar_readq(iommu->reg, DMAR_CAP_REG);
   3.208      iommu->ecap = dmar_readq(iommu->reg, DMAR_ECAP_REG);
   3.209  
   3.210 +    printk("iommu_alloc: cap = %"PRIx64"\n",iommu->cap);
   3.211 +    printk("iommu_alloc: ecap = %"PRIx64"\n", iommu->ecap);
   3.212 +
   3.213      spin_lock_init(&iommu->lock);
   3.214      spin_lock_init(&iommu->register_lock);
   3.215  
   3.216 +    qi_ctrl = iommu_qi_ctrl(iommu);
   3.217 +    spin_lock_init(&qi_ctrl->qinval_lock);
   3.218 +    spin_lock_init(&qi_ctrl->qinval_poll_lock);
   3.219 +
   3.220 +    ir_ctrl = iommu_ir_ctrl(iommu);
   3.221 +    spin_lock_init(&ir_ctrl->iremap_lock);
   3.222 +
   3.223      drhd->iommu = iommu;
   3.224      return iommu;
   3.225   error:
   3.226 @@ -1071,8 +1124,10 @@ static int domain_context_mapping_one(
   3.227  
   3.228      if ( ecap_pass_thru(iommu->ecap) )
   3.229          context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
   3.230 +#ifdef CONTEXT_PASSTHRU
   3.231      else
   3.232      {
   3.233 +#endif
   3.234          if ( !hd->pgd )
   3.235          {
   3.236              struct dma_pte *pgd = (struct dma_pte *)alloc_xenheap_page();
   3.237 @@ -1087,7 +1142,9 @@ static int domain_context_mapping_one(
   3.238   
   3.239          context_set_address_root(*context, virt_to_maddr(hd->pgd));
   3.240          context_set_translation_type(*context, CONTEXT_TT_MULTI_LEVEL);
   3.241 +#ifdef CONTEXT_PASSTHRU
   3.242      }
   3.243 +#endif
   3.244  
   3.245      context_set_fault_enable(*context);
   3.246      context_set_present(*context);
   3.247 @@ -1462,7 +1519,6 @@ void iommu_domain_teardown(struct domain
   3.248                  if ( pgd[0].val != 0 )
   3.249                      free_xenheap_page((void*)maddr_to_virt(
   3.250                          dma_pte_addr(pgd[0])));
   3.251 -
   3.252                  free_xenheap_page((void *)hd->pgd);
   3.253              }
   3.254              break;
   3.255 @@ -1503,9 +1559,11 @@ int iommu_map_page(struct domain *d, pad
   3.256      drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
   3.257      iommu = drhd->iommu;
   3.258  
   3.259 +#ifdef CONTEXT_PASSTHRU
   3.260      /* do nothing if dom0 and iommu supports pass thru */
   3.261      if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
   3.262          return 0;
   3.263 +#endif
   3.264  
   3.265      pg = addr_to_dma_page(d, gfn << PAGE_SHIFT_4K);
   3.266      if ( !pg )
   3.267 @@ -1538,9 +1596,11 @@ int iommu_unmap_page(struct domain *d, d
   3.268      drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
   3.269      iommu = drhd->iommu;
   3.270  
   3.271 +#ifdef CONTEXT_PASSTHRU
   3.272      /* do nothing if dom0 and iommu supports pass thru */
   3.273      if ( ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
   3.274          return 0;
   3.275 +#endif
   3.276  
   3.277      dma_pte_clear_one(d, gfn << PAGE_SHIFT_4K);
   3.278  
   3.279 @@ -1711,7 +1771,7 @@ void __init setup_dom0_devices(void)
   3.280                  pdev->bus, PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn));
   3.281  }
   3.282  
   3.283 -void clear_fault_bit(struct iommu *iommu)
   3.284 +void clear_fault_bits(struct iommu *iommu)
   3.285  {
   3.286      u64 val;
   3.287  
   3.288 @@ -1722,13 +1782,15 @@ void clear_fault_bit(struct iommu *iommu
   3.289          iommu->reg,
   3.290          cap_fault_reg_offset(dmar_readq(iommu->reg,DMAR_CAP_REG))+8,
   3.291          val);
   3.292 -    dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_PFO);
   3.293 +    dmar_writel(iommu->reg, DMAR_FSTS_REG, DMA_FSTS_FAULTS);
   3.294  }
   3.295  
   3.296  static int init_vtd_hw(void)
   3.297  {
   3.298      struct acpi_drhd_unit *drhd;
   3.299      struct iommu *iommu;
   3.300 +    struct iommu_flush *flush = NULL;
   3.301 +    int vector;
   3.302      int ret;
   3.303  
   3.304      for_each_drhd_unit ( drhd )
   3.305 @@ -1740,8 +1802,23 @@ static int init_vtd_hw(void)
   3.306              gdprintk(XENLOG_ERR VTDPREFIX, "IOMMU: set root entry failed\n");
   3.307              return -EIO;
   3.308          }
   3.309 +
   3.310 +        vector = iommu_set_interrupt(iommu);
   3.311 +        dma_msi_data_init(iommu, vector);
   3.312 +        dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map)));
   3.313 +        iommu->vector = vector;
   3.314 +        clear_fault_bits(iommu);
   3.315 +        dmar_writel(iommu->reg, DMAR_FECTL_REG, 0);
   3.316 +
   3.317 +        /* initialize flush functions */
   3.318 +        flush = iommu_get_flush(iommu);
   3.319 +        flush->context = flush_context_reg;
   3.320 +        flush->iotlb = flush_iotlb_reg;
   3.321 +
   3.322 +        if ( qinval_setup(iommu) != 0);
   3.323 +            dprintk(XENLOG_ERR VTDPREFIX,
   3.324 +                    "Queued Invalidation hardware not found\n");
   3.325      }
   3.326 -
   3.327      return 0;
   3.328  }
   3.329  
   3.330 @@ -1749,20 +1826,13 @@ static int enable_vtd_translation(void)
   3.331  {
   3.332      struct acpi_drhd_unit *drhd;
   3.333      struct iommu *iommu;
   3.334 -    int vector = 0;
   3.335  
   3.336      for_each_drhd_unit ( drhd )
   3.337      {
   3.338          iommu = drhd->iommu;
   3.339 -        vector = iommu_set_interrupt(iommu);
   3.340 -        dma_msi_data_init(iommu, vector);
   3.341 -        dma_msi_addr_init(iommu, cpu_physical_id(first_cpu(cpu_online_map)));
   3.342 -        iommu->vector = vector;
   3.343 -        clear_fault_bit(iommu);
   3.344          if ( iommu_enable_translation(iommu) )
   3.345              return -EIO;
   3.346      }
   3.347 -
   3.348      return 0;
   3.349  }
   3.350  
   3.351 @@ -1793,9 +1863,6 @@ int iommu_setup(void)
   3.352      spin_lock_init(&domid_bitmap_lock);
   3.353      INIT_LIST_HEAD(&hd->pdev_list);
   3.354  
   3.355 -    /* start from scratch */
   3.356 -    iommu_flush_all();
   3.357 -
   3.358      /* setup clflush size */
   3.359      x86_clflush_size = ((cpuid_ebx(1) >> 8) & 0xff) * 8;
   3.360  
   3.361 @@ -1815,12 +1882,12 @@ int iommu_setup(void)
   3.362      for ( i = 0; i < max_page; i++ )
   3.363          iommu_map_page(dom0, i, i);
   3.364  
   3.365 +    enable_vtd_translation();
   3.366      if ( init_vtd_hw() )
   3.367          goto error;
   3.368      setup_dom0_devices();
   3.369      setup_dom0_rmrr();
   3.370 -    if ( enable_vtd_translation() )
   3.371 -        goto error;
   3.372 +    iommu_flush_all();
   3.373  
   3.374      return 0;
   3.375  
     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);