97168e
From b972c5a2763a91024725c147cf1691ed8e180c7c Mon Sep 17 00:00:00 2001
97168e
From: Matthew Rosato <mjrosato@linux.ibm.com>
97168e
Date: Fri, 28 Oct 2022 15:47:57 -0400
97168e
Subject: [PATCH 09/11] s390x/pci: coalesce unmap operations
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: [2/4] 7b5ee38eca565f5a7cbede4b9883ba3a508fb46c
97168e
97168e
Currently, each unmapped page is handled as an individual iommu
97168e
region notification.  Attempt to group contiguous unmap operations
97168e
into fewer notifications to reduce overhead.
97168e
97168e
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
97168e
Message-Id: <20221028194758.204007-3-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 ef536007c3301bbd6a787e4c2210ea289adaa6f0)
97168e
Signed-off-by: Cédric Le Goater <clg@redhat.com>
97168e
---
97168e
 hw/s390x/s390-pci-inst.c | 51 ++++++++++++++++++++++++++++++++++++++++
97168e
 1 file changed, 51 insertions(+)
97168e
97168e
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
97168e
index 7cc4bcf850..66e764f901 100644
97168e
--- a/hw/s390x/s390-pci-inst.c
97168e
+++ b/hw/s390x/s390-pci-inst.c
97168e
@@ -640,6 +640,8 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
97168e
         }
97168e
         g_hash_table_remove(iommu->iotlb, &entry->iova);
97168e
         inc_dma_avail(iommu);
97168e
+        /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */
97168e
+        goto out;
97168e
     } else {
97168e
         if (cache) {
97168e
             if (cache->perm == entry->perm &&
97168e
@@ -663,15 +665,44 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
97168e
         dec_dma_avail(iommu);
97168e
     }
97168e
 
97168e
+    /*
97168e
+     * All associated iotlb entries have already been cleared, trigger the
97168e
+     * unmaps.
97168e
+     */
97168e
     memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
97168e
 
97168e
 out:
97168e
     return iommu->dma_limit ? iommu->dma_limit->avail : 1;
97168e
 }
97168e
 
97168e
+static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova,
97168e
+                                 uint64_t len)
97168e
+{
97168e
+    uint64_t remain = len, start = iova, end = start + len - 1, mask, size;
97168e
+    IOMMUTLBEvent event = {
97168e
+        .type = IOMMU_NOTIFIER_UNMAP,
97168e
+        .entry = {
97168e
+            .target_as = &address_space_memory,
97168e
+            .translated_addr = 0,
97168e
+            .perm = IOMMU_NONE,
97168e
+        },
97168e
+    };
97168e
+
97168e
+    while (remain >= TARGET_PAGE_SIZE) {
97168e
+        mask = dma_aligned_pow2_mask(start, end, 64);
97168e
+        size = mask + 1;
97168e
+        event.entry.iova = start;
97168e
+        event.entry.addr_mask = mask;
97168e
+        memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
97168e
+        start += size;
97168e
+        remain -= size;
97168e
+    }
97168e
+}
97168e
+
97168e
 int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
 {
97168e
     CPUS390XState *env = &cpu->env;
97168e
+    uint64_t iova, coalesce = 0;
97168e
     uint32_t fh;
97168e
     uint16_t error = 0;
97168e
     S390PCIBusDevice *pbdev;
97168e
@@ -742,6 +773,21 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
             break;
97168e
         }
97168e
 
97168e
+        /*
97168e
+         * If this is an unmap of a PTE, let's try to coalesce multiple unmaps
97168e
+         * into as few notifier events as possible.
97168e
+         */
97168e
+        if (entry.perm == IOMMU_NONE && entry.len == TARGET_PAGE_SIZE) {
97168e
+            if (coalesce == 0) {
97168e
+                iova = entry.iova;
97168e
+            }
97168e
+            coalesce += entry.len;
97168e
+        } else if (coalesce > 0) {
97168e
+            /* Unleash the coalesced unmap before processing a new map */
97168e
+            s390_pci_batch_unmap(iommu, iova, coalesce);
97168e
+            coalesce = 0;
97168e
+        }
97168e
+
97168e
         start += entry.len;
97168e
         while (entry.iova < start && entry.iova < end) {
97168e
             if (dma_avail > 0 || entry.perm == IOMMU_NONE) {
97168e
@@ -759,6 +805,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
97168e
             }
97168e
         }
97168e
     }
97168e
+    if (coalesce) {
97168e
+            /* Unleash the coalesced unmap before finishing rpcit */
97168e
+            s390_pci_batch_unmap(iommu, iova, coalesce);
97168e
+            coalesce = 0;
97168e
+    }
97168e
     if (again && dma_avail > 0)
97168e
         goto retry;
97168e
 err:
97168e
-- 
97168e
2.37.3
97168e