git: 3848dc4fe6f3 - main - dmar: on unmap, postpone freeing page table pages after the invalidation is done
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 27 Sep 2024 17:34:49 UTC
The branch main has been updated by kib: URL: https://cgit.FreeBSD.org/src/commit/?id=3848dc4fe6f37cbcfaea29eb94fa560a503f60ab commit 3848dc4fe6f37cbcfaea29eb94fa560a503f60ab Author: Konstantin Belousov <kib@FreeBSD.org> AuthorDate: 2024-09-25 03:54:44 +0000 Commit: Konstantin Belousov <kib@FreeBSD.org> CommitDate: 2024-09-27 17:34:23 +0000 dmar: on unmap, postpone freeing page table pages after the invalidation is done IOMMU is free to access page tables until we invalidate them Sponsored by: Advanced Micro Devices (AMD) Sponsored by: The FreeBSD Foundation MFC after: 1 week --- sys/x86/iommu/intel_idpgtbl.c | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c index da2750df5567..6f66106822fe 100644 --- a/sys/x86/iommu/intel_idpgtbl.c +++ b/sys/x86/iommu/intel_idpgtbl.c @@ -68,7 +68,8 @@ #include <x86/iommu/intel_dmar.h> static int dmar_unmap_buf_locked(struct dmar_domain *domain, - iommu_gaddr_t base, iommu_gaddr_t size, int flags); + iommu_gaddr_t base, iommu_gaddr_t size, int flags, + struct iommu_map_entry *entry); /* * The cache of the identity mapping page tables for the DMARs. Using @@ -386,7 +387,8 @@ retry: static int dmar_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, - iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags) + iommu_gaddr_t size, vm_page_t *ma, uint64_t pflags, int flags, + struct iommu_map_entry *entry) { iommu_pte_t *pte; struct sf_buf *sf; @@ -446,7 +448,7 @@ dmar_map_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, if (sf != NULL) iommu_unmap_pgtbl(sf); dmar_unmap_buf_locked(domain, base1, base - base1, - flags); + flags, entry); TD_PINNED_ASSERT; return (ENOMEM); } @@ -517,7 +519,8 @@ dmar_map_buf(struct iommu_domain *iodom, struct iommu_map_entry *entry, KASSERT((flags & ~IOMMU_PGF_WAITOK) == 0, ("invalid flags %x", flags)); DMAR_DOMAIN_PGLOCK(domain); - error = dmar_map_buf_locked(domain, base, size, ma, pflags, flags); + error = dmar_map_buf_locked(domain, base, size, ma, pflags, flags, + entry); DMAR_DOMAIN_PGUNLOCK(domain); if (error != 0) return (error); @@ -535,11 +538,11 @@ dmar_map_buf(struct iommu_domain *iodom, struct iommu_map_entry *entry, static void dmar_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl, int flags, iommu_pte_t *pte, - struct sf_buf **sf, bool free_fs); + struct sf_buf **sf, struct iommu_map_entry *entry, bool free_fs); static void dmar_free_pgtbl_pde(struct dmar_domain *domain, iommu_gaddr_t base, - int lvl, int flags) + int lvl, int flags, struct iommu_map_entry *entry) { struct sf_buf *sf; iommu_pte_t *pde; @@ -547,12 +550,14 @@ dmar_free_pgtbl_pde(struct dmar_domain *domain, iommu_gaddr_t base, sf = NULL; pde = dmar_pgtbl_map_pte(domain, base, lvl, flags, &idx, &sf); - dmar_unmap_clear_pte(domain, base, lvl, flags, pde, &sf, true); + dmar_unmap_clear_pte(domain, base, lvl, flags, pde, &sf, + entry, true); } static void dmar_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl, - int flags, iommu_pte_t *pte, struct sf_buf **sf, bool free_sf) + int flags, iommu_pte_t *pte, struct sf_buf **sf, + struct iommu_map_entry *entry, bool free_sf) { vm_page_t m; @@ -571,8 +576,8 @@ dmar_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)); - iommu_pgfree(domain->pgtbl_obj, m->pindex, flags, NULL); - dmar_free_pgtbl_pde(domain, base, lvl - 1, flags); + iommu_pgfree(domain->pgtbl_obj, m->pindex, flags, entry); + dmar_free_pgtbl_pde(domain, base, lvl - 1, flags, entry); } /* @@ -580,7 +585,7 @@ dmar_unmap_clear_pte(struct dmar_domain *domain, iommu_gaddr_t base, int lvl, */ static int dmar_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, - iommu_gaddr_t size, int flags) + iommu_gaddr_t size, int flags, struct iommu_map_entry *entry) { iommu_pte_t *pte; struct sf_buf *sf; @@ -631,7 +636,7 @@ dmar_unmap_buf_locked(struct dmar_domain *domain, iommu_gaddr_t base, if ((pte->pte & DMAR_PTE_SP) != 0 || lvl == domain->pglvl - 1) { dmar_unmap_clear_pte(domain, base, lvl, - flags, pte, &sf, false); + flags, pte, &sf, entry, false); break; } } @@ -661,7 +666,7 @@ dmar_unmap_buf(struct iommu_domain *iodom, struct iommu_map_entry *entry, DMAR_DOMAIN_PGLOCK(domain); error = dmar_unmap_buf_locked(domain, entry->start, entry->end - - entry->start, flags); + entry->start, flags, entry); DMAR_DOMAIN_PGUNLOCK(domain); return (error); }