Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69eea95c authored by Gerald Schaefer's avatar Gerald Schaefer Committed by Martin Schwidefsky
Browse files

s390/pci_dma: fix DMA table corruption with > 4 TB main memory



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: default avatarGerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 40612351
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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)
+1 −2
Original line number Diff line number Diff line
@@ -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:
+14 −5
Original line number Diff line number Diff line
@@ -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;