7f1c5b
From ed90f91b61844abd2dff2eb970f721a6cf072235 Mon Sep 17 00:00:00 2001
7f1c5b
From: Matthew Rosato <mjrosato@linux.ibm.com>
7f1c5b
Date: Fri, 28 Oct 2022 15:47:57 -0400
7f1c5b
Subject: [PATCH 6/9] s390x/pci: coalesce unmap operations
7f1c5b
MIME-Version: 1.0
7f1c5b
Content-Type: text/plain; charset=UTF-8
7f1c5b
Content-Transfer-Encoding: 8bit
7f1c5b
7f1c5b
RH-Author: Cédric Le Goater <clg@redhat.com>
7f1c5b
RH-MergeRequest: 141: s390x/pci: reset ISM passthrough devices on shutdown and system reset
7f1c5b
RH-Bugzilla: 2163701
7f1c5b
RH-Acked-by: Thomas Huth <thuth@redhat.com>
7f1c5b
RH-Acked-by: Cornelia Huck <cohuck@redhat.com>
7f1c5b
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
7f1c5b
RH-Commit: [1/3] 80c3a2c1d720057ae2a80b338ea06c9c6c804532 (clegoate/qemu-kvm-c9s)
7f1c5b
7f1c5b
Currently, each unmapped page is handled as an individual iommu
7f1c5b
region notification.  Attempt to group contiguous unmap operations
7f1c5b
into fewer notifications to reduce overhead.
7f1c5b
7f1c5b
Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
7f1c5b
Message-Id: <20221028194758.204007-3-mjrosato@linux.ibm.com>
7f1c5b
Reviewed-by: Eric Farman <farman@linux.ibm.com>
7f1c5b
Signed-off-by: Thomas Huth <thuth@redhat.com>
7f1c5b
(cherry picked from commit ef536007c3301bbd6a787e4c2210ea289adaa6f0)
7f1c5b
Signed-off-by: Cédric Le Goater <clg@redhat.com>
7f1c5b
---
7f1c5b
 hw/s390x/s390-pci-inst.c | 51 ++++++++++++++++++++++++++++++++++++++++
7f1c5b
 1 file changed, 51 insertions(+)
7f1c5b
7f1c5b
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
7f1c5b
index 7cc4bcf850..66e764f901 100644
7f1c5b
--- a/hw/s390x/s390-pci-inst.c
7f1c5b
+++ b/hw/s390x/s390-pci-inst.c
7f1c5b
@@ -640,6 +640,8 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
7f1c5b
         }
7f1c5b
         g_hash_table_remove(iommu->iotlb, &entry->iova);
7f1c5b
         inc_dma_avail(iommu);
7f1c5b
+        /* Don't notify the iommu yet, maybe we can bundle contiguous unmaps */
7f1c5b
+        goto out;
7f1c5b
     } else {
7f1c5b
         if (cache) {
7f1c5b
             if (cache->perm == entry->perm &&
7f1c5b
@@ -663,15 +665,44 @@ static uint32_t s390_pci_update_iotlb(S390PCIIOMMU *iommu,
7f1c5b
         dec_dma_avail(iommu);
7f1c5b
     }
7f1c5b
 
7f1c5b
+    /*
7f1c5b
+     * All associated iotlb entries have already been cleared, trigger the
7f1c5b
+     * unmaps.
7f1c5b
+     */
7f1c5b
     memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
7f1c5b
 
7f1c5b
 out:
7f1c5b
     return iommu->dma_limit ? iommu->dma_limit->avail : 1;
7f1c5b
 }
7f1c5b
 
7f1c5b
+static void s390_pci_batch_unmap(S390PCIIOMMU *iommu, uint64_t iova,
7f1c5b
+                                 uint64_t len)
7f1c5b
+{
7f1c5b
+    uint64_t remain = len, start = iova, end = start + len - 1, mask, size;
7f1c5b
+    IOMMUTLBEvent event = {
7f1c5b
+        .type = IOMMU_NOTIFIER_UNMAP,
7f1c5b
+        .entry = {
7f1c5b
+            .target_as = &address_space_memory,
7f1c5b
+            .translated_addr = 0,
7f1c5b
+            .perm = IOMMU_NONE,
7f1c5b
+        },
7f1c5b
+    };
7f1c5b
+
7f1c5b
+    while (remain >= TARGET_PAGE_SIZE) {
7f1c5b
+        mask = dma_aligned_pow2_mask(start, end, 64);
7f1c5b
+        size = mask + 1;
7f1c5b
+        event.entry.iova = start;
7f1c5b
+        event.entry.addr_mask = mask;
7f1c5b
+        memory_region_notify_iommu(&iommu->iommu_mr, 0, event);
7f1c5b
+        start += size;
7f1c5b
+        remain -= size;
7f1c5b
+    }
7f1c5b
+}
7f1c5b
+
7f1c5b
 int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
7f1c5b
 {
7f1c5b
     CPUS390XState *env = &cpu->env;
7f1c5b
+    uint64_t iova, coalesce = 0;
7f1c5b
     uint32_t fh;
7f1c5b
     uint16_t error = 0;
7f1c5b
     S390PCIBusDevice *pbdev;
7f1c5b
@@ -742,6 +773,21 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
7f1c5b
             break;
7f1c5b
         }
7f1c5b
 
7f1c5b
+        /*
7f1c5b
+         * If this is an unmap of a PTE, let's try to coalesce multiple unmaps
7f1c5b
+         * into as few notifier events as possible.
7f1c5b
+         */
7f1c5b
+        if (entry.perm == IOMMU_NONE && entry.len == TARGET_PAGE_SIZE) {
7f1c5b
+            if (coalesce == 0) {
7f1c5b
+                iova = entry.iova;
7f1c5b
+            }
7f1c5b
+            coalesce += entry.len;
7f1c5b
+        } else if (coalesce > 0) {
7f1c5b
+            /* Unleash the coalesced unmap before processing a new map */
7f1c5b
+            s390_pci_batch_unmap(iommu, iova, coalesce);
7f1c5b
+            coalesce = 0;
7f1c5b
+        }
7f1c5b
+
7f1c5b
         start += entry.len;
7f1c5b
         while (entry.iova < start && entry.iova < end) {
7f1c5b
             if (dma_avail > 0 || entry.perm == IOMMU_NONE) {
7f1c5b
@@ -759,6 +805,11 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2, uintptr_t ra)
7f1c5b
             }
7f1c5b
         }
7f1c5b
     }
7f1c5b
+    if (coalesce) {
7f1c5b
+            /* Unleash the coalesced unmap before finishing rpcit */
7f1c5b
+            s390_pci_batch_unmap(iommu, iova, coalesce);
7f1c5b
+            coalesce = 0;
7f1c5b
+    }
7f1c5b
     if (again && dma_avail > 0)
7f1c5b
         goto retry;
7f1c5b
 err:
7f1c5b
-- 
7f1c5b
2.31.1
7f1c5b