git: 29e227047065 - main - x86 iommu: move page level related functions to common utils

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Wed, 04 Sep 2024 21:50:50 UTC
The branch main has been updated by kib:

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

commit 29e227047065c6b1d08fdb72a21f33560637332b
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-07-19 23:47:48 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-09-04 21:50:19 +0000

    x86 iommu: move page level related functions to common utils
    
    Also improve pglvl_page_size() to handle level 6.
    
    Sponsored by:   Advanced Micro Devices (AMD)
    Sponsored by:   The FreeBSD Foundation
    MFC after:      1 week
---
 sys/x86/iommu/intel_dmar.h    |  2 --
 sys/x86/iommu/intel_idpgtbl.c | 38 ++---------------------
 sys/x86/iommu/intel_utils.c   | 37 ----------------------
 sys/x86/iommu/iommu_utils.c   | 71 +++++++++++++++++++++++++++++++++++++++++++
 sys/x86/iommu/x86_iommu.h     |  5 +++
 5 files changed, 78 insertions(+), 75 deletions(-)

diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h
index edb152f42fe7..c1e6c8f06f64 100644
--- a/sys/x86/iommu/intel_dmar.h
+++ b/sys/x86/iommu/intel_dmar.h
@@ -175,9 +175,7 @@ bool dmar_pglvl_supported(struct dmar_unit *unit, int pglvl);
 int domain_set_agaw(struct dmar_domain *domain, int mgaw);
 int dmar_maxaddr2mgaw(struct dmar_unit *unit, iommu_gaddr_t maxaddr,
     bool allow_less);
-vm_pindex_t pglvl_max_pages(int pglvl);
 int domain_is_sp_lvl(struct dmar_domain *domain, int lvl);
-iommu_gaddr_t pglvl_page_size(int total_pglvl, int lvl);
 iommu_gaddr_t domain_page_size(struct dmar_domain *domain, int lvl);
 int calc_am(struct dmar_unit *unit, iommu_gaddr_t base, iommu_gaddr_t size,
     iommu_gaddr_t *isizep);
diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c
index eb6a51216dfd..53851622340b 100644
--- a/sys/x86/iommu/intel_idpgtbl.c
+++ b/sys/x86/iommu/intel_idpgtbl.c
@@ -316,40 +316,6 @@ put_idmap_pgtbl(vm_object_t obj)
  * address.  Support superpages.
  */
 
-/*
- * Index of the pte for the guest address base in the page table at
- * the level lvl.
- */
-static int
-domain_pgtbl_pte_off(struct dmar_domain *domain, iommu_gaddr_t base, int lvl)
-{
-
-	base >>= IOMMU_PAGE_SHIFT + (domain->pglvl - lvl - 1) *
-	    IOMMU_NPTEPGSHIFT;
-	return (base & IOMMU_PTEMASK);
-}
-
-/*
- * Returns the page index of the page table page in the page table
- * object, which maps the given address base at the page table level
- * lvl.
- */
-static vm_pindex_t
-domain_pgtbl_get_pindex(struct dmar_domain *domain, iommu_gaddr_t base, int lvl)
-{
-	vm_pindex_t idx, pidx;
-	int i;
-
-	KASSERT(lvl >= 0 && lvl < domain->pglvl,
-	    ("wrong lvl %p %d", domain, lvl));
-
-	for (pidx = idx = 0, i = 0; i < lvl; i++, pidx = idx) {
-		idx = domain_pgtbl_pte_off(domain, base, i) +
-		    pidx * IOMMU_NPTEPG + 1;
-	}
-	return (idx);
-}
-
 static iommu_pte_t *
 domain_pgtbl_map_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
     int flags, vm_pindex_t *idxp, struct sf_buf **sf)
@@ -362,7 +328,7 @@ domain_pgtbl_map_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
 	DMAR_DOMAIN_ASSERT_PGLOCKED(domain);
 	KASSERT((flags & IOMMU_PGF_OBJL) != 0, ("lost PGF_OBJL"));
 
-	idx = domain_pgtbl_get_pindex(domain, base, lvl);
+	idx = pglvl_pgtbl_get_pindex(domain->pglvl, base, lvl);
 	if (*sf != NULL && idx == *idxp) {
 		pte = (iommu_pte_t *)sf_buf_kva(*sf);
 	} else {
@@ -414,7 +380,7 @@ retry:
 			goto retry;
 		}
 	}
-	pte += domain_pgtbl_pte_off(domain, base, lvl);
+	pte += pglvl_pgtbl_pte_off(domain->pglvl, base, lvl);
 	return (pte);
 }
 
diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c
index a96f65fddfc5..141452b3393d 100644
--- a/sys/x86/iommu/intel_utils.c
+++ b/sys/x86/iommu/intel_utils.c
@@ -172,23 +172,6 @@ dmar_maxaddr2mgaw(struct dmar_unit *unit, iommu_gaddr_t maxaddr, bool allow_less
 	return (-1);
 }
 
