]> git.hungrycats.org Git - linux/commitdiff
iommu/vt-d: Disable translation if already enabled
authorTakao Indoh <indou.takao@jp.fujitsu.com>
Tue, 23 Apr 2013 08:35:03 +0000 (17:35 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 28 Jul 2014 14:06:46 +0000 (07:06 -0700)
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
drivers/iommu/intel-iommu.c

index 97b2e21ac46acc13a63dfe46ee429360a5813654..cf065df9bb18fd592b1a89bba8da5c97133dbeb5 100644 (file)
@@ -582,7 +582,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
        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 *drhd)
                (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;
index 4e1c6bfc9c8d95365db30a0ad12d6b7ef2876eba..dd255c578ad9a0d98ec1fdae03f9d0474309fcf3 100644 (file)
@@ -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");