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); 222