git: e9d948cfe0d2 - main - iommu: move context link and ref count into device-independent parts

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sun, 13 Oct 2024 22:30:52 UTC
The branch main has been updated by kib:

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

commit e9d948cfe0d21780d2e94137e322ecfe89f75d6a
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-10-12 19:56:14 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-10-13 22:30:26 +0000

    iommu: move context link and ref count into device-independent parts
    
    This also allows to move some bits of ddb print routines into
    iommu_utils.c common for x86 iommu drivers.
    
    Sponsored by:   Advanced Micro Devices (AMD)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
---
 sys/dev/iommu/iommu.h       |  3 +++
 sys/x86/iommu/intel_ctx.c   | 38 ++++++++++++++--------------
 sys/x86/iommu/intel_dmar.h  |  3 ---
 sys/x86/iommu/intel_drv.c   | 61 +++++++++------------------------------------
 sys/x86/iommu/iommu_utils.c | 41 ++++++++++++++++++++++++++++++
 sys/x86/iommu/x86_iommu.h   |  3 +++
 6 files changed, 78 insertions(+), 71 deletions(-)

diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h
index f425024117d3..b1858f0df9f7 100644
--- a/sys/dev/iommu/iommu.h
+++ b/sys/dev/iommu/iommu.h
@@ -121,11 +121,14 @@ struct iommu_domain {
 	iommu_gaddr_t msi_base;		/* (d) Arch-specific */
 	vm_paddr_t msi_phys;		/* (d) Arch-specific */
 	u_int flags;			/* (u) */
+	LIST_HEAD(, iommu_ctx) contexts;/* (u) */
 };
 
 struct iommu_ctx {
 	struct iommu_domain *domain;	/* (c) */
 	struct bus_dma_tag_iommu *tag;	/* (c) Root tag */
+	LIST_ENTRY(iommu_ctx) link;	/* (u) Member in the domain list */
+	u_int refs;			/* (u) References from tags */
 	u_long loads;			/* atomic updates, for stat only */
 	u_long unloads;			/* same */
 	u_int flags;			/* (u) */
diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c
index 5af5ac7335b8..c2371d4d9c4f 100644
--- a/sys/x86/iommu/intel_ctx.c
+++ b/sys/x86/iommu/intel_ctx.c
@@ -375,7 +375,7 @@ dmar_domain_alloc(struct dmar_unit *dmar, bool id_mapped)
 	iodom = DOM2IODOM(domain);
 	unit = DMAR2IOMMU(dmar);
 	domain->domain = id;
-	LIST_INIT(&domain->contexts);
+	LIST_INIT(&iodom->contexts);
 	iommu_domain_init(unit, iodom, &dmar_domain_map_ops);
 
 	domain->dmar = dmar;
@@ -430,7 +430,7 @@ dmar_ctx_alloc(struct dmar_domain *domain, uint16_t rid)
 	ctx->context.tag = malloc(sizeof(struct bus_dma_tag_iommu),
 	    M_DMAR_CTX, M_WAITOK | M_ZERO);
 	ctx->context.rid = rid;
-	ctx->refs = 1;
+	ctx->context.refs = 1;
 	return (ctx);
 }
 
@@ -446,7 +446,7 @@ dmar_ctx_link(struct dmar_ctx *ctx)
 	    domain->ctx_cnt));
 	domain->refs++;
 	domain->ctx_cnt++;
-	LIST_INSERT_HEAD(&domain->contexts, ctx, link);
+	LIST_INSERT_HEAD(&domain->iodom.contexts, &ctx->context, link);
 }
 
 static void
@@ -463,7 +463,7 @@ dmar_ctx_unlink(struct dmar_ctx *ctx)
 	    domain->refs, domain->ctx_cnt));
 	domain->refs--;
 	domain->ctx_cnt--;
-	LIST_REMOVE(ctx, link);
+	LIST_REMOVE(&ctx->context, link);
 }
 
 static void
@@ -476,7 +476,7 @@ dmar_domain_destroy(struct dmar_domain *domain)
 
 	KASSERT(TAILQ_EMPTY(&domain->iodom.unload_entries),
 	    ("unfinished unloads %p", domain));
