git: 339b47f01985 - stable/14 - x86/iommu: extract useful utilities into x86_iommu.c

From: Konstantin Belousov <kib_at_FreeBSD.org>
Date: Sat, 01 Jun 2024 09:24:46 UTC
The branch stable/14 has been updated by kib:

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

commit 339b47f01985628ccc4c3e9a29c36f26edb034c3
Author:     Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-05-25 00:47:26 +0000
Commit:     Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-06-01 09:24:24 +0000

    x86/iommu: extract useful utilities into x86_iommu.c
    
    (cherry picked from commit 40d951bc5932deb87635f5c1780a6706d0c7c012)
---
 sys/conf/files.x86            |   1 +
 sys/x86/include/iommu.h       |   1 +
 sys/x86/iommu/intel_ctx.c     |  25 +++----
 sys/x86/iommu/intel_dmar.h    |   9 +--
 sys/x86/iommu/intel_drv.c     |   7 +-
 sys/x86/iommu/intel_fault.c   |   1 +
 sys/x86/iommu/intel_idpgtbl.c |  77 ++++++++++----------
 sys/x86/iommu/intel_intrmap.c |   3 +-
 sys/x86/iommu/intel_qi.c      |   3 +-
 sys/x86/iommu/intel_quirks.c  |   1 +
 sys/x86/iommu/intel_reg.h     |  15 +---
 sys/x86/iommu/intel_utils.c   | 128 +++------------------------------
 sys/x86/iommu/iommu_utils.c   | 164 ++++++++++++++++++++++++++++++++++++++++++
 sys/x86/iommu/x86_iommu.h     |  62 ++++++++++++++++
 14 files changed, 302 insertions(+), 195 deletions(-)

diff --git a/sys/conf/files.x86 b/sys/conf/files.x86
index 15781eea8fee..445bbf9091ba 100644
--- a/sys/conf/files.x86
+++ b/sys/conf/files.x86
@@ -320,6 +320,7 @@ x86/iommu/intel_intrmap.c	optional	acpi iommu pci
 x86/iommu/intel_qi.c		optional	acpi iommu pci
 x86/iommu/intel_quirks.c	optional	acpi iommu pci
 x86/iommu/intel_utils.c		optional	acpi iommu pci
+x86/iommu/iommu_utils.c		optional	acpi iommu pci
 x86/isa/atrtc.c			standard
 x86/isa/clock.c			standard
 x86/isa/isa.c			optional	isa
diff --git a/sys/x86/include/iommu.h b/sys/x86/include/iommu.h
index a95480b53acc..98c6661aa8e3 100644
--- a/sys/x86/include/iommu.h
+++ b/sys/x86/include/iommu.h
@@ -7,6 +7,7 @@
 
 #include <x86/include/busdma_impl.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 #endif /* !_MACHINE_IOMMU_H_ */
diff --git a/sys/x86/iommu/intel_ctx.c b/sys/x86/iommu/intel_ctx.c
index 65ca88b052ed..444640570df7 100644
--- a/sys/x86/iommu/intel_ctx.c
+++ b/sys/x86/iommu/intel_ctx.c
@@ -66,6 +66,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 static MALLOC_DEFINE(M_DMAR_CTX, "dmar_ctx", "Intel DMAR Context");
@@ -85,7 +86,7 @@ dmar_ensure_ctx_page(struct dmar_unit *dmar, int bus)
 	/*
 	 * Allocated context page must be linked.
 	 */
-	ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_NOALLOC);
+	ctxm = iommu_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_NOALLOC);
 	if (ctxm != NULL)
 		return;
 
@@ -96,14 +97,14 @@ dmar_ensure_ctx_page(struct dmar_unit *dmar, int bus)
 	 * threads are equal.
 	 */
 	TD_PREP_PINNED_ASSERT;
-	ctxm = dmar_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_ZERO |
+	ctxm = iommu_pgalloc(dmar->ctx_obj, 1 + bus, IOMMU_PGF_ZERO |
 	    IOMMU_PGF_WAITOK);
-	re = dmar_map_pgtbl(dmar->ctx_obj, 0, IOMMU_PGF_NOALLOC, &sf);
+	re = iommu_map_pgtbl(dmar->ctx_obj, 0, IOMMU_PGF_NOALLOC, &sf);
 	re += bus;
 	dmar_pte_store(&re->r1, DMAR_ROOT_R1_P | (DMAR_ROOT_R1_CTP_MASK &
 	    VM_PAGE_TO_PHYS(ctxm)));
 	dmar_flush_root_to_ram(dmar, re);
-	dmar_unmap_pgtbl(sf);
+	iommu_unmap_pgtbl(sf);
 	TD_PINNED_ASSERT;
 }
 
@@ -115,7 +116,7 @@ dmar_map_ctx_entry(struct dmar_ctx *ctx, struct sf_buf **sfp)
 
 	dmar = CTX2DMAR(ctx);
 
-	ctxp = dmar_map_pgtbl(dmar->ctx_obj, 1 + PCI_RID2BUS(ctx->context.rid),
+	ctxp = iommu_map_pgtbl(dmar->ctx_obj, 1 + PCI_RID2BUS(ctx->context.rid),
 	    IOMMU_PGF_NOALLOC | IOMMU_PGF_WAITOK, sfp);
 	ctxp += ctx->context.rid & 0xff;
 	return (ctxp);
@@ -188,7 +189,7 @@ ctx_id_entry_init(struct dmar_ctx *ctx, dmar_ctx_entry_t *ctxp, bool move,
 		    ("ctx %p non-null pgtbl_obj", ctx));
 		ctx_root = NULL;
 	} else {
-		ctx_root = dmar_pgalloc(domain->pgtbl_obj, 0,
+		ctx_root = iommu_pgalloc(domain->pgtbl_obj, 0,
 		    IOMMU_PGF_NOALLOC);
 	}
 
@@ -274,7 +275,7 @@ domain_init_rmrr(struct dmar_domain *domain, device_t dev, int bus,
 				    "region (%jx, %jx) corrected\n",
 				    domain->iodom.iommu->unit, start, end);
 			}
