git: 304c24df44d3 - stable/15 - LinuxKPI: Implement vmap_pfn
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 24 Dec 2025 20:12:28 UTC
The branch stable/15 has been updated by wulf:
URL: https://cgit.FreeBSD.org/src/commit/?id=304c24df44d3ff70a26d1a8fd6653c5c4e765165
commit 304c24df44d3ff70a26d1a8fd6653c5c4e765165
Author: Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2025-12-17 21:31:11 +0000
Commit: Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2025-12-24 20:06:08 +0000
LinuxKPI: Implement vmap_pfn
Required by i915kms to support recent discrete graphics cards.
MFC after: 1 week
Reviewed by: kib
Differential Revision: https://reviews.freebsd.org/D54225
(cherry picked from commit df49fd8efa1a885089488458df0e7e88c9649c90)
---
sys/compat/linuxkpi/common/include/linux/vmalloc.h | 3 +
sys/compat/linuxkpi/common/src/linux_page.c | 65 ++++++++++++++++++++++
2 files changed, 68 insertions(+)
diff --git a/sys/compat/linuxkpi/common/include/linux/vmalloc.h b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
index 00650a2df9b6..a7f77f090755 100644
--- a/sys/compat/linuxkpi/common/include/linux/vmalloc.h
+++ b/sys/compat/linuxkpi/common/include/linux/vmalloc.h
@@ -35,8 +35,11 @@
#define VM_MAP 0x0000
#define PAGE_KERNEL 0x0000
+#define vmap_pfn(...) linuxkpi_vmap_pfn(__VA_ARGS__)
+
void *vmap(struct page **pages, unsigned int count, unsigned long flags,
int prot);
+void *linuxkpi_vmap_pfn(unsigned long *pfns, unsigned int count, int prot);
void vunmap(void *addr);
#endif /* _LINUXKPI_LINUX_VMALLOC_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_page.c b/sys/compat/linuxkpi/common/src/linux_page.c
index 57ca1401b912..82f3a2a4639f 100644
--- a/sys/compat/linuxkpi/common/src/linux_page.c
+++ b/sys/compat/linuxkpi/common/src/linux_page.c
@@ -341,6 +341,16 @@ static struct mtx vmmaplock;
int
is_vmalloc_addr(const void *addr)
{
+ struct vmmap *vmmap;
+
+ mtx_lock(&vmmaplock);
+ LIST_FOREACH(vmmap, &vmmaphead[VM_HASH(addr)], vm_next)
+ if (addr == vmmap->vm_addr)
+ break;
+ mtx_unlock(&vmmaplock);
+ if (vmmap != NULL)
+ return (1);
+
return (vtoslab((vm_offset_t)addr & ~UMA_SLAB_MASK) != NULL);
}
@@ -418,6 +428,61 @@ vmap(struct page **pages, unsigned int count, unsigned long flags, int prot)
return ((void *)off);
}
+#define VMAP_MAX_CHUNK_SIZE (65536U / sizeof(struct vm_page)) /* KMEM_ZMAX */
+
+void *
+linuxkpi_vmap_pfn(unsigned long *pfns, unsigned int count, int prot)
+{
+ vm_page_t m, *ma, fma;
+ vm_offset_t off, coff;
+ vm_paddr_t pa;
+ vm_memattr_t attr;
+ size_t size;
+ unsigned int i, c, chunk;
+
+ size = ptoa(count);
+ off = kva_alloc(size);
+ if (off == 0)
+ return (NULL);
+ vmmap_add((void *)off, size);
+
+ chunk = MIN(count, VMAP_MAX_CHUNK_SIZE);
+ attr = pgprot2cachemode(prot);
+ ma = malloc(chunk * sizeof(vm_page_t), M_TEMP, M_WAITOK | M_ZERO);
+ fma = NULL;
+ c = 0;
+ coff = off;
+ for (i = 0; i < count; i++) {
+ pa = IDX_TO_OFF(pfns[i]);
+ m = PHYS_TO_VM_PAGE(pa);
+ if (m == NULL) {
+ if (fma == NULL)
+ fma = malloc(chunk * sizeof(struct vm_page),
+ M_TEMP, M_WAITOK | M_ZERO);
+ m = fma + c;
+ vm_page_initfake(m, pa, attr);
+ } else {
+ pmap_page_set_memattr(m, attr);
+ }
+ ma[c] = m;
+ c++;
+ if (c == chunk || i == count - 1) {
+ pmap_qenter(coff, ma, c);
+ if (i == count - 1)
+ break;
+ coff += ptoa(c);
+ c = 0;
+ memset(ma, 0, chunk * sizeof(vm_page_t));
+ if (fma != NULL)
+ memset(fma, 0, chunk * sizeof(struct vm_page));
+ }
+ }
+ free(fma, M_TEMP);
+ free(ma, M_TEMP);
+
+ return ((void *)off);
+}
+
void
vunmap(void *addr)
{