Merge tag 'iommu-updates-v3.8' of git://git.kernel.org/pub/scm/linux/kernel/git/joro...
[deliverable/linux.git] / drivers / iommu / intel-iommu.c
index 0badfa48b32b7e84a16449ebc8804e461529c8b9..c2c07a4a7f21c5f57d9eca2884933dd99088b60a 100644 (file)
@@ -1827,10 +1827,17 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        if (!pte)
                                return -ENOMEM;
                        /* It is large page*/
-                       if (largepage_lvl > 1)
+                       if (largepage_lvl > 1) {
                                pteval |= DMA_PTE_LARGE_PAGE;
-                       else
+                               /* Ensure that old small page tables are removed to make room
+                                  for superpage, if they exist. */
+                               dma_pte_clear_range(domain, iov_pfn,
+                                                   iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                               dma_pte_free_pagetable(domain, iov_pfn,
+                                                      iov_pfn + lvl_to_nr_pages(largepage_lvl) - 1);
+                       } else {
                                pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
+                       }
 
                }
                /* We don't need lock here, nobody else
@@ -2320,8 +2327,39 @@ static int domain_add_dev_info(struct dmar_domain *domain,
        return 0;
 }
 
+static bool device_has_rmrr(struct pci_dev *dev)
+{
+       struct dmar_rmrr_unit *rmrr;
+       int i;
+
+       for_each_rmrr_units(rmrr) {
+               for (i = 0; i < rmrr->devices_cnt; i++) {
+                       /*
+                        * Return TRUE if this RMRR contains the device that
+                        * is passed in.
+                        */
+                       if (rmrr->devices[i] == dev)
+                               return true;
+               }
+       }
+       return false;
+}
+
 static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
 {
+
+       /*
+        * We want to prevent any device associated with an RMRR from
+        * getting placed into the SI Domain. This is done because
+        * problems exist when devices are moved in and out of domains
+        * and their respective RMRR info is lost. We exempt USB devices
+        * from this process due to their usage of RMRRs that are known
+        * to not be needed after BIOS hand-off to OS.
+        */
+       if (device_has_rmrr(pdev) &&
+           (pdev->class >> 8) != PCI_CLASS_SERIAL_USB)
+               return 0;
+
        if ((iommu_identity_mapping & IDENTMAP_AZALIA) && IS_AZALIA(pdev))
                return 1;
 
This page took 0.035857 seconds and 5 git commands to generate.