1d711dafcSJani Nikula // SPDX-License-Identifier: MIT 2d711dafcSJani Nikula /* Copyright © 2026 Intel Corporation */ 3d711dafcSJani Nikula 4d711dafcSJani Nikula #include <drm/drm_cache.h> 5d711dafcSJani Nikula #include <drm/drm_panic.h> 68430d20cSJani Nikula #include <drm/intel/display_parent_interface.h> 7d711dafcSJani Nikula 8d711dafcSJani Nikula #include "i915_gem_object.h" 9d711dafcSJani Nikula #include "i915_gem_panic.h" 10d711dafcSJani Nikula 11d711dafcSJani Nikula struct intel_panic { 12d711dafcSJani Nikula struct page **pages; 13d711dafcSJani Nikula int page; 14d711dafcSJani Nikula void *vaddr; 15*53f12a26SJani Nikula 16*53f12a26SJani Nikula unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width); 17d711dafcSJani Nikula }; 18d711dafcSJani Nikula 19d711dafcSJani Nikula static void i915_panic_kunmap(struct intel_panic *panic) 20d711dafcSJani Nikula { 21d711dafcSJani Nikula if (panic->vaddr) { 22d711dafcSJani Nikula drm_clflush_virt_range(panic->vaddr, PAGE_SIZE); 23d711dafcSJani Nikula kunmap_local(panic->vaddr); 24d711dafcSJani Nikula panic->vaddr = NULL; 25d711dafcSJani Nikula } 26d711dafcSJani Nikula } 27d711dafcSJani Nikula 28d711dafcSJani Nikula static struct page **i915_gem_object_panic_pages(struct drm_i915_gem_object *obj) 29d711dafcSJani Nikula { 30d711dafcSJani Nikula unsigned long n_pages = obj->base.size >> PAGE_SHIFT, i; 31d711dafcSJani Nikula struct page *page; 32d711dafcSJani Nikula struct page **pages; 33d711dafcSJani Nikula struct sgt_iter iter; 34d711dafcSJani Nikula 35d711dafcSJani Nikula /* For a 3840x2160 32 bits Framebuffer, this should require ~64K */ 36d711dafcSJani Nikula pages = kmalloc_objs(*pages, n_pages, GFP_ATOMIC); 37d711dafcSJani Nikula if (!pages) 38d711dafcSJani Nikula return NULL; 39d711dafcSJani Nikula 40d711dafcSJani Nikula i = 0; 41d711dafcSJani Nikula for_each_sgt_page(page, iter, obj->mm.pages) 42d711dafcSJani Nikula pages[i++] = page; 43d711dafcSJani Nikula return pages; 44d711dafcSJani Nikula } 45d711dafcSJani Nikula 46d711dafcSJani Nikula static void i915_gem_object_panic_map_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, 47d711dafcSJani Nikula unsigned int y, u32 color) 48d711dafcSJani Nikula { 49*53f12a26SJani Nikula struct intel_panic *panic = sb->private; 50*53f12a26SJani Nikula unsigned int offset = panic->tiling(sb->width, x, y); 51d711dafcSJani Nikula 52d711dafcSJani Nikula iosys_map_wr(&sb->map[0], offset, u32, color); 53d711dafcSJani Nikula } 54d711dafcSJani Nikula 55d711dafcSJani Nikula /* 56d711dafcSJani Nikula * The scanout buffer pages are not mapped, so for each pixel, 57d711dafcSJani Nikula * use kmap_local_page_try_from_panic() to map the page, and write the pixel. 58d711dafcSJani Nikula * Try to keep the map from the previous pixel, to avoid too much map/unmap. 59d711dafcSJani Nikula */ 60d711dafcSJani Nikula static void i915_gem_object_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x, 61d711dafcSJani Nikula unsigned int y, u32 color) 62d711dafcSJani Nikula { 63*53f12a26SJani Nikula struct intel_panic *panic = sb->private; 64d711dafcSJani Nikula unsigned int new_page; 65d711dafcSJani Nikula unsigned int offset; 66d711dafcSJani Nikula 67*53f12a26SJani Nikula if (panic->tiling) 68*53f12a26SJani Nikula offset = panic->tiling(sb->width, x, y); 69d711dafcSJani Nikula else 70d711dafcSJani Nikula offset = y * sb->pitch[0] + x * sb->format->cpp[0]; 71d711dafcSJani Nikula 72d711dafcSJani Nikula new_page = offset >> PAGE_SHIFT; 73d711dafcSJani Nikula offset = offset % PAGE_SIZE; 74d711dafcSJani Nikula if (new_page != panic->page) { 75d711dafcSJani Nikula i915_panic_kunmap(panic); 76d711dafcSJani Nikula panic->page = new_page; 77d711dafcSJani Nikula panic->vaddr = 78d711dafcSJani Nikula kmap_local_page_try_from_panic(panic->pages[panic->page]); 79d711dafcSJani Nikula } 80d711dafcSJani Nikula if (panic->vaddr) { 81d711dafcSJani Nikula u32 *pix = panic->vaddr + offset; 82d711dafcSJani Nikula *pix = color; 83d711dafcSJani Nikula } 84d711dafcSJani Nikula } 85d711dafcSJani Nikula 868430d20cSJani Nikula static struct intel_panic *i915_gem_object_alloc_panic(void) 87d711dafcSJani Nikula { 88d711dafcSJani Nikula struct intel_panic *panic; 89d711dafcSJani Nikula 90d711dafcSJani Nikula panic = kzalloc_obj(*panic); 91d711dafcSJani Nikula 92d711dafcSJani Nikula return panic; 93d711dafcSJani Nikula } 94d711dafcSJani Nikula 95d711dafcSJani Nikula /* 96d711dafcSJani Nikula * Setup the gem framebuffer for drm_panic access. 97d711dafcSJani Nikula * Use current vaddr if it exists, or setup a list of pages. 98d711dafcSJani Nikula * pfn is not supported yet. 99d711dafcSJani Nikula */ 100c55b6936SJani Nikula static int i915_gem_object_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb, 101*53f12a26SJani Nikula struct drm_gem_object *_obj, 102*53f12a26SJani Nikula unsigned int (*tiling)(unsigned int x, unsigned int y, unsigned int width)) 103d711dafcSJani Nikula { 104d711dafcSJani Nikula enum i915_map_type has_type; 105d711dafcSJani Nikula struct drm_i915_gem_object *obj = to_intel_bo(_obj); 106d711dafcSJani Nikula void *ptr; 107d711dafcSJani Nikula 108*53f12a26SJani Nikula sb->private = panic; 109*53f12a26SJani Nikula 110d711dafcSJani Nikula ptr = page_unpack_bits(obj->mm.mapping, &has_type); 111d711dafcSJani Nikula if (ptr) { 112d711dafcSJani Nikula if (i915_gem_object_has_iomem(obj)) 113d711dafcSJani Nikula iosys_map_set_vaddr_iomem(&sb->map[0], (void __iomem *)ptr); 114d711dafcSJani Nikula else 115d711dafcSJani Nikula iosys_map_set_vaddr(&sb->map[0], ptr); 116d711dafcSJani Nikula 117*53f12a26SJani Nikula if (tiling) { 118*53f12a26SJani Nikula panic->tiling = tiling; 119d711dafcSJani Nikula sb->set_pixel = i915_gem_object_panic_map_set_pixel; 120*53f12a26SJani Nikula } 121d711dafcSJani Nikula return 0; 122d711dafcSJani Nikula } 123d711dafcSJani Nikula if (i915_gem_object_has_struct_page(obj)) { 124d711dafcSJani Nikula panic->pages = i915_gem_object_panic_pages(obj); 125d711dafcSJani Nikula if (!panic->pages) 126d711dafcSJani Nikula return -ENOMEM; 127d711dafcSJani Nikula panic->page = -1; 128*53f12a26SJani Nikula panic->tiling = tiling; 129d711dafcSJani Nikula sb->set_pixel = i915_gem_object_panic_page_set_pixel; 130d711dafcSJani Nikula return 0; 131d711dafcSJani Nikula } 132d711dafcSJani Nikula return -EOPNOTSUPP; 133d711dafcSJani Nikula } 134d711dafcSJani Nikula 1358430d20cSJani Nikula static void i915_gem_object_panic_finish(struct intel_panic *panic) 136d711dafcSJani Nikula { 137d711dafcSJani Nikula i915_panic_kunmap(panic); 138d711dafcSJani Nikula panic->page = -1; 139d711dafcSJani Nikula kfree(panic->pages); 140d711dafcSJani Nikula panic->pages = NULL; 141d711dafcSJani Nikula } 1428430d20cSJani Nikula 1438430d20cSJani Nikula const struct intel_display_panic_interface i915_display_panic_interface = { 144566ef352SJani Nikula .alloc = i915_gem_object_alloc_panic, 145566ef352SJani Nikula .setup = i915_gem_object_panic_setup, 146566ef352SJani Nikula .finish = i915_gem_object_panic_finish, 1478430d20cSJani Nikula }; 148