git: 9f39aabec76c - stable/13 - iommu: add iommu_gas_remove_locked()

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Tue, 02 Jan 2024 00:42:44 UTC
The branch stable/13 has been updated by kib:

URL: https://cgit.FreeBSD.org/src/commit/?id=9f39aabec76ca4152cd6bbd808b816b80cf6b421

commit 9f39aabec76ca4152cd6bbd808b816b80cf6b421
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2023-12-14 02:41:31 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-01-02 00:42:13 +0000

    iommu: add iommu_gas_remove_locked()
    
    (cherry picked from commit 273b4de3462d7825ebe4ace7a1930f098311287f)
---
 sys/dev/iommu/iommu_gas.c | 83 ++++++++++++++++++++++++++++++++---------------
 1 file changed, 57 insertions(+), 26 deletions(-)

diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c
index dc850747512a..9a74854f926f 100644
--- a/sys/dev/iommu/iommu_gas.c
+++ b/sys/dev/iommu/iommu_gas.c
@@ -708,28 +708,20 @@ iommu_gas_remove_unmap(struct iommu_domain *domain,
 	TAILQ_INSERT_TAIL(gcp, entry, dmamap_link);
 }
 
-/*
- * Remove specified range from the GAS of the domain.  Note that the
- * removal is not guaranteed to occur upon the function return, it
- * might be finalized some time after, when hardware reports that
- * (queued) IOTLB invalidation was performed.
- */
-void
-iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start,
-    iommu_gaddr_t size)
+static void
+iommu_gas_remove_locked(struct iommu_domain *domain,
+    iommu_gaddr_t start, iommu_gaddr_t size,
+    struct iommu_map_entries_tailq *gc,
+    struct iommu_map_entry **r1, struct iommu_map_entry **r2)
 {
-	struct iommu_map_entry *entry, *nentry, *r1, *r2;
-	struct iommu_map_entries_tailq gc;
+	struct iommu_map_entry *entry, *nentry;
 	iommu_gaddr_t end;
 
-	end = start + size;
-	r1 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK);
-	r2 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK);
-	TAILQ_INIT(&gc);
+	IOMMU_DOMAIN_ASSERT_LOCKED(domain);
 
-	IOMMU_DOMAIN_LOCK(domain);
+	end = start + size;
 
-	nentry = iommu_gas_remove_clip_left(domain, start, end, &r1);
+	nentry = iommu_gas_remove_clip_left(domain, start, end, r1);
 	RB_FOREACH_FROM(entry, iommu_gas_entries_tree, nentry) {
 		if (entry->start >= end)
 			break;
@@ -738,11 +730,11 @@ iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start,
 		    entry->start, entry->end, start));
 		if ((entry->flags & IOMMU_MAP_ENTRY_RMRR) != 0)
 			continue;
-		iommu_gas_remove_unmap(domain, entry, &gc);
+		iommu_gas_remove_unmap(domain, entry, gc);
 	}
-	if (iommu_gas_remove_clip_right(domain, end, entry, r2)) {
-		iommu_gas_remove_unmap(domain, r2, &gc);
-		r2 = NULL;
+	if (iommu_gas_remove_clip_right(domain, end, entry, *r2)) {
+		iommu_gas_remove_unmap(domain, *r2, gc);
+		*r2 = NULL;
 	}
 
 #ifdef INVARIANTS
@@ -755,13 +747,52 @@ iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start,
 		    entry->start, entry->end, start, end));
 	}
 #endif
+}
+
+static void
+iommu_gas_remove_init(struct iommu_domain *domain,
+    struct iommu_map_entries_tailq *gc, struct iommu_map_entry **r1,
+    struct iommu_map_entry **r2)
+{
+	TAILQ_INIT(gc);
+	*r1 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK);
+	*r2 = iommu_gas_alloc_entry(domain, IOMMU_PGF_WAITOK);
+}
 
+static void
+iommu_gas_remove_cleanup(struct iommu_domain *domain,
+    struct iommu_map_entries_tailq *gc, struct iommu_map_entry **r1,
+    struct iommu_map_entry **r2)
+{
+	if (*r1 != NULL) {
+		iommu_gas_free_entry(*r1);
+		*r1 = NULL;
+	}
+	if (*r2 != NULL) {
+		iommu_gas_free_entry(*r2);
+		*r2 = NULL;
+	}
+	iommu_domain_unload(domain, gc, true);
+}
+
+/*
+ * Remove specified range from the GAS of the domain.  Note that the
+ * removal is not guaranteed to occur upon the function return, it
+ * might be finalized some time after, when hardware reports that
+ * (queued) IOTLB invalidation was performed.
+ */
+void
+iommu_gas_remove(struct iommu_domain *domain, iommu_gaddr_t start,
+    iommu_gaddr_t size)
+{
+	struct iommu_map_entry *r1, *r2;
+	struct iommu_map_entries_tailq gc;
+
+	iommu_gas_remove_init(domain, &gc, &r1, &r2);
+	IOMMU_DOMAIN_LOCK(domain);
+	iommu_gas_remove_locked(domain, start, size, &gc, &r1, &r2);
 	IOMMU_DOMAIN_UNLOCK(domain);
-	if (r1 != NULL)
-		iommu_gas_free_entry(r1);
-	if (r2 != NULL)
-		iommu_gas_free_entry(r2);
-	iommu_domain_unload(domain, &gc, true);
+	iommu_gas_remove_cleanup(domain, &gc, &r1, &r2);
 }
 
 int