Merge tag 'iommu-fixes-v5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Mar 2019 22:37:10 +0000 (15:37 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 29 Mar 2019 22:37:10 +0000 (15:37 -0700)
Pull IOMMU fixes from Joerg Roedel:

 - Fix a bug in the AMD IOMMU driver not handling exclusion ranges
   correctly. In fact the driver did not reserve these ranges for IOVA
   allocations, so that dma-handles could be allocated in an exclusion
   range, leading to data corruption. Exclusion ranges have not been
   used by any firmware up to now, so this issue remained undiscovered
   for quite some time.

 - Fix wrong warning messages that the IOMMU core code prints when it
   tries to allocate the default domain for an iommu group and the
   driver does not support any of the default domain types (like Intel
   VT-d).

* tag 'iommu-fixes-v5.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/joro/iommu:
  iommu/amd: Reserve exclusion range in iova-domain
  iommu: Don't print warning when IOMMU driver only supports unmanaged domains

drivers/iommu/amd_iommu.c
drivers/iommu/amd_iommu_init.c
drivers/iommu/amd_iommu_types.h
drivers/iommu/iommu.c

index 21cb088d66877a4bd6c8c914e72eff5c385de031..f7cdd2ab7f11f6cba22003d4cf71576b4bc77b72 100644 (file)
@@ -3169,21 +3169,24 @@ static void amd_iommu_get_resv_regions(struct device *dev,
                return;
 
        list_for_each_entry(entry, &amd_iommu_unity_map, list) {
+               int type, prot = 0;
                size_t length;
-               int prot = 0;
 
                if (devid < entry->devid_start || devid > entry->devid_end)
                        continue;
 
+               type   = IOMMU_RESV_DIRECT;
                length = entry->address_end - entry->address_start;
                if (entry->prot & IOMMU_PROT_IR)
                        prot |= IOMMU_READ;
                if (entry->prot & IOMMU_PROT_IW)
                        prot |= IOMMU_WRITE;
+               if (entry->prot & IOMMU_UNITY_MAP_FLAG_EXCL_RANGE)
+                       /* Exclusion range */
+                       type = IOMMU_RESV_RESERVED;
 
                region = iommu_alloc_resv_region(entry->address_start,
-                                                length, prot,
-                                                IOMMU_RESV_DIRECT);
+                                                length, prot, type);
                if (!region) {
                        dev_err(dev, "Out of memory allocating dm-regions\n");
                        return;
index f773792d77fd533be53ec3796692c140f77121d7..1b1378619fc9ec2f0caa0bbbd262192c21de61e4 100644 (file)
@@ -2013,6 +2013,9 @@ static int __init init_unity_map_range(struct ivmd_header *m)
        if (e == NULL)
                return -ENOMEM;
 
+       if (m->flags & IVMD_FLAG_EXCL_RANGE)
+               init_exclusion_range(m);
+
        switch (m->type) {
        default:
                kfree(e);
@@ -2059,9 +2062,7 @@ static int __init init_memory_definitions(struct acpi_table_header *table)
 
        while (p < end) {
                m = (struct ivmd_header *)p;
-               if (m->flags & IVMD_FLAG_EXCL_RANGE)
-                       init_exclusion_range(m);
-               else if (m->flags & IVMD_FLAG_UNITY_MAP)
+               if (m->flags & (IVMD_FLAG_UNITY_MAP | IVMD_FLAG_EXCL_RANGE))
                        init_unity_map_range(m);
 
                p += m->length;
index eae0741f72dce2fcea771e415a986b062515c7fc..87965e4d964771bd2352d6254bba299f43734107 100644 (file)
 #define IOMMU_PROT_IR 0x01
 #define IOMMU_PROT_IW 0x02
 
+#define IOMMU_UNITY_MAP_FLAG_EXCL_RANGE        (1 << 2)
+
 /* IOMMU capabilities */
 #define IOMMU_CAP_IOTLB   24
 #define IOMMU_CAP_NPCACHE 26
index 33a982e33716369b7d2bf5885ef5a8ed22f04414..109de67d5d727c227d3970b2879edd60d6478357 100644 (file)
@@ -1105,10 +1105,12 @@ struct iommu_group *iommu_group_get_for_dev(struct device *dev)
 
                dom = __iommu_domain_alloc(dev->bus, iommu_def_domain_type);
                if (!dom && iommu_def_domain_type != IOMMU_DOMAIN_DMA) {
-                       dev_warn(dev,
-                                "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA",
-                                iommu_def_domain_type);
                        dom = __iommu_domain_alloc(dev->bus, IOMMU_DOMAIN_DMA);
+                       if (dom) {
+                               dev_warn(dev,
+                                        "failed to allocate default IOMMU domain of type %u; falling back to IOMMU_DOMAIN_DMA",
+                                        iommu_def_domain_type);
+                       }
                }
 
                group->default_domain = dom;