-/*
- * Calculate the total amount of page table pages needed to map the
- * whole bus address space on the context with the selected agaw.
- */
-vm_pindex_t
-pglvl_max_pages(int pglvl)
-{
-	vm_pindex_t res;
-	int i;
-
-	for (res = 0, i = pglvl; i > 0; i--) {
-		res *= IOMMU_NPTEPG;
-		res++;
-	}
-	return (res);
-}
-
 /*
  * Return true if the page table level lvl supports the superpage for
  * the context ctx.
@@ -209,26 +192,6 @@ domain_is_sp_lvl(struct dmar_domain *domain, int lvl)
 	return (alvl < nitems(sagaw_sp) && (sagaw_sp[alvl] & cap_sps) != 0);
 }
 
-iommu_gaddr_t
-pglvl_page_size(int total_pglvl, int lvl)
-{
-	int rlvl;
-	static const iommu_gaddr_t pg_sz[] = {
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE,
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE << IOMMU_NPTEPGSHIFT,
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (2 * IOMMU_NPTEPGSHIFT),
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (3 * IOMMU_NPTEPGSHIFT),
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (4 * IOMMU_NPTEPGSHIFT),
-		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (5 * IOMMU_NPTEPGSHIFT),
-	};
-
-	KASSERT(lvl >= 0 && lvl < total_pglvl,
-	    ("total %d lvl %d", total_pglvl, lvl));
-	rlvl = total_pglvl - lvl - 1;
-	KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl));
-	return (pg_sz[rlvl]);
-}
-
 iommu_gaddr_t
 domain_page_size(struct dmar_domain *domain, int lvl)
 {
diff --git a/sys/x86/iommu/iommu_utils.c b/sys/x86/iommu/iommu_utils.c
index 9c6cae5ff51f..645c7e15740a 100644
--- a/sys/x86/iommu/iommu_utils.c
+++ b/sys/x86/iommu/iommu_utils.c
@@ -619,3 +619,74 @@ iommu_domain_free_entry(struct iommu_map_entry *entry, bool free)
 		entry->flags = 0;
 }
 
+/*
+ * Index of the pte for the guest address base in the page table at
+ * the level lvl.
+ */
+int
+pglvl_pgtbl_pte_off(int pglvl, iommu_gaddr_t base, int lvl)
+{
+
+	base >>= IOMMU_PAGE_SHIFT + (pglvl - lvl - 1) *
+	    IOMMU_NPTEPGSHIFT;
+	return (base & IOMMU_PTEMASK);
+}
+
+/*
+ * Returns the page index of the page table page in the page table
+ * object, which maps the given address base at the page table level
+ * lvl.
+ */
+vm_pindex_t
+pglvl_pgtbl_get_pindex(int pglvl, iommu_gaddr_t base, int lvl)
+{
+	vm_pindex_t idx, pidx;
+	int i;
+
+	KASSERT(lvl >= 0 && lvl < pglvl,
+	    ("wrong lvl %d %d", pglvl, lvl));
+
+	for (pidx = idx = 0, i = 0; i < lvl; i++, pidx = idx) {
+		idx = pglvl_pgtbl_pte_off(pglvl, base, i) +
+		    pidx * IOMMU_NPTEPG + 1;
+	}
+	return (idx);
+}
+
+/*
+ * Calculate the total amount of page table pages needed to map the
+ * whole bus address space on the context with the selected agaw.
+ */
+vm_pindex_t
+pglvl_max_pages(int pglvl)
+{
+	vm_pindex_t res;
+	int i;
+
+	for (res = 0, i = pglvl; i > 0; i--) {
+		res *= IOMMU_NPTEPG;
+		res++;
+	}
+	return (res);
+}
+
+iommu_gaddr_t
+pglvl_page_size(int total_pglvl, int lvl)
+{
+	int rlvl;
+	static const iommu_gaddr_t pg_sz[] = {
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE,
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << IOMMU_NPTEPGSHIFT,
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (2 * IOMMU_NPTEPGSHIFT),
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (3 * IOMMU_NPTEPGSHIFT),
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (4 * IOMMU_NPTEPGSHIFT),
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (5 * IOMMU_NPTEPGSHIFT),
+		(iommu_gaddr_t)IOMMU_PAGE_SIZE << (6 * IOMMU_NPTEPGSHIFT),
+	};
+
+	KASSERT(lvl >= 0 && lvl < total_pglvl,
+	    ("total %d lvl %d", total_pglvl, lvl));
+	rlvl = total_pglvl - lvl - 1;
+	KASSERT(rlvl < nitems(pg_sz), ("sizeof pg_sz lvl %d", lvl));
+	return (pg_sz[rlvl]);
+}
diff --git a/sys/x86/iommu/x86_iommu.h b/sys/x86/iommu/x86_iommu.h
index 9e3a82283729..b2caed550e35 100644
--- a/sys/x86/iommu/x86_iommu.h
+++ b/sys/x86/iommu/x86_iommu.h
@@ -187,4 +187,9 @@ void iommu_release_intr(struct iommu_unit *unit, int idx);
 
 void iommu_device_tag_init(struct iommu_ctx *ctx, device_t dev);
 
+int pglvl_pgtbl_pte_off(int pglvl, iommu_gaddr_t base, int lvl);
+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);
+
 #endif