diff options
| author | 2026-09-08 17:50:52 +0100 | |
|---|---|---|
| committer | 2026-09-14 09:09:01 -0400 | |
| commit | de40d31275cd57408ff1fdd97ea117a3f8c50cc5 (patch) | |
| tree | 67fc14ce8ae528dea91c432d2764e8b5f97c5d49 | |
| parent | drm/xe/mmio_gem: Revoke drm_vma_node on xe_mmio_gem destroy (diff) | |
drm/xe/mmio_gem: cache the dummy page per object
Currently, when the fault handler provides a dummy page, it
allocates a new one on every invocation and ties its lifetime to
the drm_device via drmm_add_action_or_reset(). Concurrent faults
after hot-unplug therefore accumulate pages that persist until
device teardown.
Cache a single dummy page in the xe_mmio_gem object and use dma_resv
lock to protect its allocation. Free it with the object.
v2: use dma_resv lock to protect the allocation (Matt Auld)
Assisted-by: GitHub-Copilot:claude-opus-4.6
Signed-off-by: Ilia Levi <ilia.levi@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Signed-off-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patch.msgid.link/20260908165046.1393557-15-matthew.auld@intel.com
(cherry picked from commit 8bf6213f9831e46313af4722a1ee6db1b7596378)
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
| -rw-r--r-- | drivers/gpu/drm/xe/xe_mmio_gem.c | 27 |
1 files changed, 16 insertions, 11 deletions
diff --git a/drivers/gpu/drm/xe/xe_mmio_gem.c b/drivers/gpu/drm/xe/xe_mmio_gem.c index 3c42d8358c7d..970b1e2f4981 100644 --- a/drivers/gpu/drm/xe/xe_mmio_gem.c +++ b/drivers/gpu/drm/xe/xe_mmio_gem.c @@ -5,9 +5,9 @@ #include "xe_mmio_gem.h" +#include <linux/dma-resv.h> #include <drm/drm_drv.h> #include <drm/drm_gem.h> -#include <drm/drm_managed.h> #include "xe_device_types.h" @@ -37,6 +37,7 @@ static vm_fault_t xe_mmio_gem_vm_fault(struct vm_fault *); struct xe_mmio_gem { struct drm_gem_object base; phys_addr_t phys_addr; + struct page *dummy_page; /* protected by the GEM's dma_resv */ }; static int xe_mmio_gem_vm_may_split(struct vm_area_struct *area, unsigned long addr) @@ -131,6 +132,8 @@ static void xe_mmio_gem_free(struct drm_gem_object *base) { struct xe_mmio_gem *obj = to_xe_mmio_gem(base); + if (obj->dummy_page) + __free_page(obj->dummy_page); drm_gem_object_release(base); kfree(obj); } @@ -169,27 +172,29 @@ static int xe_mmio_gem_mmap(struct drm_gem_object *base, struct vm_area_struct * return 0; } -static void xe_mmio_gem_release_dummy_page(struct drm_device *dev, void *res) +static int alloc_dummy_page_if_needed(struct drm_gem_object *base) { - __free_page((struct page *)res); + struct xe_mmio_gem *obj = to_xe_mmio_gem(base); + + dma_resv_lock(base->resv, NULL); + if (!obj->dummy_page) + obj->dummy_page = alloc_page(GFP_KERNEL | __GFP_ZERO); + dma_resv_unlock(base->resv); + + return obj->dummy_page ? 0 : -ENOMEM; } static vm_fault_t xe_mmio_gem_vm_fault_dummy_page(struct vm_fault *vmf) { struct vm_area_struct *vma = vmf->vma; struct drm_gem_object *base = vma->vm_private_data; - struct drm_device *dev = base->dev; - struct page *page; + struct xe_mmio_gem *obj = to_xe_mmio_gem(base); unsigned long pfn; - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) - return VM_FAULT_OOM; - - if (drmm_add_action_or_reset(dev, xe_mmio_gem_release_dummy_page, page)) + if (alloc_dummy_page_if_needed(base)) return VM_FAULT_OOM; - pfn = page_to_pfn(page); + pfn = page_to_pfn(obj->dummy_page); return vmf_insert_pfn_prot(vma, vmf->address, pfn, vm_get_page_prot(vma->vm_flags)); |
