s390/pci_dma: fix DMA table corruption with > 4 TB main memory
authorGerald Schaefer <gerald.schaefer@de.ibm.com>
Mon, 16 Nov 2015 13:35:48 +0000 (14:35 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Fri, 27 Nov 2015 08:24:15 +0000 (09:24 +0100)
DMA addresses returned from map_page() are calculated by using an iommu
bitmap plus a start_dma offset. The size of this bitmap is based on the main
memory size. If we have more than (4 TB - start_dma) main memory, the DMA
address calculation will also produce addresses > 4 TB. Such addresses
cannot be inserted in the 3-level DMA page table, instead the entries
modulo 4 TB will be overwritten.

Fix this by restricting the iommu bitmap size to (4 TB - start_dma).
Also set zdev->end_dma to the actual end address of the usable
range, instead of the theoretical maximum as reported by the hardware,
which fixes a sanity check in dma_map() and also the IOMMU API domain
geometry aperture calculation.

Signed-off-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/include/asm/pci_dma.h
arch/s390/pci/pci.c
arch/s390/pci/pci_dma.c

index 1aac41e..92df3eb 100644 (file)
@@ -23,6 +23,8 @@ enum zpci_ioat_dtype {
 #define ZPCI_IOTA_FS_2G                        2
 #define ZPCI_KEY                       (PAGE_DEFAULT_KEY << 5)
 
+#define ZPCI_TABLE_SIZE_RT     (1UL << 42)
+
 #define ZPCI_IOTA_STO_FLAG     (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST)
 #define ZPCI_IOTA_RTTO_FLAG    (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT)
 #define ZPCI_IOTA_RSTO_FLAG    (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS)
index 7ef12a3..11d4f27 100644 (file)
@@ -701,8 +701,7 @@ static int zpci_restore(struct device *dev)
                goto out;
 
        zpci_map_resources(pdev);
-       zpci_register_ioat(zdev, 0, zdev->start_dma + PAGE_OFFSET,
-                          zdev->start_dma + zdev->iommu_size - 1,
+       zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
                           (u64) zdev->dma_table);
 
 out:
index d348f2c..3a40f71 100644 (file)
@@ -458,7 +458,19 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
                goto out_clean;
        }
 
-       zdev->iommu_size = (unsigned long) high_memory - PAGE_OFFSET;
+       /*
+        * Restrict the iommu bitmap size to the minimum of the following:
+        * - main memory size
+        * - 3-level pagetable address limit minus start_dma offset
+        * - DMA address range allowed by the hardware (clp query pci fn)
+        *
+        * Also set zdev->end_dma to the actual end address of the usable
+        * range, instead of the theoretical maximum as reported by hardware.
+        */
+       zdev->iommu_size = min3((u64) high_memory,
+                               ZPCI_TABLE_SIZE_RT - zdev->start_dma,
+                               zdev->end_dma - zdev->start_dma + 1);
+       zdev->end_dma = zdev->start_dma + zdev->iommu_size - 1;
        zdev->iommu_pages = zdev->iommu_size >> PAGE_SHIFT;
        zdev->iommu_bitmap = vzalloc(zdev->iommu_pages / 8);
        if (!zdev->iommu_bitmap) {
@@ -466,10 +478,7 @@ int zpci_dma_init_device(struct zpci_dev *zdev)
                goto out_reg;
        }
 
-       rc = zpci_register_ioat(zdev,
-                               0,
-                               zdev->start_dma + PAGE_OFFSET,
-                               zdev->start_dma + zdev->iommu_size - 1,
+       rc = zpci_register_ioat(zdev, 0, zdev->start_dma, zdev->end_dma,
                                (u64) zdev->dma_table);
        if (rc)
                goto out_reg;