ia64/xen-unstable

changeset 19734:4fb8a6c993e2

VT-d: correct way to submit command to GCMD register

Per VT-d spec, software should submit only one "incremental" command
at a time to Global Command reigster. Current implementation uses a
variable (gcmd) to record the state of Global Status register. It's
error prone.

Signed-off-by: Weidong Han <weidong.han@intel.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 09:29:42 2009 +0100 (2009-06-05)
parents a69daf23602a
children 21d1fcb0be41
files xen/drivers/passthrough/vtd/intremap.c xen/drivers/passthrough/vtd/iommu.c xen/drivers/passthrough/vtd/qinval.c xen/include/xen/iommu.h
line diff
     1.1 --- a/xen/drivers/passthrough/vtd/intremap.c	Fri Jun 05 09:27:18 2009 +0100
     1.2 +++ b/xen/drivers/passthrough/vtd/intremap.c	Fri Jun 05 09:29:42 2009 +0100
     1.3 @@ -534,7 +534,7 @@ void msi_msg_write_remap_rte(
     1.4  int enable_intremap(struct iommu *iommu)
     1.5  {
     1.6      struct ir_ctrl *ir_ctrl;
     1.7 -    u32 sts;
     1.8 +    u32 sts, gcmd;
     1.9  
    1.10      ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
    1.11  
    1.12 @@ -561,22 +561,23 @@ int enable_intremap(struct iommu *iommu)
    1.13      dmar_writeq(iommu->reg, DMAR_IRTA_REG, ir_ctrl->iremap_maddr);
    1.14  
    1.15      /* set SIRTP */
    1.16 -    iommu->gcmd |= DMA_GCMD_SIRTP;
    1.17 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    1.18 +    gcmd = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    1.19 +    gcmd |= DMA_GCMD_SIRTP;
    1.20 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
    1.21  
    1.22      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    1.23                    (sts & DMA_GSTS_SIRTPS), sts);
    1.24   
    1.25      /* enable comaptiblity format interrupt pass through */
    1.26 -    iommu->gcmd |= DMA_GCMD_CFI;
    1.27 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    1.28 +    gcmd |= DMA_GCMD_CFI;
    1.29 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
    1.30  
    1.31      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    1.32                    (sts & DMA_GSTS_CFIS), sts);
    1.33  
    1.34      /* enable interrupt remapping hardware */
    1.35 -    iommu->gcmd |= DMA_GCMD_IRE;
    1.36 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    1.37 +    gcmd |= DMA_GCMD_IRE;
    1.38 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
    1.39  
    1.40      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    1.41                    (sts & DMA_GSTS_IRES), sts);
    1.42 @@ -593,8 +594,8 @@ void disable_intremap(struct iommu *iomm
    1.43  
    1.44      ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
    1.45  
    1.46 -    iommu->gcmd &= ~(DMA_GCMD_SIRTP | DMA_GCMD_CFI | DMA_GCMD_IRE);
    1.47 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    1.48 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    1.49 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_IRE));
    1.50  
    1.51      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    1.52                    !(sts & DMA_GSTS_IRES), sts);
     2.1 --- a/xen/drivers/passthrough/vtd/iommu.c	Fri Jun 05 09:27:18 2009 +0100
     2.2 +++ b/xen/drivers/passthrough/vtd/iommu.c	Fri Jun 05 09:29:42 2009 +0100
     2.3 @@ -233,10 +233,10 @@ static void iommu_flush_write_buffer(str
     2.4  
     2.5      if ( !rwbf_quirk && !cap_rwbf(iommu->cap) )
     2.6          return;
     2.7 -    val = iommu->gcmd | DMA_GCMD_WBF;
     2.8  
     2.9      spin_lock_irqsave(&iommu->register_lock, flag);
    2.10 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, val);
    2.11 +    val = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    2.12 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, val | DMA_GCMD_WBF);
    2.13  
    2.14      /* Make sure hardware complete it */
    2.15      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    2.16 @@ -548,7 +548,7 @@ static void iommu_free_pagetable(u64 pt_
    2.17  
    2.18  static int iommu_set_root_entry(struct iommu *iommu)
    2.19  {
    2.20 -    u32 cmd, sts;
    2.21 +    u32 sts;
    2.22      unsigned long flags;
    2.23  
    2.24      spin_lock(&iommu->lock);
    2.25 @@ -564,8 +564,9 @@ static int iommu_set_root_entry(struct i
    2.26      spin_unlock(&iommu->lock);
    2.27      spin_lock_irqsave(&iommu->register_lock, flags);
    2.28      dmar_writeq(iommu->reg, DMAR_RTADDR_REG, iommu->root_maddr);
    2.29 -    cmd = iommu->gcmd | DMA_GCMD_SRTP;
    2.30 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd);
    2.31 +
    2.32 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    2.33 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_SRTP);
    2.34  
    2.35      /* Make sure hardware complete it */
    2.36      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    2.37 @@ -583,8 +584,8 @@ static void iommu_enable_translation(str
    2.38      dprintk(XENLOG_INFO VTDPREFIX,
    2.39              "iommu_enable_translation: iommu->reg = %p\n", iommu->reg);
    2.40      spin_lock_irqsave(&iommu->register_lock, flags);
    2.41 -    iommu->gcmd |= DMA_GCMD_TE;
    2.42 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    2.43 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    2.44 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_TE);
    2.45  
    2.46      /* Make sure hardware complete it */
    2.47      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    2.48 @@ -601,8 +602,8 @@ static void iommu_disable_translation(st
    2.49      unsigned long flags;
    2.50  
    2.51      spin_lock_irqsave(&iommu->register_lock, flags);
    2.52 -    iommu->gcmd &= ~ DMA_GCMD_TE;
    2.53 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    2.54 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    2.55 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_TE));
    2.56  
    2.57      /* Make sure hardware complete it */
    2.58      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
     3.1 --- a/xen/drivers/passthrough/vtd/qinval.c	Fri Jun 05 09:27:18 2009 +0100
     3.2 +++ b/xen/drivers/passthrough/vtd/qinval.c	Fri Jun 05 09:29:42 2009 +0100
     3.3 @@ -454,8 +454,8 @@ int enable_qinval(struct iommu *iommu)
     3.4      dmar_writeq(iommu->reg, DMAR_IQT_REG, 0);
     3.5  
     3.6      /* enable queued invalidation hardware */
     3.7 -    iommu->gcmd |= DMA_GCMD_QIE;
     3.8 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
     3.9 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    3.10 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_QIE);
    3.11  
    3.12      /* Make sure hardware complete it */
    3.13      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
    3.14 @@ -471,8 +471,8 @@ void disable_qinval(struct iommu *iommu)
    3.15  
    3.16      ASSERT(ecap_queued_inval(iommu->ecap) && iommu_qinval);
    3.17  
    3.18 -    iommu->gcmd &= ~DMA_GCMD_QIE;
    3.19 -    dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
    3.20 +    sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
    3.21 +    dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_QIE));
    3.22  
    3.23      /* Make sure hardware complete it */
    3.24      IOMMU_WAIT_OP(iommu, DMAR_GSTS_REG, dmar_readl,
     4.1 --- a/xen/include/xen/iommu.h	Fri Jun 05 09:27:18 2009 +0100
     4.2 +++ b/xen/include/xen/iommu.h	Fri Jun 05 09:29:42 2009 +0100
     4.3 @@ -47,7 +47,6 @@ struct iommu {
     4.4      struct list_head list;
     4.5      void __iomem *reg; /* Pointer to hardware regs, virtual addr */
     4.6      u32	index;         /* Sequence number of iommu */
     4.7 -    u32	gcmd;          /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
     4.8      u32 nr_pt_levels;
     4.9      u64	cap;
    4.10      u64	ecap;