File 19734-vtd-gcmd-submit.patch of Package xen
# HG changeset patch
# User Keir Fraser <keir.fraser@citrix.com>
# Date 1244190582 -3600
# Node ID 4fb8a6c993e21e18b5eefddd6d5df20e7f8c7848
# Parent a69daf23602a8b7f41a7dc304c7050def59597c7
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>
--- a/xen/drivers/passthrough/vtd/intremap.c
+++ b/xen/drivers/passthrough/vtd/intremap.c
@@ -538,6 +538,7 @@ void msi_msg_write_remap_rte(
int enable_intremap(struct iommu *iommu)
{
struct ir_ctrl *ir_ctrl;
+ u32 gcmd;
s_time_t start_time;
ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
@@ -565,8 +566,9 @@ int enable_intremap(struct iommu *iommu)
dmar_writeq(iommu->reg, DMAR_IRTA_REG, ir_ctrl->iremap_maddr);
/* set SIRTP */
- iommu->gcmd |= DMA_GCMD_SIRTP;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ gcmd = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ gcmd |= DMA_GCMD_SIRTP;
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
/* Make sure hardware complete it */
start_time = NOW();
@@ -578,8 +580,8 @@ int enable_intremap(struct iommu *iommu)
}
/* enable comaptiblity format interrupt pass through */
- iommu->gcmd |= DMA_GCMD_CFI;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ gcmd |= DMA_GCMD_CFI;
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
start_time = NOW();
while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_CFIS) )
@@ -590,8 +592,8 @@ int enable_intremap(struct iommu *iommu)
}
/* enable interrupt remapping hardware */
- iommu->gcmd |= DMA_GCMD_IRE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ gcmd |= DMA_GCMD_IRE;
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, gcmd);
start_time = NOW();
while ( !(dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES) )
@@ -611,12 +613,13 @@ int enable_intremap(struct iommu *iommu)
void disable_intremap(struct iommu *iommu)
{
+ u32 sts;
s_time_t start_time;
ASSERT(ecap_intr_remap(iommu->ecap) && iommu_intremap);
- iommu->gcmd &= ~(DMA_GCMD_SIRTP | DMA_GCMD_CFI | DMA_GCMD_IRE);
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_IRE));
start_time = NOW();
while ( dmar_readl(iommu->reg, DMAR_GSTS_REG) & DMA_GSTS_IRES )
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -266,10 +266,10 @@ static void iommu_flush_write_buffer(str
if ( !rwbf_quirk && !cap_rwbf(iommu->cap) )
return;
- val = iommu->gcmd | DMA_GCMD_WBF;
spin_lock_irqsave(&iommu->register_lock, flag);
- dmar_writel(iommu->reg, DMAR_GCMD_REG, val);
+ val = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, val | DMA_GCMD_WBF);
/* Make sure hardware complete it */
start_time = NOW();
@@ -616,7 +616,7 @@ static void iommu_free_pagetable(u64 pt_
static int iommu_set_root_entry(struct iommu *iommu)
{
- u32 cmd, sts;
+ u32 sts;
unsigned long flags;
s_time_t start_time;
@@ -631,8 +631,9 @@ static int iommu_set_root_entry(struct i
}
dmar_writeq(iommu->reg, DMAR_RTADDR_REG, iommu->root_maddr);
- cmd = iommu->gcmd | DMA_GCMD_SRTP;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, cmd);
+
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_SRTP);
/* Make sure hardware complete it */
start_time = NOW();
@@ -661,8 +662,9 @@ static int iommu_enable_translation(stru
dprintk(XENLOG_INFO VTDPREFIX,
"iommu_enable_translation: iommu->reg = %p\n", iommu->reg);
spin_lock_irqsave(&iommu->register_lock, flags);
- iommu->gcmd |= DMA_GCMD_TE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_TE);
+
/* Make sure hardware complete it */
start_time = NOW();
for ( ; ; )
@@ -689,8 +691,8 @@ static void iommu_disable_translation(st
s_time_t start_time;
spin_lock_irqsave(&iommu->register_lock, flags);
- iommu->gcmd &= ~ DMA_GCMD_TE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_TE));
/* Make sure hardware complete it */
start_time = NOW();
--- a/xen/drivers/passthrough/vtd/qinval.c
+++ b/xen/drivers/passthrough/vtd/qinval.c
@@ -415,6 +415,7 @@ static int flush_iotlb_qi(
int enable_qinval(struct iommu *iommu)
{
+ u32 sts;
s_time_t start_time;
struct qi_ctrl *qi_ctrl;
struct iommu_flush *flush;
@@ -449,8 +450,8 @@ int enable_qinval(struct iommu *iommu)
dmar_writeq(iommu->reg, DMAR_IQT_REG, 0);
/* enable queued invalidation hardware */
- iommu->gcmd |= DMA_GCMD_QIE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts | DMA_GCMD_QIE);
/* Make sure hardware complete it */
start_time = NOW();
@@ -466,12 +467,13 @@ int enable_qinval(struct iommu *iommu)
void disable_qinval(struct iommu *iommu)
{
+ u32 sts;
s_time_t start_time;
ASSERT(ecap_queued_inval(iommu->ecap) && iommu_qinval);
- iommu->gcmd &= ~DMA_GCMD_QIE;
- dmar_writel(iommu->reg, DMAR_GCMD_REG, iommu->gcmd);
+ sts = dmar_readl(iommu->reg, DMAR_GSTS_REG);
+ dmar_writel(iommu->reg, DMAR_GCMD_REG, sts & (~DMA_GCMD_QIE));
/* Make sure hardware complete it */
start_time = NOW();
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -49,7 +49,6 @@ struct iommu {
struct list_head list;
void __iomem *reg; /* Pointer to hardware regs, virtual addr */
u32 index; /* Sequence number of iommu */
- u32 gcmd; /* Holds TE, EAFL. Don't need SRTP, SFL, WBF */
u32 nr_pt_levels;
u64 cap;
u64 ecap;