Module Name: src Committed By: riastradh Date: Fri Jan 19 22:23:04 UTC 2024
Modified Files: src/sys/external/bsd/drm2/dist/drm/i915/gem: i915_gem_phys.c Log Message: i915_gem_phys: Fill sg_pgs. This is needed by i915 gem fault, which maps user virtual addresses to those pages, and by i915 gem object destruction, which does pmap_page_protect on the pages to remove any of those user virtual mappings. This needs pmap_kenter_pa rather than pmap_enter(pmap_kernel(), ...) in order to preserve the _kernel's_ mapping of the pages after pmap_page_protect. But bus_dmamem_map currently uses pmap_enter(pmap_kernel(), ...) instead which creates a mapping that is removed by pmap_page_protect. So we use a variant of bus_dmamem_map that uses pmap_kenter_pa instead. Perhaps bus_dmamem_map should do this itself, but this change is less risky to pull up than a change to bus_dmamem_map itself. PR kern/57833: kernel panic on xorg exit XXX pullup-10 To generate a diff of this commit: cvs rdiff -u -r1.8 -r1.9 \ src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c diff -u src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c:1.8 src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c:1.9 --- src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c:1.8 Sun Dec 19 12:45:43 2021 +++ src/sys/external/bsd/drm2/dist/drm/i915/gem/i915_gem_phys.c Fri Jan 19 22:23:04 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: i915_gem_phys.c,v 1.8 2021/12/19 12:45:43 riastradh Exp $ */ +/* $NetBSD: i915_gem_phys.c,v 1.9 2024/01/19 22:23:04 riastradh Exp $ */ /* * SPDX-License-Identifier: MIT @@ -7,7 +7,91 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: i915_gem_phys.c,v 1.8 2021/12/19 12:45:43 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i915_gem_phys.c,v 1.9 2024/01/19 22:23:04 riastradh Exp $"); + +#ifdef __NetBSD__ +/* + * Make sure this block comes before any linux includes, so we don't + * get mixed up by the PAGE_MASK complementation. + */ + +#include <sys/bus.h> + +#include <uvm/uvm.h> +#include <uvm/uvm_extern.h> + +#include <machine/pmap_private.h> /* kvtopte, pmap_pte_clearbits */ + +/* + * Version of bus_dmamem_map that uses pmap_kenter_pa, not pmap_enter, + * so that it isn't affected by pmap_page_protect on the physical + * address. Adapted from sys/arch/x86/x86/bus_dma.c. + */ +static int +bus_dmamem_kmap(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, + size_t size, void **kvap, int flags) +{ + vaddr_t va; + bus_addr_t addr; + int curseg; + const uvm_flag_t kmflags = + (flags & BUS_DMA_NOWAIT) != 0 ? UVM_KMF_NOWAIT : 0; + u_int pmapflags = PMAP_WIRED | VM_PROT_READ | VM_PROT_WRITE; + + size = round_page(size); + if (flags & BUS_DMA_NOCACHE) + pmapflags |= PMAP_NOCACHE; + + va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags); + + if (va == 0) + return ENOMEM; + + *kvap = (void *)va; + + for (curseg = 0; curseg < nsegs; curseg++) { + for (addr = segs[curseg].ds_addr; + addr < (segs[curseg].ds_addr + segs[curseg].ds_len); + addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) { + if (size == 0) + panic("bus_dmamem_kmap: size botch"); + pmap_kenter_pa(va, addr, + VM_PROT_READ | VM_PROT_WRITE, + pmapflags); + } + } + pmap_update(pmap_kernel()); + + return 0; +} + +static void +bus_dmamem_kunmap(bus_dma_tag_t t, void *kva, size_t size) +{ + pt_entry_t *pte, opte; + vaddr_t va, sva, eva; + + KASSERTMSG(((uintptr_t)kva & PGOFSET) == 0, "kva=%p", kva); + + size = round_page(size); + sva = (vaddr_t)kva; + eva = sva + size; + + /* + * mark pages cacheable again. + */ + for (va = sva; va < eva; va += PAGE_SIZE) { + pte = kvtopte(va); + opte = *pte; + if ((opte & PTE_PCD) != 0) + pmap_pte_clearbits(pte, PTE_PCD); + } + pmap_kremove((vaddr_t)kva, size); + pmap_update(pmap_kernel()); + uvm_km_free(kernel_map, (vaddr_t)kva, size, UVM_KMF_VAONLY); +} + +#endif #include <linux/highmem.h> #include <linux/shmem_fs.h> @@ -65,7 +149,7 @@ static int i915_gem_object_get_pages_phy if (ret) return -ENOMEM; KASSERT(rsegs == 1); - ret = -bus_dmamem_map(dmat, &obj->mm.u.phys.seg, 1, + ret = -bus_dmamem_kmap(dmat, &obj->mm.u.phys.seg, 1, roundup_pow_of_two(obj->base.size), &vaddr, BUS_DMA_WAITOK|BUS_DMA_COHERENT); if (ret) @@ -83,7 +167,12 @@ static int i915_gem_object_get_pages_phy if (!st) goto err_pci; +#ifdef __NetBSD__ + if (sg_alloc_table_from_bus_dmamem(st, dmat, &obj->mm.u.phys.seg, 1, + GFP_KERNEL)) +#else if (sg_alloc_table(st, 1, GFP_KERNEL)) +#endif goto err_st; sg = st->sgl; @@ -151,7 +240,7 @@ err_st: err_pci: #ifdef __NetBSD__ if (vaddr) { - bus_dmamem_unmap(dmat, vaddr, + bus_dmamem_kunmap(dmat, vaddr, roundup_pow_of_two(obj->base.size)); } obj->mm.u.phys.kva = NULL; @@ -225,7 +314,7 @@ i915_gem_object_put_pages_phys(struct dr kfree(pages); #ifdef __NetBSD__ - bus_dmamem_unmap(dmat, obj->mm.u.phys.kva, + bus_dmamem_kunmap(dmat, obj->mm.u.phys.kva, roundup_pow_of_two(obj->base.size)); obj->mm.u.phys.kva = NULL; bus_dmamem_free(dmat, &obj->mm.u.phys.seg, 1);