Skip to content

Commit 91ce414

Browse files
author
Jocelyn Falempe
committed
drm/panic: Add kunit tests for drm_panic
Add kunit tests for drm_panic. They check that drawing the panic screen doesn't crash, but they don't check the correctness of the resulting image. Reviewed-by: Maxime Ripard <mripard@kernel.org> Link: https://patch.msgid.link/20251216082524.115980-3-jfalempe@redhat.com Signed-off-by: Jocelyn Falempe <jfalempe@redhat.com>
1 parent 5555a30 commit 91ce414

3 files changed

Lines changed: 226 additions & 0 deletions

File tree

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8749,6 +8749,7 @@ T: git https://gitlab.freedesktop.org/drm/misc/kernel.git
87498749
F: drivers/gpu/drm/drm_draw.c
87508750
F: drivers/gpu/drm/drm_draw_internal.h
87518751
F: drivers/gpu/drm/drm_panic*.c
8752+
F: drivers/gpu/drm/tests/drm_panic_test.c
87528753
F: include/drm/drm_panic*
87538754

87548755
DRM PANIC QR CODE

drivers/gpu/drm/drm_panic.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,3 +1084,7 @@ void drm_panic_exit(void)
10841084
{
10851085
drm_panic_qr_exit();
10861086
}
1087+
1088+
#ifdef CONFIG_DRM_KUNIT_TEST
1089+
#include "tests/drm_panic_test.c"
1090+
#endif
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
// SPDX-License-Identifier: GPL-2.0 or MIT
2+
/*
3+
* Copyright (c) 2025 Red Hat.
4+
* Author: Jocelyn Falempe <jfalempe@redhat.com>
5+
*
6+
* KUNIT tests for drm panic
7+
*/
8+
9+
#include <drm/drm_fourcc.h>
10+
#include <drm/drm_panic.h>
11+
12+
#include <kunit/test.h>
13+
14+
#include <linux/units.h>
15+
#include <linux/vmalloc.h>
16+
17+
/* Check the framebuffer color only if the panic colors are the default */
18+
#if (CONFIG_DRM_PANIC_BACKGROUND_COLOR == 0 && \
19+
CONFIG_DRM_PANIC_FOREGROUND_COLOR == 0xffffff)
20+
21+
static void drm_panic_check_color_byte(struct kunit *test, u8 b)
22+
{
23+
KUNIT_EXPECT_TRUE(test, (b == 0 || b == 0xff));
24+
}
25+
#else
26+
static void drm_panic_check_color_byte(struct kunit *test, u8 b) {}
27+
#endif
28+
29+
struct drm_test_mode {
30+
const int width;
31+
const int height;
32+
const u32 format;
33+
void (*draw_screen)(struct drm_scanout_buffer *sb);
34+
const char *fname;
35+
};
36+
37+
/*
38+
* Run all tests for the 3 panic screens: user, kmsg and qr_code
39+
*/
40+
#define DRM_TEST_MODE_LIST(func) \
41+
DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_XRGB8888, func) \
42+
DRM_PANIC_TEST_MODE(300, 200, DRM_FORMAT_XRGB8888, func) \
43+
DRM_PANIC_TEST_MODE(1920, 1080, DRM_FORMAT_XRGB8888, func) \
44+
DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB565, func) \
45+
DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB888, func) \
46+
47+
#define DRM_PANIC_TEST_MODE(w, h, f, name) { \
48+
.width = w, \
49+
.height = h, \
50+
.format = f, \
51+
.draw_screen = draw_panic_screen_##name, \
52+
.fname = #name, \
53+
}, \
54+
55+
static const struct drm_test_mode drm_test_modes_cases[] = {
56+
DRM_TEST_MODE_LIST(user)
57+
DRM_TEST_MODE_LIST(kmsg)
58+
#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
59+
DRM_TEST_MODE_LIST(qr_code)
60+
#endif
61+
};
62+
63+
#undef DRM_PANIC_TEST_MODE
64+
65+
static int drm_test_panic_init(struct kunit *test)
66+
{
67+
struct drm_scanout_buffer *priv;
68+
69+
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
70+
KUNIT_ASSERT_NOT_NULL(test, priv);
71+
72+
test->priv = priv;
73+
74+
drm_panic_set_description("Kunit testing");
75+
76+
return 0;
77+
}
78+
79+
/*
80+
* Test drawing the panic screen, using a memory mapped framebuffer
81+
* Set the whole buffer to 0xa5, and then check that all pixels have been
82+
* written.
83+
*/
84+
static void drm_test_panic_screen_user_map(struct kunit *test)
85+
{
86+
struct drm_scanout_buffer *sb = test->priv;
87+
const struct drm_test_mode *params = test->param_value;
88+
char *fb;
89+
int fb_size;
90+
int i;
91+
92+
sb->format = drm_format_info(params->format);
93+
fb_size = params->width * params->height * sb->format->cpp[0];
94+
95+
fb = vmalloc(fb_size);
96+
KUNIT_ASSERT_NOT_NULL(test, fb);
97+
98+
memset(fb, 0xa5, fb_size);
99+
100+
iosys_map_set_vaddr(&sb->map[0], fb);
101+
sb->width = params->width;
102+
sb->height = params->height;
103+
sb->pitch[0] = params->width * sb->format->cpp[0];
104+
105+
params->draw_screen(sb);
106+
107+
for (i = 0; i < fb_size; i++)
108+
drm_panic_check_color_byte(test, fb[i]);
109+
110+
vfree(fb);
111+
}
112+
113+
/*
114+
* Test drawing the panic screen, using a list of pages framebuffer
115+
* Set the whole buffer to 0xa5, and then check that all pixels have been
116+
* written.
117+
*/
118+
static void drm_test_panic_screen_user_page(struct kunit *test)
119+
{
120+
struct drm_scanout_buffer *sb = test->priv;
121+
const struct drm_test_mode *params = test->param_value;
122+
int fb_size, p, i, npages;
123+
struct page **pages;
124+
u8 *vaddr;
125+
126+
sb->format = drm_format_info(params->format);
127+
fb_size = params->width * params->height * sb->format->cpp[0];
128+
npages = DIV_ROUND_UP(fb_size, PAGE_SIZE);
129+
130+
pages = kmalloc_array(npages, sizeof(struct page *), GFP_KERNEL);
131+
KUNIT_ASSERT_NOT_NULL(test, pages);
132+
133+
for (p = 0; p < npages; p++) {
134+
pages[p] = alloc_page(GFP_KERNEL);
135+
if (!pages[p]) {
136+
npages = p - 1;
137+
KUNIT_FAIL(test, "Can't allocate page\n");
138+
goto free_pages;
139+
}
140+
vaddr = kmap_local_page(pages[p]);
141+
memset(vaddr, 0xa5, PAGE_SIZE);
142+
kunmap_local(vaddr);
143+
}
144+
sb->pages = pages;
145+
sb->width = params->width;
146+
sb->height = params->height;
147+
sb->pitch[0] = params->width * sb->format->cpp[0];
148+
149+
params->draw_screen(sb);
150+
151+
for (p = 0; p < npages; p++) {
152+
int bytes_in_page = (p == npages - 1) ? fb_size - p * PAGE_SIZE : PAGE_SIZE;
153+
154+
vaddr = kmap_local_page(pages[p]);
155+
for (i = 0; i < bytes_in_page; i++)
156+
drm_panic_check_color_byte(test, vaddr[i]);
157+
158+
kunmap_local(vaddr);
159+
}
160+
161+
free_pages:
162+
for (p = 0; p < npages; p++)
163+
__free_page(pages[p]);
164+
kfree(pages);
165+
}
166+
167+
static void drm_test_panic_set_pixel(struct drm_scanout_buffer *sb,
168+
unsigned int x,
169+
unsigned int y,
170+
u32 color)
171+
{
172+
struct kunit *test = (struct kunit *)sb->private;
173+
174+
KUNIT_ASSERT_TRUE(test, x < sb->width && y < sb->height);
175+
}
176+
177+
/*
178+
* Test drawing the panic screen, using the set_pixel callback
179+
* Check that all calls to set_pixel() are within the framebuffer
180+
*/
181+
static void drm_test_panic_screen_user_set_pixel(struct kunit *test)
182+
{
183+
struct drm_scanout_buffer *sb = test->priv;
184+
const struct drm_test_mode *params = test->param_value;
185+
186+
sb->format = drm_format_info(params->format);
187+
sb->set_pixel = drm_test_panic_set_pixel;
188+
sb->width = params->width;
189+
sb->height = params->height;
190+
sb->private = test;
191+
192+
params->draw_screen(sb);
193+
}
194+
195+
static void drm_test_panic_desc(const struct drm_test_mode *t, char *desc)
196+
{
197+
sprintf(desc, "Panic screen %s, mode: %d x %d \t%p4cc",
198+
t->fname, t->width, t->height, &t->format);
199+
}
200+
201+
KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_map, drm_test_modes_cases, drm_test_panic_desc);
202+
KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_page, drm_test_modes_cases, drm_test_panic_desc);
203+
KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_set_pixel, drm_test_modes_cases, drm_test_panic_desc);
204+
205+
static struct kunit_case drm_panic_screen_user_test[] = {
206+
KUNIT_CASE_PARAM(drm_test_panic_screen_user_map,
207+
drm_test_panic_screen_user_map_gen_params),
208+
KUNIT_CASE_PARAM(drm_test_panic_screen_user_page,
209+
drm_test_panic_screen_user_page_gen_params),
210+
KUNIT_CASE_PARAM(drm_test_panic_screen_user_set_pixel,
211+
drm_test_panic_screen_user_set_pixel_gen_params),
212+
{ }
213+
};
214+
215+
static struct kunit_suite drm_panic_suite = {
216+
.name = "drm_panic",
217+
.init = drm_test_panic_init,
218+
.test_cases = drm_panic_screen_user_test,
219+
};
220+
221+
kunit_test_suite(drm_panic_suite);

0 commit comments

Comments
 (0)