git: 29e227047065 - main - x86 iommu: move page level related functions to common utils
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
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