97168e
From 2f0febd6813c4ad7f52e43afb3ecce7aef3557e6 Mon Sep 17 00:00:00 2001
97168e
From: Matthew Rosato <mjrosato@linux.ibm.com>
97168e
Date: Fri, 28 Oct 2022 15:47:56 -0400
97168e
Subject: [PATCH 08/11] s390x/pci: RPCIT second pass when mappings exhausted
97168e
MIME-Version: 1.0
97168e
Content-Type: text/plain; charset=UTF-8
97168e
Content-Transfer-Encoding: 8bit
97168e
97168e
RH-Author: Cédric Le Goater <clg@redhat.com>
97168e
RH-MergeRequest: 250: s390x/pci: reset ISM passthrough devices on shutdown and system reset
97168e
RH-Bugzilla: 2163713
97168e
RH-Acked-by: Thomas Huth <thuth@redhat.com>
97168e
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
97168e
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
97168e
RH-Commit: [1/4] 0b4500b9247725b1ef0b290bb85392300a618cac
97168e
97168e
If we encounter a new mapping while the number of available DMA entries
97168e
in vfio is 0, we are currently skipping that mapping which is a problem
97168e
if we manage to free up DMA space after that within the same RPCIT --
97168e
we will return to the guest with CC0 and have not mapped everything
97168e
within the specified range.  This issue was uncovered while testing
97168e
changes to the s390 linux kernel iommu/dma code, where a different
97168e
usage pattern was employed (new mappings start at the end of the
97168e
aperture and work back towards the front, making us far more likely
97168e
to encounter new mappings before invalidated mappings during a
97168e
global refresh).
97168e
97168e
Fix this by tracking whether any mappings were skipped due to vfio
97168e
DMA limit hitting 0; when this occurs, we still continue the range
97168e
and unmap/map anything we can - then we must re-run the range again
97168e
to pickup anything that was missed.  This must occur in a loop until
97168e
all requests are satisfied (success) or we detect that we are still
97168e
unable to complete all mappings (return ZPCI_RPCIT_ST_INSUFF_RES).
97168e
97168e
Link: https://lore.kernel.org/linux-s390/20221019144435.369902-1-schnelle@linux.ibm.com/
97168e
Fixes: 37fa32de70 ("s390x/pci: Honor DMA limits set by vfio")
97168e
Reported-by: Niklas Schnelle <schnelle@linux.ibm.com>
97168e
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
97168e
Message-Id: <20221028194758.204007-2-mjrosato@linux.ibm.com>
97168e
Reviewed-by: Eric Farman <farman@linux.ibm.com>
97168e
Signed-off-by: Thomas Huth <thuth@redhat.com>
97168e
(cherry picked from commit 4a8d21ba50fc8625c3bd51dab903872952f95718)
97168e
Signed-off-by: Cédric Le Goater <clg@redhat.com>
97168e
---
97168e
 hw/s390x/s390-pci-inst.c | 29 ++++++++++++++++++++++-------
97168e
 1 file changed, 22 insertions(+), 7 deletions(-)
97168e
97168e
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
97168e
index 20a9bcc7af..7cc4bcf850 100644
97168e
--- a/hw/s390x/s390-pci-inst.c
97168e
+++ b/hw/s390x/s390-pci-inst.c
97168e
@@ -677,8 +677,9 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
     S390PCIBusDevice *pbdev;
97168e
     S390PCIIOMMU *iommu;
97168e
     S390IOTLBEntry entry;
97168e
-    hwaddr start, end;
97168e
+    hwaddr start, end, sstart;
97168e
     uint32_t dma_avail;
97168e
+    bool again;
97168e
 
97168e
     if (env->psw.mask & PSW_MASK_PSTATE) {
97168e
         s390_program_interrupt(env, PGM_PRIVILEGED, ra);
97168e
@@ -691,7 +692,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
     }
97168e
 
97168e
     fh = env->regs[r1] >> 32;
97168e
-    start = env->regs[r2];
97168e
+    sstart = start = env->regs[r2];
97168e
     end = start + env->regs[r2 + 1];
97168e
 
97168e
     pbdev = s390_pci_find_dev_by_fh(s390_get_phb(), fh);
97168e
@@ -732,6 +733,9 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
         goto err;
97168e
     }
97168e
 
97168e
+ retry:
97168e
+    start = sstart;
97168e
+    again = false;
97168e
     while (start < end) {
97168e
         error = s390_guest_io_table_walk(iommu->g_iota, start, &entry);
97168e
         if (error) {
97168e
@@ -739,13 +743,24 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
         }
97168e
 
97168e
         start += entry.len;
97168e
-        while (entry.iova < start && entry.iova < end &&
97168e
-               (dma_avail > 0 || entry.perm == IOMMU_NONE)) {
97168e
-            dma_avail = s390_pci_update_iotlb(iommu, &entry);
97168e
-            entry.iova += TARGET_PAGE_SIZE;
97168e
-            entry.translated_addr += TARGET_PAGE_SIZE;
97168e
+        while (entry.iova < start && entry.iova < end) {
97168e
+            if (dma_avail > 0 || entry.perm == IOMMU_NONE) {
97168e
+                dma_avail = s390_pci_update_iotlb(iommu, &entry);
97168e
+                entry.iova += TARGET_PAGE_SIZE;
97168e
+                entry.translated_addr += TARGET_PAGE_SIZE;
97168e
+            } else {
97168e
+                /*
97168e
+                 * We are unable to make a new mapping at this time, continue
97168e
+                 * on and hopefully free up more space.  Then attempt another
97168e
+                 * pass.
97168e
+                 */
97168e
+                again = true;
97168e
+                break;
97168e
+            }
97168e
         }
97168e
     }
97168e
+    if (again && dma_avail > 0)
97168e
+        goto retry;
97168e
 err:
97168e
     if (error) {
97168e
         pbdev->state = ZPCI_FS_ERROR;
97168e
-- 
97168e
2.37.3
97168e