Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Sebastian Ott <sebott@linux.vnet.ibm.com>
Reviewed-by: Gerald Schaefer <gerald.schaefer@de.ibm.com>
Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Sebastian Ott and committed by
Martin Schwidefsky
a5f10055 d39a01ef

+22 -2
+19 -2
arch/s390/pci/pci_dma.c
··· 181 181 static int __dma_purge_tlb(struct zpci_dev *zdev, dma_addr_t dma_addr, 182 182 size_t size, int flags) 183 183 { 184 + unsigned long irqflags; 185 + int ret; 186 + 184 187 /* 185 188 * With zdev->tlb_refresh == 0, rpcit is not required to establish new 186 189 * translations when previously invalid translation-table entries are ··· 199 196 return 0; 200 197 } 201 198 202 - return zpci_refresh_trans((u64) zdev->fh << 32, dma_addr, 203 - PAGE_ALIGN(size)); 199 + ret = zpci_refresh_trans((u64) zdev->fh << 32, dma_addr, 200 + PAGE_ALIGN(size)); 201 + if (ret == -ENOMEM && !s390_iommu_strict) { 202 + /* enable the hypervisor to free some resources */ 203 + if (zpci_refresh_global(zdev)) 204 + goto out; 205 + 206 + spin_lock_irqsave(&zdev->iommu_bitmap_lock, irqflags); 207 + bitmap_andnot(zdev->iommu_bitmap, zdev->iommu_bitmap, 208 + zdev->lazy_bitmap, zdev->iommu_pages); 209 + bitmap_zero(zdev->lazy_bitmap, zdev->iommu_pages); 210 + spin_unlock_irqrestore(&zdev->iommu_bitmap_lock, irqflags); 211 + ret = 0; 212 + } 213 + out: 214 + return ret; 204 215 } 205 216 206 217 static int dma_update_trans(struct zpci_dev *zdev, unsigned long pa,
+3
arch/s390/pci/pci_insn.c
··· 89 89 if (cc) 90 90 zpci_err_insn(cc, status, addr, range); 91 91 92 + if (cc == 1 && (status == 4 || status == 16)) 93 + return -ENOMEM; 94 + 92 95 return (cc) ? -EIO : 0; 93 96 } 94 97