The branch stable/15 has been updated by wulf:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=304c24df44d3ff70a26d1a8fd6653c5c4e765165

commit 304c24df44d3ff70a26d1a8fd6653c5c4e765165
Author:     Vladimir Kondratyev <[email protected]>
AuthorDate: 2025-12-17 21:31:11 +0000
Commit:     Vladimir Kondratyev <[email protected]>
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)
 {

Reply via email to