ia64/xen-unstable

changeset 19385:6d65dc14d21b

vtd: Only enable some VT-d features if all VT-d engines support them.

By default, we enable snoop control, queued invalidation and interrupt
remapping if all VT-d engines support them, and for DMA passthrough we
don't enable it by default.

A user can use 'iommu=passthrough' to enable DMA passthrough (only
for Dom0). A user can use 'iommu=no-snoop,no-qinval,no-intremap' to
disable the 3 features.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>=
author Keir Fraser <keir.fraser@citrix.com>
date Wed Mar 18 11:46:32 2009 +0000 (2009-03-18)
parents 33270c9a3d2f
children f00e5d83b9ec
files xen/drivers/passthrough/iommu.c xen/drivers/passthrough/vtd/dmar.c xen/drivers/passthrough/vtd/iommu.c xen/include/xen/iommu.h
line diff
     1.1 --- a/xen/drivers/passthrough/iommu.c	Wed Mar 18 11:37:59 2009 +0000
     1.2 +++ b/xen/drivers/passthrough/iommu.c	Wed Mar 18 11:46:32 2009 +0000
     1.3 @@ -32,9 +32,11 @@ int amd_iov_detect(void);
     1.4   *   pv                         Enable IOMMU for PV domains
     1.5   *   no-pv                      Disable IOMMU for PV domains (default)
     1.6   *   force|required             Don't boot unless IOMMU is enabled
     1.7 - *   passthrough                Bypass VT-d translation for Dom0
     1.8 - *   snoop                      Utilize the snoop control for IOMMU (default)
     1.9 - *   no-snoop                   Dont utilize the snoop control for IOMMU
    1.10 + *   passthrough                Enable VT-d DMA passthrough (no DMA
    1.11 + *                              translation for Dom0)
    1.12 + *   no-snoop                   Disable VT-d Snoop Control
    1.13 + *   no-qinval                  Disable VT-d Queued Invalidation
    1.14 + *   no-intremap                Disable VT-d Interrupt Remapping
    1.15   */
    1.16  custom_param("iommu", parse_iommu_param);
    1.17  int iommu_enabled = 0;
    1.18 @@ -42,12 +44,16 @@ int iommu_pv_enabled = 0;
    1.19  int force_iommu = 0;
    1.20  int iommu_passthrough = 0;
    1.21  int iommu_snoop = 0;
    1.22 +int iommu_qinval = 0;
    1.23 +int iommu_intremap = 0;
    1.24  
    1.25  static void __init parse_iommu_param(char *s)
    1.26  {
    1.27      char *ss;
    1.28      iommu_enabled = 1;
    1.29      iommu_snoop = 1;
    1.30 +    iommu_qinval = 1;
    1.31 +    iommu_intremap = 1;
    1.32  
    1.33      do {
    1.34          ss = strchr(s, ',');
    1.35 @@ -65,10 +71,12 @@ static void __init parse_iommu_param(cha
    1.36              force_iommu = 1;
    1.37          else if ( !strcmp(s, "passthrough") )
    1.38              iommu_passthrough = 1;
    1.39 -        else if ( !strcmp(s, "snoop") )
    1.40 -            iommu_snoop = 1;
    1.41          else if ( !strcmp(s, "no-snoop") )
    1.42              iommu_snoop = 0;
    1.43 +        else if ( !strcmp(s, "no-qinval") )
    1.44 +            iommu_qinval = 0;
    1.45 +        else if ( !strcmp(s, "no-intremap") )
    1.46 +            iommu_intremap = 0;
    1.47  
    1.48          s = ss + 1;
    1.49      } while ( ss );
     2.1 --- a/xen/drivers/passthrough/vtd/dmar.c	Wed Mar 18 11:37:59 2009 +0000
     2.2 +++ b/xen/drivers/passthrough/vtd/dmar.c	Wed Mar 18 11:46:32 2009 +0000
     2.3 @@ -548,7 +548,7 @@ int acpi_dmar_init(void)
     2.4      if ( list_empty(&acpi_drhd_units) )
     2.5          goto fail;
     2.6  
     2.7 -    printk("Intel VT-d has been enabled\n");
     2.8 +    printk("Intel VT-d DMAR tables have been parsed.\n");
     2.9  
    2.10      return 0;
    2.11  
     3.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Wed Mar 18 11:37:59 2009 +0000
     3.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Wed Mar 18 11:46:32 2009 +0000
     3.3 @@ -1041,8 +1041,7 @@ static int domain_context_mapping_one(
     3.4          return res;
     3.5      }
     3.6  
     3.7 -    if ( iommu_passthrough &&
     3.8 -         ecap_pass_thru(iommu->ecap) && (domain->domain_id == 0) )
     3.9 +    if ( iommu_passthrough && (domain->domain_id == 0) )
    3.10      {
    3.11          context_set_translation_type(*context, CONTEXT_TT_PASS_THRU);
    3.12          agaw = level_to_agaw(iommu->nr_pt_levels);
    3.13 @@ -1449,8 +1448,7 @@ int intel_iommu_map_page(
    3.14      iommu = drhd->iommu;
    3.15  
    3.16      /* do nothing if dom0 and iommu supports pass thru */
    3.17 -    if ( iommu_passthrough &&
    3.18 -         ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
    3.19 +    if ( iommu_passthrough && (d->domain_id == 0) )
    3.20          return 0;
    3.21  
    3.22      spin_lock(&hd->mapping_lock);
    3.23 @@ -1504,8 +1502,7 @@ int intel_iommu_unmap_page(struct domain
    3.24      iommu = drhd->iommu;
    3.25  
    3.26      /* do nothing if dom0 and iommu supports pass thru */
    3.27 -    if ( iommu_passthrough &&
    3.28 -         ecap_pass_thru(iommu->ecap) && (d->domain_id == 0) )
    3.29 +    if ( iommu_passthrough && (d->domain_id == 0) )
    3.30          return 0;
    3.31  
    3.32      dma_pte_clear_one(d, (paddr_t)gfn << PAGE_SHIFT_4K);
    3.33 @@ -1682,20 +1679,32 @@ static int init_vtd_hw(void)
    3.34          flush->iotlb = flush_iotlb_reg;
    3.35      }
    3.36  
    3.37 -    for_each_drhd_unit ( drhd )
    3.38 +    if ( iommu_qinval )
    3.39      {
    3.40 -        iommu = drhd->iommu;
    3.41 -        if ( qinval_setup(iommu) != 0 )
    3.42 -            dprintk(XENLOG_INFO VTDPREFIX,
    3.43 -                    "Queued Invalidation hardware not found\n");
    3.44 +        for_each_drhd_unit ( drhd )
    3.45 +        {
    3.46 +            iommu = drhd->iommu;
    3.47 +            if ( qinval_setup(iommu) != 0 )
    3.48 +            {
    3.49 +                dprintk(XENLOG_INFO VTDPREFIX,
    3.50 +                        "Failed to enable Queued Invalidation!\n");
    3.51 +                break;
    3.52 +            }
    3.53 +        }
    3.54      }
    3.55  
    3.56 -    for_each_drhd_unit ( drhd )
    3.57 +    if ( iommu_intremap )
    3.58      {
    3.59 -        iommu = drhd->iommu;
    3.60 -        if ( intremap_setup(iommu) != 0 )
    3.61 -            dprintk(XENLOG_INFO VTDPREFIX,
    3.62 -                    "Interrupt Remapping hardware not found\n");
    3.63 +        for_each_drhd_unit ( drhd )
    3.64 +        {
    3.65 +            iommu = drhd->iommu;
    3.66 +            if ( intremap_setup(iommu) != 0 )
    3.67 +            {
    3.68 +                dprintk(XENLOG_INFO VTDPREFIX,
    3.69 +                        "Failed to enable Interrupt Remapping!\n");
    3.70 +                break;
    3.71 +            }
    3.72 +        }
    3.73      }
    3.74  
    3.75      return 0;
    3.76 @@ -1744,10 +1753,36 @@ int intel_vtd_setup(void)
    3.77      spin_lock_init(&domid_bitmap_lock);
    3.78      clflush_size = get_cache_line_size();
    3.79  
    3.80 +    /* We enable the following features only if they are supported by all VT-d
    3.81 +     * engines: Snoop Control, DMA passthrough, Queued Invalidation and
    3.82 +     * Interrupt Remapping.
    3.83 +     */
    3.84      for_each_drhd_unit ( drhd )
    3.85 +    {
    3.86          if ( iommu_alloc(drhd) != 0 )
    3.87              goto error;
    3.88  
    3.89 +        iommu = drhd->iommu;
    3.90 +
    3.91 +        if ( iommu_snoop && !ecap_snp_ctl(iommu->ecap) )
    3.92 +            iommu_snoop = 0;
    3.93 +
    3.94 +        if ( iommu_passthrough && !ecap_pass_thru(iommu->ecap) )
    3.95 +            iommu_passthrough = 0;
    3.96 +
    3.97 +        if ( iommu_qinval && !ecap_queued_inval(iommu->ecap) )
    3.98 +            iommu_qinval = 0;
    3.99 +
   3.100 +        if ( iommu_intremap && !ecap_intr_remap(iommu->ecap) )
   3.101 +            iommu_intremap = 0;
   3.102 +    }
   3.103 +#define P(p,s) printk("Intel VT-d %s %ssupported.\n", s, (p)? "" : "not ")
   3.104 +    P(iommu_snoop, "Snoop Control");
   3.105 +    P(iommu_passthrough, "DMA Passthrough");
   3.106 +    P(iommu_qinval, "Queued Invalidation");
   3.107 +    P(iommu_intremap, "Interrupt Remapping");
   3.108 +#undef P
   3.109 +
   3.110      /* Allocate IO page directory page for the domain. */
   3.111      drhd = list_entry(acpi_drhd_units.next, typeof(*drhd), list);
   3.112      iommu = drhd->iommu;
   3.113 @@ -1764,23 +1799,6 @@ int intel_vtd_setup(void)
   3.114      if ( init_vtd_hw() )
   3.115          goto error;
   3.116  
   3.117 -    /* Giving that all devices within guest use same io page table,
   3.118 -     * enable snoop control only if all VT-d engines support it.
   3.119 -     */
   3.120 -
   3.121 -    if ( iommu_snoop )
   3.122 -    {
   3.123 -        for_each_drhd_unit ( drhd )
   3.124 -        {
   3.125 -            iommu = drhd->iommu;
   3.126 -            if ( !ecap_snp_ctl(iommu->ecap) ) {
   3.127 -                iommu_snoop = 0;
   3.128 -                break;
   3.129 -            }
   3.130 -        }
   3.131 -    }
   3.132 -    
   3.133 -    printk("Intel VT-d snoop control %sabled\n", iommu_snoop ? "en" : "dis");
   3.134      register_keyhandler('V', dump_iommu_info, "dump iommu info");
   3.135  
   3.136      return 0;
   3.137 @@ -1790,6 +1808,9 @@ int intel_vtd_setup(void)
   3.138          iommu_free(drhd);
   3.139      vtd_enabled = 0;
   3.140      iommu_snoop = 0;
   3.141 +    iommu_passthrough = 0;
   3.142 +    iommu_qinval = 0;
   3.143 +    iommu_intremap = 0;
   3.144      return -ENOMEM;
   3.145  }
   3.146  
     4.1 --- a/xen/include/xen/iommu.h	Wed Mar 18 11:37:59 2009 +0000
     4.2 +++ b/xen/include/xen/iommu.h	Wed Mar 18 11:46:32 2009 +0000
     4.3 @@ -32,6 +32,8 @@ extern int iommu_pv_enabled;
     4.4  extern int force_iommu;
     4.5  extern int iommu_passthrough;
     4.6  extern int iommu_snoop;
     4.7 +extern int iommu_qinval;
     4.8 +extern int iommu_intremap;
     4.9  
    4.10  #define domain_hvm_iommu(d)     (&d->arch.hvm_domain.hvm_iommu)
    4.11