221 lines · 5.8 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0 or MIT/* * Copyright (c) 2025 Red Hat. * Author: Jocelyn Falempe <jfalempe@redhat.com> * * KUNIT tests for drm panic */ #include <drm/drm_fourcc.h>#include <drm/drm_panic.h> #include <kunit/test.h> #include <linux/units.h>#include <linux/vmalloc.h> /* Check the framebuffer color only if the panic colors are the default */#if (CONFIG_DRM_PANIC_BACKGROUND_COLOR == 0 && \	CONFIG_DRM_PANIC_FOREGROUND_COLOR == 0xffffff) static void drm_panic_check_color_byte(struct kunit *test, u8 b){	KUNIT_EXPECT_TRUE(test, (b == 0 || b == 0xff));}#elsestatic void drm_panic_check_color_byte(struct kunit *test, u8 b) {}#endif struct drm_test_mode {	const int width;	const int height;	const u32 format;	void (*draw_screen)(struct drm_scanout_buffer *sb);	const char *fname;}; /* * Run all tests for the 3 panic screens: user, kmsg and qr_code */#define DRM_TEST_MODE_LIST(func) \	DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_XRGB8888, func) \	DRM_PANIC_TEST_MODE(300, 200, DRM_FORMAT_XRGB8888, func) \	DRM_PANIC_TEST_MODE(1920, 1080, DRM_FORMAT_XRGB8888, func) \	DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB565, func) \	DRM_PANIC_TEST_MODE(1024, 768, DRM_FORMAT_RGB888, func) \ #define DRM_PANIC_TEST_MODE(w, h, f, name) { \	.width = w, \	.height = h, \	.format = f, \	.draw_screen = draw_panic_screen_##name, \	.fname = #name, \	}, \ static const struct drm_test_mode drm_test_modes_cases[] = {	DRM_TEST_MODE_LIST(user)	DRM_TEST_MODE_LIST(kmsg)#if IS_ENABLED(CONFIG_DRM_PANIC_SCREEN_QR_CODE)	DRM_TEST_MODE_LIST(qr_code)#endif}; #undef DRM_PANIC_TEST_MODE static int drm_test_panic_init(struct kunit *test){	struct drm_scanout_buffer *priv; 	priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);	KUNIT_ASSERT_NOT_NULL(test, priv); 	test->priv = priv; 	drm_panic_set_description("Kunit testing"); 	return 0;} /* * Test drawing the panic screen, using a memory mapped framebuffer * Set the whole buffer to 0xa5, and then check that all pixels have been * written. */static void drm_test_panic_screen_user_map(struct kunit *test){	struct drm_scanout_buffer *sb = test->priv;	const struct drm_test_mode *params = test->param_value;	char *fb;	int fb_size;	int i; 	sb->format = drm_format_info(params->format);	fb_size = params->width * params->height * sb->format->cpp[0]; 	fb = vmalloc(fb_size);	KUNIT_ASSERT_NOT_NULL(test, fb); 	memset(fb, 0xa5, fb_size); 	iosys_map_set_vaddr(&sb->map[0], fb);	sb->width = params->width;	sb->height = params->height;	sb->pitch[0] = params->width * sb->format->cpp[0]; 	params->draw_screen(sb); 	for (i = 0; i < fb_size; i++)		drm_panic_check_color_byte(test, fb[i]); 	vfree(fb);} /* * Test drawing the panic screen, using a list of pages framebuffer * Set the whole buffer to 0xa5, and then check that all pixels have been * written. */static void drm_test_panic_screen_user_page(struct kunit *test){	struct drm_scanout_buffer *sb = test->priv;	const struct drm_test_mode *params = test->param_value;	int fb_size, p, i, npages;	struct page **pages;	u8 *vaddr; 	sb->format = drm_format_info(params->format);	fb_size = params->width * params->height * sb->format->cpp[0];	npages = DIV_ROUND_UP(fb_size, PAGE_SIZE); 	pages = kmalloc_objs(struct page *, npages);	KUNIT_ASSERT_NOT_NULL(test, pages); 	for (p = 0; p < npages; p++) {		pages[p] = alloc_page(GFP_KERNEL);		if (!pages[p]) {			npages = p - 1;			KUNIT_FAIL(test, "Can't allocate page\n");			goto free_pages;		}		vaddr = kmap_local_page(pages[p]);		memset(vaddr, 0xa5, PAGE_SIZE);		kunmap_local(vaddr);	}	sb->pages = pages;	sb->width = params->width;	sb->height = params->height;	sb->pitch[0] = params->width * sb->format->cpp[0]; 	params->draw_screen(sb); 	for (p = 0; p < npages; p++) {		int bytes_in_page = (p == npages - 1) ? fb_size - p * PAGE_SIZE : PAGE_SIZE; 		vaddr = kmap_local_page(pages[p]);		for (i = 0; i < bytes_in_page; i++)			drm_panic_check_color_byte(test, vaddr[i]); 		kunmap_local(vaddr);	} free_pages:	for (p = 0; p < npages; p++)		__free_page(pages[p]);	kfree(pages);} static void drm_test_panic_set_pixel(struct drm_scanout_buffer *sb,				     unsigned int x,				     unsigned int y,				     u32 color){	struct kunit *test = (struct kunit *)sb->private; 	KUNIT_ASSERT_TRUE(test, x < sb->width && y < sb->height);} /* * Test drawing the panic screen, using the set_pixel callback * Check that all calls to set_pixel() are within the framebuffer */static void drm_test_panic_screen_user_set_pixel(struct kunit *test){	struct drm_scanout_buffer *sb = test->priv;	const struct drm_test_mode *params = test->param_value; 	sb->format = drm_format_info(params->format);	sb->set_pixel = drm_test_panic_set_pixel;	sb->width = params->width;	sb->height = params->height;	sb->private = test; 	params->draw_screen(sb);} static void drm_test_panic_desc(const struct drm_test_mode *t, char *desc){	sprintf(desc, "Panic screen %s, mode: %d x %d \t%p4cc",		t->fname, t->width, t->height, &t->format);} KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_map, drm_test_modes_cases, drm_test_panic_desc);KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_page, drm_test_modes_cases, drm_test_panic_desc);KUNIT_ARRAY_PARAM(drm_test_panic_screen_user_set_pixel, drm_test_modes_cases, drm_test_panic_desc); static struct kunit_case drm_panic_screen_user_test[] = {	KUNIT_CASE_PARAM(drm_test_panic_screen_user_map,			 drm_test_panic_screen_user_map_gen_params),	KUNIT_CASE_PARAM(drm_test_panic_screen_user_page,			 drm_test_panic_screen_user_page_gen_params),	KUNIT_CASE_PARAM(drm_test_panic_screen_user_set_pixel,			 drm_test_panic_screen_user_set_pixel_gen_params),	{ }}; static struct kunit_suite drm_panic_suite = {	.name = "drm_panic",	.init = drm_test_panic_init,	.test_cases = drm_panic_screen_user_test,}; kunit_test_suite(drm_panic_suite);