xref: /linux/drivers/gpu/drm/i915/gem/i915_gem_panic.c (revision 4e69c1856bfd9ffb7e9d335a25842fa211628929)
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