Merge git://git.infradead.org/iommu-2.6
[firefly-linux-kernel-4.4.55.git] / drivers / pci / intel-iommu.c
index 5493c79dde4788cbcf0e585405196ec6152c6ec6..855dd7ca47f3be2c6f8e79da514035ea5a3ad77c 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/iommu.h>
 #include <linux/intel-iommu.h>
 #include <linux/sysdev.h>
+#include <linux/tboot.h>
 #include <linux/dmi.h>
 #include <asm/cacheflush.h>
 #include <asm/iommu.h>
@@ -735,7 +736,7 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
                                return NULL;
 
                        domain_flush_cache(domain, tmp_page, VTD_PAGE_SIZE);
-                       pteval = (virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
+                       pteval = ((uint64_t)virt_to_dma_pfn(tmp_page) << VTD_PAGE_SHIFT) | DMA_PTE_READ | DMA_PTE_WRITE;
                        if (cmpxchg64(&pte->val, 0ULL, pteval)) {
                                /* Someone else set it while we were thinking; use theirs. */
                                free_pgtable_page(tmp_page);
@@ -2403,11 +2404,12 @@ int __init init_dmars(void)
 
                iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
-               iommu_disable_protect_mem_regions(iommu);
 
                ret = iommu_enable_translation(iommu);
                if (ret)
                        goto error;
+
+               iommu_disable_protect_mem_regions(iommu);
        }
 
        return 0;
@@ -2648,10 +2650,9 @@ static void flush_unmaps(void)
                        unsigned long mask;
                        struct iova *iova = deferred_flush[i].iova[j];
 
-                       mask = (iova->pfn_hi - iova->pfn_lo + 1) << PAGE_SHIFT;
-                       mask = ilog2(mask >> VTD_PAGE_SHIFT);
+                       mask = ilog2(mm_to_dma_pfn(iova->pfn_hi - iova->pfn_lo + 1));
                        iommu_flush_dev_iotlb(deferred_flush[i].domain[j],
-                                       iova->pfn_lo << PAGE_SHIFT, mask);
+                                       (uint64_t)iova->pfn_lo << PAGE_SHIFT, mask);
                        __free_iova(&deferred_flush[i].domain[j]->iovad, iova);
                }
                deferred_flush[i].next = 0;
@@ -3067,8 +3068,8 @@ static int init_iommu_hw(void)
                                           DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
-               iommu_disable_protect_mem_regions(iommu);
                iommu_enable_translation(iommu);
+               iommu_disable_protect_mem_regions(iommu);
        }
 
        return 0;
@@ -3195,12 +3196,22 @@ static int __init init_iommu_sysfs(void)
 int __init intel_iommu_init(void)
 {
        int ret = 0;
+       int force_on = 0;
+
+       /* VT-d is required for a TXT/tboot launch, so enforce that */
+       force_on = tboot_force_iommu();
 
-       if (dmar_table_init())
+       if (dmar_table_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR table\n");
                return  -ENODEV;
+       }
 
-       if (dmar_dev_scope_init())
+       if (dmar_dev_scope_init()) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMAR device scope\n");
                return  -ENODEV;
+       }
 
        /*
         * Check the need for DMA-remapping initialization now.
@@ -3216,6 +3227,8 @@ int __init intel_iommu_init(void)
 
        ret = init_dmars();
        if (ret) {
+               if (force_on)
+                       panic("tboot: Failed to initialize DMARs\n");
                printk(KERN_ERR "IOMMU: dmar init failed\n");
                put_iova_domain(&reserved_iova_list);
                iommu_exit_mempool();