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

Commit a5f10055 authored by Sebastian Ott's avatar Sebastian Ott Committed by Martin Schwidefsky
Browse files

s390/pci: handle insufficient resources during dma tlb flush



In a virtualized setup lazy flushing can lead to the hypervisor
running out of resources when lots of guest pages need to be
pinned. In this situation simply trigger a global flush to give
the hypervisor a chance to free some of these resources.

Signed-off-by: default avatarSebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: default avatarGerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: default avatarPierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent d39a01ef
Loading
Loading
Loading
Loading
+19 −2
Original line number Diff line number Diff line
@@ -181,6 +181,9 @@ static int __dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr,
			   size_t size, int flags)
{
	unsigned long irqflags;
	int ret;

	/*
	 * With zdev->tlb_refresh == 0, rpcit is not required to establish new
	 * translations when previously invalid translation-table entries are
@@ -196,8 +199,22 @@ static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr,
			return 0;
	}

	return zpci_refresh_trans((u64) zdev->fh << 32, dma_addr,
	ret = zpci_refresh_trans((u64) zdev->fh << 32, dma_addr,
				 PAGE_ALIGN(size));
	if (ret == -ENOMEM && !s390_iommu_strict) {
		/* enable the hypervisor to free some resources */
		if (zpci_refresh_global(zdev))
			goto out;

		spin_lock_irqsave(&zdev->iommu_bitmap_lock, irqflags);
		bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap,
			      zdev->lazy_bitmap, zdev->iommu_pages);
		bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages);
		spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, irqflags);
		ret = 0;
	}
out:
	return ret;
}

static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
+3 −0
Original line number Diff line number Diff line
@@ -89,6 +89,9 @@ int zpci_refresh_trans(u64 fn, u64 addr, u64 range)
	if (cc)
		zpci_err_insn(cc, status, addr, range);

	if (cc == 1 && (status == 4 || status == 16))
		return -ENOMEM;

	return (cc) ? -EIO : 0;
}