-	KASSERT(LIST_EMPTY(&domain->contexts),
+	KASSERT(LIST_EMPTY(&iodom->contexts),
 	    ("destroying dom %p with contexts", domain));
 	KASSERT(domain->ctx_cnt == 0,
 	    ("destroying dom %p with ctx_cnt %d", domain, domain->ctx_cnt));
@@ -593,13 +593,13 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid,
 			/* Nothing needs to be done to destroy ctx1. */
 			free(ctx1, M_DMAR_CTX);
 			domain = CTX2DOM(ctx);
-			ctx->refs++; /* tag referenced us */
+			ctx->context.refs++; /* tag referenced us */
 		}
 	} else {
 		domain = CTX2DOM(ctx);
 		if (ctx->context.tag->owner == NULL)
 			ctx->context.tag->owner = dev;
-		ctx->refs++; /* tag referenced us */
+		ctx->context.refs++; /* tag referenced us */
 	}
 
 	error = dmar_flush_for_ctx_entry(dmar, enable);
@@ -737,15 +737,15 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
 	struct dmar_domain *domain;
 
 	DMAR_ASSERT_LOCKED(dmar);
-	KASSERT(ctx->refs >= 1,
-	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
+	KASSERT(ctx->context.refs >= 1,
+	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->context.refs));
 
 	/*
 	 * If our reference is not last, only the dereference should
 	 * be performed.
 	 */
-	if (ctx->refs > 1) {
-		ctx->refs--;
+	if (ctx->context.refs > 1) {
+		ctx->context.refs--;
 		DMAR_UNLOCK(dmar);
 		return;
 	}
@@ -762,15 +762,15 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
 	TD_PREP_PINNED_ASSERT;
 	ctxp = dmar_map_ctx_entry(ctx, &sf);
 	DMAR_LOCK(dmar);
-	KASSERT(ctx->refs >= 1,
-	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->refs));
+	KASSERT(ctx->context.refs >= 1,
+	    ("dmar %p ctx %p refs %u", dmar, ctx, ctx->context.refs));
 
 	/*
 	 * Other thread might have referenced the context, in which
 	 * case again only the dereference should be performed.
 	 */