-			entry->end += DMAR_PAGE_SIZE * 0x20;
+			entry->end += IOMMU_PAGE_SIZE * 0x20;
 		}
 		size = OFF_TO_IDX(entry->end - entry->start);
 		ma = malloc(sizeof(vm_page_t) * size, M_TEMP, M_WAITOK);
@@ -603,9 +604,9 @@ dmar_get_ctx_for_dev1(struct dmar_unit *dmar, device_t dev, uint16_t rid,
 				    func, rid, domain->domain, domain->mgaw,
 				    domain->agaw, id_mapped ? "id" : "re");
 			}
-			dmar_unmap_pgtbl(sf);
+			iommu_unmap_pgtbl(sf);
 		} else {
-			dmar_unmap_pgtbl(sf);
+			iommu_unmap_pgtbl(sf);
 			dmar_domain_destroy(domain1);
 			/* Nothing needs to be done to destroy ctx1. */
 			free(ctx1, M_DMAR_CTX);
@@ -705,7 +706,7 @@ dmar_move_ctx_to_domain(struct dmar_domain *domain, struct dmar_ctx *ctx)
 	ctx->context.domain = &domain->iodom;
 	dmar_ctx_link(ctx);
 	ctx_id_entry_init(ctx, ctxp, true, PCI_BUSMAX + 100);
-	dmar_unmap_pgtbl(sf);
+	iommu_unmap_pgtbl(sf);
 	error = dmar_flush_for_ctx_entry(dmar, true);
 	/* If flush failed, rolling back would not work as well. */
 	printf("dmar%d rid %x domain %d->%d %s-mapped\n",
@@ -789,7 +790,7 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
 	if (ctx->refs > 1) {
 		ctx->refs--;
 		DMAR_UNLOCK(dmar);
-		dmar_unmap_pgtbl(sf);
+		iommu_unmap_pgtbl(sf);
 		TD_PINNED_ASSERT;
 		return;
 	}
@@ -811,7 +812,7 @@ dmar_free_ctx_locked(struct dmar_unit *dmar, struct dmar_ctx *ctx)
 		else
 			dmar_inv_iotlb_glob(dmar);
 	}
-	dmar_unmap_pgtbl(sf);
+	iommu_unmap_pgtbl(sf);
 	domain = CTX2DOM(ctx);
 	dmar_ctx_unlink(ctx);
 	free(ctx->context.tag, M_DMAR_CTX);
diff --git a/sys/x86/iommu/intel_dmar.h b/sys/x86/iommu/intel_dmar.h
index e20144094c80..8289478aed19 100644
--- a/sys/x86/iommu/intel_dmar.h
+++ b/sys/x86/iommu/intel_dmar.h
@@ -238,16 +238,11 @@ 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);
-struct vm_page *dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags);
-void dmar_pgfree(vm_object_t obj, vm_pindex_t idx, int flags);
-void *dmar_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
-    struct sf_buf **sf);
-void dmar_unmap_pgtbl(struct sf_buf *sf);
 int dmar_load_root_entry_ptr(struct dmar_unit *unit);
 int dmar_inv_ctx_glob(struct dmar_unit *unit);
 int dmar_inv_iotlb_glob(struct dmar_unit *unit);
 int dmar_flush_write_bufs(struct dmar_unit *unit);
-void dmar_flush_pte_to_ram(struct dmar_unit *unit, dmar_pte_t *dst);
+void dmar_flush_pte_to_ram(struct dmar_unit *unit, iommu_pte_t *dst);
 void dmar_flush_ctx_to_ram(struct dmar_unit *unit, dmar_ctx_entry_t *dst);
 void dmar_flush_root_to_ram(struct dmar_unit *unit, dmar_root_entry_t *dst);
 int dmar_disable_protected_regions(struct dmar_unit *unit);
@@ -315,9 +310,7 @@ void dmar_quirks_pre_use(struct iommu_unit *dmar);
 int dmar_init_irt(struct dmar_unit *unit);
 void dmar_fini_irt(struct dmar_unit *unit);
 
-extern iommu_haddr_t dmar_high;
 extern int haw;
-extern int dmar_tbl_pagecnt;
 extern int dmar_batch_coalesce;
 extern int dmar_rmrr_enable;
 
diff --git a/sys/x86/iommu/intel_drv.c b/sys/x86/iommu/intel_drv.c
index 7346162d1502..9a2fedf90b6a 100644
--- a/sys/x86/iommu/intel_drv.c
+++ b/sys/x86/iommu/intel_drv.c
@@ -67,6 +67,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 #ifdef DEV_APIC
@@ -179,9 +180,9 @@ dmar_identify(driver_t *driver, device_t parent)
 		return;
 	haw = dmartbl->Width + 1;
 	if ((1ULL << (haw + 1)) > BUS_SPACE_MAXADDR)
-		dmar_high = BUS_SPACE_MAXADDR;
+		iommu_high = BUS_SPACE_MAXADDR;
 	else
