git: 0c7e13cfe204 - stable/14 - iommu: extend iommu_map_entry to store the list of associated freed page table pages
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 05 Oct 2024 07:11:35 UTC
The branch stable/14 has been updated by kib:
URL: https://cgit.FreeBSD.org/src/commit/?id=0c7e13cfe2045fb17a0583d0a2a1f685225bf7d5
commit 0c7e13cfe2045fb17a0583d0a2a1f685225bf7d5
Author: Konstantin Belousov <kib@FreeBSD.org>
AuthorDate: 2024-09-25 01:50:34 +0000
Commit: Konstantin Belousov <kib@FreeBSD.org>
CommitDate: 2024-10-05 07:08:56 +0000
iommu: extend iommu_map_entry to store the list of associated freed page table pages
(cherry picked from commit f713ed6694d949ec37365533afbb47c04f919572)
---
sys/dev/iommu/iommu.h | 3 +++
sys/dev/iommu/iommu_gas.c | 14 +++++++++++---
sys/x86/iommu/intel_idpgtbl.c | 4 ++--
sys/x86/iommu/iommu_utils.c | 15 +++++++++++----
sys/x86/iommu/x86_iommu.h | 3 ++-
5 files changed, 29 insertions(+), 10 deletions(-)
diff --git a/sys/dev/iommu/iommu.h b/sys/dev/iommu/iommu.h
index 84d8c3680b71..73d0a6f1279b 100644
--- a/sys/dev/iommu/iommu.h
+++ b/sys/dev/iommu/iommu.h
@@ -31,6 +31,8 @@
#ifndef _DEV_IOMMU_IOMMU_H_
#define _DEV_IOMMU_IOMMU_H_
+#include <vm/vm.h>
+#include <vm/vm_page.h>
#include <dev/iommu/iommu_types.h>
struct bus_dma_tag_common;
@@ -61,6 +63,7 @@ struct iommu_map_entry {
RB_ENTRY(iommu_map_entry) rb_entry; /* Links for domain entries */
struct iommu_domain *domain;
struct iommu_qi_genseq gseq;
+ struct spglist pgtbl_free;
};
struct iommu_unit {
diff --git a/sys/dev/iommu/iommu_gas.c b/sys/dev/iommu/iommu_gas.c
index 26ac38da3c4f..d97bdee47b28 100644
--- a/sys/dev/iommu/iommu_gas.c
+++ b/sys/dev/iommu/iommu_gas.c
@@ -96,9 +96,12 @@ iommu_gas_alloc_entry(struct iommu_domain *domain, u_int flags)
res = uma_zalloc(iommu_map_entry_zone, ((flags & IOMMU_PGF_WAITOK) !=
0 ? M_WAITOK : M_NOWAIT) | M_ZERO);
- if (res != NULL && domain != NULL) {
- res->domain = domain;
- atomic_add_int(&domain->entries_cnt, 1);
+ if (res != NULL) {
+ SLIST_INIT(&res->pgtbl_free);
+ if (domain != NULL) {
+ res->domain = domain;
+ atomic_add_int(&domain->entries_cnt, 1);
+ }
}
return (res);
}
@@ -107,7 +110,12 @@ void
iommu_gas_free_entry(struct iommu_map_entry *entry)
{
struct iommu_domain *domain;
+ int n __unused;
+ n = vm_page_free_pages_toq(&entry->pgtbl_free, false);
+#if defined(__i386__) || defined(__amd64__)
+ atomic_subtract_int(&iommu_tbl_pagecnt, n);
+#endif
domain = entry->domain;
if (domain != NULL)
atomic_subtract_int(&domain->entries_cnt, 1);
diff --git a/sys/x86/iommu/intel_idpgtbl.c b/sys/x86/iommu/intel_idpgtbl.c
index a949e38cc9b1..9dc7a2d58b3f 100644
--- a/sys/x86/iommu/intel_idpgtbl.c
+++ b/sys/x86/iommu/intel_idpgtbl.c
@@ -368,7 +368,7 @@ retry:
("loosing root page %p", domain));
vm_page_unwire_noq(m);
iommu_pgfree(domain->pgtbl_obj, m->pindex,
- flags);
+ flags, NULL);
return (NULL);
}
dmar_pte_store(&ptep->pte, DMAR_PTE_R | DMAR_PTE_W |
@@ -572,7 +572,7 @@ 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);
+ iommu_pgfree(domain->pgtbl_obj, m->pindex, flags, NULL);
dmar_free_pgtbl_pde(domain, base, lvl - 1, flags);
}
diff --git a/sys/x86/iommu/iommu_utils.c b/sys/x86/iommu/iommu_utils.c
index 2011c632f770..8ff15cc86cb8 100644
--- a/sys/x86/iommu/iommu_utils.c
+++ b/sys/x86/iommu/iommu_utils.c
@@ -109,7 +109,8 @@ iommu_pgalloc(vm_object_t obj, vm_pindex_t idx, int flags)
}
void
-iommu_pgfree(vm_object_t obj, vm_pindex_t idx, int flags)
+iommu_pgfree(vm_object_t obj, vm_pindex_t idx, int flags,
+ struct iommu_map_entry *entry)
{
vm_page_t m;
@@ -117,8 +118,13 @@ iommu_pgfree(vm_object_t obj, vm_pindex_t idx, int flags)
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 (entry == NULL) {
+ vm_page_free(m);
+ atomic_subtract_int(&iommu_tbl_pagecnt, 1);
+ } else {
+ vm_page_remove_xbusy(m); /* keep page busy */
+ SLIST_INSERT_HEAD(&entry->pgtbl_free, m, plinks.s.ss);
+ }
}
if ((flags & IOMMU_PGF_OBJL) == 0)
VM_OBJECT_WUNLOCK(obj);
@@ -154,7 +160,8 @@ iommu_map_pgtbl(vm_object_t obj, vm_pindex_t idx, int flags,
sched_unpin();
if (allocated) {
VM_OBJECT_ASSERT_WLOCKED(obj);
- iommu_pgfree(obj, m->pindex, flags | IOMMU_PGF_OBJL);
+ iommu_pgfree(obj, m->pindex, flags | IOMMU_PGF_OBJL,
+ NULL);
}
if ((flags & IOMMU_PGF_OBJL) == 0)
VM_OBJECT_WUNLOCK(obj);
diff --git a/sys/x86/iommu/x86_iommu.h b/sys/x86/iommu/x86_iommu.h
index a1ed5c71c513..4d0ac8351e2e 100644
--- a/sys/x86/iommu/x86_iommu.h
+++ b/sys/x86/iommu/x86_iommu.h
@@ -48,7 +48,8 @@ struct vm_object;
struct vm_page *iommu_pgalloc(struct vm_object *obj, vm_pindex_t idx,
int flags);
-void iommu_pgfree(struct vm_object *obj, vm_pindex_t idx, int flags);
+void iommu_pgfree(struct vm_object *obj, vm_pindex_t idx, int flags,
+ struct iommu_map_entry *entry);
void *iommu_map_pgtbl(struct vm_object *obj, vm_pindex_t idx, int flags,
struct sf_buf **sf);
void iommu_unmap_pgtbl(struct sf_buf *sf);