-	if (ctx->refs > 1) {
-		ctx->refs--;
+	if (ctx->context.refs > 1) {
+		ctx->context.refs--;
 		DMAR_UNLOCK(dmar);
 		iommu_unmap_pgtbl(sf);
 		TD_PINNED_ASSERT;
@@ -820,14 +820,14 @@ struct dmar_ctx *
 dmar_find_ctx_locked(struct dmar_unit *dmar, uint16_t rid)
 {
 	struct dmar_domain *domain;
-	struct dmar_ctx *ctx;
+	struct iommu_ctx *ctx;
 
 	DMAR_ASSERT_LOCKED(dmar);
 
 	LIST_FOREACH(domain, &dmar->domains, link) {
-		LIST_FOREACH(ctx, &domain->contexts, link) {
-			if (ctx->context.rid == rid)
-				return (ctx);
+		LIST_FOREACH(ctx, &domain->iodom.contexts, link) {
+			if (ctx->rid == rid)
+				return (IOCTX2CTX(ctx));
 		}
 	}
 	return (NULL);
diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h
index fcdc915abcfd..c3163abf6f92 100644
--- a/sys/x86/iommu/intel_dmar.h
+++ b/sys/x86/iommu/intel_dmar.h
@@ -65,7 +65,6 @@ struct dmar_domain {
 	u_int refs;			/* (u) Refs, including ctx */
 	struct dmar_unit *dmar;		/* (c) */
 	LIST_ENTRY(dmar_domain) link;	/* (u) Member in the dmar list */
-	LIST_HEAD(, dmar_ctx) contexts;	/* (u) */
 	vm_object_t pgtbl_obj;		/* (c) Page table pages */
 	u_int batch_no;
 };
@@ -73,8 +72,6 @@ struct dmar_domain {
 struct dmar_ctx {
 	struct iommu_ctx context;
 	uint64_t last_fault_rec[2];	/* Last fault reported */
-	LIST_ENTRY(dmar_ctx) link;	/* (u) Member in the domain list */
-	u_int refs;			/* (u) References from tags */
 };
 
 #define	DMAR_DOMAIN_PGLOCK(dom)		VM_OBJECT_WLOCK((dom)->pgtbl_obj)
diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c
index cc16759ebe34..e973115df21b 100644
--- a/sys/x86/iommu/intel_drv.c
+++ b/sys/x86/iommu/intel_drv.c
@@ -1053,48 +1053,12 @@ dmar_instantiate_rmrr_ctxs(struct iommu_unit *unit)
 #include <ddb/ddb.h>
 #include <ddb/db_lex.h>
 
-static void
-dmar_print_domain_entry(const struct iommu_map_entry *entry)
-{
-	struct iommu_map_entry *l, *r;
-
-	db_printf(
-	    "    start %jx end %jx first %jx last %jx free_down %jx flags %x ",
-	    entry->start, entry->end, entry->first, entry->last,
-	    entry->free_down, entry->flags);
-	db_printf("left ");
-	l = RB_LEFT(entry, rb_entry);
-	if (l == NULL)
-		db_printf("NULL ");
-	else
-		db_printf("%jx ", l->start);
-	db_printf("right ");
-	r = RB_RIGHT(entry, rb_entry);
-	if (r == NULL)
-		db_printf("NULL");
-	else
-		db_printf("%jx", r->start);
-	db_printf("\n");
-}
-
-static void
-dmar_print_ctx(struct dmar_ctx *ctx)
-{
-
-	db_printf(
-	    "    @%p pci%d:%d:%d refs %d flags %x loads %lu unloads %lu\n",
-	    ctx, pci_get_bus(ctx->context.tag->owner),
-	    pci_get_slot(ctx->context.tag->owner),
-	    pci_get_function(ctx->context.tag->owner), ctx->refs,
-	    ctx->context.flags, ctx->context.loads, ctx->context.unloads);
-}
-
 static void
 dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
 {
 	struct iommu_domain *iodom;
 	struct iommu_map_entry *entry;
-	struct dmar_ctx *ctx;
+	struct iommu_ctx *ctx;
 
 	iodom = DOM2IODOM(domain);
 
@@ -1104,16 +1068,16 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
 	    domain, domain->domain, domain->mgaw, domain->agaw, domain->pglvl,
 	    (uintmax_t)domain->iodom.end, domain->refs, domain->ctx_cnt,
 	    domain->iodom.flags, domain->pgtbl_obj, domain->iodom.entries_cnt);
-	if (!LIST_EMPTY(&domain->contexts)) {
+	if (!LIST_EMPTY(&iodom->contexts)) {
 		db_printf("  Contexts:\n");
-		LIST_FOREACH(ctx, &domain->contexts, link)
-			dmar_print_ctx(ctx);
+		LIST_FOREACH(ctx, &iodom->contexts, link)
+			iommu_db_print_ctx(ctx);
 	}
 	if (!show_mappings)
 		return;
 	db_printf("    mapped:\n");
 	RB_FOREACH(entry, iommu_gas_entries_tree, &iodom->rb_root) {
-		dmar_print_domain_entry(entry);
+		iommu_db_print_domain_entry(entry);
 		if (db_pager_quit)
 			break;
 	}
@@ -1121,7 +1085,7 @@ dmar_print_domain(struct dmar_domain *domain, bool show_mappings)
 		return;
 	db_printf("    unloading:\n");
 	TAILQ_FOREACH(entry, &domain->iodom.unload_entries, dmamap_link) {
-		dmar_print_domain_entry(entry);
+		iommu_db_print_domain_entry(entry);
 		if (db_pager_quit)
 			break;
 	}
@@ -1131,7 +1095,7 @@ DB_SHOW_COMMAND_FLAGS(dmar_domain, db_dmar_print_domain, CS_OWN)
 {
 	struct dmar_unit *unit;
 	struct dmar_domain *domain;
-	struct dmar_ctx *ctx;
+	struct iommu_ctx *ctx;
 	bool show_mappings, valid;
 	int pci_domain, bus, device, function, i, t;
 	db_expr_t radix;
@@ -1179,13 +1143,12 @@ DB_SHOW_COMMAND_FLAGS(dmar_domain, db_dmar_print_domain, CS_OWN)
 	for (i = 0; i < dmar_devcnt; i++) {
 		unit = device_get_softc(dmar_devs[i]);
 		LIST_FOREACH(domain, &unit->domains, link) {
-			LIST_FOREACH(ctx, &domain->contexts, link) {
+			LIST_FOREACH(ctx, &domain->iodom.contexts, link) {
 				if (pci_domain == unit->segment && 
-				    bus == pci_get_bus(ctx->context.tag->owner) &&
-				    device ==
-				    pci_get_slot(ctx->context.tag->owner) &&
-				    function ==
-				    pci_get_function(ctx->context.tag->owner)) {
+				    bus == pci_get_bus(ctx->tag->owner) &&
+				    device == pci_get_slot(ctx->tag->owner) &&
+				    function == pci_get_function(ctx->tag->
+				    owner)) {
 					dmar_print_domain(domain,
 					    show_mappings);
 					goto out;
diff --git a/sys/x86/iommu/iommu_utils.c b/sys/x86/iommu/iommu_utils.c
index db8f94eb584f..fde3f150947b 100644
--- a/sys/x86/iommu/iommu_utils.c
+++ b/sys/x86/iommu/iommu_utils.c
@@ -34,6 +34,7 @@
 #else
 #include "opt_apic.h"
 #endif
+#include "opt_ddb.h"
 
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -756,3 +757,43 @@ pglvl_page_size(int total_pglvl, int lvl)
 	KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl));
 	return (pg_sz[rlvl]);
 }
+
+#ifdef DDB
+#include <ddb/ddb.h>
+#include <ddb/db_lex.h>
+
+void
+iommu_db_print_domain_entry(const struct iommu_map_entry *entry)
+{
+	struct iommu_map_entry *l, *r;
+
+	db_printf(
+	    "    start %jx end %jx first %jx last %jx free_down %jx flags %x ",
+	    entry->start, entry->end, entry->first, entry->last,
+	    entry->free_down, entry->flags);
+	db_printf("left ");
+	l = RB_LEFT(entry, rb_entry);
+	if (l == NULL)
+		db_printf("NULL ");
+	else
+		db_printf("%jx ", l->start);
+	db_printf("right ");
+	r = RB_RIGHT(entry, rb_entry);
+	if (r == NULL)
+		db_printf("NULL");
+	else
+		db_printf("%jx", r->start);
+	db_printf("\n");
+}
+
+void
+iommu_db_print_ctx(struct iommu_ctx *ctx)
+{
+	db_printf(
+	    "    @%p pci%d:%d:%d refs %d flags %#x loads %lu unloads %lu\n",
+	    ctx, pci_get_bus(ctx->tag->owner),
+	    pci_get_slot(ctx->tag->owner),
+	    pci_get_function(ctx->tag->owner), ctx->refs,
+	    ctx->flags, ctx->loads, ctx->unloads);
+}
+#endif
diff --git a/sys/x86/iommu/x86_iommu.h b/sys/x86/iommu/x86_iommu.h
index 4d0ac8351e2e..043935a3e0de 100644
--- a/sys/x86/iommu/x86_iommu.h
+++ b/sys/x86/iommu/x86_iommu.h
@@ -194,4 +194,7 @@ vm_pindex_t pglvl_pgtbl_get_pindex(int pglvl, iommu_gaddr_t base, int lvl);
 vm_pindex_t pglvl_max_pages(int pglvl);
 iommu_gaddr_t pglvl_page_size(int total_pglvl, int lvl);
 
+void iommu_db_print_domain_entry(const struct iommu_map_entry *entry);
+void iommu_db_print_ctx(struct iommu_ctx *ctx);
+
 #endif