Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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>

+226
+1
MAINTAINERS
··· 8749 8749 F: drivers/gpu/drm/drm_draw.c 8750 8750 F: drivers/gpu/drm/drm_draw_internal.h 8751 8751 F: drivers/gpu/drm/drm_panic*.c 8752 + F: drivers/gpu/drm/tests/drm_panic_test.c 8752 8753 F: include/drm/drm_panic* 8753 8754 8754 8755 DRM PANIC QR CODE
+4
drivers/gpu/drm/drm_panic.c
··· 1084 1084 { 1085 1085 drm_panic_qr_exit(); 1086 1086 } 1087 + 1088 + #ifdef CONFIG_DRM_KUNIT_TEST 1089 + #include "tests/drm_panic_test.c" 1090 + #endif
+221
drivers/gpu/drm/tests/drm_panic_test.c
··· 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);