drm_panic_test.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  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. #include <drm/drm_fourcc.h>
  9. #include <drm/drm_panic.h>
  10. #include <kunit/test.h>
  11. #include <linux/units.h>
  12. #include <linux/vmalloc.h>
  13. /* Check the framebuffer color only if the panic colors are the default */
  14. #if (CONFIG_DRM_PANIC_BACKGROUND_COLOR == 0 && \
  15. CONFIG_DRM_PANIC_FOREGROUND_COLOR == 0xffffff)
  16. static void drm_panic_check_color_byte(struct kunit *test, u8 b)
  17. {
  18. KUNIT_EXPECT_TRUE(test, (b == 0 || b == 0xff));
  19. }
  20. #else
  21. static void drm_panic_check_color_byte(struct kunit *test, u8 b) {}
  22. #endif
  23. struct drm_test_mode {
  24. const int width;
  25. const int height;
  26. const u32 format;
  27. void (*draw_screen)(struct drm_scanout_buffer *sb);
  28. const char *fname;
  29. };
  30. /*
  31. * Run all tests for the 3 panic screens: user, kmsg and qr_code
  32. */
  33. #define DRM_TEST_MODE_LIST(func) \
  34. DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_XRGB8888, func) \
  35. DRM_PANIC_TEST_MODE(300, 200, DRM_FORMAT_XRGB8888, func) \
  36. DRM_PANIC_TEST_MODE(1920, 1080, DRM_FORMAT_XRGB8888, func) \
  37. DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB565, func) \
  38. DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB888, func) \
  39. #define DRM_PANIC_TEST_MODE(w, h, f, name) { \
  40. .width = w, \
  41. .height = h, \
  42. .format = f, \
  43. .draw_screen = draw_panic_screen_##name, \
  44. .fname = #name, \
  45. }, \
  46. static const struct drm_test_mode drm_test_modes_cases[] = {
  47. DRM_TEST_MODE_LIST(user)
  48. DRM_TEST_MODE_LIST(kmsg)
  49. #if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)
  50. DRM_TEST_MODE_LIST(qr_code)
  51. #endif
  52. };
  53. #undef DRM_PANIC_TEST_MODE
  54. static int drm_test_panic_init(struct kunit *test)
  55. {
  56. struct drm_scanout_buffer *priv;
  57. priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
  58. KUNIT_ASSERT_NOT_NULL(test, priv);
  59. test->priv = priv;
  60. drm_panic_set_description("Kunit testing");
  61. return 0;
  62. }
  63. /*
  64. * Test drawing the panic screen, using a memory mapped framebuffer
  65. * Set the whole buffer to 0xa5, and then check that all pixels have been
  66. * written.
  67. */
  68. static void drm_test_panic_screen_user_map(struct kunit *test)
  69. {
  70. struct drm_scanout_buffer *sb = test->priv;
  71. const struct drm_test_mode *params = test->param_value;
  72. char *fb;
  73. int fb_size;
  74. int i;
  75. sb->format = drm_format_info(params->format);
  76. fb_size = params->width * params->height * sb->format->cpp[0];
  77. fb = vmalloc(fb_size);
  78. KUNIT_ASSERT_NOT_NULL(test, fb);
  79. memset(fb, 0xa5, fb_size);
  80. iosys_map_set_vaddr(&sb->map[0], fb);
  81. sb->width = params->width;
  82. sb->height = params->height;
  83. sb->pitch[0] = params->width * sb->format->cpp[0];
  84. params->draw_screen(sb);
  85. for (i = 0; i < fb_size; i++)
  86. drm_panic_check_color_byte(test, fb[i]);
  87. vfree(fb);
  88. }
  89. /*
  90. * Test drawing the panic screen, using a list of pages framebuffer
  91. * Set the whole buffer to 0xa5, and then check that all pixels have been
  92. * written.
  93. */
  94. static void drm_test_panic_screen_user_page(struct kunit *test)
  95. {
  96. struct drm_scanout_buffer *sb = test->priv;
  97. const struct drm_test_mode *params = test->param_value;
  98. int fb_size, p, i, npages;
  99. struct page **pages;
  100. u8 *vaddr;
  101. sb->format = drm_format_info(params->format);
  102. fb_size = params->width * params->height * sb->format->cpp[0];
  103. npages = DIV_ROUND_UP(fb_size, PAGE_SIZE);
  104. pages = kmalloc_objs(struct page *, npages);
  105. KUNIT_ASSERT_NOT_NULL(test, pages);
  106. for (p = 0; p < npages; p++) {
  107. pages[p] = alloc_page(GFP_KERNEL);
  108. if (!pages[p]) {
  109. npages = p - 1;
  110. KUNIT_FAIL(test, "Can't allocate page\n");
  111. goto free_pages;
  112. }
  113. vaddr = kmap_local_page(pages[p]);
  114. memset(vaddr, 0xa5, PAGE_SIZE);
  115. kunmap_local(vaddr);
  116. }
  117. sb->pages = pages;
  118. sb->width = params->width;
  119. sb->height = params->height;
  120. sb->pitch[0] = params->width * sb->format->cpp[0];
  121. params->draw_screen(sb);
  122. for (p = 0; p < npages; p++) {
  123. int bytes_in_page = (p == npages - 1) ? fb_size - p * PAGE_SIZE : PAGE_SIZE;
  124. vaddr = kmap_local_page(pages[p]);
  125. for (i = 0; i < bytes_in_page; i++)
  126. drm_panic_check_color_byte(test, vaddr[i]);
  127. kunmap_local(vaddr);
  128. }
  129. free_pages:
  130. for (p = 0; p < npages; p++)
  131. __free_page(pages[p]);
  132. kfree(pages);
  133. }
  134. static void drm_test_panic_set_pixel(struct drm_scanout_buffer *sb,
  135. unsigned int x,
  136. unsigned int y,
  137. u32 color)
  138. {
  139. struct kunit *test = (struct kunit *)sb->private;
  140. KUNIT_ASSERT_TRUE(test, x < sb->width && y < sb->height);
  141. }
  142. /*
  143. * Test drawing the panic screen, using the set_pixel callback
  144. * Check that all calls to set_pixel() are within the framebuffer
  145. */
  146. static void drm_test_panic_screen_user_set_pixel(struct kunit *test)
  147. {
  148. struct drm_scanout_buffer *sb = test->priv;
  149. const struct drm_test_mode *params = test->param_value;
  150. sb->format = drm_format_info(params->format);
  151. sb->set_pixel = drm_test_panic_set_pixel;
  152. sb->width = params->width;
  153. sb->height = params->height;
  154. sb->private = test;
  155. params->draw_screen(sb);
  156. }
  157. static void drm_test_panic_desc(const struct drm_test_mode *t, char *desc)
  158. {
  159. sprintf(desc, "Panic screen %s, mode: %d x %d \t%p4cc",
  160. t->fname, t->width, t->height, &t->format);
  161. }
  162. KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_map, drm_test_modes_cases, drm_test_panic_desc);
  163. KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_page, drm_test_modes_cases, drm_test_panic_desc);
  164. KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_set_pixel, drm_test_modes_cases, drm_test_panic_desc);
  165. static struct kunit_case drm_panic_screen_user_test[] = {
  166. KUNIT_CASE_PARAM(drm_test_panic_screen_user_map,
  167. drm_test_panic_screen_user_map_gen_params),
  168. KUNIT_CASE_PARAM(drm_test_panic_screen_user_page,
  169. drm_test_panic_screen_user_page_gen_params),
  170. KUNIT_CASE_PARAM(drm_test_panic_screen_user_set_pixel,
  171. drm_test_panic_screen_user_set_pixel_gen_params),
  172. { }
  173. };
  174. static struct kunit_suite drm_panic_suite = {
  175. .name = "drm_panic",
  176. .init = drm_test_panic_init,
  177. .test_cases = drm_panic_screen_user_test,
  178. };
  179. kunit_test_suite(drm_panic_suite);