-		dmar_high = 1ULL << (haw + 1);
+		iommu_high = 1ULL << (haw + 1);
 	if (bootverbose) {
 		printf("DMAR HAW=%d flags=<%b>\n", dmartbl->Width,
 		    (unsigned)dmartbl->Flags,
@@ -490,7 +491,7 @@ dmar_attach(device_t dev)
 	 * address translation after the required invalidations are
 	 * done.
 	 */
-	dmar_pgalloc(unit->ctx_obj, 0, IOMMU_PGF_WAITOK | IOMMU_PGF_ZERO);
+	iommu_pgalloc(unit->ctx_obj, 0, IOMMU_PGF_WAITOK | IOMMU_PGF_ZERO);
 	DMAR_LOCK(unit);
 	error = dmar_load_root_entry_ptr(unit);
 	if (error != 0) {
diff --git a/sys/x86/iommu/intel_fault.c b/sys/x86/iommu/intel_fault.c
index e275304c8d51..59b482720cf1 100644
--- a/sys/x86/iommu/intel_fault.c
+++ b/sys/x86/iommu/intel_fault.c
@@ -54,6 +54,7 @@
 #include <x86/include/busdma_impl.h>
 #include <x86/iommu/intel_reg.h>
 #include <dev/iommu/busdma_iommu.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 /*
diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c
index 26f067e35278..82cac8bb2d39 100644
--- a/sys/x86/iommu/intel_idpgtbl.c
+++ b/sys/x86/iommu/intel_idpgtbl.c
@@ -64,6 +64,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 static int domain_unmap_buf_locked(struct dmar_domain *domain,
@@ -109,7 +110,7 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx,
     iommu_gaddr_t addr)
 {
 	vm_page_t m1;
-	dmar_pte_t *pte;
+	iommu_pte_t *pte;
 	struct sf_buf *sf;
 	iommu_gaddr_t f, pg_sz;
 	vm_pindex_t base;
@@ -118,28 +119,28 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx,
 	VM_OBJECT_ASSERT_LOCKED(tbl->pgtbl_obj);
 	if (addr >= tbl->maxaddr)
 		return;
-	(void)dmar_pgalloc(tbl->pgtbl_obj, idx, IOMMU_PGF_OBJL |
+	(void)iommu_pgalloc(tbl->pgtbl_obj, idx, IOMMU_PGF_OBJL |
 	    IOMMU_PGF_WAITOK | IOMMU_PGF_ZERO);
-	base = idx * DMAR_NPTEPG + 1; /* Index of the first child page of idx */
+	base = idx * IOMMU_NPTEPG + 1; /* Index of the first child page of idx */
 	pg_sz = pglvl_page_size(tbl->pglvl, lvl);
 	if (lvl != tbl->leaf) {
-		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz)
+		for (i = 0, f = addr; i < IOMMU_NPTEPG; i++, f += pg_sz)
 			domain_idmap_nextlvl(tbl, lvl + 1, base + i, f);
 	}
 	VM_OBJECT_WUNLOCK(tbl->pgtbl_obj);
-	pte = dmar_map_pgtbl(tbl->pgtbl_obj, idx, IOMMU_PGF_WAITOK, &sf);
+	pte = iommu_map_pgtbl(tbl->pgtbl_obj, idx, IOMMU_PGF_WAITOK, &sf);
 	if (lvl == tbl->leaf) {
-		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz) {
+		for (i = 0, f = addr; i < IOMMU_NPTEPG; i++, f += pg_sz) {
 			if (f >= tbl->maxaddr)
 				break;
 			pte[i].pte = (DMAR_PTE_ADDR_MASK & f) |
 			    DMAR_PTE_R | DMAR_PTE_W;
 		}
 	} else {
-		for (i = 0, f = addr; i < DMAR_NPTEPG; i++, f += pg_sz) {
+		for (i = 0, f = addr; i < IOMMU_NPTEPG; i++, f += pg_sz) {
 			if (f >= tbl->maxaddr)
 				break;
-			m1 = dmar_pgalloc(tbl->pgtbl_obj, base + i,
+			m1 = iommu_pgalloc(tbl->pgtbl_obj, base + i,
 			    IOMMU_PGF_NOALLOC);
 			KASSERT(m1 != NULL, ("lost page table page"));
 			pte[i].pte = (DMAR_PTE_ADDR_MASK &
@@ -147,7 +148,7 @@ domain_idmap_nextlvl(struct idpgtbl *tbl, int lvl, vm_pindex_t idx,
 		}
 	}
 	/* domain_get_idmap_pgtbl flushes CPU cache if needed. */
-	dmar_unmap_pgtbl(sf);
+	iommu_unmap_pgtbl(sf);
 	VM_OBJECT_WLOCK(tbl->pgtbl_obj);
 }
 
@@ -301,7 +302,7 @@ put_idmap_pgtbl(vm_object_t obj)
 		rmobj = tbl->pgtbl_obj;
 		if (rmobj->ref_count == 1) {
 			LIST_REMOVE(tbl, link);
-			atomic_subtract_int(&dmar_tbl_pagecnt,
+			atomic_subtract_int(&iommu_tbl_pagecnt,
 			    rmobj->resident_page_count);
 			vm_object_deallocate(rmobj);
 			free(tbl, M_DMAR_IDPGTBL);
@@ -323,9 +324,9 @@ static int
 domain_pgtbl_pte_off(struct dmar_domain *domain, iommu_gaddr_t base, int lvl)
 {
 
-	base >>= DMAR_PAGE_SHIFT + (domain->pglvl - lvl - 1) *
-	    DMAR_NPTEPGSHIFT;
-	return (base & DMAR_PTEMASK);
+	base >>= IOMMU_PAGE_SHIFT + (domain->pglvl - lvl - 1) *
+	    IOMMU_NPTEPGSHIFT;
+	return (base & IOMMU_PTEMASK);
 }
 
 /*
@@ -344,18 +345,18 @@ domain_pgtbl_get_pindex(struct dmar_domain *domain, iommu_gaddr_t base, int lvl)
 
 	for (pidx = idx = 0, i = 0; i < lvl; i++, pidx = idx) {
 		idx = domain_pgtbl_pte_off(domain, base, i) +
-		    pidx * DMAR_NPTEPG + 1;
+		    pidx * IOMMU_NPTEPG + 1;
 	}
 	return (idx);
 }
 
-static dmar_pte_t *
+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)
 {
 	vm_page_t m;
 	struct sf_buf *sfp;
-	dmar_pte_t *pte, *ptep;
+	iommu_pte_t *pte, *ptep;
 	vm_pindex_t idx, idx1;
 
 	DMAR_DOMAIN_ASSERT_PGLOCKED(domain);
@@ -363,13 +364,13 @@ domain_pgtbl_map_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
 
 	idx = domain_pgtbl_get_pindex(domain, base, lvl);
 	if (*sf != NULL && idx == *idxp) {
-		pte = (dmar_pte_t *)sf_buf_kva(*sf);
+		pte = (iommu_pte_t *)sf_buf_kva(*sf);
 	} else {
 		if (*sf != NULL)
-			dmar_unmap_pgtbl(*sf);
+			iommu_unmap_pgtbl(*sf);
 		*idxp = idx;
 retry:
-		pte = dmar_map_pgtbl(domain->pgtbl_obj, idx, flags, sf);
+		pte = iommu_map_pgtbl(domain->pgtbl_obj, idx, flags, sf);
 		if (pte == NULL) {
 			KASSERT(lvl > 0,
 			    ("lost root page table page %p", domain));
@@ -378,7 +379,7 @@ retry:
 			 * it and create a pte in the preceeding page level
 			 * to reference the allocated page table page.
 			 */
-			m = dmar_pgalloc(domain->pgtbl_obj, idx, flags |
+			m = iommu_pgalloc(domain->pgtbl_obj, idx, flags |
 			    IOMMU_PGF_ZERO);
 			if (m == NULL)
 				return (NULL);
@@ -399,7 +400,7 @@ retry:
 				KASSERT(m->pindex != 0,
 				    ("loosing root page %p", domain));
 				m->ref_count--;
-				dmar_pgfree(domain->pgtbl_obj, m->pindex,
+				iommu_pgfree(domain->pgtbl_obj, m->pindex,
 				    flags);
 				return (NULL);
 			}
@@ -408,7 +409,7 @@ retry:
 			dmar_flush_pte_to_ram(domain->dmar, ptep);
 			sf_buf_page(sfp)->ref_count += 1;
 			m->ref_count--;
-			dmar_unmap_pgtbl(sfp);
+			iommu_unmap_pgtbl(sfp);
 			/* Only executed once. */
 			goto retry;
 		}
@@ -421,7 +422,7 @@ static int
 domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
     iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags)
 {
-	dmar_pte_t *pte;
+	iommu_pte_t *pte;
 	struct sf_buf *sf;
 	iommu_gaddr_t pg_sz, base1;
 	vm_pindex_t pi, c, idx, run_sz;
@@ -438,7 +439,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
 	    pi += run_sz) {
 		for (lvl = 0, c = 0, superpage = false;; lvl++) {
 			pg_sz = domain_page_size(domain, lvl);
-			run_sz = pg_sz >> DMAR_PAGE_SHIFT;
+			run_sz = pg_sz >> IOMMU_PAGE_SHIFT;
 			if (lvl == domain->pglvl - 1)
 				break;
 			/*
@@ -477,7 +478,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
 			KASSERT((flags & IOMMU_PGF_WAITOK) == 0,
 			    ("failed waitable pte alloc %p", domain));
 			if (sf != NULL)
-				dmar_unmap_pgtbl(sf);
+				iommu_unmap_pgtbl(sf);
 			domain_unmap_buf_locked(domain, base1, base - base1,
 			    flags);
 			TD_PINNED_ASSERT;
@@ -489,7 +490,7 @@ domain_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
 		sf_buf_page(sf)->ref_count += 1;
 	}
 	if (sf != NULL)
-		dmar_unmap_pgtbl(sf);
+		iommu_unmap_pgtbl(sf);
 	TD_PINNED_ASSERT;
 	return (0);
 }
@@ -513,10 +514,10 @@ domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base,
 
 	KASSERT((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) == 0,
 	    ("modifying idmap pagetable domain %p", domain));
-	KASSERT((base & DMAR_PAGE_MASK) == 0,
+	KASSERT((base & IOMMU_PAGE_MASK) == 0,
 	    ("non-aligned base %p %jx %jx", domain, (uintmax_t)base,
 	    (uintmax_t)size));
-	KASSERT((size & DMAR_PAGE_MASK) == 0,
+	KASSERT((size & IOMMU_PAGE_MASK) == 0,
 	    ("non-aligned size %p %jx %jx", domain, (uintmax_t)base,
 	    (uintmax_t)size));
 	KASSERT(size > 0, ("zero size %p %jx %jx", domain, (uintmax_t)base,
@@ -563,7 +564,7 @@ domain_map_buf(struct iommu_domain *iodom, iommu_gaddr_t base,
 }
 
 static void domain_unmap_clear_pte(struct dmar_domain *domain,
-    iommu_gaddr_t base, int lvl, int flags, dmar_pte_t *pte,
+    iommu_gaddr_t base, int lvl, int flags, iommu_pte_t *pte,
     struct sf_buf **sf, bool free_fs);
 
 static void
@@ -571,7 +572,7 @@ domain_free_pgtbl_pde(struct dmar_domain *domain, iommu_gaddr_t base,
     int lvl, int flags)
 {
 	struct sf_buf *sf;
-	dmar_pte_t *pde;
+	iommu_pte_t *pde;
 	vm_pindex_t idx;
 
 	sf = NULL;
@@ -581,7 +582,7 @@ domain_free_pgtbl_pde(struct dmar_domain *domain, iommu_gaddr_t base,
 
 static void
 domain_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
-    int flags, dmar_pte_t *pte, struct sf_buf **sf, bool free_sf)
+    int flags, iommu_pte_t *pte, struct sf_buf **sf, bool free_sf)
 {
 	vm_page_t m;
 
@@ -589,7 +590,7 @@ domain_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
 	dmar_flush_pte_to_ram(domain->dmar, pte);
 	m = sf_buf_page(*sf);
 	if (free_sf) {
-		dmar_unmap_pgtbl(*sf);
+		iommu_unmap_pgtbl(*sf);
 		*sf = NULL;
 	}
 	m->ref_count--;
@@ -601,7 +602,7 @@ domain_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl,
 	KASSERT(m->pindex != 0,
 	    ("lost reference (idx) on root pg domain %p base %jx lvl %d",
 	    domain, (uintmax_t)base, lvl));
-	dmar_pgfree(domain->pgtbl_obj, m->pindex, flags);
+	iommu_pgfree(domain->pgtbl_obj, m->pindex, flags);
 	domain_free_pgtbl_pde(domain, base, lvl - 1, flags);
 }
 
@@ -612,7 +613,7 @@ static int
 domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
     iommu_gaddr_t size, int flags)
 {
-	dmar_pte_t *pte;
+	iommu_pte_t *pte;
 	struct sf_buf *sf;
 	vm_pindex_t idx;
 	iommu_gaddr_t pg_sz;
@@ -624,10 +625,10 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
 
 	KASSERT((domain->iodom.flags & IOMMU_DOMAIN_IDMAP) == 0,
 	    ("modifying idmap pagetable domain %p", domain));
-	KASSERT((base & DMAR_PAGE_MASK) == 0,
+	KASSERT((base & IOMMU_PAGE_MASK) == 0,
 	    ("non-aligned base %p %jx %jx", domain, (uintmax_t)base,
 	    (uintmax_t)size));
-	KASSERT((size & DMAR_PAGE_MASK) == 0,
+	KASSERT((size & IOMMU_PAGE_MASK) == 0,
 	    ("non-aligned size %p %jx %jx", domain, (uintmax_t)base,
 	    (uintmax_t)size));
 	KASSERT(base < (1ULL << domain->agaw),
@@ -670,7 +671,7 @@ domain_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base,
 		    (uintmax_t)base, (uintmax_t)size, (uintmax_t)pg_sz));
 	}
 	if (sf != NULL)
-		dmar_unmap_pgtbl(sf);
+		iommu_unmap_pgtbl(sf);
 	/*
 	 * See 11.1 Write Buffer Flushing for an explanation why RWBF
 	 * can be ignored there.
@@ -706,7 +707,7 @@ domain_alloc_pgtbl(struct dmar_domain *domain)
 	domain->pgtbl_obj = vm_pager_allocate(OBJT_PHYS, NULL,
 	    IDX_TO_OFF(pglvl_max_pages(domain->pglvl)), 0, 0, NULL);
 	DMAR_DOMAIN_PGLOCK(domain);
-	m = dmar_pgalloc(domain->pgtbl_obj, 0, IOMMU_PGF_WAITOK |
+	m = iommu_pgalloc(domain->pgtbl_obj, 0, IOMMU_PGF_WAITOK |
 	    IOMMU_PGF_ZERO | IOMMU_PGF_OBJL);
 	/* No implicit free of the top level page table page. */
 	m->ref_count = 1;
diff --git a/sys/x86/iommu/intel_intrmap.c b/sys/x86/iommu/intel_intrmap.c
index b2642197902a..02bf58dde299 100644
--- a/sys/x86/iommu/intel_intrmap.c
+++ b/sys/x86/iommu/intel_intrmap.c
@@ -55,6 +55,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 #include <x86/iommu/iommu_intrmap.h>
 
@@ -341,7 +342,7 @@ dmar_init_irt(struct dmar_unit *unit)
 	}
 	unit->irte_cnt = clp2(num_io_irqs);
 	unit->irt = kmem_alloc_contig(unit->irte_cnt * sizeof(dmar_irte_t),
-	    M_ZERO | M_WAITOK, 0, dmar_high, PAGE_SIZE, 0,
+	    M_ZERO | M_WAITOK, 0, iommu_high, PAGE_SIZE, 0,
 	    DMAR_IS_COHERENT(unit) ?
 	    VM_MEMATTR_DEFAULT : VM_MEMATTR_UNCACHEABLE);
 	if (unit->irt == NULL)
diff --git a/sys/x86/iommu/intel_qi.c b/sys/x86/iommu/intel_qi.c
index 37e2bf211e32..590cbac9bcbd 100644
--- a/sys/x86/iommu/intel_qi.c
+++ b/sys/x86/iommu/intel_qi.c
@@ -55,6 +55,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 static bool
@@ -501,7 +502,7 @@ dmar_init_qi(struct dmar_unit *unit)
 
 	/* The invalidation queue reads by DMARs are always coherent. */
 	unit->inv_queue = kmem_alloc_contig(unit->inv_queue_size, M_WAITOK |
-	    M_ZERO, 0, dmar_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+	    M_ZERO, 0, iommu_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
 	unit->inv_waitd_seq_hw_phys = pmap_kextract(
 	    (vm_offset_t)&unit->inv_waitd_seq_hw);
 
diff --git a/sys/x86/iommu/intel_quirks.c b/sys/x86/iommu/intel_quirks.c
index 589764bd0fa9..486bd1bc9496 100644
--- a/sys/x86/iommu/intel_quirks.c
+++ b/sys/x86/iommu/intel_quirks.c
@@ -59,6 +59,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 typedef void (*dmar_quirk_cpu_fun)(struct dmar_unit *);
diff --git a/sys/x86/iommu/intel_reg.h b/sys/x86/iommu/intel_reg.h
index 26a18ff94890..0fafcce7accf 100644
--- a/sys/x86/iommu/intel_reg.h
+++ b/sys/x86/iommu/intel_reg.h
@@ -31,16 +31,6 @@
 #ifndef __X86_IOMMU_INTEL_REG_H
 #define	__X86_IOMMU_INTEL_REG_H
 
-#define	DMAR_PAGE_SIZE	PAGE_SIZE
-#define	DMAR_PAGE_MASK	(DMAR_PAGE_SIZE - 1)
-#define	DMAR_PAGE_SHIFT	PAGE_SHIFT
-#define	DMAR_NPTEPG	(DMAR_PAGE_SIZE / sizeof(dmar_pte_t))
-#define	DMAR_NPTEPGSHIFT 9
-#define	DMAR_PTEMASK	(DMAR_NPTEPG - 1)
-
-#define	IOMMU_PAGE_SIZE	DMAR_PAGE_SIZE
-#define	IOMMU_PAGE_MASK	DMAR_PAGE_MASK
-
 typedef struct dmar_root_entry {
 	uint64_t r1;
 	uint64_t r2;
@@ -49,7 +39,7 @@ typedef struct dmar_root_entry {
 #define	DMAR_ROOT_R1_CTP_MASK	0xfffffffffffff000 /* Mask for Context-Entry
 						      Table Pointer */
 
-#define	DMAR_CTX_CNT		(DMAR_PAGE_SIZE / sizeof(dmar_root_entry_t))
+#define	DMAR_CTX_CNT		(IOMMU_PAGE_SIZE / sizeof(dmar_root_entry_t))
 
 typedef	struct dmar_ctx_entry {
 	uint64_t ctx1;
@@ -73,9 +63,6 @@ typedef	struct dmar_ctx_entry {
 #define	DMAR_CTX2_DID(x)	((x) << 8)	/* Domain Identifier */
 #define	DMAR_CTX2_GET_DID(ctx2)	(((ctx2) & DMAR_CTX2_DID_MASK) >> 8)
 
-typedef struct dmar_pte {
-	uint64_t pte;
-} dmar_pte_t;
 #define	DMAR_PTE_R		1		/* Read */
 #define	DMAR_PTE_W		(1 << 1)	/* Write */
 #define	DMAR_PTE_SP		(1 << 7)	/* Super Page */
diff --git a/sys/x86/iommu/intel_utils.c b/sys/x86/iommu/intel_utils.c
index 19d4ec7d22bd..b0f2d167658a 100644
--- a/sys/x86/iommu/intel_utils.c
+++ b/sys/x86/iommu/intel_utils.c
@@ -64,6 +64,7 @@
 #include <x86/include/busdma_impl.h>
 #include <dev/iommu/busdma_iommu.h>
 #include <x86/iommu/intel_reg.h>
+#include <x86/iommu/x86_iommu.h>
 #include <x86/iommu/intel_dmar.h>
 
 u_int
@@ -183,7 +184,7 @@ pglvl_max_pages(int pglvl)
 	int i;
 
 	for (res = 0, i = pglvl; i > 0; i--) {
-		res *= DMAR_NPTEPG;
+		res *= IOMMU_NPTEPG;
 		res++;
 	}
 	return (res);
@@ -214,12 +215,12 @@ pglvl_page_size(int total_pglvl, int lvl)
 {
 	int rlvl;
 	static const iommu_gaddr_t pg_sz[] = {
-		(iommu_gaddr_t)DMAR_PAGE_SIZE,
-		(iommu_gaddr_t)DMAR_PAGE_SIZE << DMAR_NPTEPGSHIFT,
-		(iommu_gaddr_t)DMAR_PAGE_SIZE << (2 * DMAR_NPTEPGSHIFT),
-		(iommu_gaddr_t)DMAR_PAGE_SIZE << (3 * DMAR_NPTEPGSHIFT),
-		(iommu_gaddr_t)DMAR_PAGE_SIZE << (4 * DMAR_NPTEPGSHIFT),
-		(iommu_gaddr_t)DMAR_PAGE_SIZE << (5 * DMAR_NPTEPGSHIFT)
+		(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,
@@ -244,7 +245,7 @@ calc_am(struct dmar_unit *unit, iommu_gaddr_t base, iommu_gaddr_t size,
 	int am;
 
 	for (am = DMAR_CAP_MAMV(unit->hw_cap);; am--) {
-		isize = 1ULL << (am + DMAR_PAGE_SHIFT);
+		isize = 1ULL << (am + IOMMU_PAGE_SHIFT);
 		if ((base & (isize - 1)) == 0 && size >= isize)
 			break;
 		if (am == 0)
@@ -254,113 +255,9 @@ calc_am(struct dmar_unit *unit, iommu_gaddr_t base, iommu_gaddr_t size,
 	return (am);
 }
 
-iommu_haddr_t dmar_high;
 int haw;
 int dmar_tbl_pagecnt;
 
-vm_page_t
-dmar_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags)
-{
-	vm_page_t m;
-	int zeroed, aflags;
-
-	zeroed = (flags & IOMMU_PGF_ZERO) != 0 ? VM_ALLOC_ZERO : 0;
-	aflags = zeroed | VM_ALLOC_NOBUSY | VM_ALLOC_SYSTEM | VM_ALLOC_NODUMP |
-	    ((flags & IOMMU_PGF_WAITOK) != 0 ? VM_ALLOC_WAITFAIL :
-	    VM_ALLOC_NOWAIT);
-	for (;;) {
-		if ((flags & IOMMU_PGF_OBJL) == 0)
-			VM_OBJECT_WLOCK(obj);
-		m = vm_page_lookup(obj, idx);
-		if ((flags & IOMMU_PGF_NOALLOC) != 0 || m != NULL) {
-			if ((flags & IOMMU_PGF_OBJL) == 0)
-				VM_OBJECT_WUNLOCK(obj);
-			break;
-		}
-		m = vm_page_alloc_contig(obj, idx, aflags, 1, 0,
-		    dmar_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
-		if ((flags & IOMMU_PGF_OBJL) == 0)
-			VM_OBJECT_WUNLOCK(obj);
-		if (m != NULL) {
-			if (zeroed && (m->flags & PG_ZERO) == 0)
-				pmap_zero_page(m);
-			atomic_add_int(&dmar_tbl_pagecnt, 1);
-			break;
-		}
-		if ((flags & IOMMU_PGF_WAITOK) == 0)
-			break;
-	}
-	return (m);
-}
-
-void
-dmar_pgfree(vm_object_t obj, vm_pindex_t idx, int flags)
-{
-	vm_page_t m;
-
-	if ((flags & IOMMU_PGF_OBJL) == 0)
-		VM_OBJECT_WLOCK(obj);
-	m = vm_page_grab(obj, idx, VM_ALLOC_NOCREAT);
-	if (m != NULL) {
-		vm_page_free(m);
-		atomic_subtract_int(&dmar_tbl_pagecnt, 1);
-	}
-	if ((flags & IOMMU_PGF_OBJL) == 0)
-		VM_OBJECT_WUNLOCK(obj);
-}
-
-void *
-dmar_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
-    struct sf_buf **sf)
-{
-	vm_page_t m;
-	bool allocated;
-
-	if ((flags & IOMMU_PGF_OBJL) == 0)
-		VM_OBJECT_WLOCK(obj);
-	m = vm_page_lookup(obj, idx);
-	if (m == NULL && (flags & IOMMU_PGF_ALLOC) != 0) {
-		m = dmar_pgalloc(obj, idx, flags | IOMMU_PGF_OBJL);
-		allocated = true;
-	} else
-		allocated = false;
-	if (m == NULL) {
-		if ((flags & IOMMU_PGF_OBJL) == 0)
-			VM_OBJECT_WUNLOCK(obj);
-		return (NULL);
-	}
-	/* Sleepable allocations cannot fail. */
-	if ((flags & IOMMU_PGF_WAITOK) != 0)
-		VM_OBJECT_WUNLOCK(obj);
-	sched_pin();
-	*sf = sf_buf_alloc(m, SFB_CPUPRIVATE | ((flags & IOMMU_PGF_WAITOK)
-	    == 0 ? SFB_NOWAIT : 0));
-	if (*sf == NULL) {
-		sched_unpin();
-		if (allocated) {
-			VM_OBJECT_ASSERT_WLOCKED(obj);
-			dmar_pgfree(obj, m->pindex, flags | IOMMU_PGF_OBJL);
-		}
-		if ((flags & IOMMU_PGF_OBJL) == 0)
-			VM_OBJECT_WUNLOCK(obj);
-		return (NULL);
-	}
-	if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) ==
-	    (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL))
-		VM_OBJECT_WLOCK(obj);
-	else if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) == 0)
-		VM_OBJECT_WUNLOCK(obj);
-	return ((void *)sf_buf_kva(*sf));
-}
-
-void
-dmar_unmap_pgtbl(struct sf_buf *sf)
-{
-
-	sf_buf_free(sf);
-	sched_unpin();
-}
-
 static void
 dmar_flush_transl_to_ram(struct dmar_unit *unit, void *dst, size_t sz)
 {
@@ -375,7 +272,7 @@ dmar_flush_transl_to_ram(struct dmar_unit *unit, void *dst, size_t sz)
 }
 
 void
-dmar_flush_pte_to_ram(struct dmar_unit *unit, dmar_pte_t *dst)
+dmar_flush_pte_to_ram(struct dmar_unit *unit, iommu_pte_t *dst)
 {
 
 	dmar_flush_transl_to_ram(unit, dst, sizeof(*dst));
@@ -687,11 +584,6 @@ dmar_timeout_sysctl(SYSCTL_HANDLER_ARGS)
 	return (error);
 }
 
-static SYSCTL_NODE(_hw_iommu, OID_AUTO, dmar, CTLFLAG_RD | CTLFLAG_MPSAFE,
-    NULL, "");
-SYSCTL_INT(_hw_iommu_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD,
-    &dmar_tbl_pagecnt, 0,
-    "Count of pages used for DMAR pagetables");
 SYSCTL_INT(_hw_iommu_dmar, OID_AUTO, batch_coalesce, CTLFLAG_RWTUN,
     &dmar_batch_coalesce, 0,
     "Number of qi batches between interrupt");
diff --git a/sys/x86/iommu/iommu_utils.c b/sys/x86/iommu/iommu_utils.c
new file mode 100644
index 000000000000..ffea1cc1a190
--- /dev/null
+++ b/sys/x86/iommu/iommu_utils.c
@@ -0,0 +1,164 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013, 2014 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/systm.h>
+#include <sys/lock.h>
+#include <sys/memdesc.h>
+#include <sys/mutex.h>
+#include <sys/sf_buf.h>
+#include <sys/sysctl.h>
+#include <sys/proc.h>
+#include <sys/sched.h>
+#include <sys/rwlock.h>
+#include <sys/taskqueue.h>
+#include <sys/tree.h>
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/vm_object.h>
+#include <dev/pci/pcireg.h>
+#include <machine/atomic.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <x86/include/busdma_impl.h>
+#include <dev/iommu/busdma_iommu.h>
+#include <dev/iommu/iommu.h>
+#include <x86/iommu/x86_iommu.h>
+
+vm_page_t
+iommu_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags)
+{
+	vm_page_t m;
+	int zeroed, aflags;
+
+	zeroed = (flags & IOMMU_PGF_ZERO) != 0 ? VM_ALLOC_ZERO : 0;
+	aflags = zeroed | VM_ALLOC_NOBUSY | VM_ALLOC_SYSTEM | VM_ALLOC_NODUMP |
+	    ((flags & IOMMU_PGF_WAITOK) != 0 ? VM_ALLOC_WAITFAIL :
+	    VM_ALLOC_NOWAIT);
+	for (;;) {
+		if ((flags & IOMMU_PGF_OBJL) == 0)
+			VM_OBJECT_WLOCK(obj);
+		m = vm_page_lookup(obj, idx);
+		if ((flags & IOMMU_PGF_NOALLOC) != 0 || m != NULL) {
+			if ((flags & IOMMU_PGF_OBJL) == 0)
+				VM_OBJECT_WUNLOCK(obj);
+			break;
+		}
+		m = vm_page_alloc_contig(obj, idx, aflags, 1, 0,
+		    iommu_high, PAGE_SIZE, 0, VM_MEMATTR_DEFAULT);
+		if ((flags & IOMMU_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		if (m != NULL) {
+			if (zeroed && (m->flags & PG_ZERO) == 0)
+				pmap_zero_page(m);
+			atomic_add_int(&iommu_tbl_pagecnt, 1);
+			break;
+		}
+		if ((flags & IOMMU_PGF_WAITOK) == 0)
+			break;
+	}
+	return (m);
+}
+
+void
+iommu_pgfree(vm_object_t obj, vm_pindex_t idx, int flags)
+{
+	vm_page_t m;
+
+	if ((flags & IOMMU_PGF_OBJL) == 0)
+		VM_OBJECT_WLOCK(obj);
+	m = vm_page_grab(obj, idx, VM_ALLOC_NOCREAT);
+	if (m != NULL) {
+		vm_page_free(m);
+		atomic_subtract_int(&iommu_tbl_pagecnt, 1);
+	}
+	if ((flags & IOMMU_PGF_OBJL) == 0)
+		VM_OBJECT_WUNLOCK(obj);
+}
+
+void *
+iommu_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
+    struct sf_buf **sf)
+{
+	vm_page_t m;
+	bool allocated;
+
+	if ((flags & IOMMU_PGF_OBJL) == 0)
+		VM_OBJECT_WLOCK(obj);
+	m = vm_page_lookup(obj, idx);
+	if (m == NULL && (flags & IOMMU_PGF_ALLOC) != 0) {
+		m = iommu_pgalloc(obj, idx, flags | IOMMU_PGF_OBJL);
+		allocated = true;
+	} else
+		allocated = false;
+	if (m == NULL) {
+		if ((flags & IOMMU_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		return (NULL);
+	}
+	/* Sleepable allocations cannot fail. */
+	if ((flags & IOMMU_PGF_WAITOK) != 0)
+		VM_OBJECT_WUNLOCK(obj);
+	sched_pin();
+	*sf = sf_buf_alloc(m, SFB_CPUPRIVATE | ((flags & IOMMU_PGF_WAITOK)
+	    == 0 ? SFB_NOWAIT : 0));
+	if (*sf == NULL) {
+		sched_unpin();
+		if (allocated) {
+			VM_OBJECT_ASSERT_WLOCKED(obj);
+			iommu_pgfree(obj, m->pindex, flags | IOMMU_PGF_OBJL);
+		}
+		if ((flags & IOMMU_PGF_OBJL) == 0)
+			VM_OBJECT_WUNLOCK(obj);
+		return (NULL);
+	}
+	if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) ==
+	    (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL))
+		VM_OBJECT_WLOCK(obj);
+	else if ((flags & (IOMMU_PGF_WAITOK | IOMMU_PGF_OBJL)) == 0)
+		VM_OBJECT_WUNLOCK(obj);
+	return ((void *)sf_buf_kva(*sf));
+}
+
+void
+iommu_unmap_pgtbl(struct sf_buf *sf)
+{
+
+	sf_buf_free(sf);
+	sched_unpin();
+}
+
+iommu_haddr_t iommu_high;
+int iommu_tbl_pagecnt;
+
+SYSCTL_NODE(_hw_iommu, OID_AUTO, dmar, CTLFLAG_RD | CTLFLAG_MPSAFE,
+    NULL, "");
+SYSCTL_INT(_hw_iommu_dmar, OID_AUTO, tbl_pagecnt, CTLFLAG_RD,
+    &iommu_tbl_pagecnt, 0,
+    "Count of pages used for DMAR pagetables");
diff --git a/sys/x86/iommu/x86_iommu.h b/sys/x86/iommu/x86_iommu.h
new file mode 100644
index 000000000000..3789586f1eaf
--- /dev/null
+++ b/sys/x86/iommu/x86_iommu.h
@@ -0,0 +1,62 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2013-2015 The FreeBSD Foundation
+ *
+ * This software was developed by Konstantin Belousov <kib@FreeBSD.org>
+ * under sponsorship from the FreeBSD Foundation.
+ *
*** 54 LINES SKIPPED ***