ia64/xen-unstable

changeset 18418:c503269192f2

vtd: fix Dom0 S3 when VT-d is enabled.

Now if VT-d is enabled, when Dom0 does S3, Xen doesn't suspend/resume
the IOMMU states.

The patch adds the missing invocations of
iommu_suspend()/iommu_resume() and makes some nesessary fixes:
1) In iommu_set_root_entry(), we should not re-allocate the root-entry
when Xen returns from S3;
2) Define the array iommu_state correctly (u8 -> u32);
3) Only save/restore the necessary IOMMU registers.

The patch was tested on Weybridge.

NOTE: if we have some HVM guests which have assigned devices, and we
want to do Dom S3, we MUST do HVM S3 for each HVM guest first.
Namely, the steps are:
1) Use HVM S3 in guest to suspend the guest (for example, in Linux HVM
guest, this is "echo mem > /sys/power/state");
2) Use Dom0 S3 to suspend Dom0: "echo mem > /sys/power/state";
3) At some point, Dom0 resumes from S3 (for example, by pressing the
power button or using the acpi alarm);
4) Use "xm trigger HVM_DOM_ID s3resume" to resume every HVM guest
which were suspended previously.

Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Aug 29 16:16:33 2008 +0100 (2008-08-29)
parents 481f0dc6beb0
children 48b33c4275f1
files xen/arch/x86/acpi/power.c xen/drivers/passthrough/vtd/iommu.c xen/include/xen/iommu.h
line diff
     1.1 --- a/xen/arch/x86/acpi/power.c	Fri Aug 29 16:11:05 2008 +0100
     1.2 +++ b/xen/arch/x86/acpi/power.c	Fri Aug 29 16:16:33 2008 +0100
     1.3 @@ -24,6 +24,7 @@
     1.4  #include <xen/sched.h>
     1.5  #include <xen/domain.h>
     1.6  #include <xen/console.h>
     1.7 +#include <xen/iommu.h>
     1.8  #include <public/platform.h>
     1.9  #include <asm/tboot.h>
    1.10  
    1.11 @@ -41,6 +42,8 @@ void do_suspend_lowlevel(void);
    1.12  
    1.13  static int device_power_down(void)
    1.14  {
    1.15 +    iommu_suspend();
    1.16 +
    1.17      console_suspend();
    1.18  
    1.19      time_suspend();
    1.20 @@ -65,6 +68,8 @@ static void device_power_up(void)
    1.21      time_resume();
    1.22  
    1.23      console_resume();
    1.24 +
    1.25 +    iommu_resume();
    1.26  }
    1.27  
    1.28  static void freeze_domains(void)
     2.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Fri Aug 29 16:11:05 2008 +0100
     2.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Fri Aug 29 16:16:33 2008 +0100
     2.3 @@ -624,15 +624,10 @@ static int iommu_set_root_entry(struct i
     2.4      unsigned long flags;
     2.5      s_time_t start_time;
     2.6  
     2.7 -    if ( iommu->root_maddr != 0 )
     2.8 -    {
     2.9 -        free_pgtable_maddr(iommu->root_maddr);
    2.10 -        iommu->root_maddr = 0;
    2.11 -    }
    2.12 -
    2.13      spin_lock_irqsave(&iommu->register_lock, flags);
    2.14  
    2.15 -    iommu->root_maddr = alloc_pgtable_maddr();
    2.16 +    if ( iommu->root_maddr == 0 )
    2.17 +        iommu->root_maddr = alloc_pgtable_maddr();
    2.18      if ( iommu->root_maddr == 0 )
    2.19      {
    2.20          spin_unlock_irqrestore(&iommu->register_lock, flags);
    2.21 @@ -1864,37 +1859,31 @@ static int intel_iommu_group_id(u8 bus, 
    2.22          return -1;
    2.23  }
    2.24  
    2.25 -u8 iommu_state[MAX_IOMMU_REGS * MAX_IOMMUS];
    2.26 +static u32 iommu_state[MAX_IOMMUS][MAX_IOMMU_REGS];
    2.27  int iommu_suspend(void)
    2.28  {
    2.29      struct acpi_drhd_unit *drhd;
    2.30      struct iommu *iommu;
    2.31 -    int i = 0;
    2.32 +    u32    i;
    2.33 +
    2.34 +    if ( !vtd_enabled )
    2.35 +        return 0;
    2.36  
    2.37      iommu_flush_all();
    2.38  
    2.39      for_each_drhd_unit ( drhd )
    2.40      {
    2.41          iommu = drhd->iommu;
    2.42 -        iommu_state[DMAR_RTADDR_REG * i] =
    2.43 -            (u64) dmar_readq(iommu->reg, DMAR_RTADDR_REG);
    2.44 -        iommu_state[DMAR_FECTL_REG * i] =
    2.45 +        i = iommu->index;
    2.46 +
    2.47 +        iommu_state[i][DMAR_FECTL_REG] =
    2.48              (u32) dmar_readl(iommu->reg, DMAR_FECTL_REG);
    2.49 -        iommu_state[DMAR_FEDATA_REG * i] =
    2.50 +        iommu_state[i][DMAR_FEDATA_REG] =
    2.51              (u32) dmar_readl(iommu->reg, DMAR_FEDATA_REG);
    2.52 -        iommu_state[DMAR_FEADDR_REG * i] =
    2.53 +        iommu_state[i][DMAR_FEADDR_REG] =
    2.54              (u32) dmar_readl(iommu->reg, DMAR_FEADDR_REG);
    2.55 -        iommu_state[DMAR_FEUADDR_REG * i] =
    2.56 +        iommu_state[i][DMAR_FEUADDR_REG] =
    2.57              (u32) dmar_readl(iommu->reg, DMAR_FEUADDR_REG);
    2.58 -        iommu_state[DMAR_PLMBASE_REG * i] =
    2.59 -            (u32) dmar_readl(iommu->reg, DMAR_PLMBASE_REG);
    2.60 -        iommu_state[DMAR_PLMLIMIT_REG * i] =
    2.61 -            (u32) dmar_readl(iommu->reg, DMAR_PLMLIMIT_REG);
    2.62 -        iommu_state[DMAR_PHMBASE_REG * i] =
    2.63 -            (u64) dmar_readq(iommu->reg, DMAR_PHMBASE_REG);
    2.64 -        iommu_state[DMAR_PHMLIMIT_REG * i] =
    2.65 -            (u64) dmar_readq(iommu->reg, DMAR_PHMLIMIT_REG);
    2.66 -        i++;
    2.67      }
    2.68  
    2.69      return 0;
    2.70 @@ -1904,37 +1893,34 @@ int iommu_resume(void)
    2.71  {
    2.72      struct acpi_drhd_unit *drhd;
    2.73      struct iommu *iommu;
    2.74 -    int i = 0;
    2.75 +    u32 i;
    2.76 +
    2.77 +    if ( !vtd_enabled )
    2.78 +        return 0;
    2.79  
    2.80      iommu_flush_all();
    2.81  
    2.82 -    init_vtd_hw();
    2.83 +    if ( init_vtd_hw() != 0  && force_iommu )
    2.84 +         panic("IOMMU setup failed, crash Xen for security purpose!\n");
    2.85 +
    2.86      for_each_drhd_unit ( drhd )
    2.87      {
    2.88          iommu = drhd->iommu;
    2.89 -        dmar_writeq( iommu->reg, DMAR_RTADDR_REG,
    2.90 -                     (u64) iommu_state[DMAR_RTADDR_REG * i]);
    2.91 +        i = iommu->index;
    2.92 +
    2.93          dmar_writel(iommu->reg, DMAR_FECTL_REG,
    2.94 -                    (u32) iommu_state[DMAR_FECTL_REG * i]);
    2.95 +                    (u32) iommu_state[i][DMAR_FECTL_REG]);
    2.96          dmar_writel(iommu->reg, DMAR_FEDATA_REG,
    2.97 -                    (u32) iommu_state[DMAR_FEDATA_REG * i]);
    2.98 +                    (u32) iommu_state[i][DMAR_FEDATA_REG]);
    2.99          dmar_writel(iommu->reg, DMAR_FEADDR_REG,
   2.100 -                    (u32) iommu_state[DMAR_FEADDR_REG * i]);
   2.101 +                    (u32) iommu_state[i][DMAR_FEADDR_REG]);
   2.102          dmar_writel(iommu->reg, DMAR_FEUADDR_REG,
   2.103 -                    (u32) iommu_state[DMAR_FEUADDR_REG * i]);
   2.104 -        dmar_writel(iommu->reg, DMAR_PLMBASE_REG,
   2.105 -                    (u32) iommu_state[DMAR_PLMBASE_REG * i]);
   2.106 -        dmar_writel(iommu->reg, DMAR_PLMLIMIT_REG,
   2.107 -                    (u32) iommu_state[DMAR_PLMLIMIT_REG * i]);
   2.108 -        dmar_writeq(iommu->reg, DMAR_PHMBASE_REG,
   2.109 -                    (u64) iommu_state[DMAR_PHMBASE_REG * i]);
   2.110 -        dmar_writeq(iommu->reg, DMAR_PHMLIMIT_REG,
   2.111 -                    (u64) iommu_state[DMAR_PHMLIMIT_REG * i]);
   2.112 +                    (u32) iommu_state[i][DMAR_FEUADDR_REG]);
   2.113  
   2.114          if ( iommu_enable_translation(iommu) )
   2.115              return -EIO;
   2.116 -        i++;
   2.117      }
   2.118 +
   2.119      return 0;
   2.120  }
   2.121  
     3.1 --- a/xen/include/xen/iommu.h	Fri Aug 29 16:11:05 2008 +0100
     3.2 +++ b/xen/include/xen/iommu.h	Fri Aug 29 16:16:33 2008 +0100
     3.3 @@ -109,4 +109,8 @@ struct iommu_ops {
     3.4  
     3.5  void iommu_update_ire_from_apic(unsigned int apic, unsigned int reg, unsigned int value);
     3.6  void iommu_update_ire_from_msi(struct msi_desc *msi_desc, struct msi_msg *msg);
     3.7 +
     3.8 +int iommu_suspend(void);
     3.9 +int iommu_resume(void);
    3.10 +
    3.11  #endif /* _IOMMU_H_ */