--- /dev/null
+From 3a93c841c2b3b14824f7728dd74bd00a1cedb806 Mon Sep 17 00:00:00 2001
+From: Takao Indoh <indou.takao@jp.fujitsu.com>
+Date: Tue, 23 Apr 2013 17:35:03 +0900
+Subject: iommu/vt-d: Disable translation if already enabled
+
+From: Takao Indoh <indou.takao@jp.fujitsu.com>
+
+commit 3a93c841c2b3b14824f7728dd74bd00a1cedb806 upstream.
+
+This patch disables translation(dma-remapping) before its initialization
+if it is already enabled.
+
+This is needed for kexec/kdump boot. If dma-remapping is enabled in the
+first kernel, it need to be disabled before initializing its page table
+during second kernel boot. Wei Hu also reported that this is needed
+when second kernel boots with intel_iommu=off.
+
+Basically iommu->gcmd is used to know whether translation is enabled or
+disabled, but it is always zero at boot time even when translation is
+enabled since iommu->gcmd is initialized without considering such a
+case. Therefor this patch synchronizes iommu->gcmd value with global
+command register when iommu structure is allocated.
+
+Signed-off-by: Takao Indoh <indou.takao@jp.fujitsu.com>
+Signed-off-by: Joerg Roedel <joro@8bytes.org>
+[wyj: Backported to 3.4: adjust context]
+Signed-off-by: Yijing Wang <wangyijing@huawei.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/iommu/dmar.c | 11 ++++++++++-
+ drivers/iommu/intel-iommu.c | 15 +++++++++++++++
+ 2 files changed, 25 insertions(+), 1 deletion(-)
+
+--- a/drivers/iommu/dmar.c
++++ b/drivers/iommu/dmar.c
+@@ -582,7 +582,7 @@ int alloc_iommu(struct dmar_drhd_unit *d
+ {
+ struct intel_iommu *iommu;
+ int map_size;
+- u32 ver;
++ u32 ver, sts;
+ static int iommu_allocated = 0;
+ int agaw = 0;
+ int msagaw = 0;
+@@ -652,6 +652,15 @@ int alloc_iommu(struct dmar_drhd_unit *d
+ (unsigned long long)iommu->cap,
+ (unsigned long long)iommu->ecap);
+
++ /* Reflect status in gcmd */
++ sts = readl(iommu->reg + DMAR_GSTS_REG);
++ if (sts & DMA_GSTS_IRES)
++ iommu->gcmd |= DMA_GCMD_IRE;
++ if (sts & DMA_GSTS_TES)
++ iommu->gcmd |= DMA_GCMD_TE;
++ if (sts & DMA_GSTS_QIES)
++ iommu->gcmd |= DMA_GCMD_QIE;
++
+ raw_spin_lock_init(&iommu->register_lock);
+
+ drhd->iommu = iommu;
+--- a/drivers/iommu/intel-iommu.c
++++ b/drivers/iommu/intel-iommu.c
+@@ -3659,6 +3659,7 @@ static struct notifier_block device_nb =
+ int __init intel_iommu_init(void)
+ {
+ int ret = 0;
++ struct dmar_drhd_unit *drhd;
+
+ /* VT-d is required for a TXT/tboot launch, so enforce that */
+ force_on = tboot_force_iommu();
+@@ -3669,6 +3670,20 @@ int __init intel_iommu_init(void)
+ return -ENODEV;
+ }
+
++ /*
++ * Disable translation if already enabled prior to OS handover.
++ */
++ for_each_drhd_unit(drhd) {
++ struct intel_iommu *iommu;
++
++ if (drhd->ignored)
++ continue;
++
++ iommu = drhd->iommu;
++ if (iommu->gcmd & DMA_GCMD_TE)
++ iommu_disable_translation(iommu);
++ }
++
+ if (dmar_dev_scope_init() < 0) {
+ if (force_on)
+ panic("tboot: Failed to initialize DMAR device scope\n");