All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-17 23:22 ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

KUnit unifies the test structure and provides helper tools that simplify
the development. Basic use case allows running tests as regular processes,
leveraging User Mode Linux.
For example, to execute all DRM unit tests:
./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
(the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)

For developers - it means that it's easier to run unit tests on the development
machine, tightening the feedback loop. When using UML, it also simplifies using
gdb for debug (since the kernel is just a regular process).
For CI systems - DRM tests can be moved from being executed on device under
test (that's also running IGTs and so on) to being executed on buildsystem
during build (just like checkpatch.pl).

All tests were renamed - IGT prefix is no longer used.

Compared to selftests executed by CI using IGT, there's one functional
regression - KUnit test runner is not catching WARNs.
To solve this, we could either go in the similar direction that UBSAN went in:
1195505 ("kunit: ubsan integration")
Or we could expand the test runner to catch WARN signature in dmesg.

Pastebin to preview the output and execution times:
https://gitlab.freedesktop.org/-/snippets/4139

-Michał

Michał Winiarski (10):
  drm: test-drm_cmdline_parser: Convert to KUnit
  drm: test-drm_plane_helper: Convert to KUnit
  drm: test-drm_format: Convert to KUnit
  drm: test-drm_framebuffer: Convert to KUnit
  drm: test-drm_damage_helper: Convert to KUnit
  drm: test-drm_dp_mst_helper: Convert to KUnit
  drm: test-drm_rect: Convert to KUnit
  drm: test-drm_mm: Convert to KUnit
  drm: selftests: Convert to KUnit
  drm: test: Simplify testing on UML with kunit.py

 drivers/gpu/drm/.kunitconfig                  |    3 +
 drivers/gpu/drm/Kconfig                       |   22 +-
 drivers/gpu/drm/Makefile                      |    2 +-
 drivers/gpu/drm/i915/Kconfig.debug            |    1 -
 drivers/gpu/drm/selftests/Makefile            |    7 -
 .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
 drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
 .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
 drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
 drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
 .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
 .../drm/selftests/test-drm_damage_helper.c    |  667 -----
 .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
 drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
 drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
 .../drm/selftests/test-drm_modeset_common.c   |   32 -
 .../drm/selftests/test-drm_modeset_common.h   |   52 -
 .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
 drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
 drivers/gpu/drm/test/Makefile                 |    7 +
 .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
 drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
 drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
 drivers/gpu/drm/test/test-drm_format.c        |  356 +++
 .../test-drm_framebuffer.c                    |  109 +-
 drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
 drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
 drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
 drivers/video/Kconfig                         |    4 +
 29 files changed, 5558 insertions(+), 5727 deletions(-)
 create mode 100644 drivers/gpu/drm/.kunitconfig
 delete mode 100644 drivers/gpu/drm/selftests/Makefile
 delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
 create mode 100644 drivers/gpu/drm/test/Makefile
 create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
 create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_format.c
 rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
 create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
 create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_rect.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-17 23:22 ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

KUnit unifies the test structure and provides helper tools that simplify
the development. Basic use case allows running tests as regular processes,
leveraging User Mode Linux.
For example, to execute all DRM unit tests:
./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
(the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)

For developers - it means that it's easier to run unit tests on the development
machine, tightening the feedback loop. When using UML, it also simplifies using
gdb for debug (since the kernel is just a regular process).
For CI systems - DRM tests can be moved from being executed on device under
test (that's also running IGTs and so on) to being executed on buildsystem
during build (just like checkpatch.pl).

All tests were renamed - IGT prefix is no longer used.

Compared to selftests executed by CI using IGT, there's one functional
regression - KUnit test runner is not catching WARNs.
To solve this, we could either go in the similar direction that UBSAN went in:
1195505 ("kunit: ubsan integration")
Or we could expand the test runner to catch WARN signature in dmesg.

Pastebin to preview the output and execution times:
https://gitlab.freedesktop.org/-/snippets/4139

-Michał

Michał Winiarski (10):
  drm: test-drm_cmdline_parser: Convert to KUnit
  drm: test-drm_plane_helper: Convert to KUnit
  drm: test-drm_format: Convert to KUnit
  drm: test-drm_framebuffer: Convert to KUnit
  drm: test-drm_damage_helper: Convert to KUnit
  drm: test-drm_dp_mst_helper: Convert to KUnit
  drm: test-drm_rect: Convert to KUnit
  drm: test-drm_mm: Convert to KUnit
  drm: selftests: Convert to KUnit
  drm: test: Simplify testing on UML with kunit.py

 drivers/gpu/drm/.kunitconfig                  |    3 +
 drivers/gpu/drm/Kconfig                       |   22 +-
 drivers/gpu/drm/Makefile                      |    2 +-
 drivers/gpu/drm/i915/Kconfig.debug            |    1 -
 drivers/gpu/drm/selftests/Makefile            |    7 -
 .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
 drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
 .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
 drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
 drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
 .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
 .../drm/selftests/test-drm_damage_helper.c    |  667 -----
 .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
 drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
 drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
 .../drm/selftests/test-drm_modeset_common.c   |   32 -
 .../drm/selftests/test-drm_modeset_common.h   |   52 -
 .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
 drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
 drivers/gpu/drm/test/Makefile                 |    7 +
 .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
 drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
 drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
 drivers/gpu/drm/test/test-drm_format.c        |  356 +++
 .../test-drm_framebuffer.c                    |  109 +-
 drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
 drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
 drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
 drivers/video/Kconfig                         |    4 +
 29 files changed, 5558 insertions(+), 5727 deletions(-)
 create mode 100644 drivers/gpu/drm/.kunitconfig
 delete mode 100644 drivers/gpu/drm/selftests/Makefile
 delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
 create mode 100644 drivers/gpu/drm/test/Makefile
 create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
 create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_format.c
 rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
 create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
 create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
 create mode 100644 drivers/gpu/drm/test/test-drm_rect.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [RFC 01/10] drm: test-drm_cmdline_parser: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

One-to-one conversion, no functional changes.
Negative tests were merged into single parameterized test case.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |   12 +
 drivers/gpu/drm/Makefile                      |    2 +-
 drivers/gpu/drm/selftests/Makefile            |    8 +-
 .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
 .../drm/selftests/test-drm_cmdline_parser.c   | 1680 ++++++++---------
 5 files changed, 802 insertions(+), 968 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b1f22e457fd0..21e329f32997 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -80,6 +80,18 @@ config DRM_DEBUG_SELFTEST
 
 	  If in doubt, say "N".
 
+config DRM_KUNIT_TEST
+	bool "DRM tests" if !KUNIT_ALL_TESTS
+	depends on DRM=y && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  Enables unit tests for DRM. Only useful for kernel devs running KUnit.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 301a44dc18e3..550800e81836 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -65,7 +65,7 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
+obj-y += selftests/
 
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 0856e4b12f70..6411c9a957b3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
-test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
+test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
+		      test-drm_modeset_common.o test-drm_plane_helper.o \
                       test-drm_format.o test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+
+obj-$(CONFIG_DRM_KUNIT_TEST) := \
+	test-drm_cmdline_parser.o
diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
deleted file mode 100644
index 29e367db6118..000000000000
--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_mm
- */
-
-#define cmdline_test(test)	selftest(test, test)
-
-cmdline_test(drm_cmdline_test_force_d_only)
-cmdline_test(drm_cmdline_test_force_D_only_dvi)
-cmdline_test(drm_cmdline_test_force_D_only_hdmi)
-cmdline_test(drm_cmdline_test_force_D_only_not_digital)
-cmdline_test(drm_cmdline_test_force_e_only)
-cmdline_test(drm_cmdline_test_margin_only)
-cmdline_test(drm_cmdline_test_interlace_only)
-cmdline_test(drm_cmdline_test_res)
-cmdline_test(drm_cmdline_test_res_missing_x)
-cmdline_test(drm_cmdline_test_res_missing_y)
-cmdline_test(drm_cmdline_test_res_bad_y)
-cmdline_test(drm_cmdline_test_res_missing_y_bpp)
-cmdline_test(drm_cmdline_test_res_vesa)
-cmdline_test(drm_cmdline_test_res_vesa_rblank)
-cmdline_test(drm_cmdline_test_res_rblank)
-cmdline_test(drm_cmdline_test_res_bpp)
-cmdline_test(drm_cmdline_test_res_bad_bpp)
-cmdline_test(drm_cmdline_test_res_refresh)
-cmdline_test(drm_cmdline_test_res_bad_refresh)
-cmdline_test(drm_cmdline_test_res_bpp_refresh)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_margins)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_off)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_off)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_analog)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_digital)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on)
-cmdline_test(drm_cmdline_test_res_margins_force_on)
-cmdline_test(drm_cmdline_test_res_vesa_margins)
-cmdline_test(drm_cmdline_test_res_invalid_mode)
-cmdline_test(drm_cmdline_test_res_bpp_wrong_place_mode)
-cmdline_test(drm_cmdline_test_name)
-cmdline_test(drm_cmdline_test_name_bpp)
-cmdline_test(drm_cmdline_test_name_refresh)
-cmdline_test(drm_cmdline_test_name_bpp_refresh)
-cmdline_test(drm_cmdline_test_name_refresh_wrong_mode)
-cmdline_test(drm_cmdline_test_name_refresh_invalid_mode)
-cmdline_test(drm_cmdline_test_name_option)
-cmdline_test(drm_cmdline_test_name_bpp_option)
-cmdline_test(drm_cmdline_test_rotate_0)
-cmdline_test(drm_cmdline_test_rotate_90)
-cmdline_test(drm_cmdline_test_rotate_180)
-cmdline_test(drm_cmdline_test_rotate_270)
-cmdline_test(drm_cmdline_test_rotate_multiple)
-cmdline_test(drm_cmdline_test_rotate_invalid_val)
-cmdline_test(drm_cmdline_test_rotate_truncated)
-cmdline_test(drm_cmdline_test_hmirror)
-cmdline_test(drm_cmdline_test_vmirror)
-cmdline_test(drm_cmdline_test_margin_options)
-cmdline_test(drm_cmdline_test_multiple_options)
-cmdline_test(drm_cmdline_test_invalid_option)
-cmdline_test(drm_cmdline_test_bpp_extra_and_option)
-cmdline_test(drm_cmdline_test_extra_and_option)
-cmdline_test(drm_cmdline_test_freestanding_options)
-cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
-cmdline_test(drm_cmdline_test_panel_orientation)
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
index d96cd890def6..ffe5a483320a 100644
--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
@@ -3,1139 +3,1025 @@
  * Copyright (c) 2019 Bootlin
  */
 
-#define pr_fmt(fmt) "drm_cmdline: " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <kunit/test.h>
 
 #include <drm/drm_connector.h>
 #include <drm/drm_modes.h>
 
-#define TESTS "drm_cmdline_selftests.h"
-#include "drm_selftest.h"
-#include "test-drm_modeset_common.h"
-
 static const struct drm_connector no_connector = {};
 
-static int drm_cmdline_test_force_e_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("e",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static int drm_cmdline_test_force_D_only_not_digital(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static const struct drm_connector connector_hdmi = {
-	.connector_type	= DRM_MODE_CONNECTOR_HDMIB,
-};
-
-static int drm_cmdline_test_force_D_only_hdmi(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &connector_hdmi,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
-}
-
-static const struct drm_connector connector_dvi = {
-	.connector_type	= DRM_MODE_CONNECTOR_DVII,
-};
-
-static int drm_cmdline_test_force_D_only_dvi(void *ignored)
+static void drm_cmdline_test_force_e_only(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &connector_dvi,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
-}
-
-static int drm_cmdline_test_force_d_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("d",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_OFF);
-
-	return 0;
+	const char *cmdline = "e";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_margin_only(void *ignored)
+static void drm_cmdline_test_force_D_only_not_digital(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("m",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_interlace_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("i",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_missing_x(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_missing_y(void *ignored)
+static void drm_cmdline_test_force_D_only_hdmi(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const struct drm_connector connector_hdmi = {
+		.connector_type	= DRM_MODE_CONNECTOR_HDMIB,
+	};
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector_hdmi,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_bad_y(void *ignored)
+static void drm_cmdline_test_force_D_only_dvi(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const struct drm_connector connector_dvi = {
+		.connector_type = DRM_MODE_CONNECTOR_DVII,
+	};
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector_dvi,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
+static void drm_cmdline_test_force_d_only(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "d";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF);
 }
 
-static int drm_cmdline_test_res_vesa(void *ignored)
+static void drm_cmdline_test_res(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_vesa_rblank(void *ignored)
+static void drm_cmdline_test_res_vesa(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480M";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_rblank(void *ignored)
+static void drm_cmdline_test_res_vesa_rblank(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480MR";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(!mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp(void *ignored)
+static void drm_cmdline_test_res_rblank(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480R";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bad_bpp(void *ignored)
+static void drm_cmdline_test_res_bpp(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480-24";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_res_bad_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh(void *ignored)
+static void drm_cmdline_test_res_refresh(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480@60";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
 
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(!mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24@60";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_interlaced(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24@60i";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_TRUE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_margins(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_OFF);
-
-	return 0;
+	const char *cmdline = "720x480-24@60m";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_off(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "720x480-24@60d";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60e";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on_analog(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on_digital(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-	static const struct drm_connector connector = {
+	const struct drm_connector connector = {
 		.connector_type = DRM_MODE_CONNECTOR_DVII,
 	};
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
-							   &connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
+	const char *cmdline = "720x480-24@60D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(!mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60ime";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_TRUE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_margins_force_on(void *ignored)
+static void drm_cmdline_test_res_margins_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480me";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_vesa_margins(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_res_invalid_mode(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
+static void drm_cmdline_test_res_vesa_margins(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480Mm";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_name(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_name_bpp(void *ignored)
+static void drm_cmdline_test_name(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	return 0;
+	const char *cmdline = "NTSC";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 }
 
-static int drm_cmdline_test_name_bpp_refresh(void *ignored)
+static void drm_cmdline_test_name_bpp(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "NTSC-24";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
 
-	return 0;
-}
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-static int drm_cmdline_test_name_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 }
 
-static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
+static void drm_cmdline_test_name_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "NTSC,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
 }
 
-static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
+static void drm_cmdline_test_name_bpp_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "NTSC-24,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 }
 
-static int drm_cmdline_test_name_option(void *ignored)
+static void drm_cmdline_test_rotate_0(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=0";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_0);
 
-	return 0;
-}
-
-static int drm_cmdline_test_name_bpp_option(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_0(void *ignored)
+static void drm_cmdline_test_rotate_90(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=90";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_0);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_90);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_90(void *ignored)
+static void drm_cmdline_test_rotate_180(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=180";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_90);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_180(void *ignored)
+static void drm_cmdline_test_rotate_270(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=270";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_270);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_270(void *ignored)
+static void drm_cmdline_test_hmirror(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,reflect_x";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_270);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X));
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_multiple(void *ignored)
+static void drm_cmdline_test_vmirror(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,reflect_y";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=0,rotate=90",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y));
 
-	return 0;
-}
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-static int drm_cmdline_test_rotate_invalid_val(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_truncated(void *ignored)
+static void drm_cmdline_test_margin_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline =
+		"720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_hmirror(void *ignored)
+static void drm_cmdline_test_multiple_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=270,reflect_x";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X));
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_vmirror(void *ignored)
+static void drm_cmdline_test_bpp_extra_and_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24e,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_margin_options(void *ignored)
+static void drm_cmdline_test_extra_and_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480e,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_multiple_options(void *ignored)
+static void drm_cmdline_test_freestanding_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_invalid_option(void *ignored)
+static void drm_cmdline_test_freestanding_force_e_and_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_bpp_extra_and_option(void *ignored)
+static void drm_cmdline_test_panel_orientation(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "panel_orientation=upside_down";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.panel_orientation, DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_extra_and_option(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
+struct drm_cmdline_negative_test {
+	const char *name;
+	const char *cmdline;
+};
 
-static int drm_cmdline_test_freestanding_options(void *ignored)
+static void drm_cmdline_test_negative(struct kunit *test)
 {
+	const struct drm_cmdline_negative_test *params = test->param_value;
 	struct drm_cmdline_mode mode = { };
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(params->cmdline,
+									   &no_connector,
+									   &mode));
 }
 
-static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
+static const struct drm_cmdline_negative_test drm_cmdline_negative_tests[] = {
+	{
+		.name = "margin_only",
+		.cmdline = "m",
+	},
+	{
+		.name = "interlace_only",
+		.cmdline = "i",
+	},
+	{
+		.name = "res_missing_x",
+		.cmdline = "x480",
+	},
+	{
+		.name = "res_missing_y",
+		.cmdline = "1024x",
+	},
+	{
+		.name = "res_bad_y",
+		.cmdline = "1024xtest",
+	},
+	{
+		.name = "res_missing_y_bpp",
+		.cmdline = "1024x-24",
+	},
+	{
+		.name = "res_bad_bpp",
+		.cmdline = "720x480-test",
+	},
+	{
+		.name = "res_bad_refresh",
+		.cmdline = "720x480@refresh",
+	},
+	{
+		.name = "res_bpp_refresh_force_on_off",
+		.cmdline = "720x480-24@60de",
+	},
+	{
+		.name = "res_invalid_mode",
+		.cmdline = "720x480f",
+	},
+	{
+		.name = "res_bpp_wrong_place_mode",
+		.cmdline = "720x480e-24",
+	},
+	{
+		.name = "name_bpp_refresh",
+		.cmdline = "NTSC-24@60",
+	},
+	{
+		.name = "name_refresh",
+		.cmdline = "NTSC@60",
+	},
+	{
+		.name = "name_refresh_wrong_mode",
+		.cmdline = "NTSC@60m",
+	},
+	{
+		.name = "name_refresh_invalid_mode",
+		.cmdline = "NTSC@60f",
+	},
+	{
+		.name = "rotate_multiple",
+		.cmdline = "720x480,rotate=0,rotate=90",
+	},
+	{
+		.name = "rotate_invalid_val",
+		.cmdline = "720x480,rotate=42",
+	},
+	{
+		.name = "rotate_truncated",
+		.cmdline = "720x480,rotate=",
+	},
+	{
+		.name = "invalid_option",
+		.cmdline = "720x480,test=42",
+	},
+};
 
-static int drm_cmdline_test_panel_orientation(void *ignored)
+static void drm_cmdline_negative_desc(const struct drm_cmdline_negative_test *t,
+				      char *desc)
 {
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	sprintf(desc, "%s", t->name);
 }
 
-#include "drm_selftest.c"
-
-static int __init test_drm_cmdline_init(void)
-{
-	int err;
+KUNIT_ARRAY_PARAM(drm_cmdline_negative, drm_cmdline_negative_tests, drm_cmdline_negative_desc);
+
+static struct kunit_case drm_cmdline_tests[] = {
+	KUNIT_CASE(drm_cmdline_test_force_d_only),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_dvi),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_hdmi),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_not_digital),
+	KUNIT_CASE(drm_cmdline_test_force_e_only),
+	KUNIT_CASE(drm_cmdline_test_res),
+	KUNIT_CASE(drm_cmdline_test_res_vesa),
+	KUNIT_CASE(drm_cmdline_test_res_vesa_rblank),
+	KUNIT_CASE(drm_cmdline_test_res_rblank),
+	KUNIT_CASE(drm_cmdline_test_res_bpp),
+	KUNIT_CASE(drm_cmdline_test_res_refresh),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_margins),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_off),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_analog),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_digital),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_margins_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_vesa_margins),
+	KUNIT_CASE(drm_cmdline_test_name),
+	KUNIT_CASE(drm_cmdline_test_name_bpp),
+	KUNIT_CASE(drm_cmdline_test_name_option),
+	KUNIT_CASE(drm_cmdline_test_name_bpp_option),
+	KUNIT_CASE(drm_cmdline_test_rotate_0),
+	KUNIT_CASE(drm_cmdline_test_rotate_90),
+	KUNIT_CASE(drm_cmdline_test_rotate_180),
+	KUNIT_CASE(drm_cmdline_test_rotate_270),
+	KUNIT_CASE(drm_cmdline_test_hmirror),
+	KUNIT_CASE(drm_cmdline_test_vmirror),
+	KUNIT_CASE(drm_cmdline_test_margin_options),
+	KUNIT_CASE(drm_cmdline_test_multiple_options),
+	KUNIT_CASE(drm_cmdline_test_bpp_extra_and_option),
+	KUNIT_CASE(drm_cmdline_test_extra_and_option),
+	KUNIT_CASE(drm_cmdline_test_freestanding_options),
+	KUNIT_CASE(drm_cmdline_test_freestanding_force_e_and_options),
+	KUNIT_CASE(drm_cmdline_test_panel_orientation),
+	KUNIT_CASE_PARAM(drm_cmdline_test_negative, drm_cmdline_negative_gen_params),
+	{}
+};
 
-	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+static struct kunit_suite drm_cmdline_test_suite = {
+	.name = "drm_cmdline_tests",
+	.test_cases = drm_cmdline_tests,
+};
 
-	return err > 0 ? 0 : err;
-}
-module_init(test_drm_cmdline_init);
+kunit_test_suite(drm_cmdline_test_suite);
 
 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
 MODULE_LICENSE("GPL");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 01/10] drm: test-drm_cmdline_parser: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

One-to-one conversion, no functional changes.
Negative tests were merged into single parameterized test case.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |   12 +
 drivers/gpu/drm/Makefile                      |    2 +-
 drivers/gpu/drm/selftests/Makefile            |    8 +-
 .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
 .../drm/selftests/test-drm_cmdline_parser.c   | 1680 ++++++++---------
 5 files changed, 802 insertions(+), 968 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index b1f22e457fd0..21e329f32997 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -80,6 +80,18 @@ config DRM_DEBUG_SELFTEST
 
 	  If in doubt, say "N".
 
+config DRM_KUNIT_TEST
+	bool "DRM tests" if !KUNIT_ALL_TESTS
+	depends on DRM=y && KUNIT=y
+	default KUNIT_ALL_TESTS
+	help
+	  Enables unit tests for DRM. Only useful for kernel devs running KUnit.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
+
 config DRM_KMS_HELPER
 	tristate
 	depends on DRM
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 301a44dc18e3..550800e81836 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -65,7 +65,7 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += selftests/
+obj-y += selftests/
 
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 0856e4b12f70..6411c9a957b3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,11 @@
 # SPDX-License-Identifier: GPL-2.0-only
-test-drm_modeset-y := test-drm_modeset_common.o test-drm_plane_helper.o \
+test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
+		      test-drm_modeset_common.o test-drm_plane_helper.o \
                       test-drm_format.o test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o test-drm_cmdline_parser.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+
+obj-$(CONFIG_DRM_KUNIT_TEST) := \
+	test-drm_cmdline_parser.o
diff --git a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h b/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
deleted file mode 100644
index 29e367db6118..000000000000
--- a/drivers/gpu/drm/selftests/drm_cmdline_selftests.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_mm
- */
-
-#define cmdline_test(test)	selftest(test, test)
-
-cmdline_test(drm_cmdline_test_force_d_only)
-cmdline_test(drm_cmdline_test_force_D_only_dvi)
-cmdline_test(drm_cmdline_test_force_D_only_hdmi)
-cmdline_test(drm_cmdline_test_force_D_only_not_digital)
-cmdline_test(drm_cmdline_test_force_e_only)
-cmdline_test(drm_cmdline_test_margin_only)
-cmdline_test(drm_cmdline_test_interlace_only)
-cmdline_test(drm_cmdline_test_res)
-cmdline_test(drm_cmdline_test_res_missing_x)
-cmdline_test(drm_cmdline_test_res_missing_y)
-cmdline_test(drm_cmdline_test_res_bad_y)
-cmdline_test(drm_cmdline_test_res_missing_y_bpp)
-cmdline_test(drm_cmdline_test_res_vesa)
-cmdline_test(drm_cmdline_test_res_vesa_rblank)
-cmdline_test(drm_cmdline_test_res_rblank)
-cmdline_test(drm_cmdline_test_res_bpp)
-cmdline_test(drm_cmdline_test_res_bad_bpp)
-cmdline_test(drm_cmdline_test_res_refresh)
-cmdline_test(drm_cmdline_test_res_bad_refresh)
-cmdline_test(drm_cmdline_test_res_bpp_refresh)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_margins)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_off)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_off)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_analog)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_force_on_digital)
-cmdline_test(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on)
-cmdline_test(drm_cmdline_test_res_margins_force_on)
-cmdline_test(drm_cmdline_test_res_vesa_margins)
-cmdline_test(drm_cmdline_test_res_invalid_mode)
-cmdline_test(drm_cmdline_test_res_bpp_wrong_place_mode)
-cmdline_test(drm_cmdline_test_name)
-cmdline_test(drm_cmdline_test_name_bpp)
-cmdline_test(drm_cmdline_test_name_refresh)
-cmdline_test(drm_cmdline_test_name_bpp_refresh)
-cmdline_test(drm_cmdline_test_name_refresh_wrong_mode)
-cmdline_test(drm_cmdline_test_name_refresh_invalid_mode)
-cmdline_test(drm_cmdline_test_name_option)
-cmdline_test(drm_cmdline_test_name_bpp_option)
-cmdline_test(drm_cmdline_test_rotate_0)
-cmdline_test(drm_cmdline_test_rotate_90)
-cmdline_test(drm_cmdline_test_rotate_180)
-cmdline_test(drm_cmdline_test_rotate_270)
-cmdline_test(drm_cmdline_test_rotate_multiple)
-cmdline_test(drm_cmdline_test_rotate_invalid_val)
-cmdline_test(drm_cmdline_test_rotate_truncated)
-cmdline_test(drm_cmdline_test_hmirror)
-cmdline_test(drm_cmdline_test_vmirror)
-cmdline_test(drm_cmdline_test_margin_options)
-cmdline_test(drm_cmdline_test_multiple_options)
-cmdline_test(drm_cmdline_test_invalid_option)
-cmdline_test(drm_cmdline_test_bpp_extra_and_option)
-cmdline_test(drm_cmdline_test_extra_and_option)
-cmdline_test(drm_cmdline_test_freestanding_options)
-cmdline_test(drm_cmdline_test_freestanding_force_e_and_options)
-cmdline_test(drm_cmdline_test_panel_orientation)
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
index d96cd890def6..ffe5a483320a 100644
--- a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
+++ b/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
@@ -3,1139 +3,1025 @@
  * Copyright (c) 2019 Bootlin
  */
 
-#define pr_fmt(fmt) "drm_cmdline: " fmt
-
-#include <linux/kernel.h>
-#include <linux/module.h>
+#include <kunit/test.h>
 
 #include <drm/drm_connector.h>
 #include <drm/drm_modes.h>
 
-#define TESTS "drm_cmdline_selftests.h"
-#include "drm_selftest.h"
-#include "test-drm_modeset_common.h"
-
 static const struct drm_connector no_connector = {};
 
-static int drm_cmdline_test_force_e_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("e",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static int drm_cmdline_test_force_D_only_not_digital(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static const struct drm_connector connector_hdmi = {
-	.connector_type	= DRM_MODE_CONNECTOR_HDMIB,
-};
-
-static int drm_cmdline_test_force_D_only_hdmi(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &connector_hdmi,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
-}
-
-static const struct drm_connector connector_dvi = {
-	.connector_type	= DRM_MODE_CONNECTOR_DVII,
-};
-
-static int drm_cmdline_test_force_D_only_dvi(void *ignored)
+static void drm_cmdline_test_force_e_only(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("D",
-							   &connector_dvi,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
-}
-
-static int drm_cmdline_test_force_d_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("d",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_OFF);
-
-	return 0;
+	const char *cmdline = "e";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_margin_only(void *ignored)
+static void drm_cmdline_test_force_D_only_not_digital(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("m",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_interlace_only(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("i",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_missing_x(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("x480",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_missing_y(void *ignored)
+static void drm_cmdline_test_force_D_only_hdmi(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const struct drm_connector connector_hdmi = {
+		.connector_type	= DRM_MODE_CONNECTOR_HDMIB,
+	};
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector_hdmi,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_bad_y(void *ignored)
+static void drm_cmdline_test_force_D_only_dvi(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024xtest",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const struct drm_connector connector_dvi = {
+		.connector_type = DRM_MODE_CONNECTOR_DVII,
+	};
+	const char *cmdline = "D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector_dvi,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_missing_y_bpp(void *ignored)
+static void drm_cmdline_test_force_d_only(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("1024x-24",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "d";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF);
 }
 
-static int drm_cmdline_test_res_vesa(void *ignored)
+static void drm_cmdline_test_res(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480M",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_vesa_rblank(void *ignored)
+static void drm_cmdline_test_res_vesa(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480M";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480MR",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_rblank(void *ignored)
+static void drm_cmdline_test_res_vesa_rblank(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480MR";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480R",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(!mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp(void *ignored)
+static void drm_cmdline_test_res_rblank(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480R";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bad_bpp(void *ignored)
+static void drm_cmdline_test_res_bpp(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480-24";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-test",
-							  &no_connector,
-							  &mode));
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480@60",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_res_bad_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480@refresh",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh(void *ignored)
+static void drm_cmdline_test_res_refresh(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480@60";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
 
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_interlaced(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60i",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(!mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24@60";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_margins(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_interlaced(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60m",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24@60i";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_TRUE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_off(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_margins(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60d",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_OFF);
-
-	return 0;
+	const char *cmdline = "720x480-24@60m";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_off(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_off(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480-24@60de",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "720x480-24@60d";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_OFF);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60e",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60e";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_analog(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on_analog(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_force_on_digital(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_force_on_digital(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-	static const struct drm_connector connector = {
+	const struct drm_connector connector = {
 		.connector_type = DRM_MODE_CONNECTOR_DVII,
 	};
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60D",
-							   &connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON_DIGITAL);
-
-	return 0;
+	const char *cmdline = "720x480-24@60D";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON_DIGITAL);
 }
 
-static int drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(void *ignored)
+static void drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24@60ime",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(!mode.refresh_specified);
-	FAIL_ON(mode.refresh != 60);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(!mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "720x480-24@60ime";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+
+	KUNIT_EXPECT_TRUE(test, mode.refresh_specified);
+	KUNIT_EXPECT_EQ(test, mode.refresh, 60);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_TRUE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_margins_force_on(void *ignored)
+static void drm_cmdline_test_res_margins_force_on(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480me";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480me",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
-
-static int drm_cmdline_test_res_vesa_margins(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480Mm",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(!mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(!mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_res_invalid_mode(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480f",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_res_bpp_wrong_place_mode(void *ignored)
+static void drm_cmdline_test_res_vesa_margins(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480Mm";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480e-24",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
 
-	return 0;
-}
-
-static int drm_cmdline_test_name(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_TRUE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_TRUE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_name_bpp(void *ignored)
+static void drm_cmdline_test_name(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	return 0;
+	const char *cmdline = "NTSC";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 }
 
-static int drm_cmdline_test_name_bpp_refresh(void *ignored)
+static void drm_cmdline_test_name_bpp(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "NTSC-24";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC-24@60",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
 
-	return 0;
-}
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-static int drm_cmdline_test_name_refresh(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 }
 
-static int drm_cmdline_test_name_refresh_wrong_mode(void *ignored)
+static void drm_cmdline_test_name_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60m",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "NTSC,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
 }
 
-static int drm_cmdline_test_name_refresh_invalid_mode(void *ignored)
+static void drm_cmdline_test_name_bpp_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("NTSC@60f",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "NTSC-24,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_STREQ(test, mode.name, "NTSC");
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
 }
 
-static int drm_cmdline_test_name_option(void *ignored)
+static void drm_cmdline_test_rotate_0(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=0";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_0);
 
-	return 0;
-}
-
-static int drm_cmdline_test_name_bpp_option(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("NTSC-24,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(strcmp(mode.name, "NTSC"));
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_0(void *ignored)
+static void drm_cmdline_test_rotate_90(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=90";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=0",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_0);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_90);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_90(void *ignored)
+static void drm_cmdline_test_rotate_180(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=180";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=90",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_90);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_180(void *ignored)
+static void drm_cmdline_test_rotate_270(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=270";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_270);
 
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_270(void *ignored)
+static void drm_cmdline_test_hmirror(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,reflect_x";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_270);
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X));
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_multiple(void *ignored)
+static void drm_cmdline_test_vmirror(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,reflect_y";
 
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=0,rotate=90",
-							  &no_connector,
-							  &mode));
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y));
 
-	return 0;
-}
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-static int drm_cmdline_test_rotate_invalid_val(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=42",
-							  &no_connector,
-							  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_rotate_truncated(void *ignored)
+static void drm_cmdline_test_margin_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,rotate=",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline =
+		"720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_hmirror(void *ignored)
+static void drm_cmdline_test_multiple_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
+	const char *cmdline = "720x480,rotate=270,reflect_x";
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_x",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_X));
-
-	FAIL_ON(mode.refresh_specified);
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
 
-	FAIL_ON(mode.bpp_specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
 
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
 
-	return 0;
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_vmirror(void *ignored)
+static void drm_cmdline_test_bpp_extra_and_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,reflect_y",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_0 | DRM_MODE_REFLECT_Y));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480-24e,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+
+	KUNIT_EXPECT_TRUE(test, mode.bpp_specified);
+	KUNIT_EXPECT_EQ(test, mode.bpp, 24);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_margin_options(void *ignored)
+static void drm_cmdline_test_extra_and_option(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "720x480e,rotate=180";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_TRUE(test, mode.specified);
+	KUNIT_EXPECT_EQ(test, mode.xres, 720);
+	KUNIT_EXPECT_EQ(test, mode.yres, 480);
+	KUNIT_EXPECT_EQ(test, mode.rotation_reflection, DRM_MODE_ROTATE_180);
+
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_multiple_options(void *ignored)
+static void drm_cmdline_test_freestanding_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480,rotate=270,reflect_x",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != (DRM_MODE_ROTATE_270 | DRM_MODE_REFLECT_X));
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	const char *cmdline = "margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_invalid_option(void *ignored)
+static void drm_cmdline_test_freestanding_force_e_and_options(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(drm_mode_parse_command_line_for_connector("720x480,test=42",
-							  &no_connector,
-							  &mode));
-
-	return 0;
+	const char *cmdline = "e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.right, 14);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.left, 24);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.bottom, 36);
+	KUNIT_EXPECT_EQ(test, mode.tv_margins.top, 42);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_ON);
 }
 
-static int drm_cmdline_test_bpp_extra_and_option(void *ignored)
+static void drm_cmdline_test_panel_orientation(struct kunit *test)
 {
 	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480-24e,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-
-	FAIL_ON(mode.refresh_specified);
-
-	FAIL_ON(!mode.bpp_specified);
-	FAIL_ON(mode.bpp != 24);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
+	const char *cmdline = "panel_orientation=upside_down";
+
+	KUNIT_ASSERT_TRUE(test, drm_mode_parse_command_line_for_connector(cmdline,
+									  &no_connector,
+									  &mode));
+	KUNIT_EXPECT_FALSE(test, mode.specified);
+	KUNIT_EXPECT_FALSE(test, mode.refresh_specified);
+	KUNIT_EXPECT_FALSE(test, mode.bpp_specified);
+
+	KUNIT_EXPECT_EQ(test, mode.panel_orientation, DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
+
+	KUNIT_EXPECT_FALSE(test, mode.rb);
+	KUNIT_EXPECT_FALSE(test, mode.cvt);
+	KUNIT_EXPECT_FALSE(test, mode.interlace);
+	KUNIT_EXPECT_FALSE(test, mode.margins);
+	KUNIT_EXPECT_EQ(test, mode.force, DRM_FORCE_UNSPECIFIED);
 }
 
-static int drm_cmdline_test_extra_and_option(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("720x480e,rotate=180",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(!mode.specified);
-	FAIL_ON(mode.xres != 720);
-	FAIL_ON(mode.yres != 480);
-	FAIL_ON(mode.rotation_reflection != DRM_MODE_ROTATE_180);
-
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
+struct drm_cmdline_negative_test {
+	const char *name;
+	const char *cmdline;
+};
 
-static int drm_cmdline_test_freestanding_options(void *ignored)
+static void drm_cmdline_test_negative(struct kunit *test)
 {
+	const struct drm_cmdline_negative_test *params = test->param_value;
 	struct drm_cmdline_mode mode = { };
 
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	KUNIT_EXPECT_FALSE(test, drm_mode_parse_command_line_for_connector(params->cmdline,
+									   &no_connector,
+									   &mode));
 }
 
-static int drm_cmdline_test_freestanding_force_e_and_options(void *ignored)
-{
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("e,margin_right=14,margin_left=24,margin_bottom=36,margin_top=42",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.tv_margins.right != 14);
-	FAIL_ON(mode.tv_margins.left != 24);
-	FAIL_ON(mode.tv_margins.bottom != 36);
-	FAIL_ON(mode.tv_margins.top != 42);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_ON);
-
-	return 0;
-}
+static const struct drm_cmdline_negative_test drm_cmdline_negative_tests[] = {
+	{
+		.name = "margin_only",
+		.cmdline = "m",
+	},
+	{
+		.name = "interlace_only",
+		.cmdline = "i",
+	},
+	{
+		.name = "res_missing_x",
+		.cmdline = "x480",
+	},
+	{
+		.name = "res_missing_y",
+		.cmdline = "1024x",
+	},
+	{
+		.name = "res_bad_y",
+		.cmdline = "1024xtest",
+	},
+	{
+		.name = "res_missing_y_bpp",
+		.cmdline = "1024x-24",
+	},
+	{
+		.name = "res_bad_bpp",
+		.cmdline = "720x480-test",
+	},
+	{
+		.name = "res_bad_refresh",
+		.cmdline = "720x480@refresh",
+	},
+	{
+		.name = "res_bpp_refresh_force_on_off",
+		.cmdline = "720x480-24@60de",
+	},
+	{
+		.name = "res_invalid_mode",
+		.cmdline = "720x480f",
+	},
+	{
+		.name = "res_bpp_wrong_place_mode",
+		.cmdline = "720x480e-24",
+	},
+	{
+		.name = "name_bpp_refresh",
+		.cmdline = "NTSC-24@60",
+	},
+	{
+		.name = "name_refresh",
+		.cmdline = "NTSC@60",
+	},
+	{
+		.name = "name_refresh_wrong_mode",
+		.cmdline = "NTSC@60m",
+	},
+	{
+		.name = "name_refresh_invalid_mode",
+		.cmdline = "NTSC@60f",
+	},
+	{
+		.name = "rotate_multiple",
+		.cmdline = "720x480,rotate=0,rotate=90",
+	},
+	{
+		.name = "rotate_invalid_val",
+		.cmdline = "720x480,rotate=42",
+	},
+	{
+		.name = "rotate_truncated",
+		.cmdline = "720x480,rotate=",
+	},
+	{
+		.name = "invalid_option",
+		.cmdline = "720x480,test=42",
+	},
+};
 
-static int drm_cmdline_test_panel_orientation(void *ignored)
+static void drm_cmdline_negative_desc(const struct drm_cmdline_negative_test *t,
+				      char *desc)
 {
-	struct drm_cmdline_mode mode = { };
-
-	FAIL_ON(!drm_mode_parse_command_line_for_connector("panel_orientation=upside_down",
-							   &no_connector,
-							   &mode));
-	FAIL_ON(mode.specified);
-	FAIL_ON(mode.refresh_specified);
-	FAIL_ON(mode.bpp_specified);
-
-	FAIL_ON(mode.panel_orientation != DRM_MODE_PANEL_ORIENTATION_BOTTOM_UP);
-
-	FAIL_ON(mode.rb);
-	FAIL_ON(mode.cvt);
-	FAIL_ON(mode.interlace);
-	FAIL_ON(mode.margins);
-	FAIL_ON(mode.force != DRM_FORCE_UNSPECIFIED);
-
-	return 0;
+	sprintf(desc, "%s", t->name);
 }
 
-#include "drm_selftest.c"
-
-static int __init test_drm_cmdline_init(void)
-{
-	int err;
+KUNIT_ARRAY_PARAM(drm_cmdline_negative, drm_cmdline_negative_tests, drm_cmdline_negative_desc);
+
+static struct kunit_case drm_cmdline_tests[] = {
+	KUNIT_CASE(drm_cmdline_test_force_d_only),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_dvi),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_hdmi),
+	KUNIT_CASE(drm_cmdline_test_force_D_only_not_digital),
+	KUNIT_CASE(drm_cmdline_test_force_e_only),
+	KUNIT_CASE(drm_cmdline_test_res),
+	KUNIT_CASE(drm_cmdline_test_res_vesa),
+	KUNIT_CASE(drm_cmdline_test_res_vesa_rblank),
+	KUNIT_CASE(drm_cmdline_test_res_rblank),
+	KUNIT_CASE(drm_cmdline_test_res_bpp),
+	KUNIT_CASE(drm_cmdline_test_res_refresh),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_margins),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_off),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_analog),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_force_on_digital),
+	KUNIT_CASE(drm_cmdline_test_res_bpp_refresh_interlaced_margins_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_margins_force_on),
+	KUNIT_CASE(drm_cmdline_test_res_vesa_margins),
+	KUNIT_CASE(drm_cmdline_test_name),
+	KUNIT_CASE(drm_cmdline_test_name_bpp),
+	KUNIT_CASE(drm_cmdline_test_name_option),
+	KUNIT_CASE(drm_cmdline_test_name_bpp_option),
+	KUNIT_CASE(drm_cmdline_test_rotate_0),
+	KUNIT_CASE(drm_cmdline_test_rotate_90),
+	KUNIT_CASE(drm_cmdline_test_rotate_180),
+	KUNIT_CASE(drm_cmdline_test_rotate_270),
+	KUNIT_CASE(drm_cmdline_test_hmirror),
+	KUNIT_CASE(drm_cmdline_test_vmirror),
+	KUNIT_CASE(drm_cmdline_test_margin_options),
+	KUNIT_CASE(drm_cmdline_test_multiple_options),
+	KUNIT_CASE(drm_cmdline_test_bpp_extra_and_option),
+	KUNIT_CASE(drm_cmdline_test_extra_and_option),
+	KUNIT_CASE(drm_cmdline_test_freestanding_options),
+	KUNIT_CASE(drm_cmdline_test_freestanding_force_e_and_options),
+	KUNIT_CASE(drm_cmdline_test_panel_orientation),
+	KUNIT_CASE_PARAM(drm_cmdline_test_negative, drm_cmdline_negative_gen_params),
+	{}
+};
 
-	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
+static struct kunit_suite drm_cmdline_test_suite = {
+	.name = "drm_cmdline_tests",
+	.test_cases = drm_cmdline_tests,
+};
 
-	return err > 0 ? 0 : err;
-}
-module_init(test_drm_cmdline_init);
+kunit_test_suite(drm_cmdline_test_suite);
 
 MODULE_AUTHOR("Maxime Ripard <maxime.ripard@bootlin.com>");
 MODULE_LICENSE("GPL");
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 02/10] drm: test-drm_plane_helper: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

Tests were converted into parameterized test cases.
Negative tests were separated. Mocking was moved to test->init().
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |   1 +
 drivers/gpu/drm/selftests/Makefile            |   4 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   1 -
 .../drm/selftests/test-drm_modeset_common.h   |   1 -
 .../gpu/drm/selftests/test-drm_plane_helper.c | 483 +++++++++++-------
 5 files changed, 289 insertions(+), 201 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 21e329f32997..89be0df7b0e9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -83,6 +83,7 @@ config DRM_DEBUG_SELFTEST
 config DRM_KUNIT_TEST
 	bool "DRM tests" if !KUNIT_ALL_TESTS
 	depends on DRM=y && KUNIT=y
+	select DRM_KMS_HELPER
 	default KUNIT_ALL_TESTS
 	help
 	  Enables unit tests for DRM. Only useful for kernel devs running KUnit.
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 6411c9a957b3..82e568665ace 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
-		      test-drm_modeset_common.o test-drm_plane_helper.o \
+		      test-drm_modeset_common.o \
                       test-drm_format.o test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
@@ -8,4 +8,4 @@ test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
-	test-drm_cmdline_parser.o
+	test-drm_cmdline_parser.o test-drm_plane_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 782e285ca383..19d1142725c6 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,7 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_plane_state, igt_check_plane_state)
 selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
 selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
 selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index cfb51d8da2bc..8744fd840406 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_plane_state(void *ignored);
 int igt_check_drm_format_block_width(void *ignored);
 int igt_check_drm_format_block_height(void *ignored);
 int igt_check_drm_format_min_pitch(void *ignored);
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
index ceebeede55ea..f2c0cd37a949 100644
--- a/drivers/gpu/drm/selftests/test-drm_plane_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
@@ -3,221 +3,310 @@
  * Test cases for the drm_plane_helper functions
  */
 
-#define pr_fmt(fmt) "drm_plane_helper: " fmt
+#include <kunit/test.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_modes.h>
 
-#include "test-drm_modeset_common.h"
-
-static void set_src(struct drm_plane_state *plane_state,
-		    unsigned src_x, unsigned src_y,
-		    unsigned src_w, unsigned src_h)
+static void expect_src_eq(struct kunit *test, struct drm_plane_state *plane_state,
+			  unsigned int src_x, unsigned int src_y,
+			  unsigned int src_w, unsigned int src_h)
 {
-	plane_state->src_x = src_x;
-	plane_state->src_y = src_y;
-	plane_state->src_w = src_w;
-	plane_state->src_h = src_h;
+	KUNIT_EXPECT_GE_MSG(test, plane_state->src.x1, 0,
+			    "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+			    plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src));
+	KUNIT_EXPECT_GE_MSG(test, plane_state->src.y1, 0,
+			    "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+			    plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src));
+
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      plane_state->src.x1 == src_x &&
+			      plane_state->src.y1 == src_y &&
+			      drm_rect_width(&plane_state->src) == src_w &&
+			      drm_rect_height(&plane_state->src) == src_h,
+			      "src: " DRM_RECT_FP_FMT, DRM_RECT_FP_ARG(&plane_state->src));
 }
 
-static bool check_src_eq(struct drm_plane_state *plane_state,
-			 unsigned src_x, unsigned src_y,
-			 unsigned src_w, unsigned src_h)
+static void expect_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state,
+			   int crtc_x, int crtc_y,
+			   unsigned int crtc_w, unsigned int crtc_h)
 {
-	if (plane_state->src.x1 < 0) {
-		pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-	if (plane_state->src.y1 < 0) {
-		pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-
-	if (plane_state->src.x1 != src_x ||
-	    plane_state->src.y1 != src_y ||
-	    drm_rect_width(&plane_state->src) != src_w ||
-	    drm_rect_height(&plane_state->src) != src_h) {
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-
-	return true;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      plane_state->dst.x1 == crtc_x &&
+			      plane_state->dst.y1 == crtc_y &&
+			      drm_rect_width(&plane_state->dst) == crtc_w &&
+			      drm_rect_height(&plane_state->dst) == crtc_h,
+			      "dst: " DRM_RECT_FMT, DRM_RECT_ARG(&plane_state->dst));
 }
 
-static void set_crtc(struct drm_plane_state *plane_state,
-		     int crtc_x, int crtc_y,
-		     unsigned crtc_w, unsigned crtc_h)
+const struct drm_crtc_state crtc_state = {
+	.crtc = ZERO_SIZE_PTR,
+	.enable = true,
+	.active = true,
+	.mode = {
+		DRM_MODE("1024x768", 0, 65000, 1024, 1048,
+			 1184, 1344, 0, 768, 771, 777, 806, 0,
+			 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+	},
+};
+
+struct drm_check_plane_state_test {
+	const char *name;
+	const char *msg;
+	struct {
+		unsigned int x;
+		unsigned int y;
+		unsigned int w;
+		unsigned int h;
+	} src, src_expected;
+	struct {
+		int x;
+		int y;
+		unsigned int w;
+		unsigned int h;
+	} crtc, crtc_expected;
+	unsigned int rotation;
+	int min_scale;
+	int max_scale;
+	bool can_position;
+};
+
+static int drm_plane_helper_init(struct kunit *test)
 {
-	plane_state->crtc_x = crtc_x;
-	plane_state->crtc_y = crtc_y;
-	plane_state->crtc_w = crtc_w;
-	plane_state->crtc_h = crtc_h;
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane *plane;
+	struct drm_framebuffer *fb;
+	struct drm_plane_state *mock;
+
+	plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
+
+	fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb);
+	fb->width = 2048;
+	fb->height = 2048;
+
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
+	mock->plane = plane;
+	mock->crtc = ZERO_SIZE_PTR;
+	mock->fb = fb;
+	mock->rotation = params->rotation;
+	mock->src_x = params->src.x;
+	mock->src_y = params->src.y;
+	mock->src_w = params->src.w;
+	mock->src_h = params->src.h;
+	mock->crtc_x = params->crtc.x;
+	mock->crtc_y = params->crtc.y;
+	mock->crtc_w = params->crtc.w;
+	mock->crtc_h = params->crtc.h;
+
+	test->priv = mock;
+
+	return 0;
 }
 
-static bool check_crtc_eq(struct drm_plane_state *plane_state,
-			  int crtc_x, int crtc_y,
-			  unsigned crtc_w, unsigned crtc_h)
+void drm_check_plane_state(struct kunit *test)
 {
-	if (plane_state->dst.x1 != crtc_x ||
-	    plane_state->dst.y1 != crtc_y ||
-	    drm_rect_width(&plane_state->dst) != crtc_w ||
-	    drm_rect_height(&plane_state->dst) != crtc_h) {
-		drm_rect_debug_print("dst: ", &plane_state->dst, false);
-
-		return false;
-	}
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane_state *plane_state = test->priv;
 
-	return true;
+	KUNIT_ASSERT_EQ_MSG(test,
+			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+								params->min_scale,
+								params->max_scale,
+								params->can_position, false),
+			    0, params->msg);
+	KUNIT_EXPECT_TRUE(test, plane_state->visible);
+	expect_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y,
+		      params->src_expected.w, params->src_expected.h);
+	expect_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y,
+		       params->crtc_expected.w, params->crtc_expected.h);
 }
 
-int igt_check_plane_state(void *ignored)
+void drm_check_invalid_plane_state(struct kunit *test)
 {
-	int ret;
-
-	const struct drm_crtc_state crtc_state = {
-		.crtc = ZERO_SIZE_PTR,
-		.enable = true,
-		.active = true,
-		.mode = {
-			DRM_MODE("1024x768", 0, 65000, 1024, 1048,
-				1184, 1344, 0, 768, 771, 777, 806, 0,
-				DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
-		},
-	};
-	struct drm_plane plane = {
-		.dev = NULL
-	};
-	struct drm_framebuffer fb = {
-		.width = 2048,
-		.height = 2048
-	};
-	struct drm_plane_state plane_state = {
-		.plane = &plane,
-		.crtc = ZERO_SIZE_PTR,
-		.fb = &fb,
-		.rotation = DRM_MODE_ROTATE_0
-	};
-
-	/* Simple clipping, no scaling. */
-	set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
-	set_crtc(&plane_state, 0, 0, fb.width, fb.height);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Simple clipping check should pass\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	/* Rotated clipping + reflection, no scaling. */
-	plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Rotated clipping check should pass\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-	plane_state.rotation = DRM_MODE_ROTATE_0;
-
-	/* Check whether positioning works correctly. */
-	set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
-	set_crtc(&plane_state, 0, 0, 1023, 767);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n");
-
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  true, false);
-	FAIL(ret < 0, "Simple positioning should work\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767));
-
-	/* Simple scaling tests. */
-	set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
-	set_crtc(&plane_state, 0, 0, 1024, 768);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0x8001,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(!ret, "Upscaling out of range should fail.\n");
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0x8000,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Upscaling exactly 2x should work\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x1ffff, false, false);
-	FAIL(!ret, "Downscaling out of range should fail.\n");
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x20000, false, false);
-	FAIL(ret < 0, "Should succeed with exact scaling limit\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	/* Testing rounding errors. */
-	set_src(&plane_state, 0, 0, 0x40001, 0x40001);
-	set_crtc(&plane_state, 1022, 766, 4, 4);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x10001,
-						  true, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-	set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
-	set_crtc(&plane_state, -2, -2, 1028, 772);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x10001,
-						  false, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
-	set_crtc(&plane_state, 1022, 766, 4, 4);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0xffff,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  true, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	/* Should not be rounded to 0x20001, which would be upscaling. */
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-	set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
-	set_crtc(&plane_state, -2, -2, 1028, 772);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0xffff,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane_state *plane_state = test->priv;
 
-	return 0;
+	KUNIT_ASSERT_LT_MSG(test,
+			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+								params->min_scale,
+								params->max_scale,
+								params->can_position, false),
+			    0, params->msg);
+}
+
+static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {
+	{
+		.name = "clipping_simple",
+		.msg = "Simple clipping check should pass",
+		.src = { 0, 0,
+			 2048 << 16,
+			 2048 << 16 },
+		.crtc = { 0, 0, 2048, 2048 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "clipping_rotate_reflect",
+		.msg = "Rotated clipping check should pass",
+		.src = { 0, 0,
+			 2048 << 16,
+			 2048 << 16 },
+		.crtc = { 0, 0, 2048, 2048 },
+		.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 768 << 16, 1024 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "positioning_simple",
+		.msg = "Simple positioning should work",
+		.src = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc = { 0, 0, 1023, 767 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = true,
+		.src_expected = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc_expected = { 0, 0, 1023, 767 },
+	},
+	{
+		.name = "upscaling",
+		.msg = "Upscaling exactly 2x should work",
+		.src = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0x8000,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "downscaling",
+		.msg = "Should succeed with exact scaling limit",
+		.src = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x20000,
+		.can_position = false,
+		.src_expected = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "rounding1",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0, 0, 0x40001, 0x40001 },
+		.crtc = { 1022, 766, 4, 4 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x10001,
+		.can_position = true,
+		.src_expected = { 0, 0, 2 << 16, 2 << 16 },
+		.crtc_expected = { 1022, 766, 2, 2 },
+	},
+	{
+		.name = "rounding2",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0x20001, 0x20001, 0x4040001, 0x3040001 },
+		.crtc = { -2, -2, 1028, 772 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x10001,
+		.can_position = false,
+		.src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "rounding3",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0, 0, 0x3ffff, 0x3ffff },
+		.crtc = { 1022, 766, 4, 4 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0xffff,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = true,
+		/* Should not be rounded to 0x20001, which would be upscaling. */
+		.src_expected = { 0, 0, 2 << 16, 2 << 16 },
+		.crtc_expected = { 1022, 766, 2, 2 },
+	},
+	{
+		.name = "rounding4",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff },
+		.crtc = { -2, -2, 1028, 772 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0xffff,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+};
+
+static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {
+	{
+		.name = "positioning_invalid",
+		.msg = "Should not be able to position on the crtc with can_position=false",
+		.src = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc = { 0, 0, 1023, 767 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+	},
+	{
+		.name = "upscaling_invalid",
+		.msg = "Upscaling out of range should fail",
+		.src = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0x8001,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+	},
+	{
+		.name = "downscaling_invalid",
+		.msg = "Downscaling out of range should fail",
+		.src = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x1ffff,
+		.can_position = false,
+	},
+};
+
+static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,
+				       char *desc)
+{
+	sprintf(desc, "%s", t->name);
 }
+
+KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);
+KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,
+		  drm_check_plane_state_desc);
+
+static struct kunit_case drm_plane_helper_tests[] = {
+	KUNIT_CASE_PARAM(drm_check_plane_state, drm_check_plane_state_gen_params),
+	KUNIT_CASE_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_gen_params),
+	{}
+};
+
+static struct kunit_suite drm_plane_helper_test_suite = {
+	.name = "drm_plane_helper_tests",
+	.init = drm_plane_helper_init,
+	.test_cases = drm_plane_helper_tests,
+};
+
+kunit_test_suite(drm_plane_helper_test_suite);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 02/10] drm: test-drm_plane_helper: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

Tests were converted into parameterized test cases.
Negative tests were separated. Mocking was moved to test->init().
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |   1 +
 drivers/gpu/drm/selftests/Makefile            |   4 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   1 -
 .../drm/selftests/test-drm_modeset_common.h   |   1 -
 .../gpu/drm/selftests/test-drm_plane_helper.c | 483 +++++++++++-------
 5 files changed, 289 insertions(+), 201 deletions(-)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 21e329f32997..89be0df7b0e9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -83,6 +83,7 @@ config DRM_DEBUG_SELFTEST
 config DRM_KUNIT_TEST
 	bool "DRM tests" if !KUNIT_ALL_TESTS
 	depends on DRM=y && KUNIT=y
+	select DRM_KMS_HELPER
 	default KUNIT_ALL_TESTS
 	help
 	  Enables unit tests for DRM. Only useful for kernel devs running KUnit.
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 6411c9a957b3..82e568665ace 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,6 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
-		      test-drm_modeset_common.o test-drm_plane_helper.o \
+		      test-drm_modeset_common.o \
                       test-drm_format.o test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
@@ -8,4 +8,4 @@ test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
-	test-drm_cmdline_parser.o
+	test-drm_cmdline_parser.o test-drm_plane_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 782e285ca383..19d1142725c6 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,7 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_plane_state, igt_check_plane_state)
 selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
 selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
 selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index cfb51d8da2bc..8744fd840406 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_plane_state(void *ignored);
 int igt_check_drm_format_block_width(void *ignored);
 int igt_check_drm_format_block_height(void *ignored);
 int igt_check_drm_format_min_pitch(void *ignored);
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
index ceebeede55ea..f2c0cd37a949 100644
--- a/drivers/gpu/drm/selftests/test-drm_plane_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_plane_helper.c
@@ -3,221 +3,310 @@
  * Test cases for the drm_plane_helper functions
  */
 
-#define pr_fmt(fmt) "drm_plane_helper: " fmt
+#include <kunit/test.h>
 
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 #include <drm/drm_modes.h>
 
-#include "test-drm_modeset_common.h"
-
-static void set_src(struct drm_plane_state *plane_state,
-		    unsigned src_x, unsigned src_y,
-		    unsigned src_w, unsigned src_h)
+static void expect_src_eq(struct kunit *test, struct drm_plane_state *plane_state,
+			  unsigned int src_x, unsigned int src_y,
+			  unsigned int src_w, unsigned int src_h)
 {
-	plane_state->src_x = src_x;
-	plane_state->src_y = src_y;
-	plane_state->src_w = src_w;
-	plane_state->src_h = src_h;
+	KUNIT_EXPECT_GE_MSG(test, plane_state->src.x1, 0,
+			    "src x coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+			    plane_state->src.x1, DRM_RECT_FP_ARG(&plane_state->src));
+	KUNIT_EXPECT_GE_MSG(test, plane_state->src.y1, 0,
+			    "src y coordinate %x should never be below 0, src: " DRM_RECT_FP_FMT,
+			    plane_state->src.y1, DRM_RECT_FP_ARG(&plane_state->src));
+
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      plane_state->src.x1 == src_x &&
+			      plane_state->src.y1 == src_y &&
+			      drm_rect_width(&plane_state->src) == src_w &&
+			      drm_rect_height(&plane_state->src) == src_h,
+			      "src: " DRM_RECT_FP_FMT, DRM_RECT_FP_ARG(&plane_state->src));
 }
 
-static bool check_src_eq(struct drm_plane_state *plane_state,
-			 unsigned src_x, unsigned src_y,
-			 unsigned src_w, unsigned src_h)
+static void expect_crtc_eq(struct kunit *test, struct drm_plane_state *plane_state,
+			   int crtc_x, int crtc_y,
+			   unsigned int crtc_w, unsigned int crtc_h)
 {
-	if (plane_state->src.x1 < 0) {
-		pr_err("src x coordinate %x should never be below 0.\n", plane_state->src.x1);
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-	if (plane_state->src.y1 < 0) {
-		pr_err("src y coordinate %x should never be below 0.\n", plane_state->src.y1);
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-
-	if (plane_state->src.x1 != src_x ||
-	    plane_state->src.y1 != src_y ||
-	    drm_rect_width(&plane_state->src) != src_w ||
-	    drm_rect_height(&plane_state->src) != src_h) {
-		drm_rect_debug_print("src: ", &plane_state->src, true);
-		return false;
-	}
-
-	return true;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      plane_state->dst.x1 == crtc_x &&
+			      plane_state->dst.y1 == crtc_y &&
+			      drm_rect_width(&plane_state->dst) == crtc_w &&
+			      drm_rect_height(&plane_state->dst) == crtc_h,
+			      "dst: " DRM_RECT_FMT, DRM_RECT_ARG(&plane_state->dst));
 }
 
-static void set_crtc(struct drm_plane_state *plane_state,
-		     int crtc_x, int crtc_y,
-		     unsigned crtc_w, unsigned crtc_h)
+const struct drm_crtc_state crtc_state = {
+	.crtc = ZERO_SIZE_PTR,
+	.enable = true,
+	.active = true,
+	.mode = {
+		DRM_MODE("1024x768", 0, 65000, 1024, 1048,
+			 1184, 1344, 0, 768, 771, 777, 806, 0,
+			 DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
+	},
+};
+
+struct drm_check_plane_state_test {
+	const char *name;
+	const char *msg;
+	struct {
+		unsigned int x;
+		unsigned int y;
+		unsigned int w;
+		unsigned int h;
+	} src, src_expected;
+	struct {
+		int x;
+		int y;
+		unsigned int w;
+		unsigned int h;
+	} crtc, crtc_expected;
+	unsigned int rotation;
+	int min_scale;
+	int max_scale;
+	bool can_position;
+};
+
+static int drm_plane_helper_init(struct kunit *test)
 {
-	plane_state->crtc_x = crtc_x;
-	plane_state->crtc_y = crtc_y;
-	plane_state->crtc_w = crtc_w;
-	plane_state->crtc_h = crtc_h;
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane *plane;
+	struct drm_framebuffer *fb;
+	struct drm_plane_state *mock;
+
+	plane = kunit_kzalloc(test, sizeof(*plane), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, plane);
+
+	fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb);
+	fb->width = 2048;
+	fb->height = 2048;
+
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
+	mock->plane = plane;
+	mock->crtc = ZERO_SIZE_PTR;
+	mock->fb = fb;
+	mock->rotation = params->rotation;
+	mock->src_x = params->src.x;
+	mock->src_y = params->src.y;
+	mock->src_w = params->src.w;
+	mock->src_h = params->src.h;
+	mock->crtc_x = params->crtc.x;
+	mock->crtc_y = params->crtc.y;
+	mock->crtc_w = params->crtc.w;
+	mock->crtc_h = params->crtc.h;
+
+	test->priv = mock;
+
+	return 0;
 }
 
-static bool check_crtc_eq(struct drm_plane_state *plane_state,
-			  int crtc_x, int crtc_y,
-			  unsigned crtc_w, unsigned crtc_h)
+void drm_check_plane_state(struct kunit *test)
 {
-	if (plane_state->dst.x1 != crtc_x ||
-	    plane_state->dst.y1 != crtc_y ||
-	    drm_rect_width(&plane_state->dst) != crtc_w ||
-	    drm_rect_height(&plane_state->dst) != crtc_h) {
-		drm_rect_debug_print("dst: ", &plane_state->dst, false);
-
-		return false;
-	}
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane_state *plane_state = test->priv;
 
-	return true;
+	KUNIT_ASSERT_EQ_MSG(test,
+			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+								params->min_scale,
+								params->max_scale,
+								params->can_position, false),
+			    0, params->msg);
+	KUNIT_EXPECT_TRUE(test, plane_state->visible);
+	expect_src_eq(test, plane_state, params->src_expected.x, params->src_expected.y,
+		      params->src_expected.w, params->src_expected.h);
+	expect_crtc_eq(test, plane_state, params->crtc_expected.x, params->crtc_expected.y,
+		       params->crtc_expected.w, params->crtc_expected.h);
 }
 
-int igt_check_plane_state(void *ignored)
+void drm_check_invalid_plane_state(struct kunit *test)
 {
-	int ret;
-
-	const struct drm_crtc_state crtc_state = {
-		.crtc = ZERO_SIZE_PTR,
-		.enable = true,
-		.active = true,
-		.mode = {
-			DRM_MODE("1024x768", 0, 65000, 1024, 1048,
-				1184, 1344, 0, 768, 771, 777, 806, 0,
-				DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC)
-		},
-	};
-	struct drm_plane plane = {
-		.dev = NULL
-	};
-	struct drm_framebuffer fb = {
-		.width = 2048,
-		.height = 2048
-	};
-	struct drm_plane_state plane_state = {
-		.plane = &plane,
-		.crtc = ZERO_SIZE_PTR,
-		.fb = &fb,
-		.rotation = DRM_MODE_ROTATE_0
-	};
-
-	/* Simple clipping, no scaling. */
-	set_src(&plane_state, 0, 0, fb.width << 16, fb.height << 16);
-	set_crtc(&plane_state, 0, 0, fb.width, fb.height);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Simple clipping check should pass\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	/* Rotated clipping + reflection, no scaling. */
-	plane_state.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X;
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Rotated clipping check should pass\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 768 << 16, 1024 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-	plane_state.rotation = DRM_MODE_ROTATE_0;
-
-	/* Check whether positioning works correctly. */
-	set_src(&plane_state, 0, 0, 1023 << 16, 767 << 16);
-	set_crtc(&plane_state, 0, 0, 1023, 767);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(!ret, "Should not be able to position on the crtc with can_position=false\n");
-
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  true, false);
-	FAIL(ret < 0, "Simple positioning should work\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 1023 << 16, 767 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1023, 767));
-
-	/* Simple scaling tests. */
-	set_src(&plane_state, 0, 0, 512 << 16, 384 << 16);
-	set_crtc(&plane_state, 0, 0, 1024, 768);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0x8001,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(!ret, "Upscaling out of range should fail.\n");
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0x8000,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Upscaling exactly 2x should work\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 512 << 16, 384 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	set_src(&plane_state, 0, 0, 2048 << 16, 1536 << 16);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x1ffff, false, false);
-	FAIL(!ret, "Downscaling out of range should fail.\n");
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x20000, false, false);
-	FAIL(ret < 0, "Should succeed with exact scaling limit\n");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2048 << 16, 1536 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	/* Testing rounding errors. */
-	set_src(&plane_state, 0, 0, 0x40001, 0x40001);
-	set_crtc(&plane_state, 1022, 766, 4, 4);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x10001,
-						  true, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-	set_src(&plane_state, 0x20001, 0x20001, 0x4040001, 0x3040001);
-	set_crtc(&plane_state, -2, -2, 1028, 772);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  0x10001,
-						  false, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0x40002, 0x40002, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
-
-	set_src(&plane_state, 0, 0, 0x3ffff, 0x3ffff);
-	set_crtc(&plane_state, 1022, 766, 4, 4);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0xffff,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  true, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	/* Should not be rounded to 0x20001, which would be upscaling. */
-	FAIL_ON(!check_src_eq(&plane_state, 0, 0, 2 << 16, 2 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 1022, 766, 2, 2));
-
-	set_src(&plane_state, 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff);
-	set_crtc(&plane_state, -2, -2, 1028, 772);
-	ret = drm_atomic_helper_check_plane_state(&plane_state, &crtc_state,
-						  0xffff,
-						  DRM_PLANE_HELPER_NO_SCALING,
-						  false, false);
-	FAIL(ret < 0, "Should succeed by clipping to exact multiple");
-	FAIL_ON(!plane_state.visible);
-	FAIL_ON(!check_src_eq(&plane_state, 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16));
-	FAIL_ON(!check_crtc_eq(&plane_state, 0, 0, 1024, 768));
+	const struct drm_check_plane_state_test *params = test->param_value;
+	struct drm_plane_state *plane_state = test->priv;
 
-	return 0;
+	KUNIT_ASSERT_LT_MSG(test,
+			    drm_atomic_helper_check_plane_state(plane_state, &crtc_state,
+								params->min_scale,
+								params->max_scale,
+								params->can_position, false),
+			    0, params->msg);
+}
+
+static const struct drm_check_plane_state_test drm_check_plane_state_tests[] = {
+	{
+		.name = "clipping_simple",
+		.msg = "Simple clipping check should pass",
+		.src = { 0, 0,
+			 2048 << 16,
+			 2048 << 16 },
+		.crtc = { 0, 0, 2048, 2048 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "clipping_rotate_reflect",
+		.msg = "Rotated clipping check should pass",
+		.src = { 0, 0,
+			 2048 << 16,
+			 2048 << 16 },
+		.crtc = { 0, 0, 2048, 2048 },
+		.rotation = DRM_MODE_ROTATE_90 | DRM_MODE_REFLECT_X,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 768 << 16, 1024 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "positioning_simple",
+		.msg = "Simple positioning should work",
+		.src = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc = { 0, 0, 1023, 767 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = true,
+		.src_expected = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc_expected = { 0, 0, 1023, 767 },
+	},
+	{
+		.name = "upscaling",
+		.msg = "Upscaling exactly 2x should work",
+		.src = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0x8000,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "downscaling",
+		.msg = "Should succeed with exact scaling limit",
+		.src = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x20000,
+		.can_position = false,
+		.src_expected = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "rounding1",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0, 0, 0x40001, 0x40001 },
+		.crtc = { 1022, 766, 4, 4 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x10001,
+		.can_position = true,
+		.src_expected = { 0, 0, 2 << 16, 2 << 16 },
+		.crtc_expected = { 1022, 766, 2, 2 },
+	},
+	{
+		.name = "rounding2",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0x20001, 0x20001, 0x4040001, 0x3040001 },
+		.crtc = { -2, -2, 1028, 772 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x10001,
+		.can_position = false,
+		.src_expected = { 0x40002, 0x40002, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+	{
+		.name = "rounding3",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0, 0, 0x3ffff, 0x3ffff },
+		.crtc = { 1022, 766, 4, 4 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0xffff,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = true,
+		/* Should not be rounded to 0x20001, which would be upscaling. */
+		.src_expected = { 0, 0, 2 << 16, 2 << 16 },
+		.crtc_expected = { 1022, 766, 2, 2 },
+	},
+	{
+		.name = "rounding4",
+		.msg = "Should succeed by clipping to exact multiple",
+		.src = { 0x1ffff, 0x1ffff, 0x403ffff, 0x303ffff },
+		.crtc = { -2, -2, 1028, 772 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0xffff,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+		.src_expected = { 0x3fffe, 0x3fffe, 1024 << 16, 768 << 16 },
+		.crtc_expected = { 0, 0, 1024, 768 },
+	},
+};
+
+static const struct drm_check_plane_state_test drm_check_invalid_plane_state_tests[] = {
+	{
+		.name = "positioning_invalid",
+		.msg = "Should not be able to position on the crtc with can_position=false",
+		.src = { 0, 0, 1023 << 16, 767 << 16 },
+		.crtc = { 0, 0, 1023, 767 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+	},
+	{
+		.name = "upscaling_invalid",
+		.msg = "Upscaling out of range should fail",
+		.src = { 0, 0, 512 << 16, 384 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = 0x8001,
+		.max_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.can_position = false,
+	},
+	{
+		.name = "downscaling_invalid",
+		.msg = "Downscaling out of range should fail",
+		.src = { 0, 0, 2048 << 16, 1536 << 16 },
+		.crtc = { 0, 0, 1024, 768 },
+		.rotation = DRM_MODE_ROTATE_0,
+		.min_scale = DRM_PLANE_HELPER_NO_SCALING,
+		.max_scale = 0x1ffff,
+		.can_position = false,
+	},
+};
+
+static void drm_check_plane_state_desc(const struct drm_check_plane_state_test *t,
+				       char *desc)
+{
+	sprintf(desc, "%s", t->name);
 }
+
+KUNIT_ARRAY_PARAM(drm_check_plane_state, drm_check_plane_state_tests, drm_check_plane_state_desc);
+KUNIT_ARRAY_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_tests,
+		  drm_check_plane_state_desc);
+
+static struct kunit_case drm_plane_helper_tests[] = {
+	KUNIT_CASE_PARAM(drm_check_plane_state, drm_check_plane_state_gen_params),
+	KUNIT_CASE_PARAM(drm_check_invalid_plane_state, drm_check_invalid_plane_state_gen_params),
+	{}
+};
+
+static struct kunit_suite drm_plane_helper_test_suite = {
+	.name = "drm_plane_helper_tests",
+	.init = drm_plane_helper_init,
+	.test_cases = drm_plane_helper_tests,
+};
+
+kunit_test_suite(drm_plane_helper_test_suite);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 03/10] drm: test-drm_format: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

One-to-one conversion, no functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   5 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   3 -
 drivers/gpu/drm/selftests/test-drm_format.c   | 538 ++++++++++--------
 .../drm/selftests/test-drm_modeset_common.h   |   3 -
 4 files changed, 310 insertions(+), 239 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 82e568665ace..76c127613d1a 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-                      test-drm_format.o test-drm_framebuffer.o \
+                      test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
-	test-drm_cmdline_parser.o test-drm_plane_helper.o
+	test-drm_cmdline_parser.o test-drm_plane_helper.o \
+	test-drm_format.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 19d1142725c6..5f253d9e573c 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,9 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
-selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
-selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
 selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
 selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
 selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c
index c5e212afa27a..2774990768a7 100644
--- a/drivers/gpu/drm/selftests/test-drm_format.c
+++ b/drivers/gpu/drm/selftests/test-drm_format.c
@@ -3,278 +3,354 @@
  * Test cases for the drm_format functions
  */
 
-#define pr_fmt(fmt) "drm_format: " fmt
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
+#include <kunit/test.h>
 
 #include <drm/drm_fourcc.h>
 
-#include "test-drm_modeset_common.h"
-
-int igt_check_drm_format_block_width(void *ignored)
+static void drm_format_block_width_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
 	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_block_width(info, 0) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-
-	/* Test 1 plane format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 2) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test 3 planes format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 2) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 3) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test a tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L0);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 2);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+}
+
+static void drm_format_block_width_one_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
 }
 
-int igt_check_drm_format_block_height(void *ignored)
+static void drm_format_block_width_three_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 3), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_height_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
-	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_block_height(info, 0) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-
-	/* Test 1 plane format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 2) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test 3 planes format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 2) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 3) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test a tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L0);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 2);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
 }
 
-int igt_check_drm_format_min_pitch(void *ignored)
+static void drm_format_block_height_one_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_three_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 3), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_min_pitch_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
-	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	/* Test 1 plane 8 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_RGB332);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+}
+
+static void drm_format_min_pitch_one_plane_8bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB332);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1));
+}
 
-	/* Test 1 plane 16 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_16bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1) * 2);
+}
 
-	/* Test 1 plane 24 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_RGB888);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_24bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB888);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 3);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 6);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 3072);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 5760);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 12288);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2013);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 3);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 3);
+}
 
-	/* Test 1 plane 32 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_ABGR8888);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_32bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_ABGR8888);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 8);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 2560);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 7680);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 16384);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2684);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 4);
+}
 
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 672);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1));
-	FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2),
 			(uint64_t)(UINT_MAX - 1));
+}
 
-	/* Test 3 planes 8 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_three_plane_8bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 3, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 320);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 320), 320);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 512);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 512), 512);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 960);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 960), 960);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2048), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 336);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 336), 336);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX / 2 + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX / 2 + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
+}
 
-	/* Test tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L2);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L2);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 2);
-
-	return 0;
 }
+
+static struct kunit_case drm_format_tests[] = {
+	KUNIT_CASE(drm_format_block_width_invalid),
+	KUNIT_CASE(drm_format_block_width_one_plane),
+	KUNIT_CASE(drm_format_block_width_two_plane),
+	KUNIT_CASE(drm_format_block_width_three_plane),
+	KUNIT_CASE(drm_format_block_width_tiled),
+	KUNIT_CASE(drm_format_block_height_invalid),
+	KUNIT_CASE(drm_format_block_height_one_plane),
+	KUNIT_CASE(drm_format_block_height_two_plane),
+	KUNIT_CASE(drm_format_block_height_three_plane),
+	KUNIT_CASE(drm_format_block_height_tiled),
+	KUNIT_CASE(drm_format_min_pitch_invalid),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_8bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_16bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_24bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_32bpp),
+	KUNIT_CASE(drm_format_min_pitch_two_plane),
+	KUNIT_CASE(drm_format_min_pitch_three_plane_8bpp),
+	KUNIT_CASE(drm_format_min_pitch_tiled),
+	{}
+};
+
+static struct kunit_suite drm_format_test_suite = {
+	.name = "drm_format_tests",
+	.test_cases = drm_format_tests,
+};
+
+kunit_test_suite(drm_format_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index 8744fd840406..f6cfce2a5863 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,9 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_drm_format_block_width(void *ignored);
-int igt_check_drm_format_block_height(void *ignored);
-int igt_check_drm_format_min_pitch(void *ignored);
 int igt_check_drm_framebuffer_create(void *ignored);
 int igt_damage_iter_no_damage(void *ignored);
 int igt_damage_iter_no_damage_fractional_src(void *ignored);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 03/10] drm: test-drm_format: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

One-to-one conversion, no functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   5 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   3 -
 drivers/gpu/drm/selftests/test-drm_format.c   | 538 ++++++++++--------
 .../drm/selftests/test-drm_modeset_common.h   |   3 -
 4 files changed, 310 insertions(+), 239 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 82e568665ace..76c127613d1a 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-                      test-drm_format.o test-drm_framebuffer.o \
+                      test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
-	test-drm_cmdline_parser.o test-drm_plane_helper.o
+	test-drm_cmdline_parser.o test-drm_plane_helper.o \
+	test-drm_format.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 19d1142725c6..5f253d9e573c 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,9 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_drm_format_block_width, igt_check_drm_format_block_width)
-selftest(check_drm_format_block_height, igt_check_drm_format_block_height)
-selftest(check_drm_format_min_pitch, igt_check_drm_format_min_pitch)
 selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
 selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
 selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/selftests/test-drm_format.c
index c5e212afa27a..2774990768a7 100644
--- a/drivers/gpu/drm/selftests/test-drm_format.c
+++ b/drivers/gpu/drm/selftests/test-drm_format.c
@@ -3,278 +3,354 @@
  * Test cases for the drm_format functions
  */
 
-#define pr_fmt(fmt) "drm_format: " fmt
-
-#include <linux/errno.h>
-#include <linux/kernel.h>
+#include <kunit/test.h>
 
 #include <drm/drm_fourcc.h>
 
-#include "test-drm_modeset_common.h"
-
-int igt_check_drm_format_block_width(void *ignored)
+static void drm_format_block_width_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
 	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_block_width(info, 0) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-
-	/* Test 1 plane format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 2) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test 3 planes format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 2) != 1);
-	FAIL_ON(drm_format_info_block_width(info, 3) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	/* Test a tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L0);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_width(info, 0) != 2);
-	FAIL_ON(drm_format_info_block_width(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_width(info, -1) != 0);
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+}
+
+static void drm_format_block_width_one_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
 }
 
-int igt_check_drm_format_block_height(void *ignored)
+static void drm_format_block_width_three_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 2), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 3), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_width_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 0), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_width(info, -1), 0);
+}
+
+static void drm_format_block_height_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
-	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_block_height(info, 0) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-
-	/* Test 1 plane format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 2) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test 3 planes format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 2) != 1);
-	FAIL_ON(drm_format_info_block_height(info, 3) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	/* Test a tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L0);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_block_height(info, 0) != 2);
-	FAIL_ON(drm_format_info_block_height(info, 1) != 0);
-	FAIL_ON(drm_format_info_block_height(info, -1) != 0);
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
 }
 
-int igt_check_drm_format_min_pitch(void *ignored)
+static void drm_format_block_height_one_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_three_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 2), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 3), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_block_height_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L0);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 0), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, 1), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_block_height(info, -1), 0);
+}
+
+static void drm_format_min_pitch_invalid(struct kunit *test)
 {
 	const struct drm_format_info *info = NULL;
 
-	/* Test invalid arguments */
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	/* Test 1 plane 8 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_RGB332);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+}
+
+static void drm_format_min_pitch_one_plane_8bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB332);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1));
+}
 
-	/* Test 1 plane 16 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_XRGB4444);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_16bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_XRGB4444);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1) * 2);
+}
 
-	/* Test 1 plane 24 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_RGB888);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 3);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 6);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 3072);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 5760);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 12288);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2013);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_24bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_RGB888);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 3);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 6);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 3072);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 5760);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 12288);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2013);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 3);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 3);
+}
 
-	/* Test 1 plane 32 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_ABGR8888);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 8);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 2560);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 7680);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 16384);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 2684);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_one_plane_32bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_ABGR8888);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 8);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 2560);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 7680);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 16384);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 2684);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 4);
+}
 
-	/* Test 2 planes format */
-	info = drm_format_info(DRM_FORMAT_NV12);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 672);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_two_plane(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_NV12);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 672);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1)),
 			(uint64_t)(UINT_MAX - 1));
-	FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) /  2),
 			(uint64_t)(UINT_MAX - 1));
+}
 
-	/* Test 3 planes 8 bits per pixel format */
-	info = drm_format_info(DRM_FORMAT_YUV422);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 3, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 1) != 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 2) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 640);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 320) != 320);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 320) != 320);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 1024);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 512) != 512);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 512) != 512);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 1920);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 960) != 960);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 960) != 960);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 4096);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 2048) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 2048) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 671);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 336) != 336);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, 336) != 336);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_three_plane_8bpp(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_YUV422);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 3, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 1), 1);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 640);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 320), 320);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 320), 320);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 1024);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 512), 512);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 512), 512);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 1920);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 960), 960);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 960), 960);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 4096);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 2048), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 2048), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 671);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 336), 336);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, 336), 336);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX / 2 + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, UINT_MAX / 2 + 1),
 			(uint64_t)UINT_MAX / 2 + 1);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 2, (UINT_MAX - 1) / 2),
 			(uint64_t)(UINT_MAX - 1) / 2);
+}
 
-	/* Test tiled format */
-	info = drm_format_info(DRM_FORMAT_X0L2);
-	FAIL_ON(!info);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, -1, 0) != 0);
-	FAIL_ON(drm_format_info_min_pitch(info, 1, 0) != 0);
-
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1) != 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 2) != 4);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 640) != 1280);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1024) != 2048);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 1920) != 3840);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 4096) != 8192);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, 671) != 1342);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX) !=
+static void drm_format_min_pitch_tiled(struct kunit *test)
+{
+	const struct drm_format_info *info = drm_format_info(DRM_FORMAT_X0L2);
+
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, info);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, -1, 0), 0);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 1, 0), 0);
+
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1), 2);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 2), 4);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 640), 1280);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1024), 2048);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 1920), 3840);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 4096), 8192);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, 671), 1342);
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX),
 			(uint64_t)UINT_MAX * 2);
-	FAIL_ON(drm_format_info_min_pitch(info, 0, UINT_MAX - 1) !=
+	KUNIT_EXPECT_EQ(test, drm_format_info_min_pitch(info, 0, UINT_MAX - 1),
 			(uint64_t)(UINT_MAX - 1) * 2);
-
-	return 0;
 }
+
+static struct kunit_case drm_format_tests[] = {
+	KUNIT_CASE(drm_format_block_width_invalid),
+	KUNIT_CASE(drm_format_block_width_one_plane),
+	KUNIT_CASE(drm_format_block_width_two_plane),
+	KUNIT_CASE(drm_format_block_width_three_plane),
+	KUNIT_CASE(drm_format_block_width_tiled),
+	KUNIT_CASE(drm_format_block_height_invalid),
+	KUNIT_CASE(drm_format_block_height_one_plane),
+	KUNIT_CASE(drm_format_block_height_two_plane),
+	KUNIT_CASE(drm_format_block_height_three_plane),
+	KUNIT_CASE(drm_format_block_height_tiled),
+	KUNIT_CASE(drm_format_min_pitch_invalid),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_8bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_16bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_24bpp),
+	KUNIT_CASE(drm_format_min_pitch_one_plane_32bpp),
+	KUNIT_CASE(drm_format_min_pitch_two_plane),
+	KUNIT_CASE(drm_format_min_pitch_three_plane_8bpp),
+	KUNIT_CASE(drm_format_min_pitch_tiled),
+	{}
+};
+
+static struct kunit_suite drm_format_test_suite = {
+	.name = "drm_format_tests",
+	.test_cases = drm_format_tests,
+};
+
+kunit_test_suite(drm_format_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index 8744fd840406..f6cfce2a5863 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,9 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_drm_format_block_width(void *ignored);
-int igt_check_drm_format_block_height(void *ignored);
-int igt_check_drm_format_min_pitch(void *ignored);
 int igt_check_drm_framebuffer_create(void *ignored);
 int igt_damage_iter_no_damage(void *ignored);
 int igt_damage_iter_no_damage_fractional_src(void *ignored);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 04/10] drm: test-drm_framebuffer: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

Mocking was moved to .init() in order to separate it from test logic.
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   3 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   1 -
 .../gpu/drm/selftests/test-drm_framebuffer.c  | 109 +++++++++++-------
 .../drm/selftests/test-drm_modeset_common.h   |   1 -
 4 files changed, 68 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 76c127613d1a..1235eadca884 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-                      test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
@@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
-	test-drm_format.o
+	test-drm_format.o test-drm_framebuffer.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 5f253d9e573c..66f6b31e1a7f 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,7 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
 selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
 selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
 selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
index 61b44d3a6a61..faa01cefe4e5 100644
--- a/drivers/gpu/drm/selftests/test-drm_framebuffer.c
+++ b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
@@ -3,6 +3,7 @@
  * Test cases for the drm_framebuffer functions
  */
 
+#include <kunit/test.h>
 #include <linux/kernel.h>
 
 #include <drm/drm_device.h>
@@ -12,20 +13,67 @@
 
 #include "../drm_crtc_internal.h"
 
-#include "test-drm_modeset_common.h"
-
 #define MIN_WIDTH 4
 #define MAX_WIDTH 4096
 #define MIN_HEIGHT 4
 #define MAX_HEIGHT 4096
 
-struct drm_framebuffer_test {
+static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
+					      struct drm_file *file_priv,
+					      const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	int *buffer_created = dev->dev_private;
+
+	*buffer_created = 1;
+
+	return ERR_PTR(-EINVAL);
+}
+
+static const struct drm_mode_config_funcs mock_config_funcs = {
+	.fb_create = fb_create_mock,
+};
+
+static int drm_framebuffer_test_init(struct kunit *test)
+{
+	struct drm_device *mock;
+
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
+
+	mock->mode_config = (struct drm_mode_config) {
+		.min_width = MIN_WIDTH,
+		.max_width = MAX_WIDTH,
+		.min_height = MIN_HEIGHT,
+		.max_height = MAX_HEIGHT,
+		.allow_fb_modifiers = true,
+		.funcs = &mock_config_funcs,
+	};
+
+	test->priv = mock;
+
+	return 0;
+}
+
+struct drm_framebuffer_create_test {
 	int buffer_created;
 	struct drm_mode_fb_cmd2 cmd;
 	const char *name;
 };
 
-static struct drm_framebuffer_test createbuffer_tests[] = {
+static void test_drm_framebuffer_create(struct kunit *test)
+{
+	const struct drm_framebuffer_create_test *params = test->param_value;
+	struct drm_device *mock = test->priv;
+	int buffer_created = 0;
+
+	mock->dev_private = &buffer_created;
+
+	drm_internal_framebuffer_create(mock, &params->cmd, NULL);
+
+	KUNIT_EXPECT_EQ(test, buffer_created, params->buffer_created);
+}
+
+static const struct drm_framebuffer_create_test drm_framebuffer_create_tests[] = {
 { .buffer_created = 1, .name = "ABGR8888 normal sizes",
 	.cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
 		 .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
@@ -304,48 +352,25 @@ static struct drm_framebuffer_test createbuffer_tests[] = {
 },
 };
 
-static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
-					      struct drm_file *file_priv,
-					      const struct drm_mode_fb_cmd2 *mode_cmd)
+static void drm_framebuffer_create_desc(const struct drm_framebuffer_create_test *t,
+					char *desc)
 {
-	int *buffer_created = dev->dev_private;
-	*buffer_created = 1;
-	return ERR_PTR(-EINVAL);
+	sprintf(desc, "%s", t->name);
 }
 
-static struct drm_mode_config_funcs mock_config_funcs = {
-	.fb_create = fb_create_mock,
-};
+KUNIT_ARRAY_PARAM(drm_framebuffer_create,
+		  drm_framebuffer_create_tests,
+		  drm_framebuffer_create_desc);
 
-static struct drm_device mock_drm_device = {
-	.mode_config = {
-		.min_width = MIN_WIDTH,
-		.max_width = MAX_WIDTH,
-		.min_height = MIN_HEIGHT,
-		.max_height = MAX_HEIGHT,
-		.allow_fb_modifiers = true,
-		.funcs = &mock_config_funcs,
-	},
+static struct kunit_case drm_framebuffer_tests[] = {
+	KUNIT_CASE_PARAM(test_drm_framebuffer_create, drm_framebuffer_create_gen_params),
+	{}
 };
 
-static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
-{
-	int buffer_created = 0;
-
-	mock_drm_device.dev_private = &buffer_created;
-	drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
-	return buffer_created;
-}
-
-int igt_check_drm_framebuffer_create(void *ignored)
-{
-	int i = 0;
-
-	for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
-		FAIL(createbuffer_tests[i].buffer_created !=
-				execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
-		     "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
-	}
+static struct kunit_suite drm_framebuffer_test_suite = {
+	.name = "drm_framebuffer_tests",
+	.init = drm_framebuffer_test_init,
+	.test_cases = drm_framebuffer_tests,
+};
 
-	return 0;
-}
+kunit_test_suite(drm_framebuffer_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index f6cfce2a5863..c09f38b791ad 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_drm_framebuffer_create(void *ignored);
 int igt_damage_iter_no_damage(void *ignored);
 int igt_damage_iter_no_damage_fractional_src(void *ignored);
 int igt_damage_iter_no_damage_src_moved(void *ignored);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 04/10] drm: test-drm_framebuffer: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

Mocking was moved to .init() in order to separate it from test logic.
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   3 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   1 -
 .../gpu/drm/selftests/test-drm_framebuffer.c  | 109 +++++++++++-------
 .../drm/selftests/test-drm_modeset_common.h   |   1 -
 4 files changed, 68 insertions(+), 46 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 76c127613d1a..1235eadca884 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-                      test-drm_framebuffer.o \
 		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
@@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
-	test-drm_format.o
+	test-drm_format.o test-drm_framebuffer.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 5f253d9e573c..66f6b31e1a7f 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,7 +10,6 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(check_drm_framebuffer_create, igt_check_drm_framebuffer_create)
 selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
 selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
 selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
index 61b44d3a6a61..faa01cefe4e5 100644
--- a/drivers/gpu/drm/selftests/test-drm_framebuffer.c
+++ b/drivers/gpu/drm/selftests/test-drm_framebuffer.c
@@ -3,6 +3,7 @@
  * Test cases for the drm_framebuffer functions
  */
 
+#include <kunit/test.h>
 #include <linux/kernel.h>
 
 #include <drm/drm_device.h>
@@ -12,20 +13,67 @@
 
 #include "../drm_crtc_internal.h"
 
-#include "test-drm_modeset_common.h"
-
 #define MIN_WIDTH 4
 #define MAX_WIDTH 4096
 #define MIN_HEIGHT 4
 #define MAX_HEIGHT 4096
 
-struct drm_framebuffer_test {
+static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
+					      struct drm_file *file_priv,
+					      const struct drm_mode_fb_cmd2 *mode_cmd)
+{
+	int *buffer_created = dev->dev_private;
+
+	*buffer_created = 1;
+
+	return ERR_PTR(-EINVAL);
+}
+
+static const struct drm_mode_config_funcs mock_config_funcs = {
+	.fb_create = fb_create_mock,
+};
+
+static int drm_framebuffer_test_init(struct kunit *test)
+{
+	struct drm_device *mock;
+
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
+
+	mock->mode_config = (struct drm_mode_config) {
+		.min_width = MIN_WIDTH,
+		.max_width = MAX_WIDTH,
+		.min_height = MIN_HEIGHT,
+		.max_height = MAX_HEIGHT,
+		.allow_fb_modifiers = true,
+		.funcs = &mock_config_funcs,
+	};
+
+	test->priv = mock;
+
+	return 0;
+}
+
+struct drm_framebuffer_create_test {
 	int buffer_created;
 	struct drm_mode_fb_cmd2 cmd;
 	const char *name;
 };
 
-static struct drm_framebuffer_test createbuffer_tests[] = {
+static void test_drm_framebuffer_create(struct kunit *test)
+{
+	const struct drm_framebuffer_create_test *params = test->param_value;
+	struct drm_device *mock = test->priv;
+	int buffer_created = 0;
+
+	mock->dev_private = &buffer_created;
+
+	drm_internal_framebuffer_create(mock, &params->cmd, NULL);
+
+	KUNIT_EXPECT_EQ(test, buffer_created, params->buffer_created);
+}
+
+static const struct drm_framebuffer_create_test drm_framebuffer_create_tests[] = {
 { .buffer_created = 1, .name = "ABGR8888 normal sizes",
 	.cmd = { .width = 600, .height = 600, .pixel_format = DRM_FORMAT_ABGR8888,
 		 .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 },
@@ -304,48 +352,25 @@ static struct drm_framebuffer_test createbuffer_tests[] = {
 },
 };
 
-static struct drm_framebuffer *fb_create_mock(struct drm_device *dev,
-					      struct drm_file *file_priv,
-					      const struct drm_mode_fb_cmd2 *mode_cmd)
+static void drm_framebuffer_create_desc(const struct drm_framebuffer_create_test *t,
+					char *desc)
 {
-	int *buffer_created = dev->dev_private;
-	*buffer_created = 1;
-	return ERR_PTR(-EINVAL);
+	sprintf(desc, "%s", t->name);
 }
 
-static struct drm_mode_config_funcs mock_config_funcs = {
-	.fb_create = fb_create_mock,
-};
+KUNIT_ARRAY_PARAM(drm_framebuffer_create,
+		  drm_framebuffer_create_tests,
+		  drm_framebuffer_create_desc);
 
-static struct drm_device mock_drm_device = {
-	.mode_config = {
-		.min_width = MIN_WIDTH,
-		.max_width = MAX_WIDTH,
-		.min_height = MIN_HEIGHT,
-		.max_height = MAX_HEIGHT,
-		.allow_fb_modifiers = true,
-		.funcs = &mock_config_funcs,
-	},
+static struct kunit_case drm_framebuffer_tests[] = {
+	KUNIT_CASE_PARAM(test_drm_framebuffer_create, drm_framebuffer_create_gen_params),
+	{}
 };
 
-static int execute_drm_mode_fb_cmd2(struct drm_mode_fb_cmd2 *r)
-{
-	int buffer_created = 0;
-
-	mock_drm_device.dev_private = &buffer_created;
-	drm_internal_framebuffer_create(&mock_drm_device, r, NULL);
-	return buffer_created;
-}
-
-int igt_check_drm_framebuffer_create(void *ignored)
-{
-	int i = 0;
-
-	for (i = 0; i < ARRAY_SIZE(createbuffer_tests); i++) {
-		FAIL(createbuffer_tests[i].buffer_created !=
-				execute_drm_mode_fb_cmd2(&createbuffer_tests[i].cmd),
-		     "Test %d: \"%s\" failed\n", i, createbuffer_tests[i].name);
-	}
+static struct kunit_suite drm_framebuffer_test_suite = {
+	.name = "drm_framebuffer_tests",
+	.init = drm_framebuffer_test_init,
+	.test_cases = drm_framebuffer_tests,
+};
 
-	return 0;
-}
+kunit_test_suite(drm_framebuffer_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index f6cfce2a5863..c09f38b791ad 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_check_drm_framebuffer_create(void *ignored);
 int igt_damage_iter_no_damage(void *ignored);
 int igt_damage_iter_no_damage_fractional_src(void *ignored);
 int igt_damage_iter_no_damage_src_moved(void *ignored);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 05/10] drm: test-drm_damage_helper: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

Mocking was moved to .init() in order to separate it from test logic.
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   5 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |  21 -
 .../drm/selftests/test-drm_damage_helper.c    | 570 +++++++++---------
 .../drm/selftests/test-drm_modeset_common.h   |  21 -
 4 files changed, 288 insertions(+), 329 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 1235eadca884..35f2f40dbaf3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
+		      test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
-	test-drm_format.o test-drm_framebuffer.o
+	test-drm_format.o test-drm_framebuffer.o \
+	test-drm_damage_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 66f6b31e1a7f..b6a6dba66b64 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,26 +10,5 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
-selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
-selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
-selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
-selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
-selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
-selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
-selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
-selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
-selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
-selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
-selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
-selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
-selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
-selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
-selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
-selftest(damage_iter_damage, igt_damage_iter_damage)
-selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
-selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
-selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
-selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
 selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
 selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
index 8d8d8e214c28..685d87575c3a 100644
--- a/drivers/gpu/drm/selftests/test-drm_damage_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
@@ -3,39 +3,55 @@
  * Test case for drm_damage_helper functions
  */
 
-#define pr_fmt(fmt) "drm_damage_helper: " fmt
+#include <kunit/test.h>
 
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_plane.h>
 #include <drm/drm_drv.h>
 
-#include "test-drm_modeset_common.h"
-
-struct drm_driver mock_driver;
-static struct drm_device mock_device;
-static struct drm_object_properties mock_obj_props;
-static struct drm_plane mock_plane;
-static struct drm_property mock_prop;
+/* common mocked structs many tests need */
+struct drm_damage_mock {
+	struct drm_framebuffer fb;
+	struct drm_driver driver;
+	struct drm_device device;
+	struct drm_object_properties obj_props;
+	struct drm_plane plane;
+	struct drm_property prop;
+	struct drm_plane_state state;
+	struct drm_plane_state old_state;
+};
 
-static void mock_setup(struct drm_plane_state *state)
+static int drm_damage_test_init(struct kunit *test)
 {
-	static bool setup_done = false;
+	struct drm_damage_mock *mock;
 
-	state->plane = &mock_plane;
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
 
-	if (setup_done)
-		return;
+	mock->fb.width = 2048;
+	mock->fb.height = 2048;
 
 	/* just enough so that drm_plane_enable_fb_damage_clips() works */
-	mock_device.driver = &mock_driver;
-	mock_device.mode_config.prop_fb_damage_clips = &mock_prop;
-	mock_plane.dev = &mock_device;
-	mock_obj_props.count = 0;
-	mock_plane.base.properties = &mock_obj_props;
-	mock_prop.base.id = 1; /* 0 is an invalid id */
-	mock_prop.dev = &mock_device;
-
-	drm_plane_enable_fb_damage_clips(&mock_plane);
+	mock->device.driver = &mock->driver;
+	mock->device.mode_config.prop_fb_damage_clips = &mock->prop;
+	mock->plane.dev = &mock->device;
+	mock->obj_props.count = 0;
+	mock->plane.base.properties = &mock->obj_props;
+	mock->prop.base.id = 1; /* 0 is an invalid id */
+	mock->prop.dev = &mock->device;
+
+	drm_plane_enable_fb_damage_clips(&mock->plane);
+
+	mock->state.crtc = ZERO_SIZE_PTR;
+	mock->state.fb = &mock->fb;
+	mock->state.visible = true;
+	mock->state.plane = &mock->plane;
+
+	mock->old_state.plane = &mock->plane;
+
+	test->priv = mock;
+
+	return 0;
 }
 
 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
@@ -69,8 +85,8 @@ static void set_plane_damage(struct drm_plane_state *state,
 	state->fb_damage_clips = damage_blob;
 }
 
-static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
-			      int x1, int y1, int x2, int y2)
+static void check_damage_clip(struct kunit *test, struct drm_plane_state *state,
+			      struct drm_rect *r, int x1, int y1, int x2, int y2)
 {
 	/*
 	 * Round down x1/y1 and round up x2/y2. This is because damage is not in
@@ -81,587 +97,571 @@ static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
 	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
 	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
 
-	if (x1 >= x2 || y1 >= y2) {
-		pr_err("Cannot have damage clip with no dimension.\n");
-		return false;
-	}
-
-	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
-		pr_err("Damage cannot be outside rounded plane src.\n");
-		return false;
-	}
-
-	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
-		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
-		return false;
-	}
+	KUNIT_EXPECT_FALSE_MSG(test, x1 >= x2 || y1 >= y2,
+			       "Cannot have damage clip with no dimension.");
+	KUNIT_EXPECT_FALSE_MSG(test, x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2,
+			       "Damage cannot be outside rounded plane src.");
 
-	return true;
+	KUNIT_EXPECT_TRUE_MSG(test, r->x1 == x1 && r->y1 == y1 && r->x2 == x2 && r->y2 == y2,
+			      "Damage = %d %d %d %d, expected = %d %d %d %d",
+			      r->x1, r->y1, r->x2, r->y2,
+			      x1, y1, x2, y2);
 }
 
-const struct drm_framebuffer fb = {
-	.width = 2048,
-	.height = 2048
-};
-
-/* common mocked structs many tests need */
-#define MOCK_VARIABLES() \
-	struct drm_plane_state old_state; \
-	struct drm_plane_state state = { \
-		.crtc = ZERO_SIZE_PTR, \
-		.fb = (struct drm_framebuffer *) &fb, \
-		.visible = true, \
-	}; \
-	mock_setup(&old_state); \
-	mock_setup(&state);
-
-int igt_damage_iter_no_damage(void *ignored)
+static void drm_damage_iter_no_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
+	struct drm_framebuffer *fb = &mock->fb;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src same as fb size. */
-	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
-	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, fb->width << 16, fb->height << 16);
+	set_plane_src(state, 0, 0, fb->width << 16, fb->height << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 0, 0, 2048, 2048);
 }
 
-int igt_damage_iter_no_damage_fractional_src(void *ignored)
+static void drm_damage_iter_no_damage_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return rounded off plane src as damage.");
+	check_damage_clip(test, state, &clip, 3, 3, 1028, 772);
 }
 
-int igt_damage_iter_no_damage_src_moved(void *ignored)
+static void drm_damage_iter_no_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src moved since old plane state. */
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 10 << 16, 10 << 16,
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 10 << 16, 10 << 16,
 		      (10 + 1024) << 16, (10 + 768) << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 10, 10, 1034, 778);
 }
 
-int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
+static void drm_damage_iter_no_damage_fractional_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part and it moved since old plane state. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 }
 
-int igt_damage_iter_no_damage_not_visible(void *ignored)
+static void drm_damage_iter_no_damage_not_visible(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	state.visible = false;
+	state->visible = false;
 
-	mock_setup(&old_state);
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_no_damage_no_crtc(void *ignored)
+static void drm_damage_iter_no_damage_no_crtc(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	state.crtc = NULL;
+	state->crtc = NULL;
 
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_no_damage_no_fb(void *ignored)
+static void drm_damage_iter_no_damage_no_fb(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
-	struct drm_plane_state old_state;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	struct drm_plane_state state = {
-		.crtc = ZERO_SIZE_PTR,
-		.fb = 0,
-	};
-
-	mock_setup(&old_state);
+	state->fb = NULL;
 
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 0);
 }
 
-int igt_damage_iter_simple_damage(void *ignored)
+static void drm_damage_iter_simple_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage set to plane src */
 	set_damage_clip(&damage, 0, 0, 1024, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 0, 0, 1024, 768);
 }
 
-int igt_damage_iter_single_damage(void *ignored)
+static void drm_damage_iter_single_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	set_damage_clip(&damage, 256, 192, 768, 576);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 256, 192, 768, 576);
 }
 
-int igt_damage_iter_single_damage_intersect_src(void *ignored)
+static void drm_damage_iter_single_damage_intersect_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 256, 192, 1360, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage clipped to src.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to src.");
+	check_damage_clip(test, state, &clip, 256, 192, 1024, 768);
 }
 
-int igt_damage_iter_single_damage_outside_src(void *ignored)
+static void drm_damage_iter_single_damage_outside_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_single_damage_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_damage_clip(&damage, 10, 10, 256, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 10, 10, 256, 330);
 }
 
-int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_intersect_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 10, 1, 1360, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to rounded off src.");
+	check_damage_clip(test, state, &clip, 10, 4, 1029, 330);
 }
 
-int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_outside_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 0);
 }
 
-int igt_damage_iter_single_damage_src_moved(void *ignored)
+static void drm_damage_iter_single_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src moved since old plane state. */
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 10 << 16, 10 << 16,
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 10 << 16, 10 << 16,
 		      (10 + 1024) << 16, (10 + 768) << 16);
 	set_damage_clip(&damage, 20, 30, 256, 256);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 1);
+	check_damage_clip(test, state, &clip, 10, 10, 1034, 778);
 }
 
-int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
+static void drm_damage_iter_single_damage_fractional_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src with fractional part moved since old plane state. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 20, 30, 1360, 256);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 1);
+	check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 }
 
-int igt_damage_iter_damage(void *ignored)
+static void drm_damage_iter_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
-			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+			check_damage_clip(test, state, &clip, 20, 30, 200, 180);
 		if (num_hits == 1)
-			FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+			check_damage_clip(test, state, &clip, 240, 200, 280, 250);
 		num_hits++;
 	}
 
-	FAIL(num_hits != 2, "Should return damage when set.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 2);
 }
 
-int igt_damage_iter_damage_one_intersect(void *ignored)
+static void drm_damage_iter_damage_one_intersect(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* 2 damage clips, one intersect plane src. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
 	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
-			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+			check_damage_clip(test, state, &clip, 20, 30, 200, 180);
 		if (num_hits == 1)
-			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+			check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 		num_hits++;
 	}
 
-	FAIL(num_hits != 2, "Should return damage when set.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 2);
 }
 
-int igt_damage_iter_damage_one_outside(void *ignored)
+static void drm_damage_iter_damage_one_outside(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 240, 200, 280, 250);
 }
 
-int igt_damage_iter_damage_src_moved(void *ignored)
+static void drm_damage_iter_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return round off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return round off plane src as damage.");
+	check_damage_clip(test, state, &clip, 3, 3, 1028, 772);
 }
 
-int igt_damage_iter_damage_not_visible(void *ignored)
+static void drm_damage_iter_damage_not_visible(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
+	state->visible = false;
 
-	state.visible = false;
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should not return any damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should not return any damage.");
 }
+
+static struct kunit_case drm_damage_helper_tests[] = {
+	KUNIT_CASE(drm_damage_iter_no_damage),
+	KUNIT_CASE(drm_damage_iter_no_damage_fractional_src),
+	KUNIT_CASE(drm_damage_iter_no_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_no_damage_fractional_src_moved),
+	KUNIT_CASE(drm_damage_iter_no_damage_not_visible),
+	KUNIT_CASE(drm_damage_iter_no_damage_no_crtc),
+	KUNIT_CASE(drm_damage_iter_no_damage_no_fb),
+	KUNIT_CASE(drm_damage_iter_simple_damage),
+	KUNIT_CASE(drm_damage_iter_single_damage),
+	KUNIT_CASE(drm_damage_iter_single_damage_intersect_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_outside_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_intersect_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_outside_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_single_damage_fractional_src_moved),
+	KUNIT_CASE(drm_damage_iter_damage),
+	KUNIT_CASE(drm_damage_iter_damage_one_intersect),
+	KUNIT_CASE(drm_damage_iter_damage_one_outside),
+	KUNIT_CASE(drm_damage_iter_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_damage_not_visible),
+	{}
+};
+
+static struct kunit_suite drm_damage_helper_test_suite = {
+	.name = "drm_damage_helper_tests",
+	.init = drm_damage_test_init,
+	.test_cases = drm_damage_helper_tests,
+};
+
+kunit_test_suite(drm_damage_helper_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index c09f38b791ad..1501d99aee2f 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,27 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_damage_iter_no_damage(void *ignored);
-int igt_damage_iter_no_damage_fractional_src(void *ignored);
-int igt_damage_iter_no_damage_src_moved(void *ignored);
-int igt_damage_iter_no_damage_fractional_src_moved(void *ignored);
-int igt_damage_iter_no_damage_not_visible(void *ignored);
-int igt_damage_iter_no_damage_no_crtc(void *ignored);
-int igt_damage_iter_no_damage_no_fb(void *ignored);
-int igt_damage_iter_simple_damage(void *ignored);
-int igt_damage_iter_single_damage(void *ignored);
-int igt_damage_iter_single_damage_intersect_src(void *ignored);
-int igt_damage_iter_single_damage_outside_src(void *ignored);
-int igt_damage_iter_single_damage_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_outside_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_src_moved(void *ignored);
-int igt_damage_iter_single_damage_fractional_src_moved(void *ignored);
-int igt_damage_iter_damage(void *ignored);
-int igt_damage_iter_damage_one_intersect(void *ignored);
-int igt_damage_iter_damage_one_outside(void *ignored);
-int igt_damage_iter_damage_src_moved(void *ignored);
-int igt_damage_iter_damage_not_visible(void *ignored);
 int igt_dp_mst_calc_pbn_mode(void *ignored);
 int igt_dp_mst_sideband_msg_req_decode(void *ignored);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 05/10] drm: test-drm_damage_helper: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

Mocking was moved to .init() in order to separate it from test logic.
No functional changes.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   5 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |  21 -
 .../drm/selftests/test-drm_damage_helper.c    | 570 +++++++++---------
 .../drm/selftests/test-drm_modeset_common.h   |  21 -
 4 files changed, 288 insertions(+), 329 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 1235eadca884..35f2f40dbaf3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,12 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-		      test-drm_damage_helper.o test-drm_dp_mst_helper.o \
+		      test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
-	test-drm_format.o test-drm_framebuffer.o
+	test-drm_format.o test-drm_framebuffer.o \
+	test-drm_damage_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index 66f6b31e1a7f..b6a6dba66b64 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,26 +10,5 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(damage_iter_no_damage, igt_damage_iter_no_damage)
-selftest(damage_iter_no_damage_fractional_src, igt_damage_iter_no_damage_fractional_src)
-selftest(damage_iter_no_damage_src_moved, igt_damage_iter_no_damage_src_moved)
-selftest(damage_iter_no_damage_fractional_src_moved, igt_damage_iter_no_damage_fractional_src_moved)
-selftest(damage_iter_no_damage_not_visible, igt_damage_iter_no_damage_not_visible)
-selftest(damage_iter_no_damage_no_crtc, igt_damage_iter_no_damage_no_crtc)
-selftest(damage_iter_no_damage_no_fb, igt_damage_iter_no_damage_no_fb)
-selftest(damage_iter_simple_damage, igt_damage_iter_simple_damage)
-selftest(damage_iter_single_damage, igt_damage_iter_single_damage)
-selftest(damage_iter_single_damage_intersect_src, igt_damage_iter_single_damage_intersect_src)
-selftest(damage_iter_single_damage_outside_src, igt_damage_iter_single_damage_outside_src)
-selftest(damage_iter_single_damage_fractional_src, igt_damage_iter_single_damage_fractional_src)
-selftest(damage_iter_single_damage_intersect_fractional_src, igt_damage_iter_single_damage_intersect_fractional_src)
-selftest(damage_iter_single_damage_outside_fractional_src, igt_damage_iter_single_damage_outside_fractional_src)
-selftest(damage_iter_single_damage_src_moved, igt_damage_iter_single_damage_src_moved)
-selftest(damage_iter_single_damage_fractional_src_moved, igt_damage_iter_single_damage_fractional_src_moved)
-selftest(damage_iter_damage, igt_damage_iter_damage)
-selftest(damage_iter_damage_one_intersect, igt_damage_iter_damage_one_intersect)
-selftest(damage_iter_damage_one_outside, igt_damage_iter_damage_one_outside)
-selftest(damage_iter_damage_src_moved, igt_damage_iter_damage_src_moved)
-selftest(damage_iter_damage_not_visible, igt_damage_iter_damage_not_visible)
 selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
 selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
index 8d8d8e214c28..685d87575c3a 100644
--- a/drivers/gpu/drm/selftests/test-drm_damage_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_damage_helper.c
@@ -3,39 +3,55 @@
  * Test case for drm_damage_helper functions
  */
 
-#define pr_fmt(fmt) "drm_damage_helper: " fmt
+#include <kunit/test.h>
 
 #include <drm/drm_damage_helper.h>
 #include <drm/drm_plane.h>
 #include <drm/drm_drv.h>
 
-#include "test-drm_modeset_common.h"
-
-struct drm_driver mock_driver;
-static struct drm_device mock_device;
-static struct drm_object_properties mock_obj_props;
-static struct drm_plane mock_plane;
-static struct drm_property mock_prop;
+/* common mocked structs many tests need */
+struct drm_damage_mock {
+	struct drm_framebuffer fb;
+	struct drm_driver driver;
+	struct drm_device device;
+	struct drm_object_properties obj_props;
+	struct drm_plane plane;
+	struct drm_property prop;
+	struct drm_plane_state state;
+	struct drm_plane_state old_state;
+};
 
-static void mock_setup(struct drm_plane_state *state)
+static int drm_damage_test_init(struct kunit *test)
 {
-	static bool setup_done = false;
+	struct drm_damage_mock *mock;
 
-	state->plane = &mock_plane;
+	mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock);
 
-	if (setup_done)
-		return;
+	mock->fb.width = 2048;
+	mock->fb.height = 2048;
 
 	/* just enough so that drm_plane_enable_fb_damage_clips() works */
-	mock_device.driver = &mock_driver;
-	mock_device.mode_config.prop_fb_damage_clips = &mock_prop;
-	mock_plane.dev = &mock_device;
-	mock_obj_props.count = 0;
-	mock_plane.base.properties = &mock_obj_props;
-	mock_prop.base.id = 1; /* 0 is an invalid id */
-	mock_prop.dev = &mock_device;
-
-	drm_plane_enable_fb_damage_clips(&mock_plane);
+	mock->device.driver = &mock->driver;
+	mock->device.mode_config.prop_fb_damage_clips = &mock->prop;
+	mock->plane.dev = &mock->device;
+	mock->obj_props.count = 0;
+	mock->plane.base.properties = &mock->obj_props;
+	mock->prop.base.id = 1; /* 0 is an invalid id */
+	mock->prop.dev = &mock->device;
+
+	drm_plane_enable_fb_damage_clips(&mock->plane);
+
+	mock->state.crtc = ZERO_SIZE_PTR;
+	mock->state.fb = &mock->fb;
+	mock->state.visible = true;
+	mock->state.plane = &mock->plane;
+
+	mock->old_state.plane = &mock->plane;
+
+	test->priv = mock;
+
+	return 0;
 }
 
 static void set_plane_src(struct drm_plane_state *state, int x1, int y1, int x2,
@@ -69,8 +85,8 @@ static void set_plane_damage(struct drm_plane_state *state,
 	state->fb_damage_clips = damage_blob;
 }
 
-static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
-			      int x1, int y1, int x2, int y2)
+static void check_damage_clip(struct kunit *test, struct drm_plane_state *state,
+			      struct drm_rect *r, int x1, int y1, int x2, int y2)
 {
 	/*
 	 * Round down x1/y1 and round up x2/y2. This is because damage is not in
@@ -81,587 +97,571 @@ static bool check_damage_clip(struct drm_plane_state *state, struct drm_rect *r,
 	int src_x2 = (state->src.x2 >> 16) + !!(state->src.x2 & 0xFFFF);
 	int src_y2 = (state->src.y2 >> 16) + !!(state->src.y2 & 0xFFFF);
 
-	if (x1 >= x2 || y1 >= y2) {
-		pr_err("Cannot have damage clip with no dimension.\n");
-		return false;
-	}
-
-	if (x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2) {
-		pr_err("Damage cannot be outside rounded plane src.\n");
-		return false;
-	}
-
-	if (r->x1 != x1 || r->y1 != y1 || r->x2 != x2 || r->y2 != y2) {
-		pr_err("Damage = %d %d %d %d\n", r->x1, r->y1, r->x2, r->y2);
-		return false;
-	}
+	KUNIT_EXPECT_FALSE_MSG(test, x1 >= x2 || y1 >= y2,
+			       "Cannot have damage clip with no dimension.");
+	KUNIT_EXPECT_FALSE_MSG(test, x1 < src_x1 || y1 < src_y1 || x2 > src_x2 || y2 > src_y2,
+			       "Damage cannot be outside rounded plane src.");
 
-	return true;
+	KUNIT_EXPECT_TRUE_MSG(test, r->x1 == x1 && r->y1 == y1 && r->x2 == x2 && r->y2 == y2,
+			      "Damage = %d %d %d %d, expected = %d %d %d %d",
+			      r->x1, r->y1, r->x2, r->y2,
+			      x1, y1, x2, y2);
 }
 
-const struct drm_framebuffer fb = {
-	.width = 2048,
-	.height = 2048
-};
-
-/* common mocked structs many tests need */
-#define MOCK_VARIABLES() \
-	struct drm_plane_state old_state; \
-	struct drm_plane_state state = { \
-		.crtc = ZERO_SIZE_PTR, \
-		.fb = (struct drm_framebuffer *) &fb, \
-		.visible = true, \
-	}; \
-	mock_setup(&old_state); \
-	mock_setup(&state);
-
-int igt_damage_iter_no_damage(void *ignored)
+static void drm_damage_iter_no_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
+	struct drm_framebuffer *fb = &mock->fb;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src same as fb size. */
-	set_plane_src(&old_state, 0, 0, fb.width << 16, fb.height << 16);
-	set_plane_src(&state, 0, 0, fb.width << 16, fb.height << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, fb->width << 16, fb->height << 16);
+	set_plane_src(state, 0, 0, fb->width << 16, fb->height << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 2048, 2048));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 0, 0, 2048, 2048);
 }
 
-int igt_damage_iter_no_damage_fractional_src(void *ignored)
+static void drm_damage_iter_no_damage_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return rounded off plane src as damage.");
+	check_damage_clip(test, state, &clip, 3, 3, 1028, 772);
 }
 
-int igt_damage_iter_no_damage_src_moved(void *ignored)
+static void drm_damage_iter_no_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src moved since old plane state. */
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 10 << 16, 10 << 16,
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 10 << 16, 10 << 16,
 		      (10 + 1024) << 16, (10 + 768) << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 10, 10, 1034, 778);
 }
 
-int igt_damage_iter_no_damage_fractional_src_moved(void *ignored)
+static void drm_damage_iter_no_damage_fractional_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part and it moved since old plane state. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return plane src as damage.");
+	check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 }
 
-int igt_damage_iter_no_damage_not_visible(void *ignored)
+static void drm_damage_iter_no_damage_not_visible(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	state.visible = false;
+	state->visible = false;
 
-	mock_setup(&old_state);
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_no_damage_no_crtc(void *ignored)
+static void drm_damage_iter_no_damage_no_crtc(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	state.crtc = NULL;
+	state->crtc = NULL;
 
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_no_damage_no_fb(void *ignored)
+static void drm_damage_iter_no_damage_no_fb(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
-	struct drm_plane_state old_state;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	struct drm_plane_state state = {
-		.crtc = ZERO_SIZE_PTR,
-		.fb = 0,
-	};
-
-	mock_setup(&old_state);
+	state->fb = NULL;
 
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 0);
 }
 
-int igt_damage_iter_simple_damage(void *ignored)
+static void drm_damage_iter_simple_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage set to plane src */
 	set_damage_clip(&damage, 0, 0, 1024, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 0, 0, 1024, 768));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 0, 0, 1024, 768);
 }
 
-int igt_damage_iter_single_damage(void *ignored)
+static void drm_damage_iter_single_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	set_damage_clip(&damage, 256, 192, 768, 576);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 768, 576));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 256, 192, 768, 576);
 }
 
-int igt_damage_iter_single_damage_intersect_src(void *ignored)
+static void drm_damage_iter_single_damage_intersect_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 256, 192, 1360, 768);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage clipped to src.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 256, 192, 1024, 768));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to src.");
+	check_damage_clip(test, state, &clip, 256, 192, 1024, 768);
 }
 
-int igt_damage_iter_single_damage_outside_src(void *ignored)
+static void drm_damage_iter_single_damage_outside_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should have no damage.");
 }
 
-int igt_damage_iter_single_damage_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	set_damage_clip(&damage, 10, 10, 256, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 256, 330));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 10, 10, 256, 330);
 }
 
-int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_intersect_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 10, 1, 1360, 330);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage clipped to rounded off src.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 4, 1029, 330));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage clipped to rounded off src.");
+	check_damage_clip(test, state, &clip, 10, 4, 1029, 330);
 }
 
-int igt_damage_iter_single_damage_outside_fractional_src(void *ignored)
+static void drm_damage_iter_single_damage_outside_fractional_src(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src has fractional part. */
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage clip outside plane src */
 	set_damage_clip(&damage, 1360, 1360, 1380, 1380);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should have no damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 0);
 }
 
-int igt_damage_iter_single_damage_src_moved(void *ignored)
+static void drm_damage_iter_single_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src moved since old plane state. */
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 10 << 16, 10 << 16,
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 10 << 16, 10 << 16,
 		      (10 + 1024) << 16, (10 + 768) << 16);
 	set_damage_clip(&damage, 20, 30, 256, 256);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 10, 10, 1034, 778));
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 1);
+	check_damage_clip(test, state, &clip, 10, 10, 1034, 778);
 }
 
-int igt_damage_iter_single_damage_fractional_src_moved(void *ignored)
+static void drm_damage_iter_single_damage_fractional_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage;
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
 	/* Plane src with fractional part moved since old plane state. */
-	set_plane_src(&old_state, 0x3fffe, 0x3fffe,
+	set_plane_src(old_state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* Damage intersect with plane src. */
 	set_damage_clip(&damage, 20, 30, 1360, 256);
 	set_damage_blob(&damage_blob, &damage, sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return rounded off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 1);
+	check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 }
 
-int igt_damage_iter_damage(void *ignored)
+static void drm_damage_iter_damage(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
-			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+			check_damage_clip(test, state, &clip, 20, 30, 200, 180);
 		if (num_hits == 1)
-			FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
+			check_damage_clip(test, state, &clip, 240, 200, 280, 250);
 		num_hits++;
 	}
 
-	FAIL(num_hits != 2, "Should return damage when set.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 2);
 }
 
-int igt_damage_iter_damage_one_intersect(void *ignored)
+static void drm_damage_iter_damage_one_intersect(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x40002, 0x40002,
+	set_plane_src(state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
 	/* 2 damage clips, one intersect plane src. */
 	set_damage_clip(&damage[0], 20, 30, 200, 180);
 	set_damage_clip(&damage[1], 2, 2, 1360, 1360);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip) {
 		if (num_hits == 0)
-			FAIL_ON(!check_damage_clip(&state, &clip, 20, 30, 200, 180));
+			check_damage_clip(test, state, &clip, 20, 30, 200, 180);
 		if (num_hits == 1)
-			FAIL_ON(!check_damage_clip(&state, &clip, 4, 4, 1029, 773));
+			check_damage_clip(test, state, &clip, 4, 4, 1029, 773);
 		num_hits++;
 	}
 
-	FAIL(num_hits != 2, "Should return damage when set.");
-
-	return 0;
+	KUNIT_EXPECT_EQ(test, num_hits, 2);
 }
 
-int igt_damage_iter_damage_one_outside(void *ignored)
+static void drm_damage_iter_damage_one_outside(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0, 0, 1024 << 16, 768 << 16);
-	set_plane_src(&state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(old_state, 0, 0, 1024 << 16, 768 << 16);
+	set_plane_src(state, 0, 0, 1024 << 16, 768 << 16);
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return damage when set.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 240, 200, 280, 250));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return damage when set.");
+	check_damage_clip(test, state, &clip, 240, 200, 280, 250);
 }
 
-int igt_damage_iter_damage_src_moved(void *ignored)
+static void drm_damage_iter_damage_src_moved(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 1, "Should return round off plane src as damage.");
-	FAIL_ON(!check_damage_clip(&state, &clip, 3, 3, 1028, 772));
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 1, "Should return round off plane src as damage.");
+	check_damage_clip(test, state, &clip, 3, 3, 1028, 772);
 }
 
-int igt_damage_iter_damage_not_visible(void *ignored)
+static void drm_damage_iter_damage_not_visible(struct kunit *test)
 {
+	struct drm_damage_mock *mock = test->priv;
+	struct drm_plane_state *old_state = &mock->old_state;
+	struct drm_plane_state *state = &mock->state;
 	struct drm_atomic_helper_damage_iter iter;
 	struct drm_property_blob damage_blob;
 	struct drm_mode_rect damage[2];
 	struct drm_rect clip;
 	uint32_t num_hits = 0;
 
-	MOCK_VARIABLES();
+	state->visible = false;
 
-	state.visible = false;
-
-	set_plane_src(&old_state, 0x40002, 0x40002,
+	set_plane_src(old_state, 0x40002, 0x40002,
 		      0x40002 + (1024 << 16), 0x40002 + (768 << 16));
-	set_plane_src(&state, 0x3fffe, 0x3fffe,
+	set_plane_src(state, 0x3fffe, 0x3fffe,
 		      0x3fffe + (1024 << 16), 0x3fffe + (768 << 16));
 	/* 2 damage clips, one outside plane src. */
 	set_damage_clip(&damage[0], 1360, 1360, 1380, 1380);
 	set_damage_clip(&damage[1], 240, 200, 280, 250);
 	set_damage_blob(&damage_blob, &damage[0], sizeof(damage));
-	set_plane_damage(&state, &damage_blob);
-	drm_atomic_helper_damage_iter_init(&iter, &old_state, &state);
+	set_plane_damage(state, &damage_blob);
+	drm_atomic_helper_damage_iter_init(&iter, old_state, state);
 	drm_atomic_for_each_plane_damage(&iter, &clip)
 		num_hits++;
 
-	FAIL(num_hits != 0, "Should not return any damage.");
-
-	return 0;
+	KUNIT_EXPECT_EQ_MSG(test, num_hits, 0, "Should not return any damage.");
 }
+
+static struct kunit_case drm_damage_helper_tests[] = {
+	KUNIT_CASE(drm_damage_iter_no_damage),
+	KUNIT_CASE(drm_damage_iter_no_damage_fractional_src),
+	KUNIT_CASE(drm_damage_iter_no_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_no_damage_fractional_src_moved),
+	KUNIT_CASE(drm_damage_iter_no_damage_not_visible),
+	KUNIT_CASE(drm_damage_iter_no_damage_no_crtc),
+	KUNIT_CASE(drm_damage_iter_no_damage_no_fb),
+	KUNIT_CASE(drm_damage_iter_simple_damage),
+	KUNIT_CASE(drm_damage_iter_single_damage),
+	KUNIT_CASE(drm_damage_iter_single_damage_intersect_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_outside_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_intersect_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_outside_fractional_src),
+	KUNIT_CASE(drm_damage_iter_single_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_single_damage_fractional_src_moved),
+	KUNIT_CASE(drm_damage_iter_damage),
+	KUNIT_CASE(drm_damage_iter_damage_one_intersect),
+	KUNIT_CASE(drm_damage_iter_damage_one_outside),
+	KUNIT_CASE(drm_damage_iter_damage_src_moved),
+	KUNIT_CASE(drm_damage_iter_damage_not_visible),
+	{}
+};
+
+static struct kunit_suite drm_damage_helper_test_suite = {
+	.name = "drm_damage_helper_tests",
+	.init = drm_damage_test_init,
+	.test_cases = drm_damage_helper_tests,
+};
+
+kunit_test_suite(drm_damage_helper_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index c09f38b791ad..1501d99aee2f 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,27 +20,6 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_damage_iter_no_damage(void *ignored);
-int igt_damage_iter_no_damage_fractional_src(void *ignored);
-int igt_damage_iter_no_damage_src_moved(void *ignored);
-int igt_damage_iter_no_damage_fractional_src_moved(void *ignored);
-int igt_damage_iter_no_damage_not_visible(void *ignored);
-int igt_damage_iter_no_damage_no_crtc(void *ignored);
-int igt_damage_iter_no_damage_no_fb(void *ignored);
-int igt_damage_iter_simple_damage(void *ignored);
-int igt_damage_iter_single_damage(void *ignored);
-int igt_damage_iter_single_damage_intersect_src(void *ignored);
-int igt_damage_iter_single_damage_outside_src(void *ignored);
-int igt_damage_iter_single_damage_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_intersect_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_outside_fractional_src(void *ignored);
-int igt_damage_iter_single_damage_src_moved(void *ignored);
-int igt_damage_iter_single_damage_fractional_src_moved(void *ignored);
-int igt_damage_iter_damage(void *ignored);
-int igt_damage_iter_damage_one_intersect(void *ignored);
-int igt_damage_iter_damage_one_outside(void *ignored);
-int igt_damage_iter_damage_src_moved(void *ignored);
-int igt_damage_iter_damage_not_visible(void *ignored);
 int igt_dp_mst_calc_pbn_mode(void *ignored);
 int igt_dp_mst_sideband_msg_req_decode(void *ignored);
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

igt_dp_mst_calc_pbn_mode was converted one-to-one,
igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   3 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
 .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
 .../drm/selftests/test-drm_modeset_common.h   |   2 -
 4 files changed, 330 insertions(+), 179 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 35f2f40dbaf3..77e37eebf099 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-		      test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
@@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
 	test-drm_format.o test-drm_framebuffer.o \
-	test-drm_damage_helper.o
+	test-drm_damage_helper.o test-drm_dp_mst_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index b6a6dba66b64..630770d30aba 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
-selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
index 6b4759ed6bfd..d0719f3c5a42 100644
--- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
@@ -3,54 +3,97 @@
  * Test cases for for the DRM DP MST helpers
  */
 
-#define PREFIX_STR "[drm_dp_mst_helper]"
-
+#include <kunit/test.h>
 #include <linux/random.h>
 
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_print.h>
 
 #include "../drm_dp_mst_topology_internal.h"
-#include "test-drm_modeset_common.h"
 
-int igt_dp_mst_calc_pbn_mode(void *ignored)
+struct dp_mst_calc_pbn_mode_test {
+	int rate;
+	int bpp;
+	int expected;
+	bool dsc;
+};
+
+static void dp_mst_calc_pbn_mode(struct kunit *test)
 {
-	int pbn, i;
-	const struct {
-		int rate;
-		int bpp;
-		int expected;
-		bool dsc;
-	} test_params[] = {
-		{ 154000, 30, 689, false },
-		{ 234000, 30, 1047, false },
-		{ 297000, 24, 1063, false },
-		{ 332880, 24, 50, true },
-		{ 324540, 24, 49, true },
-	};
+	const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
+	int pbn;
 
-	for (i = 0; i < ARRAY_SIZE(test_params); i++) {
-		pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
-					   test_params[i].bpp,
-					   test_params[i].dsc);
-		FAIL(pbn != test_params[i].expected,
-		     "Expected PBN %d for clock %d bpp %d, got %d\n",
-		     test_params[i].expected, test_params[i].rate,
-		     test_params[i].bpp, pbn);
-	}
+	pbn = drm_dp_calc_pbn_mode(params->rate,
+				   params->bpp,
+				   params->dsc);
+
+	KUNIT_EXPECT_EQ(test, pbn, params->expected);
+}
 
-	return 0;
+static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
+	{
+		.rate = 154000,
+		.bpp = 30,
+		.expected = 689,
+		.dsc = false,
+	},
+	{
+		.rate = 234000,
+		.bpp = 30,
+		.expected = 1047,
+		.dsc = false,
+	},
+	{
+		.rate = 297000,
+		.bpp = 24,
+		.expected = 1063,
+		.dsc = false,
+	},
+	{
+		.rate = 332880,
+		.bpp = 24,
+		.expected = 50,
+		.dsc = true,
+	},
+	{
+		.rate = 324540,
+		.bpp = 24,
+		.expected = 49,
+		.dsc = true,
+	},
+};
+
+static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
+				      char *desc)
+{
+	sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
+		t->rate, t->bpp, t->dsc ? "true" : "false");
 }
 
-static bool
-sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
-		       const struct drm_dp_sideband_msg_req_body *out)
+KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
+
+static void
+drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
+{
+	struct kunit *test = p->arg;
+
+	kunit_err(test, "%pV", vaf);
+}
+
+static void
+expect_sideband_msg_req_equal(struct kunit *test,
+			      const struct drm_dp_sideband_msg_req_body *in,
+			      const struct drm_dp_sideband_msg_req_body *out)
 {
 	const struct drm_dp_remote_i2c_read_tx *txin, *txout;
+	struct drm_printer p = {
+		.printfn = drm_dp_mst_helper_printfn,
+		.arg = test
+	};
 	int i;
 
 	if (in->req_type != out->req_type)
-		return false;
+		goto fail;
 
 	switch (in->req_type) {
 	/*
@@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		    IN.num_transactions != OUT.num_transactions ||
 		    IN.port_number != OUT.port_number ||
 		    IN.read_i2c_device_id != OUT.read_i2c_device_id)
-			return false;
+			goto fail;
 
 		for (i = 0; i < IN.num_transactions; i++) {
 			txin = &IN.transactions[i];
@@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 			    txin->num_bytes != txout->num_bytes ||
 			    txin->i2c_transaction_delay !=
 			    txout->i2c_transaction_delay)
-				return false;
+				goto fail;
 
 			if (memcmp(txin->bytes, txout->bytes,
 				   txin->num_bytes) != 0)
-				return false;
+				goto fail;
 		}
 		break;
 #undef IN
@@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		if (IN.dpcd_address != OUT.dpcd_address ||
 		    IN.num_bytes != OUT.num_bytes ||
 		    IN.port_number != OUT.port_number)
-			return false;
+			goto fail;
 
-		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
+		if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
+			goto fail;
+
+		break;
 #undef IN
 #undef OUT
 
@@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		if (IN.port_number != OUT.port_number ||
 		    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
 		    IN.num_bytes != OUT.num_bytes)
-			return false;
+			goto fail;
 
-		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
+		if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
+			goto fail;
+
+		break;
 #undef IN
 #undef OUT
 
 	default:
-		return memcmp(in, out, sizeof(*in)) == 0;
+		if (memcmp(in, out, sizeof(*in)) != 0)
+			goto fail;
 	}
 
-	return true;
+	return;
+
+fail:
+	drm_printf(&p, "Expected:\n");
+	drm_dp_dump_sideband_msg_req_body(in, 1, &p);
+	drm_printf(&p, "Got:\n");
+	drm_dp_dump_sideband_msg_req_body(out, 1, &p);
+	KUNIT_FAIL(test, "Encode/decode failed");
+}
+
+struct dp_mst_sideband_msg_req_decode_test {
+	const struct drm_dp_sideband_msg_req_body req;
+	const struct drm_dp_sideband_msg_req_body
+		(*f)(const struct drm_dp_sideband_msg_req_body *in);
+};
+
+const struct drm_dp_sideband_msg_req_body
+param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
+{
+	if (t->f)
+		return t->f(&t->req);
+
+	return t->req;
 }
 
-static bool
-sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
+static void dp_mst_sideband_msg_req_decode(struct kunit *test)
 {
+	const struct drm_dp_sideband_msg_req_body in =
+		param_to_dp_mst_sideband_msg_req_body(test->param_value);
 	struct drm_dp_sideband_msg_req_body *out;
-	struct drm_printer p = drm_err_printer(PREFIX_STR);
 	struct drm_dp_sideband_msg_tx *txmsg;
-	int i, ret;
-	bool result = true;
-
-	out = kzalloc(sizeof(*out), GFP_KERNEL);
-	if (!out)
-		return false;
-
-	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
-	if (!txmsg)
-		return false;
-
-	drm_dp_encode_sideband_req(in, txmsg);
-	ret = drm_dp_decode_sideband_req(txmsg, out);
-	if (ret < 0) {
-		drm_printf(&p, "Failed to decode sideband request: %d\n",
-			   ret);
-		result = false;
-		goto out;
-	}
+	int i;
 
-	if (!sideband_msg_req_equal(in, out)) {
-		drm_printf(&p, "Encode/decode failed, expected:\n");
-		drm_dp_dump_sideband_msg_req_body(in, 1, &p);
-		drm_printf(&p, "Got:\n");
-		drm_dp_dump_sideband_msg_req_body(out, 1, &p);
-		result = false;
-		goto out;
-	}
+	out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
 
-	switch (in->req_type) {
+	txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
+
+	drm_dp_encode_sideband_req(&in, txmsg);
+	KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
+
+	expect_sideband_msg_req_equal(test, &in, out);
+
+	switch (in.req_type) {
 	case DP_REMOTE_DPCD_WRITE:
 		kfree(out->u.dpcd_write.bytes);
 		break;
@@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
 		kfree(out->u.i2c_write.bytes);
 		break;
 	}
-
-	/* Clear everything but the req_type for the input */
-	memset(&in->u, 0, sizeof(in->u));
-
-out:
-	kfree(out);
-	kfree(txmsg);
-	return result;
 }
 
-int igt_dp_mst_sideband_msg_req_decode(void *unused)
+static u8 data[] = { 0xff, 0x0, 0xdd };
+
+const struct drm_dp_sideband_msg_req_body
+random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
 {
-	struct drm_dp_sideband_msg_req_body in = { 0 };
-	u8 data[] = { 0xff, 0x0, 0xdd };
-	int i;
+	struct drm_dp_query_stream_enc_status enc_status = { };
 
-#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
-
-	in.req_type = DP_ENUM_PATH_RESOURCES;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_POWER_UP_PHY;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_POWER_DOWN_PHY;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_ALLOCATE_PAYLOAD;
-	in.u.allocate_payload.number_sdp_streams = 3;
-	for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
-		in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
-	DO_TEST();
-	in.u.allocate_payload.port_number = 0xf;
-	DO_TEST();
-	in.u.allocate_payload.vcpi = 0x7f;
-	DO_TEST();
-	in.u.allocate_payload.pbn = U16_MAX;
-	DO_TEST();
-
-	in.req_type = DP_QUERY_PAYLOAD;
-	in.u.query_payload.port_number = 0xf;
-	DO_TEST();
-	in.u.query_payload.vcpi = 0x7f;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_DPCD_READ;
-	in.u.dpcd_read.port_number = 0xf;
-	DO_TEST();
-	in.u.dpcd_read.dpcd_address = 0xfedcb;
-	DO_TEST();
-	in.u.dpcd_read.num_bytes = U8_MAX;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_DPCD_WRITE;
-	in.u.dpcd_write.port_number = 0xf;
-	DO_TEST();
-	in.u.dpcd_write.dpcd_address = 0xfedcb;
-	DO_TEST();
-	in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
-	in.u.dpcd_write.bytes = data;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_I2C_READ;
-	in.u.i2c_read.port_number = 0xf;
-	DO_TEST();
-	in.u.i2c_read.read_i2c_device_id = 0x7f;
-	DO_TEST();
-	in.u.i2c_read.num_transactions = 3;
-	in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
-	for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
-		in.u.i2c_read.transactions[i].bytes = data;
-		in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
-		in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
-		in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
-	}
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_I2C_WRITE;
-	in.u.i2c_write.port_number = 0xf;
-	DO_TEST();
-	in.u.i2c_write.write_i2c_device_id = 0x7f;
-	DO_TEST();
-	in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
-	in.u.i2c_write.bytes = data;
-	DO_TEST();
-
-	in.req_type = DP_QUERY_STREAM_ENC_STATUS;
-	in.u.enc_status.stream_id = 1;
-	DO_TEST();
-	get_random_bytes(in.u.enc_status.client_id,
-			 sizeof(in.u.enc_status.client_id));
-	DO_TEST();
-	in.u.enc_status.stream_event = 3;
-	DO_TEST();
-	in.u.enc_status.valid_stream_event = 0;
-	DO_TEST();
-	in.u.enc_status.stream_behavior = 3;
-	DO_TEST();
-	in.u.enc_status.valid_stream_behavior = 1;
-	DO_TEST();
-
-#undef DO_TEST
-	return 0;
+	get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
+
+	return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
+							     .u.enc_status = enc_status
+	};
 }
+
+static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
+	{
+		.req = {
+			.req_type = DP_ENUM_PATH_RESOURCES,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_POWER_UP_PHY,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_POWER_DOWN_PHY,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.number_sdp_streams = 3,
+			.u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.vcpi = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.pbn = U16_MAX,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_PAYLOAD,
+			.u.query_payload.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_PAYLOAD,
+			.u.query_payload.vcpi = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.dpcd_address = 0xfedcb,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.num_bytes = U8_MAX,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.dpcd_address = 0xfedcb,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.num_bytes = ARRAY_SIZE(data),
+			.u.dpcd_write.bytes = data,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.read_i2c_device_id = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.num_transactions = 3,
+			.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
+			.u.i2c_read.transactions = {
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
+			},
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.write_i2c_device_id = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.num_bytes = ARRAY_SIZE(data),
+			.u.i2c_write.bytes = data,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_id = 1,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+		},
+		.f = random_dp_query_enc_client_id,
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_event = 3,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.valid_stream_event = 0,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_behavior = 3,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.valid_stream_behavior = 1,
+		},
+	},
+};
+
+KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
+
+static struct kunit_case drm_dp_mst_helper_tests[] = {
+	KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
+	KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
+	{}
+};
+
+static struct kunit_suite drm_dp_mst_helper_test_suite = {
+	.name = "drm_dp_mst_helper_tests",
+	.test_cases = drm_dp_mst_helper_tests,
+};
+
+kunit_test_suite(drm_dp_mst_helper_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index 1501d99aee2f..c7cc5edc65f1 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_dp_mst_calc_pbn_mode(void *ignored);
-int igt_dp_mst_sideband_msg_req_decode(void *ignored);
 
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

igt_dp_mst_calc_pbn_mode was converted one-to-one,
igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   3 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
 .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
 .../drm/selftests/test-drm_modeset_common.h   |   2 -
 4 files changed, 330 insertions(+), 179 deletions(-)

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 35f2f40dbaf3..77e37eebf099 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,7 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
 		      test-drm_modeset_common.o \
-		      test-drm_dp_mst_helper.o \
 		      test-drm_rect.o
 
 obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
@@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
 	test-drm_format.o test-drm_framebuffer.o \
-	test-drm_damage_helper.o
+	test-drm_damage_helper.o test-drm_dp_mst_helper.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
index b6a6dba66b64..630770d30aba 100644
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
@@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
 selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
 selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
 selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
-selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
-selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
index 6b4759ed6bfd..d0719f3c5a42 100644
--- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
+++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
@@ -3,54 +3,97 @@
  * Test cases for for the DRM DP MST helpers
  */
 
-#define PREFIX_STR "[drm_dp_mst_helper]"
-
+#include <kunit/test.h>
 #include <linux/random.h>
 
 #include <drm/drm_dp_mst_helper.h>
 #include <drm/drm_print.h>
 
 #include "../drm_dp_mst_topology_internal.h"
-#include "test-drm_modeset_common.h"
 
-int igt_dp_mst_calc_pbn_mode(void *ignored)
+struct dp_mst_calc_pbn_mode_test {
+	int rate;
+	int bpp;
+	int expected;
+	bool dsc;
+};
+
+static void dp_mst_calc_pbn_mode(struct kunit *test)
 {
-	int pbn, i;
-	const struct {
-		int rate;
-		int bpp;
-		int expected;
-		bool dsc;
-	} test_params[] = {
-		{ 154000, 30, 689, false },
-		{ 234000, 30, 1047, false },
-		{ 297000, 24, 1063, false },
-		{ 332880, 24, 50, true },
-		{ 324540, 24, 49, true },
-	};
+	const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
+	int pbn;
 
-	for (i = 0; i < ARRAY_SIZE(test_params); i++) {
-		pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
-					   test_params[i].bpp,
-					   test_params[i].dsc);
-		FAIL(pbn != test_params[i].expected,
-		     "Expected PBN %d for clock %d bpp %d, got %d\n",
-		     test_params[i].expected, test_params[i].rate,
-		     test_params[i].bpp, pbn);
-	}
+	pbn = drm_dp_calc_pbn_mode(params->rate,
+				   params->bpp,
+				   params->dsc);
+
+	KUNIT_EXPECT_EQ(test, pbn, params->expected);
+}
 
-	return 0;
+static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
+	{
+		.rate = 154000,
+		.bpp = 30,
+		.expected = 689,
+		.dsc = false,
+	},
+	{
+		.rate = 234000,
+		.bpp = 30,
+		.expected = 1047,
+		.dsc = false,
+	},
+	{
+		.rate = 297000,
+		.bpp = 24,
+		.expected = 1063,
+		.dsc = false,
+	},
+	{
+		.rate = 332880,
+		.bpp = 24,
+		.expected = 50,
+		.dsc = true,
+	},
+	{
+		.rate = 324540,
+		.bpp = 24,
+		.expected = 49,
+		.dsc = true,
+	},
+};
+
+static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
+				      char *desc)
+{
+	sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
+		t->rate, t->bpp, t->dsc ? "true" : "false");
 }
 
-static bool
-sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
-		       const struct drm_dp_sideband_msg_req_body *out)
+KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
+
+static void
+drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
+{
+	struct kunit *test = p->arg;
+
+	kunit_err(test, "%pV", vaf);
+}
+
+static void
+expect_sideband_msg_req_equal(struct kunit *test,
+			      const struct drm_dp_sideband_msg_req_body *in,
+			      const struct drm_dp_sideband_msg_req_body *out)
 {
 	const struct drm_dp_remote_i2c_read_tx *txin, *txout;
+	struct drm_printer p = {
+		.printfn = drm_dp_mst_helper_printfn,
+		.arg = test
+	};
 	int i;
 
 	if (in->req_type != out->req_type)
-		return false;
+		goto fail;
 
 	switch (in->req_type) {
 	/*
@@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		    IN.num_transactions != OUT.num_transactions ||
 		    IN.port_number != OUT.port_number ||
 		    IN.read_i2c_device_id != OUT.read_i2c_device_id)
-			return false;
+			goto fail;
 
 		for (i = 0; i < IN.num_transactions; i++) {
 			txin = &IN.transactions[i];
@@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 			    txin->num_bytes != txout->num_bytes ||
 			    txin->i2c_transaction_delay !=
 			    txout->i2c_transaction_delay)
-				return false;
+				goto fail;
 
 			if (memcmp(txin->bytes, txout->bytes,
 				   txin->num_bytes) != 0)
-				return false;
+				goto fail;
 		}
 		break;
 #undef IN
@@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		if (IN.dpcd_address != OUT.dpcd_address ||
 		    IN.num_bytes != OUT.num_bytes ||
 		    IN.port_number != OUT.port_number)
-			return false;
+			goto fail;
 
-		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
+		if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
+			goto fail;
+
+		break;
 #undef IN
 #undef OUT
 
@@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
 		if (IN.port_number != OUT.port_number ||
 		    IN.write_i2c_device_id != OUT.write_i2c_device_id ||
 		    IN.num_bytes != OUT.num_bytes)
-			return false;
+			goto fail;
 
-		return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
+		if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
+			goto fail;
+
+		break;
 #undef IN
 #undef OUT
 
 	default:
-		return memcmp(in, out, sizeof(*in)) == 0;
+		if (memcmp(in, out, sizeof(*in)) != 0)
+			goto fail;
 	}
 
-	return true;
+	return;
+
+fail:
+	drm_printf(&p, "Expected:\n");
+	drm_dp_dump_sideband_msg_req_body(in, 1, &p);
+	drm_printf(&p, "Got:\n");
+	drm_dp_dump_sideband_msg_req_body(out, 1, &p);
+	KUNIT_FAIL(test, "Encode/decode failed");
+}
+
+struct dp_mst_sideband_msg_req_decode_test {
+	const struct drm_dp_sideband_msg_req_body req;
+	const struct drm_dp_sideband_msg_req_body
+		(*f)(const struct drm_dp_sideband_msg_req_body *in);
+};
+
+const struct drm_dp_sideband_msg_req_body
+param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
+{
+	if (t->f)
+		return t->f(&t->req);
+
+	return t->req;
 }
 
-static bool
-sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
+static void dp_mst_sideband_msg_req_decode(struct kunit *test)
 {
+	const struct drm_dp_sideband_msg_req_body in =
+		param_to_dp_mst_sideband_msg_req_body(test->param_value);
 	struct drm_dp_sideband_msg_req_body *out;
-	struct drm_printer p = drm_err_printer(PREFIX_STR);
 	struct drm_dp_sideband_msg_tx *txmsg;
-	int i, ret;
-	bool result = true;
-
-	out = kzalloc(sizeof(*out), GFP_KERNEL);
-	if (!out)
-		return false;
-
-	txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
-	if (!txmsg)
-		return false;
-
-	drm_dp_encode_sideband_req(in, txmsg);
-	ret = drm_dp_decode_sideband_req(txmsg, out);
-	if (ret < 0) {
-		drm_printf(&p, "Failed to decode sideband request: %d\n",
-			   ret);
-		result = false;
-		goto out;
-	}
+	int i;
 
-	if (!sideband_msg_req_equal(in, out)) {
-		drm_printf(&p, "Encode/decode failed, expected:\n");
-		drm_dp_dump_sideband_msg_req_body(in, 1, &p);
-		drm_printf(&p, "Got:\n");
-		drm_dp_dump_sideband_msg_req_body(out, 1, &p);
-		result = false;
-		goto out;
-	}
+	out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
 
-	switch (in->req_type) {
+	txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
+
+	drm_dp_encode_sideband_req(&in, txmsg);
+	KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
+
+	expect_sideband_msg_req_equal(test, &in, out);
+
+	switch (in.req_type) {
 	case DP_REMOTE_DPCD_WRITE:
 		kfree(out->u.dpcd_write.bytes);
 		break;
@@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
 		kfree(out->u.i2c_write.bytes);
 		break;
 	}
-
-	/* Clear everything but the req_type for the input */
-	memset(&in->u, 0, sizeof(in->u));
-
-out:
-	kfree(out);
-	kfree(txmsg);
-	return result;
 }
 
-int igt_dp_mst_sideband_msg_req_decode(void *unused)
+static u8 data[] = { 0xff, 0x0, 0xdd };
+
+const struct drm_dp_sideband_msg_req_body
+random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
 {
-	struct drm_dp_sideband_msg_req_body in = { 0 };
-	u8 data[] = { 0xff, 0x0, 0xdd };
-	int i;
+	struct drm_dp_query_stream_enc_status enc_status = { };
 
-#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
-
-	in.req_type = DP_ENUM_PATH_RESOURCES;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_POWER_UP_PHY;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_POWER_DOWN_PHY;
-	in.u.port_num.port_number = 5;
-	DO_TEST();
-
-	in.req_type = DP_ALLOCATE_PAYLOAD;
-	in.u.allocate_payload.number_sdp_streams = 3;
-	for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
-		in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
-	DO_TEST();
-	in.u.allocate_payload.port_number = 0xf;
-	DO_TEST();
-	in.u.allocate_payload.vcpi = 0x7f;
-	DO_TEST();
-	in.u.allocate_payload.pbn = U16_MAX;
-	DO_TEST();
-
-	in.req_type = DP_QUERY_PAYLOAD;
-	in.u.query_payload.port_number = 0xf;
-	DO_TEST();
-	in.u.query_payload.vcpi = 0x7f;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_DPCD_READ;
-	in.u.dpcd_read.port_number = 0xf;
-	DO_TEST();
-	in.u.dpcd_read.dpcd_address = 0xfedcb;
-	DO_TEST();
-	in.u.dpcd_read.num_bytes = U8_MAX;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_DPCD_WRITE;
-	in.u.dpcd_write.port_number = 0xf;
-	DO_TEST();
-	in.u.dpcd_write.dpcd_address = 0xfedcb;
-	DO_TEST();
-	in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
-	in.u.dpcd_write.bytes = data;
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_I2C_READ;
-	in.u.i2c_read.port_number = 0xf;
-	DO_TEST();
-	in.u.i2c_read.read_i2c_device_id = 0x7f;
-	DO_TEST();
-	in.u.i2c_read.num_transactions = 3;
-	in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
-	for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
-		in.u.i2c_read.transactions[i].bytes = data;
-		in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
-		in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
-		in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
-	}
-	DO_TEST();
-
-	in.req_type = DP_REMOTE_I2C_WRITE;
-	in.u.i2c_write.port_number = 0xf;
-	DO_TEST();
-	in.u.i2c_write.write_i2c_device_id = 0x7f;
-	DO_TEST();
-	in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
-	in.u.i2c_write.bytes = data;
-	DO_TEST();
-
-	in.req_type = DP_QUERY_STREAM_ENC_STATUS;
-	in.u.enc_status.stream_id = 1;
-	DO_TEST();
-	get_random_bytes(in.u.enc_status.client_id,
-			 sizeof(in.u.enc_status.client_id));
-	DO_TEST();
-	in.u.enc_status.stream_event = 3;
-	DO_TEST();
-	in.u.enc_status.valid_stream_event = 0;
-	DO_TEST();
-	in.u.enc_status.stream_behavior = 3;
-	DO_TEST();
-	in.u.enc_status.valid_stream_behavior = 1;
-	DO_TEST();
-
-#undef DO_TEST
-	return 0;
+	get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
+
+	return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
+							     .u.enc_status = enc_status
+	};
 }
+
+static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
+	{
+		.req = {
+			.req_type = DP_ENUM_PATH_RESOURCES,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_POWER_UP_PHY,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_POWER_DOWN_PHY,
+			.u.port_num.port_number = 5,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.number_sdp_streams = 3,
+			.u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.vcpi = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_ALLOCATE_PAYLOAD,
+			.u.allocate_payload.pbn = U16_MAX,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_PAYLOAD,
+			.u.query_payload.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_PAYLOAD,
+			.u.query_payload.vcpi = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.dpcd_address = 0xfedcb,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_READ,
+			.u.dpcd_read.num_bytes = U8_MAX,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.dpcd_address = 0xfedcb,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_DPCD_WRITE,
+			.u.dpcd_write.num_bytes = ARRAY_SIZE(data),
+			.u.dpcd_write.bytes = data,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.read_i2c_device_id = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_READ,
+			.u.i2c_read.num_transactions = 3,
+			.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
+			.u.i2c_read.transactions = {
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
+				{ .bytes = data, .num_bytes = ARRAY_SIZE(data),
+				  .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
+			},
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.port_number = 0xf,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.write_i2c_device_id = 0x7f,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_REMOTE_I2C_WRITE,
+			.u.i2c_write.num_bytes = ARRAY_SIZE(data),
+			.u.i2c_write.bytes = data,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_id = 1,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+		},
+		.f = random_dp_query_enc_client_id,
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_event = 3,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.valid_stream_event = 0,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.stream_behavior = 3,
+		},
+	},
+	{
+		.req = {
+			.req_type = DP_QUERY_STREAM_ENC_STATUS,
+			.u.enc_status.valid_stream_behavior = 1,
+		},
+	},
+};
+
+KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
+
+static struct kunit_case drm_dp_mst_helper_tests[] = {
+	KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
+	KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
+	{}
+};
+
+static struct kunit_suite drm_dp_mst_helper_test_suite = {
+	.name = "drm_dp_mst_helper_tests",
+	.test_cases = drm_dp_mst_helper_tests,
+};
+
+kunit_test_suite(drm_dp_mst_helper_test_suite);
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
index 1501d99aee2f..c7cc5edc65f1 100644
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
@@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
 int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_clipped(void *ignored);
 int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-int igt_dp_mst_calc_pbn_mode(void *ignored);
-int igt_dp_mst_sideband_msg_req_decode(void *ignored);
 
 #endif
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 07/10] drm: test-drm_rect: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

One-to-one conversion, no functional changes.

Now that all of the modeset selftests were converted, remove the helpers
that are no longer used.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   8 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |  12 -
 .../drm/selftests/test-drm_modeset_common.c   |  32 ---
 .../drm/selftests/test-drm_modeset_common.h   |  24 --
 drivers/gpu/drm/selftests/test-drm_rect.c     | 212 ++++++++++--------
 5 files changed, 122 insertions(+), 166 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 77e37eebf099..2d524eddb4e3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
-test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
-		      test-drm_modeset_common.o \
-		      test-drm_rect.o
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
 	test-drm_format.o test-drm_framebuffer.o \
-	test-drm_damage_helper.o test-drm_dp_mst_helper.o
+	test-drm_damage_helper.o test-drm_dp_mst_helper.o \
+	test-drm_rect.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
deleted file mode 100644
index 630770d30aba..000000000000
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_selftests_helper
- */
-selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
-selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
-selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
-selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
deleted file mode 100644
index 2a7f93774006..000000000000
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.c
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Common file for modeset selftests.
- */
-
-#include <linux/module.h>
-
-#include "test-drm_modeset_common.h"
-
-#define TESTS "drm_modeset_selftests.h"
-#include "drm_selftest.h"
-
-#include "drm_selftest.c"
-
-static int __init test_drm_modeset_init(void)
-{
-	int err;
-
-	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
-
-	return err > 0 ? 0 : err;
-}
-
-static void __exit test_drm_modeset_exit(void)
-{
-}
-
-module_init(test_drm_modeset_init);
-module_exit(test_drm_modeset_exit);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
deleted file mode 100644
index c7cc5edc65f1..000000000000
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __TEST_DRM_MODESET_COMMON_H__
-#define __TEST_DRM_MODESET_COMMON_H__
-
-#include <linux/errno.h>
-#include <linux/printk.h>
-
-#define FAIL(test, msg, ...) \
-	do { \
-		if (test) { \
-			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-			return -EINVAL; \
-		} \
-	} while (0)
-
-#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
-
-int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
-int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
-int igt_drm_rect_clip_scaled_clipped(void *ignored);
-int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-
-#endif
diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/selftests/test-drm_rect.c
index 3a5ff38321f4..f3d26c31ee66 100644
--- a/drivers/gpu/drm/selftests/test-drm_rect.c
+++ b/drivers/gpu/drm/selftests/test-drm_rect.c
@@ -3,15 +3,12 @@
  * Test cases for the drm_rect functions
  */
 
-#define pr_fmt(fmt) "drm_rect: " fmt
-
+#include <kunit/test.h>
 #include <linux/limits.h>
 
 #include <drm/drm_rect.h>
 
-#include "test-drm_modeset_common.h"
-
-int igt_drm_rect_clip_scaled_div_by_zero(void *ignored)
+static void drm_rect_clip_scaled_div_by_zero(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -23,21 +20,23 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored)
 	drm_rect_init(&src, 0, 0, 0, 0);
 	drm_rect_init(&dst, 0, 0, 0, 0);
 	drm_rect_init(&clip, 1, 1, 1, 1);
+
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
-	FAIL(visible, "Destination not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
+
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 
 	drm_rect_init(&src, 0, 0, 0, 0);
 	drm_rect_init(&dst, 3, 3, 0, 0);
 	drm_rect_init(&clip, 1, 1, 1, 1);
+
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
-	FAIL(visible, "Destination not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
 
-	return 0;
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 }
 
-int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
+static void drm_rect_clip_scaled_not_clipped(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -49,14 +48,16 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -65,14 +66,16 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
-	     src.y1 != 0 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 2 << 16 &&
+			      src.y1 == 0 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling */
 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
@@ -81,19 +84,19 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
-	     dst.y1 != 0 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 2 &&
+			      dst.y1 == 0 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 }
 
-int igt_drm_rect_clip_scaled_clipped(void *ignored)
+static void drm_rect_clip_scaled_clipped(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -105,14 +108,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:1 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -121,14 +126,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
-	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
-	     dst.y1 != 1 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 1 << 16 && src.x2 == 2 << 16 &&
+			      src.y1 == 1 << 16 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 1 && dst.x2 == 2 &&
+			      dst.y1 == 1 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling top/left clip */
 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
@@ -137,14 +144,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
-	     src.y1 != 0 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 2 << 16 &&
+			      src.y1 == 0 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
@@ -153,14 +162,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
-	     src.y1 != 2 << 16 || src.y2 != 4 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
-	     dst.y1 != 1 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 2 << 16 && src.x2 == 4 << 16 &&
+			      src.y1 == 2 << 16 && src.y2 == 4 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 1 && dst.x2 == 2 &&
+			      dst.y1 == 1 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling top/left clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -169,14 +180,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
-	     dst.y1 != 0 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 2 &&
+			      dst.y1 == 0 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -185,19 +198,19 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
-	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 2 || dst.x2 != 4 ||
-	     dst.y1 != 2 || dst.y2 != 4,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 1 << 16 && src.x2 == 2 << 16 &&
+			      src.y1 == 1 << 16 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 2 && dst.x2 == 4 &&
+			      dst.y1 == 2 && dst.y2 == 4,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 }
 
-int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored)
+static void drm_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -216,8 +229,21 @@ int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(visible, "Destination should not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 }
+
+static struct kunit_case drm_rect_tests[] = {
+	KUNIT_CASE(drm_rect_clip_scaled_div_by_zero),
+	KUNIT_CASE(drm_rect_clip_scaled_not_clipped),
+	KUNIT_CASE(drm_rect_clip_scaled_clipped),
+	KUNIT_CASE(drm_rect_clip_scaled_signed_vs_unsigned),
+	{}
+};
+
+static struct kunit_suite drm_rect_test_suite = {
+	.name = "drm_rect_tests",
+	.test_cases = drm_rect_tests,
+};
+
+kunit_test_suite(drm_rect_test_suite);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 07/10] drm: test-drm_rect: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

One-to-one conversion, no functional changes.

Now that all of the modeset selftests were converted, remove the helpers
that are no longer used.

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/selftests/Makefile            |   8 +-
 .../gpu/drm/selftests/drm_modeset_selftests.h |  12 -
 .../drm/selftests/test-drm_modeset_common.c   |  32 ---
 .../drm/selftests/test-drm_modeset_common.h   |  24 --
 drivers/gpu/drm/selftests/test-drm_rect.c     | 212 ++++++++++--------
 5 files changed, 122 insertions(+), 166 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
 delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h

diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 77e37eebf099..2d524eddb4e3 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,11 +1,9 @@
 # SPDX-License-Identifier: GPL-2.0-only
-test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
-		      test-drm_modeset_common.o \
-		      test-drm_rect.o
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
+obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o
 
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
 	test-drm_format.o test-drm_framebuffer.o \
-	test-drm_damage_helper.o test-drm_dp_mst_helper.o
+	test-drm_damage_helper.o test-drm_dp_mst_helper.o \
+	test-drm_rect.o
diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
deleted file mode 100644
index 630770d30aba..000000000000
--- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_selftests_helper
- */
-selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
-selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
-selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
-selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.c b/drivers/gpu/drm/selftests/test-drm_modeset_common.c
deleted file mode 100644
index 2a7f93774006..000000000000
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.c
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Common file for modeset selftests.
- */
-
-#include <linux/module.h>
-
-#include "test-drm_modeset_common.h"
-
-#define TESTS "drm_modeset_selftests.h"
-#include "drm_selftest.h"
-
-#include "drm_selftest.c"
-
-static int __init test_drm_modeset_init(void)
-{
-	int err;
-
-	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
-
-	return err > 0 ? 0 : err;
-}
-
-static void __exit test_drm_modeset_exit(void)
-{
-}
-
-module_init(test_drm_modeset_init);
-module_exit(test_drm_modeset_exit);
-
-MODULE_AUTHOR("Intel Corporation");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
deleted file mode 100644
index c7cc5edc65f1..000000000000
--- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-
-#ifndef __TEST_DRM_MODESET_COMMON_H__
-#define __TEST_DRM_MODESET_COMMON_H__
-
-#include <linux/errno.h>
-#include <linux/printk.h>
-
-#define FAIL(test, msg, ...) \
-	do { \
-		if (test) { \
-			pr_err("%s/%u: " msg, __FUNCTION__, __LINE__, ##__VA_ARGS__); \
-			return -EINVAL; \
-		} \
-	} while (0)
-
-#define FAIL_ON(x) FAIL((x), "%s", "FAIL_ON(" __stringify(x) ")\n")
-
-int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
-int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
-int igt_drm_rect_clip_scaled_clipped(void *ignored);
-int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
-
-#endif
diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/selftests/test-drm_rect.c
index 3a5ff38321f4..f3d26c31ee66 100644
--- a/drivers/gpu/drm/selftests/test-drm_rect.c
+++ b/drivers/gpu/drm/selftests/test-drm_rect.c
@@ -3,15 +3,12 @@
  * Test cases for the drm_rect functions
  */
 
-#define pr_fmt(fmt) "drm_rect: " fmt
-
+#include <kunit/test.h>
 #include <linux/limits.h>
 
 #include <drm/drm_rect.h>
 
-#include "test-drm_modeset_common.h"
-
-int igt_drm_rect_clip_scaled_div_by_zero(void *ignored)
+static void drm_rect_clip_scaled_div_by_zero(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -23,21 +20,23 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored)
 	drm_rect_init(&src, 0, 0, 0, 0);
 	drm_rect_init(&dst, 0, 0, 0, 0);
 	drm_rect_init(&clip, 1, 1, 1, 1);
+
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
-	FAIL(visible, "Destination not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
+
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 
 	drm_rect_init(&src, 0, 0, 0, 0);
 	drm_rect_init(&dst, 3, 3, 0, 0);
 	drm_rect_init(&clip, 1, 1, 1, 1);
+
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
-	FAIL(visible, "Destination not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
 
-	return 0;
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 }
 
-int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
+static void drm_rect_clip_scaled_not_clipped(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -49,14 +48,16 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -65,14 +66,16 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
-	     src.y1 != 0 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 2 << 16 &&
+			      src.y1 == 0 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling */
 	drm_rect_init(&src, 0, 0, 1 << 16, 1 << 16);
@@ -81,19 +84,19 @@ int igt_drm_rect_clip_scaled_not_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
-	     dst.y1 != 0 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 2 &&
+			      dst.y1 == 0 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 }
 
-int igt_drm_rect_clip_scaled_clipped(void *ignored)
+static void drm_rect_clip_scaled_clipped(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -105,14 +108,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:1 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -121,14 +126,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
-	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
-	     dst.y1 != 1 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 1 << 16 && src.x2 == 2 << 16 &&
+			      src.y1 == 1 << 16 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 1 && dst.x2 == 2 &&
+			      dst.y1 == 1 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling top/left clip */
 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
@@ -137,14 +144,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 2 << 16 ||
-	     src.y1 != 0 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 1 ||
-	     dst.y1 != 0 || dst.y2 != 1,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 2 << 16 &&
+			      src.y1 == 0 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 1 &&
+			      dst.y1 == 0 && dst.y2 == 1,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 2:1 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 4 << 16, 4 << 16);
@@ -153,14 +162,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 2 << 16 || src.x2 != 4 << 16 ||
-	     src.y1 != 2 << 16 || src.y2 != 4 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 1 || dst.x2 != 2 ||
-	     dst.y1 != 1 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 2 << 16 && src.x2 == 4 << 16 &&
+			      src.y1 == 2 << 16 && src.y2 == 4 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 1 && dst.x2 == 2 &&
+			      dst.y1 == 1 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling top/left clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -169,14 +180,16 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 0 || src.x2 != 1 << 16 ||
-	     src.y1 != 0 || src.y2 != 1 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 0 || dst.x2 != 2 ||
-	     dst.y1 != 0 || dst.y2 != 2,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 0 && src.x2 == 1 << 16 &&
+			      src.y1 == 0 && src.y2 == 1 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 0 && dst.x2 == 2 &&
+			      dst.y1 == 0 && dst.y2 == 2,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 
 	/* 1:2 scaling bottom/right clip */
 	drm_rect_init(&src, 0, 0, 2 << 16, 2 << 16);
@@ -185,19 +198,19 @@ int igt_drm_rect_clip_scaled_clipped(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(src.x1 != 1 << 16 || src.x2 != 2 << 16 ||
-	     src.y1 != 1 << 16 || src.y2 != 2 << 16,
-	     "Source badly clipped\n");
-	FAIL(dst.x1 != 2 || dst.x2 != 4 ||
-	     dst.y1 != 2 || dst.y2 != 4,
-	     "Destination badly clipped\n");
-	FAIL(!visible, "Destination should be visible\n");
-	FAIL(!drm_rect_visible(&src), "Source should be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      src.x1 == 1 << 16 && src.x2 == 2 << 16 &&
+			      src.y1 == 1 << 16 && src.y2 == 2 << 16,
+			      "Source badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test,
+			      dst.x1 == 2 && dst.x2 == 4 &&
+			      dst.y1 == 2 && dst.y2 == 4,
+			      "Destination badly clipped");
+	KUNIT_EXPECT_TRUE_MSG(test, visible, "Destination should be visible");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_rect_visible(&src), "Source should be visible");
 }
 
-int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored)
+static void drm_rect_clip_scaled_signed_vs_unsigned(struct kunit *test)
 {
 	struct drm_rect src, dst, clip;
 	bool visible;
@@ -216,8 +229,21 @@ int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored)
 
 	visible = drm_rect_clip_scaled(&src, &dst, &clip);
 
-	FAIL(visible, "Destination should not be visible\n");
-	FAIL(drm_rect_visible(&src), "Source should not be visible\n");
-
-	return 0;
+	KUNIT_EXPECT_FALSE_MSG(test, visible, "Destination should not be visible");
+	KUNIT_EXPECT_FALSE_MSG(test, drm_rect_visible(&src), "Source should not be visible");
 }
+
+static struct kunit_case drm_rect_tests[] = {
+	KUNIT_CASE(drm_rect_clip_scaled_div_by_zero),
+	KUNIT_CASE(drm_rect_clip_scaled_not_clipped),
+	KUNIT_CASE(drm_rect_clip_scaled_clipped),
+	KUNIT_CASE(drm_rect_clip_scaled_signed_vs_unsigned),
+	{}
+};
+
+static struct kunit_suite drm_rect_test_suite = {
+	.name = "drm_rect_tests",
+	.test_cases = drm_rect_tests,
+};
+
+kunit_test_suite(drm_rect_test_suite);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 08/10] drm: test-drm_mm: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
                   ` (7 preceding siblings ...)
  (?)
@ 2022-01-17 23:22 ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

Tests that were looping over param (or combination of params) were
converted to parameterized test cases.

While the conversion should be roughly functionally equivalent, there
are changes in the test content and organization:
* sanitycheck was dropped (as it was only testing the test framework)
* both evict and color got a "sanitycheck" extracted as a separate test
* insert_outside_range was extracted as a separate test
* evict_range and color_evict_range were removed and expressed as
  input parameters to evict and color_evict

It's still possible to use modparams to change the number of iterations,
or force specific seed e.g. by passing the following to kunit.py:
--kernel_args 'test_drm_mm.random_seed=X'

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                      |    2 +
 drivers/gpu/drm/selftests/Makefile           |    4 +-
 drivers/gpu/drm/selftests/drm_mm_selftests.h |   28 -
 drivers/gpu/drm/selftests/test-drm_mm.c      | 3187 +++++++++---------
 4 files changed, 1566 insertions(+), 1655 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 89be0df7b0e9..c567324c96b9 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -84,6 +84,8 @@ config DRM_KUNIT_TEST
 	bool "DRM tests" if !KUNIT_ALL_TESTS
 	depends on DRM=y && KUNIT=y
 	select DRM_KMS_HELPER
+	select PRIME_NUMBERS
+	select DRM_LIB_RANDOM
 	default KUNIT_ALL_TESTS
 	help
 	  Enables unit tests for DRM. Only useful for kernel devs running KUnit.
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
index 2d524eddb4e3..3bc89b71f9f9 100644
--- a/drivers/gpu/drm/selftests/Makefile
+++ b/drivers/gpu/drm/selftests/Makefile
@@ -1,9 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o
-
 obj-$(CONFIG_DRM_KUNIT_TEST) := \
 	test-drm_cmdline_parser.o test-drm_plane_helper.o \
 	test-drm_format.o test-drm_framebuffer.o \
 	test-drm_damage_helper.o test-drm_dp_mst_helper.o \
-	test-drm_rect.o
+	test-drm_rect.o test-drm_mm.o
diff --git a/drivers/gpu/drm/selftests/drm_mm_selftests.h b/drivers/gpu/drm/selftests/drm_mm_selftests.h
deleted file mode 100644
index 8c87c964176b..000000000000
--- a/drivers/gpu/drm/selftests/drm_mm_selftests.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/* List each unit test as selftest(name, function)
- *
- * The name is used as both an enum and expanded as igt__name to create
- * a module parameter. It must be unique and legal for a C identifier.
- *
- * Tests are executed in order by igt/drm_mm
- */
-selftest(sanitycheck, igt_sanitycheck) /* keep first (selfcheck for igt) */
-selftest(init, igt_init)
-selftest(debug, igt_debug)
-selftest(reserve, igt_reserve)
-selftest(insert, igt_insert)
-selftest(replace, igt_replace)
-selftest(insert_range, igt_insert_range)
-selftest(align, igt_align)
-selftest(frag, igt_frag)
-selftest(align32, igt_align32)
-selftest(align64, igt_align64)
-selftest(evict, igt_evict)
-selftest(evict_range, igt_evict_range)
-selftest(bottomup, igt_bottomup)
-selftest(lowest, igt_lowest)
-selftest(topdown, igt_topdown)
-selftest(highest, igt_highest)
-selftest(color, igt_color)
-selftest(color_evict, igt_color_evict)
-selftest(color_evict_range, igt_color_evict_range)
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/selftests/test-drm_mm.c
index b768b53c4aee..66eca33c8e2f 100644
--- a/drivers/gpu/drm/selftests/test-drm_mm.c
+++ b/drivers/gpu/drm/selftests/test-drm_mm.c
@@ -3,8 +3,8 @@
  * Test cases for the drm_mm range manager
  */
 
-#define pr_fmt(fmt) "drm_mm: " fmt
-
+#include <kunit/test.h>
+#include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/prime_numbers.h>
 #include <linux/slab.h>
@@ -16,13 +16,152 @@
 
 #include "../lib/drm_random.h"
 
-#define TESTS "drm_mm_selftests.h"
-#include "drm_selftest.h"
-
 static unsigned int random_seed;
 static unsigned int max_iterations = 8192;
 static unsigned int max_prime = 128;
 
+static struct kunit_suite drm_mm_test_suite;
+
+#define DRM_MM_PARAM0_MASK GENMASK(7, 0)
+#define DRM_MM_PARAM1_MASK GENMASK(15, 8)
+#define DRM_MM_PARAM2_MASK GENMASK(23, 16)
+#define DRM_MM_PARAM_VALID BIT(31)
+
+static bool param_valid(const unsigned long param)
+{
+	return param & DRM_MM_PARAM_VALID;
+}
+
+#define DRM_MM_PRIME_MASK (DRM_MM_PARAM0_MASK)
+static const unsigned long prime_gen_param(const unsigned long param,
+					   const unsigned long prime_limit)
+{
+	unsigned int prime = FIELD_GET(DRM_MM_PRIME_MASK, param);
+
+	BUILD_BUG_ON(prime_limit > FIELD_MAX(DRM_MM_PRIME_MASK));
+
+	if (!param_valid(param))
+		prime = 1;
+	else
+		prime = next_prime_number(prime);
+
+	if (prime > min_t(unsigned int, prime_limit, max_prime))
+		return 0;
+
+	return FIELD_PREP(DRM_MM_PRIME_MASK, prime) | DRM_MM_PARAM_VALID;
+}
+
+#define DRM_MM_OP_MASK (DRM_MM_PARAM1_MASK)
+static const unsigned long ops_gen_param(const unsigned long param,
+					 const unsigned long ops_limit)
+{
+	unsigned int index = FIELD_GET(DRM_MM_OP_MASK, param);
+
+	BUILD_BUG_ON(ops_limit > FIELD_MAX(DRM_MM_OP_MASK));
+
+	if (!param_valid(param))
+		index = 0;
+	else
+		index++;
+
+	if (index >= ops_limit)
+		return 0;
+
+	return FIELD_PREP(DRM_MM_OP_MASK, index) | DRM_MM_PARAM_VALID;
+}
+
+#define DRM_MM_MODE_MASK (DRM_MM_PARAM2_MASK)
+static const unsigned long mode_gen_param(const unsigned long param,
+					  const unsigned int mode_limit)
+{
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+
+	BUILD_BUG_ON(mode_limit > FIELD_MAX(DRM_MM_MODE_MASK));
+
+	if (!param_valid(param))
+		mode = 0;
+	else
+		mode++;
+
+	if (mode >= mode_limit)
+		return 0;
+
+	return FIELD_PREP(DRM_MM_MODE_MASK, mode) | DRM_MM_PARAM_VALID;
+}
+
+static const unsigned long prime_ops_gen_param(const unsigned long param,
+					       const unsigned int prime_limit,
+					       const unsigned int ops_limit)
+{
+	unsigned int prime_param;
+	unsigned int ops_param;
+
+	if (!param_valid(param))
+		prime_param = prime_gen_param(param, prime_limit);
+	else
+		prime_param = (param & DRM_MM_PRIME_MASK) | DRM_MM_PARAM_VALID;
+
+	ops_param = ops_gen_param(param, ops_limit);
+	if (!param_valid(ops_param)) {
+		prime_param = prime_gen_param(param, prime_limit);
+		ops_param = ops_gen_param(ops_param, ops_limit);
+	}
+
+	if (!param_valid(prime_param))
+		return 0;
+
+	return prime_param | ops_param;
+}
+
+static const unsigned long mode_ops_gen_param(const unsigned long param,
+					      const unsigned int mode_limit,
+					      const unsigned int ops_limit)
+{
+	unsigned int mode_param;
+	unsigned int ops_param;
+
+	if (!param_valid(param))
+		mode_param = mode_gen_param(param, mode_limit);
+	else
+		mode_param = (param & DRM_MM_MODE_MASK) | DRM_MM_PARAM_VALID;
+
+	ops_param = ops_gen_param(param, ops_limit);
+	if (!param_valid(ops_param)) {
+		mode_param = mode_gen_param(param, mode_limit);
+		ops_param = ops_gen_param(ops_param, ops_limit);
+	}
+
+	if (!param_valid(mode_param))
+		return 0;
+
+	return mode_param | ops_param;
+}
+
+static const unsigned long mode_prime_ops_gen_param(const unsigned long param,
+						    const unsigned int mode_limit,
+						    const unsigned int prime_limit,
+						    const unsigned int ops_limit)
+{
+	unsigned int mode_param;
+	unsigned int prime_ops_param;
+
+	if (!param_valid(param))
+		mode_param = mode_gen_param(param, mode_limit);
+	else
+		mode_param = (param & DRM_MM_MODE_MASK) | DRM_MM_PARAM_VALID;
+
+	prime_ops_param = prime_ops_gen_param(param, prime_limit, ops_limit);
+	if (!param_valid(prime_ops_param)) {
+		mode_param = mode_gen_param(param, mode_limit);
+		prime_ops_param = prime_ops_gen_param(prime_ops_param, prime_limit, ops_limit);
+	}
+
+	if (!param_valid(mode_param))
+		return 0;
+
+	return mode_param | prime_ops_param;
+}
+
 enum {
 	BEST,
 	BOTTOMUP,
@@ -38,20 +177,34 @@ static const struct insert_mode {
 	[BOTTOMUP] = { "bottom-up", DRM_MM_INSERT_LOW },
 	[TOPDOWN] = { "top-down", DRM_MM_INSERT_HIGH },
 	[EVICT] = { "evict", DRM_MM_INSERT_EVICT },
-	{}
 }, evict_modes[] = {
 	{ "bottom-up", DRM_MM_INSERT_LOW },
 	{ "top-down", DRM_MM_INSERT_HIGH },
-	{}
 };
 
-static int igt_sanitycheck(void *ignored)
+static void kunit_drm_mm_print_params(void)
 {
-	pr_info("%s - ok!\n", __func__);
-	return 0;
+	kunit_log(KERN_INFO, &drm_mm_test_suite,
+		  "Testing DRM range manager (struct drm_mm), with random_seed=%#x max_iterations=%u max_prime=%u",
+		  random_seed, max_iterations, max_prime);
+}
+
+static void
+drm_mm_printfn(struct drm_printer *p, struct va_format *vaf)
+{
+	struct kunit *test = p->arg;
+
+	kunit_info(test, "%pV", vaf);
 }
 
-static bool assert_no_holes(const struct drm_mm *mm)
+#define show_mm(test, mm) \
+	do { \
+		struct drm_printer __p = { .printfn = drm_mm_printfn, .arg = (test) }; \
+		drm_mm_print((mm), &__p); \
+	} while (0)
+
+static bool
+has_no_holes(struct kunit *test, const struct drm_mm *mm)
 {
 	struct drm_mm_node *hole;
 	u64 hole_start, __always_unused hole_end;
@@ -61,13 +214,17 @@ static bool assert_no_holes(const struct drm_mm *mm)
 	drm_mm_for_each_hole(hole, mm, hole_start, hole_end)
 		count++;
 	if (count) {
-		pr_err("Expected to find no holes (after reserve), found %lu instead\n", count);
+		show_mm(test, mm);
+		kunit_err(test,
+			  "Expected to find no holes (after reserve), found %lu instead\n",
+			  count);
 		return false;
 	}
 
 	drm_mm_for_each_node(hole, mm) {
 		if (drm_mm_hole_follows(hole)) {
-			pr_err("Hole follows node, expected none!\n");
+			show_mm(test, mm);
+			kunit_err(test, "Hole follows node, expected none!\n");
 			return false;
 		}
 	}
@@ -75,7 +232,8 @@ static bool assert_no_holes(const struct drm_mm *mm)
 	return true;
 }
 
-static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end)
+static bool
+has_one_hole(struct kunit *test, const struct drm_mm *mm, u64 start, u64 end)
 {
 	struct drm_mm_node *hole;
 	u64 hole_start, hole_end;
@@ -89,62 +247,64 @@ static bool assert_one_hole(const struct drm_mm *mm, u64 start, u64 end)
 	drm_mm_for_each_hole(hole, mm, hole_start, hole_end) {
 		if (start != hole_start || end != hole_end) {
 			if (ok)
-				pr_err("empty mm has incorrect hole, found (%llx, %llx), expect (%llx, %llx)\n",
-				       hole_start, hole_end,
-				       start, end);
+				kunit_err(test,
+					  "incorrect hole, found (%#llx, %#llx), expect (%#llx, %#llx)\n",
+					  hole_start, hole_end, start, end);
 			ok = false;
 		}
 		count++;
 	}
 	if (count != 1) {
-		pr_err("Expected to find one hole, found %lu instead\n", count);
+		show_mm(test, mm);
+		kunit_err(test, "Expected to find one hole, found %lu instead\n", count);
 		ok = false;
 	}
 
 	return ok;
 }
 
-static bool assert_continuous(const struct drm_mm *mm, u64 size)
+static bool is_continuous(struct kunit *test, const struct drm_mm *mm, u64 size)
 {
 	struct drm_mm_node *node, *check, *found;
 	unsigned long n;
 	u64 addr;
 
-	if (!assert_no_holes(mm))
+	if (!has_no_holes(test, mm))
 		return false;
 
 	n = 0;
 	addr = 0;
 	drm_mm_for_each_node(node, mm) {
 		if (node->start != addr) {
-			pr_err("node[%ld] list out of order, expected %llx found %llx\n",
-			       n, addr, node->start);
+			kunit_err(test, "node[%ld] list out of order, expected %#llx found %#llx\n",
+				  n, addr, node->start);
 			return false;
 		}
 
 		if (node->size != size) {
-			pr_err("node[%ld].size incorrect, expected %llx, found %llx\n",
-			       n, size, node->size);
+			kunit_err(test, "node[%ld].size incorrect, expected %llu, found %llu\n",
+				  n, size, node->size);
 			return false;
 		}
 
 		if (drm_mm_hole_follows(node)) {
-			pr_err("node[%ld] is followed by a hole!\n", n);
+			kunit_err(test, "node[%ld] is followed by a hole!\n", n);
 			return false;
 		}
 
 		found = NULL;
 		drm_mm_for_each_node_in_range(check, mm, addr, addr + size) {
 			if (node != check) {
-				pr_err("lookup return wrong node, expected start %llx, found %llx\n",
-				       node->start, check->start);
+				kunit_err(test,
+					  "lookup return wrong node, expected start %#llx, found %#llx\n",
+					  node->start, check->start);
 				return false;
 			}
 			found = check;
 		}
 		if (!found) {
-			pr_err("lookup failed for node %llx + %llx\n",
-			       addr, size);
+			kunit_err(test, "lookup failed for node %#llx + %llu\n",
+				  addr, size);
 			return false;
 		}
 
@@ -166,107 +326,199 @@ static u64 misalignment(struct drm_mm_node *node, u64 alignment)
 	return rem;
 }
 
-static bool assert_node(struct drm_mm_node *node, struct drm_mm *mm,
-			u64 size, u64 alignment, unsigned long color)
+static bool check_node(struct kunit *test, struct drm_mm_node *node, struct drm_mm *mm,
+		       u64 size, u64 alignment, unsigned long color)
 {
 	bool ok = true;
 
 	if (!drm_mm_node_allocated(node) || node->mm != mm) {
-		pr_err("node not allocated\n");
+		kunit_err(test, "node not allocated\n");
 		ok = false;
 	}
 
 	if (node->size != size) {
-		pr_err("node has wrong size, found %llu, expected %llu\n",
-		       node->size, size);
+		kunit_err(test, "node has wrong size, found %llu, expected %llu\n",
+			  node->size, size);
 		ok = false;
 	}
 
 	if (misalignment(node, alignment)) {
-		pr_err("node is misaligned, start %llx rem %llu, expected alignment %llu\n",
-		       node->start, misalignment(node, alignment), alignment);
+		kunit_err(test, "node is misaligned, start %#llx rem %llu, expected alignment %llu\n",
+			  node->start, misalignment(node, alignment), alignment);
 		ok = false;
 	}
 
 	if (node->color != color) {
-		pr_err("node has wrong color, found %lu, expected %lu\n",
-		       node->color, color);
+		kunit_err(test, "node has wrong color, found %lu, expected %lu\n",
+			  node->color, color);
 		ok = false;
 	}
 
 	return ok;
 }
 
-#define show_mm(mm) do { \
-	struct drm_printer __p = drm_debug_printer(__func__); \
-	drm_mm_print((mm), &__p); } while (0)
+struct kunit_drm_mm_context {
+	u64 start;
+	u64 size;
+};
+
+static int __drm_mm_init(struct kunit_resource *res, void *context)
+{
+	struct kunit_drm_mm_context *ctx = context;
+	struct drm_mm *mm = kzalloc(sizeof(*mm), GFP_KERNEL);
+
+	drm_mm_init(mm, ctx->start, ctx->size);
+	res->data = mm;
+
+	return 0;
+}
+
+static void __drm_mm_destroy(struct kunit_resource *res)
+{
+	struct drm_mm *mm = res->data;
+	struct drm_mm_node *node, *next;
+
+	drm_mm_for_each_node_safe(node, next, mm)
+		drm_mm_remove_node(node);
+
+	drm_mm_takedown(mm);
+}
+
+static struct drm_mm *kunit_drm_mm(struct kunit *test, u64 start, u64 size)
+{
+	struct kunit_drm_mm_context context = {
+		.start = start,
+		.size = size
+	};
+
+	return kunit_alloc_resource(test, __drm_mm_init, __drm_mm_destroy, GFP_KERNEL, &context);
+}
+
+struct kunit_drm_random_order_context {
+	unsigned int count;
+	struct rnd_state *state;
+};
+
+static int __drm_random_order_init(struct kunit_resource *res, void *context)
+{
+	struct kunit_drm_random_order_context *ctx = context;
+
+	res->data = drm_random_order(ctx->count, ctx->state);
+
+	return 0;
+}
+
+static void __drm_random_order_destroy(struct kunit_resource *res)
+{
+	kfree(res->data);
+}
+
+static unsigned int *
+kunit_drm_random_order(struct kunit *test, unsigned int count, struct rnd_state *state)
+{
+	struct kunit_drm_random_order_context context = {
+		.count = count,
+		.state = state
+	};
+
+	return kunit_alloc_resource(test, __drm_random_order_init, __drm_random_order_destroy,
+				    GFP_KERNEL, &context);
+}
+
+struct kunit_vmalloc_params {
+	unsigned long size;
+	gfp_t gfp;
+};
+
+static int __kunit_vmalloc_init(struct kunit_resource *res, void *context)
+{
+	struct kunit_vmalloc_params *params = context;
+
+	res->data = __vmalloc(params->size, params->gfp);
+	if (!res->data)
+		return -ENOMEM;
+
+	return 0;
+}
+
+static void __kunit_vmalloc_destroy(struct kunit_resource *res)
+{
+	vfree(res->data);
+}
+
+static void *
+__kunit_vmalloc(struct kunit *test, unsigned long size, gfp_t gfp)
+{
+	struct kunit_vmalloc_params params = {
+		.size = size,
+		.gfp = gfp
+	};
+
+	return kunit_alloc_resource(test, __kunit_vmalloc_init, __kunit_vmalloc_destroy,
+				    GFP_KERNEL, &params);
+}
+
+static void *
+kunit_vmalloc(struct kunit *test, unsigned long size)
+{
+	return __kunit_vmalloc(test, size, GFP_KERNEL);
+}
+
+static void *
+kunit_vzalloc(struct kunit *test, unsigned long size)
+{
+	return __kunit_vmalloc(test, size, GFP_KERNEL | __GFP_ZERO);
+}
+
+static unsigned long *
+kunit_bitmap_alloc(struct kunit *test, unsigned int nbits, gfp_t flags)
+{
+	return kunit_kmalloc_array(test, BITS_TO_LONGS(nbits), sizeof(unsigned long),
+				   flags);
+}
+
+static unsigned long *
+kunit_bitmap_zalloc(struct kunit *test, unsigned int nbits, gfp_t flags)
+{
+	return kunit_bitmap_alloc(test, nbits, flags | __GFP_ZERO);
+}
 
-static int igt_init(void *ignored)
+static void test_init(struct kunit *test)
 {
 	const unsigned int size = 4096;
 	struct drm_mm mm;
 	struct drm_mm_node tmp;
-	int ret = -EINVAL;
 
 	/* Start with some simple checks on initialising the struct drm_mm */
 	memset(&mm, 0, sizeof(mm));
-	if (drm_mm_initialized(&mm)) {
-		pr_err("zeroed mm claims to be initialized\n");
-		return ret;
-	}
+	KUNIT_EXPECT_FALSE_MSG(test, drm_mm_initialized(&mm), "zeroed mm claims to be initialized");
 
 	memset(&mm, 0xff, sizeof(mm));
 	drm_mm_init(&mm, 0, size);
-	if (!drm_mm_initialized(&mm)) {
-		pr_err("mm claims not to be initialized\n");
-		goto out;
-	}
-
-	if (!drm_mm_clean(&mm)) {
-		pr_err("mm not empty on creation\n");
-		goto out;
-	}
-
-	/* After creation, it should all be one massive hole */
-	if (!assert_one_hole(&mm, 0, size)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	KUNIT_EXPECT_TRUE_MSG(test, drm_mm_initialized(&mm), "mm claims not to be initialized");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_mm_clean(&mm), "mm not empty on creation");
+	KUNIT_EXPECT_TRUE_MSG(test, has_one_hole(test, &mm, 0, size),
+			      "after creation, it should all be one massive hole");
 
 	memset(&tmp, 0, sizeof(tmp));
 	tmp.start = 0;
 	tmp.size = size;
-	ret = drm_mm_reserve_node(&mm, &tmp);
-	if (ret) {
-		pr_err("failed to reserve whole drm_mm\n");
-		goto out;
-	}
-
-	/* After filling the range entirely, there should be no holes */
-	if (!assert_no_holes(&mm)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(&mm, &tmp), 0,
+			    "failed to reserve whole drm_mm");
+	KUNIT_EXPECT_TRUE_MSG(test, has_no_holes(test, &mm),
+			      "after filling the range entirely, there should be no holes");
 
-	/* And then after emptying it again, the massive hole should be back */
 	drm_mm_remove_node(&tmp);
-	if (!assert_one_hole(&mm, 0, size)) {
-		ret = -EINVAL;
-		goto out;
-	}
+	KUNIT_EXPECT_TRUE_MSG(test, has_one_hole(test, &mm, 0, size),
+			      "after emptying it again, the massive hole should be back");
 
-out:
-	if (ret)
-		show_mm(&mm);
 	drm_mm_takedown(&mm);
-	return ret;
 }
 
-static int igt_debug(void *ignored)
+static void test_debug(struct kunit *test)
 {
 	struct drm_mm mm;
 	struct drm_mm_node nodes[2];
-	int ret;
 
 	/* Create a small drm_mm with a couple of nodes and a few holes, and
 	 * check that the debug iterator doesn't explode over a trivial drm_mm.
@@ -277,24 +529,17 @@ static int igt_debug(void *ignored)
 	memset(nodes, 0, sizeof(nodes));
 	nodes[0].start = 512;
 	nodes[0].size = 1024;
-	ret = drm_mm_reserve_node(&mm, &nodes[0]);
-	if (ret) {
-		pr_err("failed to reserve node[0] {start=%lld, size=%lld)\n",
-		       nodes[0].start, nodes[0].size);
-		return ret;
-	}
+	KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(&mm, &nodes[0]), 0,
+			    "failed to reserve node[0] {start=%lld, size=%lld)",
+			    nodes[0].start, nodes[0].size);
 
 	nodes[1].size = 1024;
 	nodes[1].start = 4096 - 512 - nodes[1].size;
-	ret = drm_mm_reserve_node(&mm, &nodes[1]);
-	if (ret) {
-		pr_err("failed to reserve node[1] {start=%lld, size=%lld)\n",
-		       nodes[1].start, nodes[1].size);
-		return ret;
-	}
+	KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(&mm, &nodes[1]), 0,
+			    "failed to reserve node[1] {start=%lld, size=%lld)",
+			    nodes[1].start, nodes[1].size);
 
-	show_mm(&mm);
-	return 0;
+	show_mm(test, &mm);
 }
 
 static struct drm_mm_node *set_node(struct drm_mm_node *node,
@@ -305,7 +550,8 @@ static struct drm_mm_node *set_node(struct drm_mm_node *node,
 	return node;
 }
 
-static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node)
+static bool
+check_reserve_fail(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node)
 {
 	int err;
 
@@ -314,19 +560,18 @@ static bool expect_reserve_fail(struct drm_mm *mm, struct drm_mm_node *node)
 		return true;
 
 	if (!err) {
-		pr_err("impossible reserve succeeded, node %llu + %llu\n",
-		       node->start, node->size);
+		kunit_err(test, "impossible reserve succeeded, node %llu + %llu\n",
+			  node->start, node->size);
 		drm_mm_remove_node(node);
 	} else {
-		pr_err("impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n",
-		       err, -ENOSPC, node->start, node->size);
+		kunit_err(test, "impossible reserve failed with wrong error %d [expected %d], node %llu + %llu\n",
+			  err, -ENOSPC, node->start, node->size);
 	}
 	return false;
 }
 
-static bool check_reserve_boundaries(struct drm_mm *mm,
-				     unsigned int count,
-				     u64 size)
+static bool
+check_reserve_boundaries(struct kunit *test, struct drm_mm *mm, unsigned int count, u64 size)
 {
 	const struct boundary {
 		u64 start, size;
@@ -339,29 +584,29 @@ static bool check_reserve_boundaries(struct drm_mm *mm,
 		B(size * count, 0),
 		B(-size, size),
 		B(-size, -size),
-		B(-size, 2*size),
+		B(-size, 2 * size),
 		B(0, -size),
 		B(size, -size),
-		B(count*size, size),
-		B(count*size, -size),
-		B(count*size, count*size),
-		B(count*size, -count*size),
-		B(count*size, -(count+1)*size),
-		B((count+1)*size, size),
-		B((count+1)*size, -size),
-		B((count+1)*size, -2*size),
+		B(count * size, size),
+		B(count * size, -size),
+		B(count * size, count * size),
+		B(count * size, -count * size),
+		B(count * size, -(count + 1) * size),
+		B((count + 1) * size, size),
+		B((count + 1) * size, -size),
+		B((count + 1) * size, -2 * size),
 #undef B
 	};
 	struct drm_mm_node tmp = {};
 	int n;
 
 	for (n = 0; n < ARRAY_SIZE(boundaries); n++) {
-		if (!expect_reserve_fail(mm,
-					 set_node(&tmp,
-						  boundaries[n].start,
-						  boundaries[n].size))) {
-			pr_err("boundary[%d:%s] failed, count=%u, size=%lld\n",
-			       n, boundaries[n].name, count, size);
+		if (!check_reserve_fail(test, mm,
+					set_node(&tmp,
+						 boundaries[n].start,
+						 boundaries[n].size))) {
+			kunit_err(test, "boundary[%d:%s] failed, count=%u, size=%lld\n",
+				  n, boundaries[n].name, count, size);
 			return false;
 		}
 	}
@@ -369,13 +614,48 @@ static bool check_reserve_boundaries(struct drm_mm *mm,
 	return true;
 }
 
-static int __igt_reserve(unsigned int count, u64 size)
+static const u64 simple_size_less(const unsigned int prime)
+{
+	return BIT_ULL(prime) - 1;
+}
+
+static const u64 simple_size_equal(const unsigned int prime)
+{
+	return BIT_ULL(prime);
+}
+
+static const u64 simple_size_more(const unsigned int prime)
+{
+	return BIT_ULL(prime) + 1;
+}
+
+static const u64 (*simple_size_ops[])(const unsigned int) = {
+	simple_size_less,
+	simple_size_equal,
+	simple_size_more,
+};
+
+struct reserve_test {
+	const u64 size;
+};
+
+static const struct reserve_test param_to_reserve_test(const unsigned long param)
+{
+	unsigned int prime = FIELD_GET(DRM_MM_PRIME_MASK, param);
+	const u64 (*op)(const unsigned int) = simple_size_ops[FIELD_GET(DRM_MM_OP_MASK, param)];
+
+	return (const struct reserve_test) { .size = op(prime) };
+}
+
+static void test_reserve(struct kunit *test)
 {
+	const struct reserve_test t = param_to_reserve_test((unsigned long)test->param_value);
+	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
+	const u64 size = t.size;
 	DRM_RND_STATE(prng, random_seed);
-	struct drm_mm mm;
-	struct drm_mm_node tmp, *nodes, *node, *next;
+	struct drm_mm *mm;
+	struct drm_mm_node tmp, *nodes, *node;
 	unsigned int *order, n, m, o = 0;
-	int ret, err;
 
 	/* For exercising drm_mm_reserve_node(), we want to check that
 	 * reservations outside of the drm_mm range are rejected, and to
@@ -383,83 +663,59 @@ static int __igt_reserve(unsigned int count, u64 size)
 	 * the tree and nodes should be intact.
 	 */
 
-	DRM_MM_BUG_ON(!count);
-	DRM_MM_BUG_ON(!size);
+	KUNIT_ASSERT_GT(test, count, 0);
+	KUNIT_ASSERT_GT(test, size, 0);
 
-	ret = -ENOMEM;
-	order = drm_random_order(count, &prng);
-	if (!order)
-		goto err;
+	order = kunit_drm_random_order(test, count, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
 
-	nodes = vzalloc(array_size(count, sizeof(*nodes)));
-	if (!nodes)
-		goto err_order;
+	nodes = kunit_vzalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, count * size);
+	mm = kunit_drm_mm(test, 0, count * size);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	if (!check_reserve_boundaries(&mm, count, size))
-		goto out;
+	KUNIT_EXPECT_TRUE(test, check_reserve_boundaries(test, mm, count, size));
 
 	for (n = 0; n < count; n++) {
 		nodes[n].start = order[n] * size;
 		nodes[n].size = size;
 
-		err = drm_mm_reserve_node(&mm, &nodes[n]);
-		if (err) {
-			pr_err("reserve failed, step %d, start %llu\n",
-			       n, nodes[n].start);
-			ret = err;
-			goto out;
-		}
-
-		if (!drm_mm_node_allocated(&nodes[n])) {
-			pr_err("reserved node not allocated! step %d, start %llu\n",
-			       n, nodes[n].start);
-			goto out;
-		}
-
-		if (!expect_reserve_fail(&mm, &nodes[n]))
-			goto out;
+		KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(mm, &nodes[n]), 0,
+				    "reserve failed, step %d, start %llu",
+				    n, nodes[n].start);
+		KUNIT_EXPECT_TRUE_MSG(test, drm_mm_node_allocated(&nodes[n]),
+				      "reserved node not allocated! step %d, start %llu",
+				      n, nodes[n].start);
+		KUNIT_EXPECT_TRUE(test, check_reserve_fail(test, mm, &nodes[n]));
 	}
 
 	/* After random insertion the nodes should be in order */
-	if (!assert_continuous(&mm, size))
-		goto out;
+	KUNIT_EXPECT_TRUE(test, is_continuous(test, mm, size));
 
 	/* Repeated use should then fail */
 	drm_random_reorder(order, count, &prng);
 	for (n = 0; n < count; n++) {
-		if (!expect_reserve_fail(&mm,
-					 set_node(&tmp, order[n] * size, 1)))
-			goto out;
+		KUNIT_EXPECT_TRUE(test,
+				  check_reserve_fail(test, mm, set_node(&tmp, order[n] * size, 1)));
 
 		/* Remove and reinsert should work */
 		drm_mm_remove_node(&nodes[order[n]]);
-		err = drm_mm_reserve_node(&mm, &nodes[order[n]]);
-		if (err) {
-			pr_err("reserve failed, step %d, start %llu\n",
-			       n, nodes[n].start);
-			ret = err;
-			goto out;
-		}
+		KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(mm, &nodes[order[n]]), 0,
+				    "reserve failed, step %d, start %llu",
+				    n, nodes[n].start);
 	}
 
-	if (!assert_continuous(&mm, size))
-		goto out;
+	KUNIT_EXPECT_TRUE(test, is_continuous(test, mm, size));
 
 	/* Overlapping use should then fail */
-	for (n = 0; n < count; n++) {
-		if (!expect_reserve_fail(&mm, set_node(&tmp, 0, size*count)))
-			goto out;
-	}
-	for (n = 0; n < count; n++) {
-		if (!expect_reserve_fail(&mm,
-					 set_node(&tmp,
-						  size * n,
-						  size * (count - n))))
-			goto out;
-	}
+	for (n = 0; n < count; n++)
+		KUNIT_EXPECT_TRUE(test,
+				  check_reserve_fail(test, mm, set_node(&tmp, 0, size * count)));
+	for (n = 0; n < count; n++)
+		KUNIT_EXPECT_TRUE(test,
+				  check_reserve_fail(test, mm, set_node(&tmp, size * n,
+									size * (count - n))));
 
 	/* Remove several, reinsert, check full */
 	for_each_prime_number(n, min(max_prime, count)) {
@@ -470,62 +726,38 @@ static int __igt_reserve(unsigned int count, u64 size)
 
 		for (m = 0; m < n; m++) {
 			node = &nodes[order[(o + m) % count]];
-			err = drm_mm_reserve_node(&mm, node);
-			if (err) {
-				pr_err("reserve failed, step %d/%d, start %llu\n",
-				       m, n, node->start);
-				ret = err;
-				goto out;
-			}
+			KUNIT_ASSERT_EQ_MSG(test, drm_mm_reserve_node(mm, node), 0,
+					    "reserve failed, step %d/%d, start %llu",
+					    m, n, node->start);
 		}
 
 		o += n;
 
-		if (!assert_continuous(&mm, size))
-			goto out;
+		KUNIT_EXPECT_TRUE(test, is_continuous(test, mm, size));
 	}
-
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	vfree(nodes);
-err_order:
-	kfree(order);
-err:
-	return ret;
 }
 
-static int igt_reserve(void *ignored)
+#define IGT_RESERVE_MAX_PRIME 54
+static const void *reserve_gen_params(const void *prev, char *desc)
 {
-	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
-	int n, ret;
-
-	for_each_prime_number_from(n, 1, 54) {
-		u64 size = BIT_ULL(n);
-
-		ret = __igt_reserve(count, size - 1);
-		if (ret)
-			return ret;
+	unsigned long param = (unsigned long)prev;
 
-		ret = __igt_reserve(count, size);
-		if (ret)
-			return ret;
+	if (!prev)
+		kunit_drm_mm_print_params();
 
-		ret = __igt_reserve(count, size + 1);
-		if (ret)
-			return ret;
+	param = prime_ops_gen_param(param,
+				    IGT_RESERVE_MAX_PRIME,
+				    ARRAY_SIZE(simple_size_ops));
 
-		cond_resched();
-	}
+	if (param_valid(param))
+		sprintf(desc, "size = %llu", param_to_reserve_test(param).size);
 
-	return 0;
+	return (void *)param;
 }
 
-static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
-			  u64 size, u64 alignment, unsigned long color,
-			  const struct insert_mode *mode)
+static bool check_insert(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node,
+			 u64 size, u64 alignment, unsigned long color,
+			 const struct insert_mode *mode)
 {
 	int err;
 
@@ -533,12 +765,12 @@ static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
 					 size, alignment, color,
 					 mode->mode);
 	if (err) {
-		pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n",
-		       size, alignment, color, mode->name, err);
+		kunit_err(test, "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) failed with err=%d\n",
+			  size, alignment, color, mode->name, err);
 		return false;
 	}
 
-	if (!assert_node(node, mm, size, alignment, color)) {
+	if (!check_node(test, node, mm, size, alignment, color)) {
 		drm_mm_remove_node(node);
 		return false;
 	}
@@ -546,7 +778,7 @@ static bool expect_insert(struct drm_mm *mm, struct drm_mm_node *node,
 	return true;
 }
 
-static bool expect_insert_fail(struct drm_mm *mm, u64 size)
+static bool check_insert_fail(struct kunit *test, struct drm_mm *mm, u64 size)
 {
 	struct drm_mm_node tmp = {};
 	int err;
@@ -556,214 +788,158 @@ static bool expect_insert_fail(struct drm_mm *mm, u64 size)
 		return true;
 
 	if (!err) {
-		pr_err("impossible insert succeeded, node %llu + %llu\n",
-		       tmp.start, tmp.size);
+		kunit_err(test, "impossible insert succeeded, node %llu + %llu\n",
+			  tmp.start, tmp.size);
 		drm_mm_remove_node(&tmp);
 	} else {
-		pr_err("impossible insert failed with wrong error %d [expected %d], size %llu\n",
-		       err, -ENOSPC, size);
+		kunit_err(test, "impossible insert failed with wrong error %d [expected %d], size %llu\n",
+			  err, -ENOSPC, size);
 	}
 	return false;
 }
 
-static int __igt_insert(unsigned int count, u64 size, bool replace)
+struct insert_replace_test {
+	const u64 size;
+	const struct insert_mode *mode;
+};
+
+static const struct insert_replace_test param_to_insert_replace_test(unsigned long param)
+{
+	unsigned int prime = FIELD_GET(DRM_MM_PRIME_MASK, param);
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+	const u64 (*op)(const unsigned int) = simple_size_ops[FIELD_GET(DRM_MM_OP_MASK, param)];
+
+	return (const struct insert_replace_test) { .size = op(prime),
+						    .mode = &insert_modes[mode] };
+}
+
+static void __test_insert(struct kunit *test, bool replace)
 {
+	const struct insert_replace_test t =
+		param_to_insert_replace_test((unsigned long)test->param_value);
+	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
+	const struct insert_mode *mode = t.mode;
+	const u64 size = t.size;
 	DRM_RND_STATE(prng, random_seed);
-	const struct insert_mode *mode;
-	struct drm_mm mm;
+	struct drm_mm *mm;
 	struct drm_mm_node *nodes, *node, *next;
 	unsigned int *order, n, m, o = 0;
-	int ret;
 
 	/* Fill a range with lots of nodes, check it doesn't fail too early */
 
-	DRM_MM_BUG_ON(!count);
-	DRM_MM_BUG_ON(!size);
+	KUNIT_ASSERT_GT(test, count, 0);
+	KUNIT_ASSERT_GT(test, size, 0);
 
-	ret = -ENOMEM;
-	nodes = vmalloc(array_size(count, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
+	nodes = kunit_vmalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-	order = drm_random_order(count, &prng);
-	if (!order)
-		goto err_nodes;
+	order = kunit_drm_random_order(test, count, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, count * size);
+	mm = kunit_drm_mm(test, 0, count * size);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	for (mode = insert_modes; mode->name; mode++) {
-		for (n = 0; n < count; n++) {
-			struct drm_mm_node tmp;
+	for (n = 0; n < count; n++) {
+		struct drm_mm_node tmp;
 
-			node = replace ? &tmp : &nodes[n];
-			memset(node, 0, sizeof(*node));
-			if (!expect_insert(&mm, node, size, 0, n, mode)) {
-				pr_err("%s insert failed, size %llu step %d\n",
-				       mode->name, size, n);
-				goto out;
-			}
+		node = replace ? &tmp : &nodes[n];
+		memset(node, 0, sizeof(*node));
+		KUNIT_ASSERT_TRUE_MSG(test,
+				      check_insert(test, mm, node, size, 0, n, mode),
+				      "insert failed, size %llu step %d", size, n);
 
-			if (replace) {
-				drm_mm_replace_node(&tmp, &nodes[n]);
-				if (drm_mm_node_allocated(&tmp)) {
-					pr_err("replaced old-node still allocated! step %d\n",
-					       n);
-					goto out;
-				}
-
-				if (!assert_node(&nodes[n], &mm, size, 0, n)) {
-					pr_err("replaced node did not inherit parameters, size %llu step %d\n",
-					       size, n);
-					goto out;
-				}
-
-				if (tmp.start != nodes[n].start) {
-					pr_err("replaced node mismatch location expected [%llx + %llx], found [%llx + %llx]\n",
-					       tmp.start, size,
-					       nodes[n].start, nodes[n].size);
-					goto out;
-				}
-			}
+		if (replace) {
+			drm_mm_replace_node(&tmp, &nodes[n]);
+			KUNIT_EXPECT_FALSE_MSG(test, drm_mm_node_allocated(&tmp),
+					       "replaced old-node still allocated! step %d", n);
+			KUNIT_EXPECT_TRUE_MSG(test, check_node(test, &nodes[n], mm, size, 0, n),
+					      "replaced node did not inherit parameters, size %llu step %d",
+					      size, n);
+			KUNIT_EXPECT_EQ_MSG(test, tmp.start, nodes[n].start,
+					    "replaced node mismatch location expected [%#llx + %#llx], found [%#llx + %#llx]",
+					    tmp.start, size, nodes[n].start, nodes[n].size);
 		}
+	}
 
-		/* After random insertion the nodes should be in order */
-		if (!assert_continuous(&mm, size))
-			goto out;
-
-		/* Repeated use should then fail */
-		if (!expect_insert_fail(&mm, size))
-			goto out;
-
-		/* Remove one and reinsert, as the only hole it should refill itself */
-		for (n = 0; n < count; n++) {
-			u64 addr = nodes[n].start;
+	KUNIT_EXPECT_TRUE_MSG(test, is_continuous(test, mm, size),
+			      "After random insertion the nodes should be in order");
+	KUNIT_EXPECT_TRUE_MSG(test, check_insert_fail(test, mm, size),
+			      "After random insertion, repeated use should fail");
 
-			drm_mm_remove_node(&nodes[n]);
-			if (!expect_insert(&mm, &nodes[n], size, 0, n, mode)) {
-				pr_err("%s reinsert failed, size %llu step %d\n",
-				       mode->name, size, n);
-				goto out;
-			}
+	/* Remove one and reinsert, as the only hole it should refill itself */
+	for (n = 0; n < count; n++) {
+		u64 addr = nodes[n].start;
 
-			if (nodes[n].start != addr) {
-				pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
-				       mode->name, n, addr, nodes[n].start);
-				goto out;
-			}
+		drm_mm_remove_node(&nodes[n]);
+		KUNIT_ASSERT_TRUE_MSG(test, check_insert(test, mm, &nodes[n], size, 0, n, mode),
+				      "reinsert failed, size %llu step %d", size, n);
+		KUNIT_EXPECT_EQ_MSG(test, nodes[n].start, addr,
+				    "reinsert node moved, step %d, expected %#llx, found %#llx",
+				    n, addr, nodes[n].start);
+		KUNIT_EXPECT_TRUE(test, is_continuous(test, mm, size));
+	}
 
-			if (!assert_continuous(&mm, size))
-				goto out;
+	/* Remove several, reinsert, check full */
+	for_each_prime_number(n, min(max_prime, count)) {
+		for (m = 0; m < n; m++) {
+			node = &nodes[order[(o + m) % count]];
+			drm_mm_remove_node(node);
 		}
 
-		/* Remove several, reinsert, check full */
-		for_each_prime_number(n, min(max_prime, count)) {
-			for (m = 0; m < n; m++) {
-				node = &nodes[order[(o + m) % count]];
-				drm_mm_remove_node(node);
-			}
-
-			for (m = 0; m < n; m++) {
-				node = &nodes[order[(o + m) % count]];
-				if (!expect_insert(&mm, node, size, 0, n, mode)) {
-					pr_err("%s multiple reinsert failed, size %llu step %d\n",
-					       mode->name, size, n);
-					goto out;
-				}
-			}
-
-			o += n;
-
-			if (!assert_continuous(&mm, size))
-				goto out;
-
-			if (!expect_insert_fail(&mm, size))
-				goto out;
+		for (m = 0; m < n; m++) {
+			node = &nodes[order[(o + m) % count]];
+			KUNIT_ASSERT_TRUE_MSG(test, check_insert(test, mm, node, size, 0, n, mode),
+					      "multiple reinsert failed, size %llu step %d",
+					      size, n);
 		}
 
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
+		o += n;
 
-		cond_resched();
+		KUNIT_EXPECT_TRUE(test, is_continuous(test, mm, size));
+		KUNIT_EXPECT_TRUE(test, check_insert_fail(test, mm, size));
 	}
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
+	drm_mm_for_each_node_safe(node, next, mm)
 		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
+	KUNIT_ASSERT_TRUE(test, drm_mm_clean(mm));
 }
 
-static int igt_insert(void *ignored)
+static void test_insert(struct kunit *test)
 {
-	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
-	unsigned int n;
-	int ret;
-
-	for_each_prime_number_from(n, 1, 54) {
-		u64 size = BIT_ULL(n);
-
-		ret = __igt_insert(count, size - 1, false);
-		if (ret)
-			return ret;
-
-		ret = __igt_insert(count, size, false);
-		if (ret)
-			return ret;
-
-		ret = __igt_insert(count, size + 1, false);
-		if (ret)
-			return ret;
-
-		cond_resched();
-	}
-
-	return 0;
+	__test_insert(test, false);
 }
 
-static int igt_replace(void *ignored)
+static void test_replace(struct kunit *test)
 {
-	const unsigned int count = min_t(unsigned int, BIT(10), max_iterations);
-	unsigned int n;
-	int ret;
-
-	/* Reuse igt_insert to exercise replacement by inserting a dummy node,
-	 * then replacing it with the intended node. We want to check that
-	 * the tree is intact and all the information we need is carried
-	 * across to the target node.
-	 */
+	__test_insert(test, true);
+}
 
-	for_each_prime_number_from(n, 1, 54) {
-		u64 size = BIT_ULL(n);
+#define IGT_INSERT_REPLACE_MAX_PRIME 54
+static const void *insert_replace_gen_params(const void *prev, char *desc)
+{
+	unsigned long param = (unsigned long)prev;
 
-		ret = __igt_insert(count, size - 1, true);
-		if (ret)
-			return ret;
+	if (!prev)
+		kunit_drm_mm_print_params();
 
-		ret = __igt_insert(count, size, true);
-		if (ret)
-			return ret;
+	param = mode_prime_ops_gen_param(param,
+					 ARRAY_SIZE(insert_modes),
+					 IGT_INSERT_REPLACE_MAX_PRIME,
+					 ARRAY_SIZE(simple_size_ops));
 
-		ret = __igt_insert(count, size + 1, true);
-		if (ret)
-			return ret;
+	if (param_valid(param)) {
+		const struct insert_replace_test t = param_to_insert_replace_test(param);
 
-		cond_resched();
+		sprintf(desc, "size = %llu %s", t.size, t.mode->name);
 	}
 
-	return 0;
+	return (void *)param;
 }
 
-static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node,
-				   u64 size, u64 alignment, unsigned long color,
-				   u64 range_start, u64 range_end,
-				   const struct insert_mode *mode)
+static bool check_insert_in_range(struct kunit *test, struct drm_mm *mm, struct drm_mm_node *node,
+				  u64 size, u64 alignment, unsigned long color,
+				  u64 range_start, u64 range_end,
+				  const struct insert_mode *mode)
 {
 	int err;
 
@@ -772,13 +948,13 @@ static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node,
 					  range_start, range_end,
 					  mode->mode);
 	if (err) {
-		pr_err("insert (size=%llu, alignment=%llu, color=%lu, mode=%s) nto range [%llx, %llx] failed with err=%d\n",
-		       size, alignment, color, mode->name,
-		       range_start, range_end, err);
+		kunit_err(test, "insert (size=%llu, alignment=%llu, color=%lu, mode=%s) into range [%#llx, %#llx] failed with err=%d\n",
+			  size, alignment, color, mode->name,
+			  range_start, range_end, err);
 		return false;
 	}
 
-	if (!assert_node(node, mm, size, alignment, color)) {
+	if (!check_node(test, node, mm, size, alignment, color)) {
 		drm_mm_remove_node(node);
 		return false;
 	}
@@ -786,10 +962,11 @@ static bool expect_insert_in_range(struct drm_mm *mm, struct drm_mm_node *node,
 	return true;
 }
 
-static bool expect_insert_in_range_fail(struct drm_mm *mm,
-					u64 size,
-					u64 range_start,
-					u64 range_end)
+static bool check_insert_in_range_fail(struct kunit *test,
+				       struct drm_mm *mm,
+				       u64 size,
+				       u64 range_start,
+				       u64 range_end)
 {
 	struct drm_mm_node tmp = {};
 	int err;
@@ -802,51 +979,53 @@ static bool expect_insert_in_range_fail(struct drm_mm *mm,
 		return true;
 
 	if (!err) {
-		pr_err("impossible insert succeeded, node %llx + %llu, range [%llx, %llx]\n",
-		       tmp.start, tmp.size, range_start, range_end);
+		kunit_err(test, "impossible insert succeeded, node %#llx + %llu, range [%#llx, %#llx]\n",
+			  tmp.start, tmp.size, range_start, range_end);
 		drm_mm_remove_node(&tmp);
 	} else {
-		pr_err("impossible insert failed with wrong error %d [expected %d], size %llu, range [%llx, %llx]\n",
-		       err, -ENOSPC, size, range_start, range_end);
+		kunit_err(test,
+			  "impossible insert failed with wrong error %d [expected %d], size %llu, range [%#llx, %#llx]\n",
+			  err, -ENOSPC, size, range_start, range_end);
 	}
 
 	return false;
 }
 
-static bool assert_contiguous_in_range(struct drm_mm *mm,
-				       u64 size,
-				       u64 start,
-				       u64 end)
+static bool check_contiguous_in_range(struct kunit *test,
+				      struct drm_mm *mm,
+				      u64 size,
+				      u64 start,
+				      u64 end)
 {
 	struct drm_mm_node *node;
 	unsigned int n;
 
-	if (!expect_insert_in_range_fail(mm, size, start, end))
+	if (!check_insert_in_range_fail(test, mm, size, start, end))
 		return false;
 
 	n = div64_u64(start + size - 1, size);
 	drm_mm_for_each_node(node, mm) {
 		if (node->start < start || node->start + node->size > end) {
-			pr_err("node %d out of range, address [%llx + %llu], range [%llx, %llx]\n",
-			       n, node->start, node->start + node->size, start, end);
+			kunit_err(test, "node %d out of range, address [%#llx + %llu], range [%#llx, %#llx]\n",
+				  n, node->start, node->start + node->size, start, end);
 			return false;
 		}
 
 		if (node->start != n * size) {
-			pr_err("node %d out of order, expected start %llx, found %llx\n",
-			       n, n * size, node->start);
+			kunit_err(test, "node %d out of order, expected start %#llx, found %#llx\n",
+				  n, n * size, node->start);
 			return false;
 		}
 
 		if (node->size != size) {
-			pr_err("node %d has wrong size, expected size %llx, found %llx\n",
-			       n, size, node->size);
+			kunit_err(test, "node %d has wrong size, expected size %#llx, found %#llx\n",
+				  n, size, node->size);
 			return false;
 		}
 
 		if (drm_mm_hole_follows(node) &&
 		    drm_mm_hole_node_end(node) < end) {
-			pr_err("node %d is followed by a hole!\n", n);
+			kunit_err(test, "node %d is followed by a hole!\n", n);
 			return false;
 		}
 
@@ -856,8 +1035,8 @@ static bool assert_contiguous_in_range(struct drm_mm *mm,
 	if (start > 0) {
 		node = __drm_mm_interval_first(mm, 0, start - 1);
 		if (drm_mm_node_allocated(node)) {
-			pr_err("node before start: node=%llx+%llu, start=%llx\n",
-			       node->start, node->size, start);
+			kunit_err(test, "node before start: node=%#llx+%llu, start=%#llx\n",
+				  node->start, node->size, start);
 			return false;
 		}
 	}
@@ -865,8 +1044,8 @@ static bool assert_contiguous_in_range(struct drm_mm *mm,
 	if (end < U64_MAX) {
 		node = __drm_mm_interval_first(mm, end, U64_MAX);
 		if (drm_mm_node_allocated(node)) {
-			pr_err("node after end: node=%llx+%llu, end=%llx\n",
-			       node->start, node->size, end);
+			kunit_err(test, "node after end: node=%#llx+%llu, end=%#llx\n",
+				  node->start, node->size, end);
 			return false;
 		}
 	}
@@ -874,181 +1053,183 @@ static bool assert_contiguous_in_range(struct drm_mm *mm,
 	return true;
 }
 
-static int __igt_insert_range(unsigned int count, u64 size, u64 start, u64 end)
-{
+struct insert_range_test {
+	const unsigned int count;
+	const u64 size;
+	const u64 start;
+	const u64 end;
 	const struct insert_mode *mode;
-	struct drm_mm mm;
+};
+
+#define __insert_range_test(name, __start, __end) \
+const struct insert_range_test insert_range_test##name(const unsigned int prime, \
+						       const unsigned int mode) \
+{ \
+	const unsigned int count = min_t(unsigned int, BIT(13), max_iterations); \
+	const u64 size = BIT_ULL(prime); \
+	const u64 max = count * size; \
+	return (const struct insert_range_test) { \
+		.count = count, \
+		.size = size, \
+		.start = (__start), \
+		.end = (__end), \
+		.mode = &insert_modes[mode] \
+	}; \
+}
+
+__insert_range_test(0, 0, max);
+__insert_range_test(1, 1, max);
+__insert_range_test(2, 0, max - 1);
+__insert_range_test(3, 0, max / 2);
+__insert_range_test(4, max / 2, max);
+__insert_range_test(5, max / 4 + 1, 3 * max / 4 - 1);
+
+static const struct insert_range_test
+(*insert_range_tests[])(const unsigned int, const unsigned int) = {
+	insert_range_test0,
+	insert_range_test1,
+	insert_range_test2,
+	insert_range_test3,
+	insert_range_test4,
+	insert_range_test5,
+};
+
+static const struct insert_range_test param_to_insert_range_test(const unsigned long param)
+{
+	unsigned int prime = FIELD_GET(DRM_MM_PRIME_MASK, param);
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+	const struct insert_range_test (*op)(const unsigned int, const unsigned int) =
+		insert_range_tests[FIELD_GET(DRM_MM_OP_MASK, param)];
+
+	return op(prime, mode);
+}
+
+static void test_insert_range(struct kunit *test)
+{
+	const struct insert_range_test t =
+		param_to_insert_range_test((unsigned long)test->param_value);
+	const unsigned int count = t.count;
+	const u64 size = t.size;
+	const u64 start = t.start;
+	const u64 end = t.end;
+	const struct insert_mode *mode = t.mode;
+	struct drm_mm *mm;
 	struct drm_mm_node *nodes, *node, *next;
 	unsigned int n, start_n, end_n;
-	int ret;
 
-	DRM_MM_BUG_ON(!count);
-	DRM_MM_BUG_ON(!size);
-	DRM_MM_BUG_ON(end <= start);
+	KUNIT_ASSERT_GT(test, count, 0);
+	KUNIT_ASSERT_GT(test, size, 0);
+	KUNIT_ASSERT_GT(test, end, start);
 
-	/* Very similar to __igt_insert(), but now instead of populating the
+	/* Very similar to test_insert(), but now instead of populating the
 	 * full range of the drm_mm, we try to fill a small portion of it.
 	 */
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(count, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
+	nodes = kunit_vzalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, count * size);
+	mm = kunit_drm_mm(test, 0, count * size);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
 	start_n = div64_u64(start + size - 1, size);
 	end_n = div64_u64(end - size, size);
 
-	for (mode = insert_modes; mode->name; mode++) {
-		for (n = start_n; n <= end_n; n++) {
-			if (!expect_insert_in_range(&mm, &nodes[n],
-						    size, size, n,
-						    start, end, mode)) {
-				pr_err("%s insert failed, size %llu, step %d [%d, %d], range [%llx, %llx]\n",
-				       mode->name, size, n,
-				       start_n, end_n,
-				       start, end);
-				goto out;
-			}
-		}
+	for (n = start_n; n <= end_n; n++)
+		KUNIT_EXPECT_TRUE_MSG(test,
+				      check_insert_in_range(test, mm, &nodes[n],
+							    size, size, n, start, end, mode),
+				      "insert failed, size %llu, step %d [%d, %d], range [%#llx, %#llx]",
+				      size, n, start_n, end_n, start, end);
 
-		if (!assert_contiguous_in_range(&mm, size, start, end)) {
-			pr_err("%s: range [%llx, %llx] not full after initialisation, size=%llu\n",
-			       mode->name, start, end, size);
-			goto out;
-		}
 
-		/* Remove one and reinsert, it should refill itself */
-		for (n = start_n; n <= end_n; n++) {
-			u64 addr = nodes[n].start;
+	KUNIT_EXPECT_TRUE_MSG(test, check_contiguous_in_range(test, mm, size, start, end),
+			      "range [%#llx, %#llx] not full after initialisation, size=%llu",
+			      start, end, size);
 
-			drm_mm_remove_node(&nodes[n]);
-			if (!expect_insert_in_range(&mm, &nodes[n],
-						    size, size, n,
-						    start, end, mode)) {
-				pr_err("%s reinsert failed, step %d\n", mode->name, n);
-				goto out;
-			}
+	/* Remove one and reinsert, it should refill itself */
+	for (n = start_n; n <= end_n; n++) {
+		u64 addr = nodes[n].start;
 
-			if (nodes[n].start != addr) {
-				pr_err("%s reinsert node moved, step %d, expected %llx, found %llx\n",
-				       mode->name, n, addr, nodes[n].start);
-				goto out;
-			}
-		}
+		drm_mm_remove_node(&nodes[n]);
+		KUNIT_EXPECT_TRUE_MSG(test,
+				      check_insert_in_range(test, mm, &nodes[n],
+							    size, size, n, start, end, mode),
+				      "reinsert failed, step %d", n);
 
-		if (!assert_contiguous_in_range(&mm, size, start, end)) {
-			pr_err("%s: range [%llx, %llx] not full after reinsertion, size=%llu\n",
-			       mode->name, start, end, size);
-			goto out;
-		}
-
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
-
-		cond_resched();
+		KUNIT_EXPECT_EQ_MSG(test, nodes[n].start, addr,
+				    "reinsert node moved, step %d, expected %#llx, found %#llx",
+				    n, addr, nodes[n].start);
 	}
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
+	KUNIT_EXPECT_TRUE_MSG(test, check_contiguous_in_range(test, mm, size, start, end),
+			      "range [%#llx, %#llx] not full after reinsertion, size=%llu",
+			      start, end, size);
+
+	drm_mm_for_each_node_safe(node, next, mm)
 		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	vfree(nodes);
-err:
-	return ret;
+	KUNIT_ASSERT_TRUE(test, drm_mm_clean(mm));
 }
 
-static int insert_outside_range(void)
+#define IGT_INSERT_RANGE_MAX_PRIME 50
+static const void *insert_range_gen_params(const void *prev, char *desc)
 {
-	struct drm_mm mm;
-	const unsigned int start = 1024;
-	const unsigned int end = 2048;
-	const unsigned int size = end - start;
-
-	drm_mm_init(&mm, start, size);
+	unsigned long param = (unsigned long)prev;
 
-	if (!expect_insert_in_range_fail(&mm, 1, 0, start))
-		return -EINVAL;
+	if (!prev)
+		kunit_drm_mm_print_params();
 
-	if (!expect_insert_in_range_fail(&mm, size,
-					 start - size/2, start + (size+1)/2))
-		return -EINVAL;
+	param = mode_prime_ops_gen_param(param,
+					 ARRAY_SIZE(insert_modes),
+					 IGT_INSERT_RANGE_MAX_PRIME,
+					 ARRAY_SIZE(insert_range_tests));
 
-	if (!expect_insert_in_range_fail(&mm, size,
-					 end - (size+1)/2, end + size/2))
-		return -EINVAL;
+	if (param_valid(param)) {
+		const struct insert_range_test t = param_to_insert_range_test(param);
 
-	if (!expect_insert_in_range_fail(&mm, 1, end, end + size))
-		return -EINVAL;
+		sprintf(desc, "count = %d, size = %llu, start = %#llx, end = %#llx %s",
+			t.count, t.size, t.start, t.end, t.mode->name);
+	}
 
-	drm_mm_takedown(&mm);
-	return 0;
+	return (void *)param;
 }
 
-static int igt_insert_range(void *ignored)
+static void test_insert_outside_range(struct kunit *test)
 {
-	const unsigned int count = min_t(unsigned int, BIT(13), max_iterations);
-	unsigned int n;
-	int ret;
-
-	/* Check that requests outside the bounds of drm_mm are rejected. */
-	ret = insert_outside_range();
-	if (ret)
-		return ret;
-
-	for_each_prime_number_from(n, 1, 50) {
-		const u64 size = BIT_ULL(n);
-		const u64 max = count * size;
-
-		ret = __igt_insert_range(count, size, 0, max);
-		if (ret)
-			return ret;
+	struct drm_mm mm;
+	const unsigned int start = 1024;
+	const unsigned int end = 2048;
+	const unsigned int size = end - start;
 
-		ret = __igt_insert_range(count, size, 1, max);
-		if (ret)
-			return ret;
+	drm_mm_init(&mm, start, size);
 
-		ret = __igt_insert_range(count, size, 0, max - 1);
-		if (ret)
-			return ret;
+	/* Check that requests outside the bounds of drm_mm are rejected. */
 
-		ret = __igt_insert_range(count, size, 0, max/2);
-		if (ret)
-			return ret;
+	KUNIT_EXPECT_TRUE(test, check_insert_in_range_fail(test, &mm, 1, 0, start));
 
-		ret = __igt_insert_range(count, size, max/2, max);
-		if (ret)
-			return ret;
+	KUNIT_EXPECT_TRUE(test, check_insert_in_range_fail(test, &mm, size,
+							   start - size / 2,
+							   start + (size + 1) / 2));
 
-		ret = __igt_insert_range(count, size, max/4+1, 3*max/4-1);
-		if (ret)
-			return ret;
+	KUNIT_EXPECT_TRUE(test, check_insert_in_range_fail(test, &mm, size,
+							   end - (size + 1) / 2,
+							   end + size / 2));
 
-		cond_resched();
-	}
+	KUNIT_EXPECT_TRUE(test, check_insert_in_range_fail(test, &mm, 1, end, end + size));
 
-	return 0;
+	drm_mm_takedown(&mm);
 }
 
-static int prepare_igt_frag(struct drm_mm *mm,
-			    struct drm_mm_node *nodes,
-			    unsigned int num_insert,
-			    const struct insert_mode *mode)
+static void prepare_test_frag(struct kunit *test,
+			      struct drm_mm *mm,
+			      struct drm_mm_node *nodes,
+			      unsigned int num_insert,
+			      const struct insert_mode *mode)
 {
 	unsigned int size = 4096;
 	unsigned int i;
 
-	for (i = 0; i < num_insert; i++) {
-		if (!expect_insert(mm, &nodes[i], size, 0, i,
-				   mode) != 0) {
-			pr_err("%s insert failed\n", mode->name);
-			return -EINVAL;
-		}
-	}
+	for (i = 0; i < num_insert; i++)
+		KUNIT_ASSERT_TRUE(test, check_insert(test, mm, &nodes[i], size, 0, i, mode));
 
 	/* introduce fragmentation by freeing every other node */
 	for (i = 0; i < num_insert; i++) {
@@ -1056,11 +1237,10 @@ static int prepare_igt_frag(struct drm_mm *mm,
 			drm_mm_remove_node(&nodes[i]);
 	}
 
-	return 0;
-
 }
 
-static u64 get_insert_time(struct drm_mm *mm,
+static u64 get_insert_time(struct kunit *test,
+			   struct drm_mm *mm,
 			   unsigned int num_insert,
 			   struct drm_mm_node *nodes,
 			   const struct insert_mode *mode)
@@ -1070,201 +1250,193 @@ static u64 get_insert_time(struct drm_mm *mm,
 	unsigned int i;
 
 	start = ktime_get();
-	for (i = 0; i < num_insert; i++) {
-		if (!expect_insert(mm, &nodes[i], size, 0, i, mode) != 0) {
-			pr_err("%s insert failed\n", mode->name);
-			return 0;
-		}
-	}
+	for (i = 0; i < num_insert; i++)
+		KUNIT_ASSERT_TRUE(test, check_insert(test, mm, &nodes[i], size, 0, i, mode));
 
 	return ktime_to_ns(ktime_sub(ktime_get(), start));
 }
 
-static int igt_frag(void *ignored)
-{
-	struct drm_mm mm;
+struct frag_test {
 	const struct insert_mode *mode;
-	struct drm_mm_node *nodes, *node, *next;
+};
+
+static const struct frag_test param_to_frag_test(const unsigned long param)
+{
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+
+	return (const struct frag_test) { .mode = &insert_modes[mode] };
+}
+
+static void test_frag(struct kunit *test)
+{
+	const struct frag_test t = param_to_frag_test((unsigned long)test->param_value);
+	const struct insert_mode *mode = t.mode;
 	unsigned int insert_size = 10000;
 	unsigned int scale_factor = 4;
-	int ret = -EINVAL;
+	struct drm_mm_node *nodes;
+	struct drm_mm *mm;
+	u64 insert_time1, insert_time2;
 
 	/* We need 4 * insert_size nodes to hold intermediate allocated
 	 * drm_mm nodes.
-	 * 1 times for prepare_igt_frag()
+	 * 1 times for prepare_test_frag()
 	 * 1 times for get_insert_time()
 	 * 2 times for get_insert_time()
 	 */
-	nodes = vzalloc(array_size(insert_size * 4, sizeof(*nodes)));
-	if (!nodes)
-		return -ENOMEM;
+	nodes = kunit_vzalloc(test, array_size(insert_size * 4, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
 	/* For BOTTOMUP and TOPDOWN, we first fragment the
-	 * address space using prepare_igt_frag() and then try to verify
+	 * address space using prepare_test_frag() and then try to verify
 	 * that that insertions scale quadratically from 10k to 20k insertions
 	 */
-	drm_mm_init(&mm, 1, U64_MAX - 2);
-	for (mode = insert_modes; mode->name; mode++) {
-		u64 insert_time1, insert_time2;
-
-		if (mode->mode != DRM_MM_INSERT_LOW &&
-		    mode->mode != DRM_MM_INSERT_HIGH)
-			continue;
-
-		ret = prepare_igt_frag(&mm, nodes, insert_size, mode);
-		if (ret)
-			goto err;
-
-		insert_time1 = get_insert_time(&mm, insert_size,
-					       nodes + insert_size, mode);
-		if (insert_time1 == 0)
-			goto err;
-
-		insert_time2 = get_insert_time(&mm, (insert_size * 2),
-					       nodes + insert_size * 2, mode);
-		if (insert_time2 == 0)
-			goto err;
-
-		pr_info("%s fragmented insert of %u and %u insertions took %llu and %llu nsecs\n",
-			mode->name, insert_size, insert_size * 2,
-			insert_time1, insert_time2);
-
-		if (insert_time2 > (scale_factor * insert_time1)) {
-			pr_err("%s fragmented insert took %llu nsecs more\n",
-			       mode->name,
-			       insert_time2 - (scale_factor * insert_time1));
-			goto err;
-		}
+	mm = kunit_drm_mm(test, 1, U64_MAX - 2);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-	}
+	prepare_test_frag(test, mm, nodes, insert_size, mode);
 
-	ret = 0;
-err:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	vfree(nodes);
+	insert_time1 = get_insert_time(test, mm, insert_size,
+				       nodes + insert_size, mode);
+	KUNIT_EXPECT_NE(test, insert_time1, 0);
+
+	insert_time2 = get_insert_time(test, mm, (insert_size * 2),
+				       nodes + insert_size * 2, mode);
+	KUNIT_EXPECT_NE(test, insert_time2, 0);
 
-	return ret;
+	kunit_info(test, "fragmented insert of %u and %u insertions took %llu and %llu nsecs\n",
+		   insert_size, insert_size * 2, insert_time1, insert_time2);
+
+	KUNIT_EXPECT_LE_MSG(test, insert_time2, scale_factor * insert_time1,
+			    "fragmented insert took %llu nsecs more",
+			    insert_time2 - (scale_factor * insert_time1));
 }
 
-static int igt_align(void *ignored)
+static const void *frag_gen_params(const void *prev, char *desc)
 {
+	unsigned long param = (unsigned long)prev;
+	struct frag_test t;
+
+	param = mode_gen_param(param, ARRAY_SIZE(insert_modes));
+	while (param_valid(param)) {
+		t = param_to_frag_test(param);
+		if (t.mode->mode != DRM_MM_INSERT_LOW && t.mode->mode != DRM_MM_INSERT_HIGH)
+			param = mode_gen_param(param, ARRAY_SIZE(insert_modes));
+		else
+			break;
+	}
+
+	if (param_valid(param))
+		sprintf(desc, "%s", param_to_frag_test(param).mode->name);
+
+	return (void *)param;
+}
+
+struct align_test {
 	const struct insert_mode *mode;
+};
+
+static const struct align_test param_to_align_test(const unsigned long param)
+{
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+
+	return (const struct align_test) { .mode = &insert_modes[mode] };
+}
+
+static void test_align(struct kunit *test)
+{
+	const struct align_test t = param_to_align_test((unsigned long)test->param_value);
+	const struct insert_mode *mode = t.mode;
 	const unsigned int max_count = min(8192u, max_prime);
-	struct drm_mm mm;
-	struct drm_mm_node *nodes, *node, *next;
+	unsigned int i = 0;
+	struct drm_mm_node *nodes;
 	unsigned int prime;
-	int ret = -EINVAL;
+	struct drm_mm *mm;
 
 	/* For each of the possible insertion modes, we pick a few
 	 * arbitrary alignments and check that the inserted node
 	 * meets our requirements.
 	 */
 
-	nodes = vzalloc(array_size(max_count, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
+	nodes = kunit_vzalloc(test, array_size(max_count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-	drm_mm_init(&mm, 1, U64_MAX - 2);
+	mm = kunit_drm_mm(test, 1, U64_MAX - 2);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	for (mode = insert_modes; mode->name; mode++) {
-		unsigned int i = 0;
+	for_each_prime_number_from(prime, 1, max_count) {
+		u64 size = next_prime_number(prime);
 
-		for_each_prime_number_from(prime, 1, max_count) {
-			u64 size = next_prime_number(prime);
+		KUNIT_EXPECT_TRUE_MSG(test, check_insert(test, mm, &nodes[i], size, prime, i, mode),
+				      "insert failed with alignment=%d", prime);
 
-			if (!expect_insert(&mm, &nodes[i],
-					   size, prime, i,
-					   mode)) {
-				pr_err("%s insert failed with alignment=%d",
-				       mode->name, prime);
-				goto out;
-			}
+		i++;
+	}
+}
 
-			i++;
-		}
+static const void *align_gen_params(const void *prev, char *desc)
+{
+	unsigned long param = (unsigned long)prev;
 
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
+	param = mode_gen_param(param, ARRAY_SIZE(insert_modes));
 
-		cond_resched();
-	}
+	if (param_valid(param))
+		sprintf(desc, "%s", param_to_align_test(param).mode->name);
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	vfree(nodes);
-err:
-	return ret;
+	return (void *)param;
 }
 
-static int igt_align_pot(int max)
+struct align_pot_test {
+	const unsigned int max;
+};
+
+static const struct align_pot_test align_pot_tests[] = {
+	{ .max = 32 },
+	{ .max = 64 },
+};
+
+static void test_align_pot(struct kunit *test)
 {
-	struct drm_mm mm;
-	struct drm_mm_node *node, *next;
+	const struct align_pot_test *t = test->param_value;
+	unsigned int max = t->max;
+	struct drm_mm *mm;
+	struct drm_mm_node *nodes;
 	int bit;
-	int ret = -EINVAL;
 
 	/* Check that we can align to the full u64 address space */
 
-	drm_mm_init(&mm, 1, U64_MAX - 2);
+	nodes = kunit_kzalloc(test, array_size(max, sizeof(*nodes)), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
+
+	mm = kunit_drm_mm(test, 1, U64_MAX - 2);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
 	for (bit = max - 1; bit; bit--) {
 		u64 align, size;
 
-		node = kzalloc(sizeof(*node), GFP_KERNEL);
-		if (!node) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
 		align = BIT_ULL(bit);
 		size = BIT_ULL(bit-1) + 1;
-		if (!expect_insert(&mm, node,
-				   size, align, bit,
-				   &insert_modes[0])) {
-			pr_err("insert failed with alignment=%llx [%d]",
-			       align, bit);
-			goto out;
-		}
-
-		cond_resched();
-	}
-
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm) {
-		drm_mm_remove_node(node);
-		kfree(node);
+		KUNIT_EXPECT_TRUE_MSG(test,
+				      check_insert(test, mm, &nodes[bit],
+						   size, align, bit, &insert_modes[0]),
+				      "insert failed with alignment=%#llx [%d]", align, bit);
 	}
-	drm_mm_takedown(&mm);
-	return ret;
 }
 
-static int igt_align32(void *ignored)
+static void align_pot_desc(const struct align_pot_test *t, char *desc)
 {
-	return igt_align_pot(32);
+	sprintf(desc, "%d", t->max);
 }
 
-static int igt_align64(void *ignored)
-{
-	return igt_align_pot(64);
-}
+KUNIT_ARRAY_PARAM(align_pot, align_pot_tests, align_pot_desc);
 
-static void show_scan(const struct drm_mm_scan *scan)
+static void show_scan(struct kunit *test, const struct drm_mm_scan *scan)
 {
-	pr_info("scan: hit [%llx, %llx], size=%lld, align=%lld, color=%ld\n",
-		scan->hit_start, scan->hit_end,
-		scan->size, scan->alignment, scan->color);
+	kunit_info(test, "scan: hit [%#llx, %#llx], size=%lld, align=%lld, color=%ld\n",
+		   scan->hit_start, scan->hit_end,
+		   scan->size, scan->alignment, scan->color);
 }
 
-static void show_holes(const struct drm_mm *mm, int count)
+static void show_holes(struct kunit *test, const struct drm_mm *mm, int count)
 {
 	u64 hole_start, hole_end;
 	struct drm_mm_node *hole;
@@ -1275,15 +1447,15 @@ static void show_holes(const struct drm_mm *mm, int count)
 
 		if (drm_mm_node_allocated(hole))
 			node1 = kasprintf(GFP_KERNEL,
-					  "[%llx + %lld, color=%ld], ",
+					  "[%#llx + %lld, color=%ld], ",
 					  hole->start, hole->size, hole->color);
 
 		if (drm_mm_node_allocated(next))
 			node2 = kasprintf(GFP_KERNEL,
-					  ", [%llx + %lld, color=%ld]",
+					  ", [%#llx + %lld, color=%ld]",
 					  next->start, next->size, next->color);
 
-		pr_info("%sHole [%llx - %llx, size %lld]%s\n",
+		pr_info("%sHole [%#llx - %#llx, size %lld]%s\n",
 			node1,
 			hole_start, hole_end, hole_end - hole_start,
 			node2);
@@ -1296,897 +1468,749 @@ static void show_holes(const struct drm_mm *mm, int count)
 	}
 }
 
-struct evict_node {
-	struct drm_mm_node node;
-	struct list_head link;
-};
+static unsigned int node_index(const struct drm_mm_node *node)
+{
+	return div64_u64(node->start, node->size);
+}
 
-static bool evict_nodes(struct drm_mm_scan *scan,
-			struct evict_node *nodes,
-			unsigned int *order,
-			unsigned int count,
-			bool use_color,
-			struct list_head *evict_list)
+static void test_topdown(struct kunit *test)
 {
-	struct evict_node *e, *en;
-	unsigned int i;
+	const unsigned long size = (unsigned long)test->param_value;
+	const struct insert_mode *topdown = &insert_modes[TOPDOWN];
+	const unsigned int count = 8192;
+	unsigned long *bitmap;
+	struct drm_mm *mm;
+	struct drm_mm_node *nodes, *node;
+	unsigned int *order, n, m, o = 0;
 
-	for (i = 0; i < count; i++) {
-		e = &nodes[order ? order[i] : i];
-		list_add(&e->link, evict_list);
-		if (drm_mm_scan_add_block(scan, &e->node))
-			break;
-	}
-	list_for_each_entry_safe(e, en, evict_list, link) {
-		if (!drm_mm_scan_remove_block(scan, &e->node))
-			list_del(&e->link);
-	}
-	if (list_empty(evict_list)) {
-		pr_err("Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n",
-		       scan->size, count, scan->alignment, scan->color);
-		return false;
-	}
+	DRM_RND_STATE(prng, random_seed);
 
-	list_for_each_entry(e, evict_list, link)
-		drm_mm_remove_node(&e->node);
+	/* When allocating top-down, we expect to be returned a node
+	 * from a suitable hole at the top of the drm_mm. We check that
+	 * the returned node does match the highest available slot.
+	 */
 
-	if (use_color) {
-		struct drm_mm_node *node;
+	nodes = kunit_vzalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-		while ((node = drm_mm_scan_color_evict(scan))) {
-			e = container_of(node, typeof(*e), node);
-			drm_mm_remove_node(&e->node);
-			list_add(&e->link, evict_list);
-		}
-	} else {
-		if (drm_mm_scan_color_evict(scan)) {
-			pr_err("drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n");
-			return false;
-		}
-	}
+	bitmap = kunit_bitmap_zalloc(test, count, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bitmap);
 
-	return true;
-}
+	order = kunit_drm_random_order(test, count, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
 
-static bool evict_nothing(struct drm_mm *mm,
-			  unsigned int total_size,
-			  struct evict_node *nodes)
-{
-	struct drm_mm_scan scan;
-	LIST_HEAD(evict_list);
-	struct evict_node *e;
-	struct drm_mm_node *node;
-	unsigned int n;
+	mm = kunit_drm_mm(test, 0, size * count);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	drm_mm_scan_init(&scan, mm, 1, 0, 0, 0);
-	for (n = 0; n < total_size; n++) {
-		e = &nodes[n];
-		list_add(&e->link, &evict_list);
-		drm_mm_scan_add_block(&scan, &e->node);
+	for (n = 0; n < count; n++) {
+		KUNIT_ASSERT_TRUE_MSG(test, check_insert(test, mm, &nodes[n], size, 0, n, topdown),
+				      "insert failed, size %u step %d", size, n);
+
+		KUNIT_EXPECT_FALSE_MSG(test, drm_mm_hole_follows(&nodes[n]),
+				       "hole after topdown insert %d, start=%#llx, size=%u",
+				       n, nodes[n].start, size);
+		KUNIT_EXPECT_TRUE(test, has_one_hole(test, mm, 0, size * (count - n - 1)));
 	}
-	list_for_each_entry(e, &evict_list, link)
-		drm_mm_scan_remove_block(&scan, &e->node);
 
-	for (n = 0; n < total_size; n++) {
-		e = &nodes[n];
+	KUNIT_EXPECT_TRUE(test,	is_continuous(test, mm, size));
 
-		if (!drm_mm_node_allocated(&e->node)) {
-			pr_err("node[%d] no longer allocated!\n", n);
-			return false;
+	drm_random_reorder(order, count, &prng);
+
+	for_each_prime_number_from(n, 1, min(count, max_prime)) {
+		for (m = 0; m < n; m++) {
+			node = &nodes[order[(o + m) % count]];
+			drm_mm_remove_node(node);
+			__set_bit(node_index(node), bitmap);
 		}
 
-		e->link.next = NULL;
-	}
+		for (m = 0; m < n; m++) {
+			unsigned int last;
 
-	drm_mm_for_each_node(node, mm) {
-		e = container_of(node, typeof(*e), node);
-		e->link.next = &e->link;
-	}
+			node = &nodes[order[(o + m) % count]];
+			KUNIT_ASSERT_TRUE_MSG(test,
+					      check_insert(test, mm, node, size, 0, 0, topdown),
+					      "insert failed, step %d/%d", m, n);
 
-	for (n = 0; n < total_size; n++) {
-		e = &nodes[n];
+			KUNIT_EXPECT_FALSE_MSG(test, drm_mm_hole_follows(node),
+					       "hole after topdown insert %d/%d, start=%#llx",
+					       m, n, node->start);
 
-		if (!e->link.next) {
-			pr_err("node[%d] no longer connected!\n", n);
-			return false;
+			last = find_last_bit(bitmap, count);
+			KUNIT_EXPECT_EQ_MSG(test, node_index(node), last,
+					    "node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d",
+					    m, n, size, last, node_index(node));
+			__clear_bit(last, bitmap);
 		}
-	}
 
-	return assert_continuous(mm, nodes[0].node.size);
+		KUNIT_ASSERT_EQ(test, find_first_bit(bitmap, count), count);
+
+		o += n;
+	}
 }
 
-static bool evict_everything(struct drm_mm *mm,
-			     unsigned int total_size,
-			     struct evict_node *nodes)
+static void test_bottomup(struct kunit *test)
 {
-	struct drm_mm_scan scan;
-	LIST_HEAD(evict_list);
-	struct evict_node *e;
-	unsigned int n;
-	int err;
+	const unsigned long size = (unsigned long)test->param_value;
+	const struct insert_mode *bottomup = &insert_modes[BOTTOMUP];
+	const unsigned int count = 8192;
+	unsigned long *bitmap;
+	struct drm_mm *mm;
+	struct drm_mm_node *nodes, *node;
+	unsigned int *order, n, m, o = 0;
 
-	drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0);
-	for (n = 0; n < total_size; n++) {
-		e = &nodes[n];
-		list_add(&e->link, &evict_list);
-		if (drm_mm_scan_add_block(&scan, &e->node))
-			break;
+	DRM_RND_STATE(prng, random_seed);
+
+	/* Like test_topdown, but instead of searching for the last hole,
+	 * we search for the first.
+	 */
+
+	nodes = kunit_vzalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
+
+	bitmap = kunit_bitmap_zalloc(test, count, GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bitmap);
+
+	order = kunit_drm_random_order(test, count, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
+
+	mm = kunit_drm_mm(test, 0, size * count);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
+
+	for (n = 0; n < count; n++) {
+		KUNIT_ASSERT_TRUE_MSG(test, check_insert(test, mm, &nodes[n], size, 0, n, bottomup),
+				      "bottomup insert failed, size %u step %d", size, n);
+
+		KUNIT_EXPECT_TRUE(test, has_one_hole(test, mm, size * (n + 1), size * count));
 	}
 
-	err = 0;
-	list_for_each_entry(e, &evict_list, link) {
-		if (!drm_mm_scan_remove_block(&scan, &e->node)) {
-			if (!err) {
-				pr_err("Node %lld not marked for eviction!\n",
-				       e->node.start);
-				err = -EINVAL;
-			}
+	KUNIT_EXPECT_TRUE(test,	is_continuous(test, mm, size));
+
+	drm_random_reorder(order, count, &prng);
+	for_each_prime_number_from(n, 1, min(count, max_prime)) {
+		for (m = 0; m < n; m++) {
+			node = &nodes[order[(o + m) % count]];
+			drm_mm_remove_node(node);
+			__set_bit(node_index(node), bitmap);
 		}
-	}
-	if (err)
-		return false;
 
-	list_for_each_entry(e, &evict_list, link)
-		drm_mm_remove_node(&e->node);
+		for (m = 0; m < n; m++) {
+			unsigned int first;
 
-	if (!assert_one_hole(mm, 0, total_size))
-		return false;
+			node = &nodes[order[(o + m) % count]];
+			KUNIT_ASSERT_TRUE_MSG(test,
+					      check_insert(test, mm, node, size, 0, 0, bottomup),
+					      "insert failed, step %d/%d", m, n);
 
-	list_for_each_entry(e, &evict_list, link) {
-		err = drm_mm_reserve_node(mm, &e->node);
-		if (err) {
-			pr_err("Failed to reinsert node after eviction: start=%llx\n",
-			       e->node.start);
-			return false;
+			first = find_first_bit(bitmap, count);
+			KUNIT_EXPECT_EQ_MSG(test, node_index(node), first,
+					    "node %d/%d not inserted into bottom hole, expected %d, found %d",
+					    m, n, first, node_index(node));
+			__clear_bit(first, bitmap);
 		}
+
+		KUNIT_ASSERT_EQ(test, find_first_bit(bitmap, count), count);
+
+		o += n;
 	}
+}
+
+static const void *topdown_bottomup_gen_params(const void *prev, char *desc)
+{
+	unsigned long param = (unsigned long)prev;
+
+	if (param == 0)
+		param = 1;
+	else if (param <= 64)
+		param <<= 1;
+	else
+		param = 0;
+
+	sprintf(desc, "size = %ld", param);
 
-	return assert_continuous(mm, nodes[0].node.size);
+	return (void *)param;
 }
 
-static int evict_something(struct drm_mm *mm,
-			   u64 range_start, u64 range_end,
-			   struct evict_node *nodes,
-			   unsigned int *order,
-			   unsigned int count,
-			   unsigned int size,
-			   unsigned int alignment,
-			   const struct insert_mode *mode)
+static void __once(struct kunit *test, unsigned int mode)
 {
-	struct drm_mm_scan scan;
-	LIST_HEAD(evict_list);
-	struct evict_node *e;
-	struct drm_mm_node tmp;
+	struct drm_mm *mm;
+	struct drm_mm_node *nodes, *rsvd_lo, *rsvd_hi, *node;
 	int err;
 
-	drm_mm_scan_init_with_range(&scan, mm,
-				    size, alignment, 0,
-				    range_start, range_end,
-				    mode->mode);
-	if (!evict_nodes(&scan,
-			 nodes, order, count, false,
-			 &evict_list))
-		return -EINVAL;
+	nodes = kunit_kzalloc(test, array_size(3, sizeof(*nodes)), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-	memset(&tmp, 0, sizeof(tmp));
-	err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0,
-					 DRM_MM_INSERT_EVICT);
-	if (err) {
-		pr_err("Failed to insert into eviction hole: size=%d, align=%d\n",
-		       size, alignment);
-		show_scan(&scan);
-		show_holes(mm, 3);
-		return err;
-	}
+	mm = kunit_drm_mm(test, 0, 7);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
-		pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
-		       tmp.start, tmp.size, range_start, range_end);
-		err = -EINVAL;
-	}
+	rsvd_lo = &nodes[0];
+	rsvd_hi = &nodes[1];
+	node = &nodes[2];
 
-	if (!assert_node(&tmp, mm, size, alignment, 0) ||
-	    drm_mm_hole_follows(&tmp)) {
-		pr_err("Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx, hole-follows?=%d\n",
-		       tmp.size, size,
-		       alignment, misalignment(&tmp, alignment),
-		       tmp.start, drm_mm_hole_follows(&tmp));
-		err = -EINVAL;
-	}
+	rsvd_lo->start = 1;
+	rsvd_lo->size = 1;
+	err = drm_mm_reserve_node(mm, rsvd_lo);
+	KUNIT_ASSERT_EQ_MSG(test, err, 0, "Could not reserve low node");
 
-	drm_mm_remove_node(&tmp);
-	if (err)
-		return err;
+	rsvd_hi->start = 5;
+	rsvd_hi->size = 1;
+	err = drm_mm_reserve_node(mm, rsvd_hi);
+	KUNIT_ASSERT_EQ_MSG(test, err, 0, "Could not reserve high node");
 
-	list_for_each_entry(e, &evict_list, link) {
-		err = drm_mm_reserve_node(mm, &e->node);
-		if (err) {
-			pr_err("Failed to reinsert node after eviction: start=%llx\n",
-			       e->node.start);
-			return err;
-		}
-	}
+	KUNIT_EXPECT_TRUE_MSG(test, drm_mm_hole_follows(rsvd_lo),
+			      "Expected a hole after low node");
+	KUNIT_EXPECT_TRUE_MSG(test, drm_mm_hole_follows(rsvd_hi),
+			      "Expected a hole after high node");
 
-	if (!assert_continuous(mm, nodes[0].node.size)) {
-		pr_err("range is no longer continuous\n");
-		return -EINVAL;
-	}
-
-	return 0;
+	err = drm_mm_insert_node_generic(mm, node, 2, 0, 0, mode);
+	KUNIT_ASSERT_EQ_MSG(test, err, 0, "Could not insert the node into the available hole!");
 }
 
-static int igt_evict(void *ignored)
+static void test_lowest(struct kunit *test)
 {
-	DRM_RND_STATE(prng, random_seed);
-	const unsigned int size = 8192;
-	const struct insert_mode *mode;
-	struct drm_mm mm;
-	struct evict_node *nodes;
-	struct drm_mm_node *node, *next;
-	unsigned int *order, n;
-	int ret, err;
+	__once(test, DRM_MM_INSERT_LOW);
+}
 
-	/* Here we populate a full drm_mm and then try and insert a new node
-	 * by evicting other nodes in a random order. The drm_mm_scan should
-	 * pick the first matching hole it finds from the random list. We
-	 * repeat that for different allocation strategies, alignments and
-	 * sizes to try and stress the hole finder.
-	 */
+static void test_highest(struct kunit *test)
+{
+	__once(test, DRM_MM_INSERT_HIGH);
+}
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(size, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
+static void separate_adjacent_colors(const struct drm_mm_node *node,
+				     unsigned long color,
+				     u64 *start,
+				     u64 *end)
+{
+	if (drm_mm_node_allocated(node) && node->color != color)
+		++*start;
 
-	order = drm_random_order(size, &prng);
-	if (!order)
-		goto err_nodes;
+	node = list_next_entry(node, node_list);
+	if (drm_mm_node_allocated(node) && node->color != color)
+		--*end;
+}
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, size);
-	for (n = 0; n < size; n++) {
-		err = drm_mm_insert_node(&mm, &nodes[n].node, 1);
-		if (err) {
-			pr_err("insert failed, step %d\n", n);
-			ret = err;
-			goto out;
-		}
+static bool colors_abutt(struct kunit *test, const struct drm_mm_node *node)
+{
+	if (!drm_mm_hole_follows(node) &&
+	    drm_mm_node_allocated(list_next_entry(node, node_list))) {
+		kunit_err(test, "colors abutt; %ld [%#llx + %#llx] is next to %ld [%#llx + %#llx]!\n",
+			  node->color, node->start, node->size,
+			  list_next_entry(node, node_list)->color,
+			  list_next_entry(node, node_list)->start,
+			  list_next_entry(node, node_list)->size);
+		return true;
 	}
 
-	/* First check that using the scanner doesn't break the mm */
-	if (!evict_nothing(&mm, size, nodes)) {
-		pr_err("evict_nothing() failed\n");
-		goto out;
-	}
-	if (!evict_everything(&mm, size, nodes)) {
-		pr_err("evict_everything() failed\n");
-		goto out;
-	}
-
-	for (mode = evict_modes; mode->name; mode++) {
-		for (n = 1; n <= size; n <<= 1) {
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, 0, U64_MAX,
-					      nodes, order, size,
-					      n, 1,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u) failed\n",
-				       mode->name, n);
-				ret = err;
-				goto out;
-			}
-		}
+	return false;
+}
 
-		for (n = 1; n < size; n <<= 1) {
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, 0, U64_MAX,
-					      nodes, order, size,
-					      size/2, n,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
-				       mode->name, size/2, n);
-				ret = err;
-				goto out;
-			}
-		}
+static void test_color_sanity(struct kunit *test)
+{
+	const unsigned int count = min(4096u, max_iterations);
+	struct drm_mm_node *nodes, *node, *nn;
+	struct drm_mm *mm;
+	unsigned int n;
 
-		for_each_prime_number_from(n, 1, min(size, max_prime)) {
-			unsigned int nsize = (size - n + 1) / 2;
-
-			DRM_MM_BUG_ON(!nsize);
-
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, 0, U64_MAX,
-					      nodes, order, size,
-					      nsize, n,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u, alignment=%u) failed\n",
-				       mode->name, nsize, n);
-				ret = err;
-				goto out;
-			}
-		}
+	nodes = kunit_vzalloc(test, array_size(count, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-		cond_resched();
-	}
+	mm = kunit_drm_mm(test, 0, U64_MAX);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
+	for (n = 1; n <= count; n++)
+		KUNIT_ASSERT_TRUE_MSG(test,
+				      check_insert(test, mm, &nodes[n - 1],
+						   n, 0, n, &insert_modes[0]),
+				      "insert failed, step %d", n);
+
+	drm_mm_for_each_node_safe(node, nn, mm)
+		KUNIT_EXPECT_EQ_MSG(test, node->color, node->size,
+				    "invalid color stored: expected %lld, found %ld",
+				    node->size, node->color);
 }
 
-static int igt_evict_range(void *ignored)
-{
-	DRM_RND_STATE(prng, random_seed);
-	const unsigned int size = 8192;
-	const unsigned int range_size = size / 2;
-	const unsigned int range_start = size / 4;
-	const unsigned int range_end = range_start + range_size;
+struct color_test {
 	const struct insert_mode *mode;
-	struct drm_mm mm;
-	struct evict_node *nodes;
-	struct drm_mm_node *node, *next;
-	unsigned int *order, n;
-	int ret, err;
-
-	/* Like igt_evict() but now we are limiting the search to a
-	 * small portion of the full drm_mm.
-	 */
-
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(size, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
-
-	order = drm_random_order(size, &prng);
-	if (!order)
-		goto err_nodes;
+};
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, size);
-	for (n = 0; n < size; n++) {
-		err = drm_mm_insert_node(&mm, &nodes[n].node, 1);
-		if (err) {
-			pr_err("insert failed, step %d\n", n);
-			ret = err;
-			goto out;
-		}
-	}
+static const struct color_test param_to_color_test(const unsigned long param)
+{
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
 
-	for (mode = evict_modes; mode->name; mode++) {
-		for (n = 1; n <= range_size; n <<= 1) {
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, range_start, range_end,
-					      nodes, order, size,
-					      n, 1,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u) failed with range [%u, %u]\n",
-				       mode->name, n, range_start, range_end);
-				goto out;
-			}
-		}
+	return (const struct color_test) { .mode = &evict_modes[mode] };
+}
 
-		for (n = 1; n <= range_size; n <<= 1) {
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, range_start, range_end,
-					      nodes, order, size,
-					      range_size/2, n,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
-				       mode->name, range_size/2, n, range_start, range_end);
-				goto out;
-			}
-		}
+static void test_color(struct kunit *test)
+{
+	const struct color_test t = param_to_color_test((unsigned long)test->param_value);
+	const struct insert_mode *mode = t.mode;
+	const unsigned int count = min(4096u, max_iterations);
+	struct drm_mm_node *nodes, *node, *nn;
+	struct drm_mm *mm;
+	unsigned int n;
+	u64 last;
+	int err;
 
-		for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
-			unsigned int nsize = (range_size - n + 1) / 2;
+	/* Color adjustment complicates everything. First we just check
+	 * that when we insert a node we apply any color_adjustment callback.
+	 * The callback we use should ensure that there is a gap between
+	 * any two nodes, and so after each insertion we check that those
+	 * holes are inserted and that they are preserved.
+	 */
 
-			DRM_MM_BUG_ON(!nsize);
+	nodes = kunit_vzalloc(test, array_size(count * 2, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-			drm_random_reorder(order, size, &prng);
-			err = evict_something(&mm, range_start, range_end,
-					      nodes, order, size,
-					      nsize, n,
-					      mode);
-			if (err) {
-				pr_err("%s evict_something(size=%u, alignment=%u) failed with range [%u, %u]\n",
-				       mode->name, nsize, n, range_start, range_end);
-				goto out;
-			}
-		}
+	node = kunit_kzalloc(test, sizeof(*node), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, node);
 
-		cond_resched();
-	}
+	mm = kunit_drm_mm(test, 0, U64_MAX);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
-}
+	/* Now, let's start experimenting with applying a color callback */
+	mm->color_adjust = separate_adjacent_colors;
 
-static unsigned int node_index(const struct drm_mm_node *node)
-{
-	return div64_u64(node->start, node->size);
-}
+	node->size = 1 + 2 * count;
+	node->color = node->size;
 
-static int igt_topdown(void *ignored)
-{
-	const struct insert_mode *topdown = &insert_modes[TOPDOWN];
-	DRM_RND_STATE(prng, random_seed);
-	const unsigned int count = 8192;
-	unsigned int size;
-	unsigned long *bitmap;
-	struct drm_mm mm;
-	struct drm_mm_node *nodes, *node, *next;
-	unsigned int *order, n, m, o = 0;
-	int ret;
+	err = drm_mm_reserve_node(mm, node);
+	KUNIT_EXPECT_EQ_MSG(test, err, 0, "initial reserve failed!");
 
-	/* When allocating top-down, we expect to be returned a node
-	 * from a suitable hole at the top of the drm_mm. We check that
-	 * the returned node does match the highest available slot.
-	 */
+	last = node->start + node->size;
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(count, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
-
-	bitmap = bitmap_zalloc(count, GFP_KERNEL);
-	if (!bitmap)
-		goto err_nodes;
-
-	order = drm_random_order(count, &prng);
-	if (!order)
-		goto err_bitmap;
-
-	ret = -EINVAL;
-	for (size = 1; size <= 64; size <<= 1) {
-		drm_mm_init(&mm, 0, size*count);
-		for (n = 0; n < count; n++) {
-			if (!expect_insert(&mm, &nodes[n],
-					   size, 0, n,
-					   topdown)) {
-				pr_err("insert failed, size %u step %d\n", size, n);
-				goto out;
-			}
+	for (n = 1; n <= count; n++) {
+		int rem;
 
-			if (drm_mm_hole_follows(&nodes[n])) {
-				pr_err("hole after topdown insert %d, start=%llx\n, size=%u",
-				       n, nodes[n].start, size);
-				goto out;
-			}
+		node = &nodes[n - 1];
 
-			if (!assert_one_hole(&mm, 0, size*(count - n - 1)))
-				goto out;
-		}
+		node->start = last;
+		node->size = n + count;
+		node->color = node->size;
 
-		if (!assert_continuous(&mm, size))
-			goto out;
+		err = drm_mm_reserve_node(mm, node);
+		KUNIT_ASSERT_EQ_MSG(test, err, -ENOSPC,
+				    "reserve %d did not report color overlap! err=%d", n, err);
 
-		drm_random_reorder(order, count, &prng);
-		for_each_prime_number_from(n, 1, min(count, max_prime)) {
-			for (m = 0; m < n; m++) {
-				node = &nodes[order[(o + m) % count]];
-				drm_mm_remove_node(node);
-				__set_bit(node_index(node), bitmap);
-			}
+		node->start += n + 1;
+		rem = misalignment(node, n + count);
+		node->start += n + count - rem;
 
-			for (m = 0; m < n; m++) {
-				unsigned int last;
+		err = drm_mm_reserve_node(mm, node);
+		KUNIT_ASSERT_EQ_MSG(test, err, 0, "reserve %d failed, err=%d", n, err);
 
-				node = &nodes[order[(o + m) % count]];
-				if (!expect_insert(&mm, node,
-						   size, 0, 0,
-						   topdown)) {
-					pr_err("insert failed, step %d/%d\n", m, n);
-					goto out;
-				}
+		last = node->start + node->size;
+	}
 
-				if (drm_mm_hole_follows(node)) {
-					pr_err("hole after topdown insert %d/%d, start=%llx\n",
-					       m, n, node->start);
-					goto out;
-				}
+	for (n = 1; n <= count; n++) {
+		node = &nodes[count + n - 1];
 
-				last = find_last_bit(bitmap, count);
-				if (node_index(node) != last) {
-					pr_err("node %d/%d, size %d, not inserted into upmost hole, expected %d, found %d\n",
-					       m, n, size, last, node_index(node));
-					goto out;
-				}
+		KUNIT_ASSERT_TRUE_MSG(test, check_insert(test, mm, node, n, n, n, mode),
+				      "insert failed, step %d", n);
+	}
 
-				__clear_bit(last, bitmap);
-			}
+	drm_mm_for_each_node_safe(node, nn, mm) {
+		u64 rem;
 
-			DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count);
+		KUNIT_EXPECT_EQ_MSG(test, node->color, node->size,
+				    "invalid color stored: expected %lld, found %ld",
+				    node->size, node->color);
 
-			o += n;
-		}
+		KUNIT_EXPECT_FALSE(test, colors_abutt(test, node));
 
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
-		cond_resched();
+		div64_u64_rem(node->start, node->size, &rem);
+		KUNIT_EXPECT_EQ_MSG(test, rem, 0,
+				    "colored node misaligned, start=%#llx expected alignment=%lld [rem=%lld]",
+				    node->start, node->size, rem);
 	}
-
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_bitmap:
-	bitmap_free(bitmap);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
 }
 
-static int igt_bottomup(void *ignored)
+static const void *color_gen_params(const void *prev, char *desc)
 {
-	const struct insert_mode *bottomup = &insert_modes[BOTTOMUP];
-	DRM_RND_STATE(prng, random_seed);
-	const unsigned int count = 8192;
-	unsigned int size;
-	unsigned long *bitmap;
-	struct drm_mm mm;
-	struct drm_mm_node *nodes, *node, *next;
-	unsigned int *order, n, m, o = 0;
-	int ret;
+	unsigned long param = (unsigned long)prev;
 
-	/* Like igt_topdown, but instead of searching for the last hole,
-	 * we search for the first.
-	 */
+	param = mode_gen_param(param, ARRAY_SIZE(evict_modes));
+	if (param_valid(param))
+		sprintf(desc, "%s", param_to_color_test(param).mode->name);
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(count, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
-
-	bitmap = bitmap_zalloc(count, GFP_KERNEL);
-	if (!bitmap)
-		goto err_nodes;
-
-	order = drm_random_order(count, &prng);
-	if (!order)
-		goto err_bitmap;
-
-	ret = -EINVAL;
-	for (size = 1; size <= 64; size <<= 1) {
-		drm_mm_init(&mm, 0, size*count);
-		for (n = 0; n < count; n++) {
-			if (!expect_insert(&mm, &nodes[n],
-					   size, 0, n,
-					   bottomup)) {
-				pr_err("bottomup insert failed, size %u step %d\n", size, n);
-				goto out;
-			}
+	return (void *)param;
+}
 
-			if (!assert_one_hole(&mm, size*(n + 1), size*count))
-				goto out;
-		}
+struct evict_node {
+	struct drm_mm_node node;
+	struct list_head link;
+};
 
-		if (!assert_continuous(&mm, size))
-			goto out;
+static bool evict_nodes(struct kunit *test,
+			struct drm_mm_scan *scan,
+			struct evict_node *nodes,
+			unsigned int *order,
+			unsigned int count,
+			bool use_color,
+			struct list_head *evict_list)
+{
+	struct evict_node *e, *en;
+	unsigned int i;
 
-		drm_random_reorder(order, count, &prng);
-		for_each_prime_number_from(n, 1, min(count, max_prime)) {
-			for (m = 0; m < n; m++) {
-				node = &nodes[order[(o + m) % count]];
-				drm_mm_remove_node(node);
-				__set_bit(node_index(node), bitmap);
-			}
+	for (i = 0; i < count; i++) {
+		e = &nodes[order ? order[i] : i];
+		list_add(&e->link, evict_list);
+		if (drm_mm_scan_add_block(scan, &e->node))
+			break;
+	}
+	list_for_each_entry_safe(e, en, evict_list, link) {
+		if (!drm_mm_scan_remove_block(scan, &e->node))
+			list_del(&e->link);
+	}
+	if (list_empty(evict_list)) {
+		kunit_err(test, "Failed to find eviction: size=%lld [avail=%d], align=%lld (color=%lu)\n",
+			  scan->size, count, scan->alignment, scan->color);
+		return false;
+	}
 
-			for (m = 0; m < n; m++) {
-				unsigned int first;
-
-				node = &nodes[order[(o + m) % count]];
-				if (!expect_insert(&mm, node,
-						   size, 0, 0,
-						   bottomup)) {
-					pr_err("insert failed, step %d/%d\n", m, n);
-					goto out;
-				}
-
-				first = find_first_bit(bitmap, count);
-				if (node_index(node) != first) {
-					pr_err("node %d/%d not inserted into bottom hole, expected %d, found %d\n",
-					       m, n, first, node_index(node));
-					goto out;
-				}
-				__clear_bit(first, bitmap);
-			}
+	list_for_each_entry(e, evict_list, link)
+		drm_mm_remove_node(&e->node);
 
-			DRM_MM_BUG_ON(find_first_bit(bitmap, count) != count);
+	if (use_color) {
+		struct drm_mm_node *node;
 
-			o += n;
+		while ((node = drm_mm_scan_color_evict(scan))) {
+			e = container_of(node, typeof(*e), node);
+			drm_mm_remove_node(&e->node);
+			list_add(&e->link, evict_list);
+		}
+	} else {
+		if (drm_mm_scan_color_evict(scan)) {
+			kunit_err(test, "drm_mm_scan_color_evict unexpectedly reported overlapping nodes!\n");
+			return false;
 		}
-
-		drm_mm_for_each_node_safe(node, next, &mm)
-			drm_mm_remove_node(node);
-		DRM_MM_BUG_ON(!drm_mm_clean(&mm));
-		cond_resched();
 	}
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_bitmap:
-	bitmap_free(bitmap);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
+	return true;
 }
 
-static int __igt_once(unsigned int mode)
+static bool evict_nothing(struct kunit *test,
+			  struct drm_mm *mm,
+			  unsigned int total_size,
+			  struct evict_node *nodes)
 {
-	struct drm_mm mm;
-	struct drm_mm_node rsvd_lo, rsvd_hi, node;
-	int err;
-
-	drm_mm_init(&mm, 0, 7);
+	struct drm_mm_scan scan;
+	LIST_HEAD(evict_list);
+	struct evict_node *e;
+	struct drm_mm_node *node;
+	unsigned int n;
 
-	memset(&rsvd_lo, 0, sizeof(rsvd_lo));
-	rsvd_lo.start = 1;
-	rsvd_lo.size = 1;
-	err = drm_mm_reserve_node(&mm, &rsvd_lo);
-	if (err) {
-		pr_err("Could not reserve low node\n");
-		goto err;
+	drm_mm_scan_init(&scan, mm, 1, 0, 0, 0);
+	for (n = 0; n < total_size; n++) {
+		e = &nodes[n];
+		list_add(&e->link, &evict_list);
+		drm_mm_scan_add_block(&scan, &e->node);
 	}
+	list_for_each_entry(e, &evict_list, link)
+		drm_mm_scan_remove_block(&scan, &e->node);
 
-	memset(&rsvd_hi, 0, sizeof(rsvd_hi));
-	rsvd_hi.start = 5;
-	rsvd_hi.size = 1;
-	err = drm_mm_reserve_node(&mm, &rsvd_hi);
-	if (err) {
-		pr_err("Could not reserve low node\n");
-		goto err_lo;
+	for (n = 0; n < total_size; n++) {
+		e = &nodes[n];
+
+		if (!drm_mm_node_allocated(&e->node)) {
+			kunit_err(test, "node[%d] no longer allocated!\n", n);
+			return false;
+		}
+
+		e->link.next = NULL;
 	}
 
-	if (!drm_mm_hole_follows(&rsvd_lo) || !drm_mm_hole_follows(&rsvd_hi)) {
-		pr_err("Expected a hole after lo and high nodes!\n");
-		err = -EINVAL;
-		goto err_hi;
+	drm_mm_for_each_node(node, mm) {
+		e = container_of(node, typeof(*e), node);
+		e->link.next = &e->link;
 	}
 
-	memset(&node, 0, sizeof(node));
-	err = drm_mm_insert_node_generic(&mm, &node, 2, 0, 0, mode);
-	if (err) {
-		pr_err("Could not insert the node into the available hole!\n");
-		err = -EINVAL;
-		goto err_hi;
+	for (n = 0; n < total_size; n++) {
+		e = &nodes[n];
+
+		if (!e->link.next) {
+			kunit_err(test, "node[%d] no longer connected!\n", n);
+			return false;
+		}
 	}
 
-	drm_mm_remove_node(&node);
-err_hi:
-	drm_mm_remove_node(&rsvd_hi);
-err_lo:
-	drm_mm_remove_node(&rsvd_lo);
-err:
-	drm_mm_takedown(&mm);
-	return err;
+	return is_continuous(test, mm, nodes[0].node.size);
 }
 
-static int igt_lowest(void *ignored)
+static bool evict_everything(struct kunit *test,
+			     struct drm_mm *mm,
+			     unsigned int total_size,
+			     struct evict_node *nodes)
 {
-	return __igt_once(DRM_MM_INSERT_LOW);
-}
+	struct drm_mm_scan scan;
+	LIST_HEAD(evict_list);
+	struct evict_node *e;
+	unsigned int n;
+	int err;
 
-static int igt_highest(void *ignored)
-{
-	return __igt_once(DRM_MM_INSERT_HIGH);
-}
+	drm_mm_scan_init(&scan, mm, total_size, 0, 0, 0);
+	for (n = 0; n < total_size; n++) {
+		e = &nodes[n];
+		list_add(&e->link, &evict_list);
+		if (drm_mm_scan_add_block(&scan, &e->node))
+			break;
+	}
 
-static void separate_adjacent_colors(const struct drm_mm_node *node,
-				     unsigned long color,
-				     u64 *start,
-				     u64 *end)
-{
-	if (drm_mm_node_allocated(node) && node->color != color)
-		++*start;
+	err = 0;
+	list_for_each_entry(e, &evict_list, link) {
+		if (!drm_mm_scan_remove_block(&scan, &e->node)) {
+			if (!err) {
+				kunit_err(test, "Node %lld not marked for eviction!\n",
+					  e->node.start);
+				err = -EINVAL;
+			}
+		}
+	}
+	if (err)
+		return false;
 
-	node = list_next_entry(node, node_list);
-	if (drm_mm_node_allocated(node) && node->color != color)
-		--*end;
-}
+	list_for_each_entry(e, &evict_list, link)
+		drm_mm_remove_node(&e->node);
 
-static bool colors_abutt(const struct drm_mm_node *node)
-{
-	if (!drm_mm_hole_follows(node) &&
-	    drm_mm_node_allocated(list_next_entry(node, node_list))) {
-		pr_err("colors abutt; %ld [%llx + %llx] is next to %ld [%llx + %llx]!\n",
-		       node->color, node->start, node->size,
-		       list_next_entry(node, node_list)->color,
-		       list_next_entry(node, node_list)->start,
-		       list_next_entry(node, node_list)->size);
-		return true;
+	if (!has_one_hole(test, mm, 0, total_size))
+		return false;
+
+	list_for_each_entry(e, &evict_list, link) {
+		err = drm_mm_reserve_node(mm, &e->node);
+		if (err) {
+			kunit_err(test, "Failed to reinsert node after eviction: start=%#llx\n",
+				  e->node.start);
+			return false;
+		}
 	}
 
-	return false;
+	return is_continuous(test, mm, nodes[0].node.size);
 }
 
-static int igt_color(void *ignored)
+static int evict_something(struct kunit *test,
+			   struct drm_mm *mm,
+			   u64 range_start, u64 range_end,
+			   struct evict_node *nodes,
+			   unsigned int *order,
+			   unsigned int count,
+			   unsigned int size,
+			   unsigned int alignment,
+			   const struct insert_mode *mode)
 {
-	const unsigned int count = min(4096u, max_iterations);
-	const struct insert_mode *mode;
-	struct drm_mm mm;
-	struct drm_mm_node *node, *nn;
-	unsigned int n;
-	int ret = -EINVAL, err;
+	struct drm_mm_scan scan;
+	LIST_HEAD(evict_list);
+	struct evict_node *e;
+	struct drm_mm_node tmp;
+	int err;
 
-	/* Color adjustment complicates everything. First we just check
-	 * that when we insert a node we apply any color_adjustment callback.
-	 * The callback we use should ensure that there is a gap between
-	 * any two nodes, and so after each insertion we check that those
-	 * holes are inserted and that they are preserved.
-	 */
+	drm_mm_scan_init_with_range(&scan, mm,
+				    size, alignment, 0,
+				    range_start, range_end,
+				    mode->mode);
+	if (!evict_nodes(test, &scan,
+			 nodes, order, count, false,
+			 &evict_list))
+		return -EINVAL;
 
-	drm_mm_init(&mm, 0, U64_MAX);
+	memset(&tmp, 0, sizeof(tmp));
+	err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, 0,
+					 DRM_MM_INSERT_EVICT);
+	if (err) {
+		kunit_err(test, "Failed to insert into eviction hole: size=%d, align=%d\n",
+			  size, alignment);
+		show_scan(test, &scan);
+		show_holes(test, mm, 3);
+		return err;
+	}
 
-	for (n = 1; n <= count; n++) {
-		node = kzalloc(sizeof(*node), GFP_KERNEL);
-		if (!node) {
-			ret = -ENOMEM;
-			goto out;
-		}
+	if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
+		kunit_err(test, "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
+			  tmp.start, tmp.size, range_start, range_end);
+		err = -EINVAL;
+	}
 
-		if (!expect_insert(&mm, node,
-				   n, 0, n,
-				   &insert_modes[0])) {
-			pr_err("insert failed, step %d\n", n);
-			kfree(node);
-			goto out;
-		}
+	if (!check_node(test, &tmp, mm, size, alignment, 0) ||
+	    drm_mm_hole_follows(&tmp)) {
+		kunit_err(test, "Inserted did not fill the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%#llx, hole-follows?=%d\n",
+			  tmp.size, size,
+			  alignment, misalignment(&tmp, alignment),
+			  tmp.start, drm_mm_hole_follows(&tmp));
+		err = -EINVAL;
 	}
 
-	drm_mm_for_each_node_safe(node, nn, &mm) {
-		if (node->color != node->size) {
-			pr_err("invalid color stored: expected %lld, found %ld\n",
-			       node->size, node->color);
+	drm_mm_remove_node(&tmp);
+	if (err)
+		return err;
 
-			goto out;
+	list_for_each_entry(e, &evict_list, link) {
+		err = drm_mm_reserve_node(mm, &e->node);
+		if (err) {
+			kunit_err(test, "Failed to reinsert node after eviction: start=%#llx\n",
+				  e->node.start);
+			return err;
 		}
-
-		drm_mm_remove_node(node);
-		kfree(node);
 	}
 
-	/* Now, let's start experimenting with applying a color callback */
-	mm.color_adjust = separate_adjacent_colors;
-	for (mode = insert_modes; mode->name; mode++) {
-		u64 last;
-
-		node = kzalloc(sizeof(*node), GFP_KERNEL);
-		if (!node) {
-			ret = -ENOMEM;
-			goto out;
-		}
-
-		node->size = 1 + 2*count;
-		node->color = node->size;
+	if (!is_continuous(test, mm, nodes[0].node.size)) {
+		kunit_err(test, "range is no longer continuous\n");
+		return -EINVAL;
+	}
 
-		err = drm_mm_reserve_node(&mm, node);
-		if (err) {
-			pr_err("initial reserve failed!\n");
-			ret = err;
-			goto out;
-		}
+	return 0;
+}
 
-		last = node->start + node->size;
+static void test_evict_sanity(struct kunit *test)
+{
+	const unsigned int size = 8192;
+	struct drm_mm *mm;
+	struct evict_node *nodes;
+	unsigned int n;
+	int err;
 
-		for (n = 1; n <= count; n++) {
-			int rem;
+	nodes = kunit_vzalloc(test, array_size(size, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-			node = kzalloc(sizeof(*node), GFP_KERNEL);
-			if (!node) {
-				ret = -ENOMEM;
-				goto out;
-			}
+	mm = kunit_drm_mm(test, 0, size);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-			node->start = last;
-			node->size = n + count;
-			node->color = node->size;
+	for (n = 0; n < size; n++) {
+		err = drm_mm_insert_node(mm, &nodes[n].node, 1);
+		KUNIT_ASSERT_EQ_MSG(test, err, 0, "insert failed, step %d", n);
+	}
 
-			err = drm_mm_reserve_node(&mm, node);
-			if (err != -ENOSPC) {
-				pr_err("reserve %d did not report color overlap! err=%d\n",
-				       n, err);
-				goto out;
-			}
+	/* Check that using the scanner doesn't break the mm */
+	KUNIT_EXPECT_TRUE(test, evict_nothing(test, mm, size, nodes));
+	KUNIT_EXPECT_TRUE(test, evict_everything(test, mm, size, nodes));
+}
 
-			node->start += n + 1;
-			rem = misalignment(node, n + count);
-			node->start += n + count - rem;
+struct evict_test {
+	const u64 size;
+	const u64 range_start;
+	const u64 range_end;
+	const u64 range_size;
+	const struct insert_mode *mode;
+};
 
-			err = drm_mm_reserve_node(&mm, node);
-			if (err) {
-				pr_err("reserve %d failed, err=%d\n", n, err);
-				ret = err;
-				goto out;
-			}
+static const struct evict_test evict(const unsigned int mode)
+{
+	const u64 size = 8192;
+	const u64 range_size = size;
+	const u64 range_start = 0;
+	const u64 range_end = U64_MAX;
+
+	return (const struct evict_test) {
+		.size = size,
+		.range_start = range_start,
+		.range_end = range_end,
+		.range_size = range_size,
+		.mode = &evict_modes[mode],
+	};
+}
 
-			last = node->start + node->size;
-		}
+static const struct evict_test evict_range(const unsigned int mode)
+{
+	const u64 size = 8192;
+	const u64 range_size = size / 2;
+	const u64 range_start = size / 4;
+	const u64 range_end = range_start + range_size;
+
+	return (const struct evict_test) {
+		.size = size,
+		.range_start = range_start,
+		.range_end = range_end,
+		.range_size = range_size,
+		.mode = &evict_modes[mode],
+	};
+}
 
-		for (n = 1; n <= count; n++) {
-			node = kzalloc(sizeof(*node), GFP_KERNEL);
-			if (!node) {
-				ret = -ENOMEM;
-				goto out;
-			}
+static const struct evict_test (*evict_tests[])(const unsigned int) = {
+	evict,
+	evict_range,
+};
 
-			if (!expect_insert(&mm, node,
-					   n, n, n,
-					   mode)) {
-				pr_err("%s insert failed, step %d\n",
-				       mode->name, n);
-				kfree(node);
-				goto out;
-			}
-		}
+static const struct evict_test param_to_evict_test(const unsigned long param)
+{
+	unsigned int mode = FIELD_GET(DRM_MM_MODE_MASK, param);
+	const struct evict_test (*op)(const unsigned int) =
+		evict_tests[FIELD_GET(DRM_MM_OP_MASK, param)];
 
-		drm_mm_for_each_node_safe(node, nn, &mm) {
-			u64 rem;
+	return op(mode);
+}
 
-			if (node->color != node->size) {
-				pr_err("%s invalid color stored: expected %lld, found %ld\n",
-				       mode->name, node->size, node->color);
+static void test_evict(struct kunit *test)
+{
+	const struct evict_test t = param_to_evict_test((unsigned long)test->param_value);
+	const unsigned int size = t.size;
+	const unsigned int range_size = t.range_size;
+	const unsigned int range_start = t.range_start;
+	const unsigned int range_end = t.range_end;
+	const struct insert_mode *mode = t.mode;
+	struct drm_mm *mm;
+	struct evict_node *nodes;
+	unsigned int *order, n;
+	int err;
 
-				goto out;
-			}
+	/*
+	 * Here we populate a full drm_mm and then try and insert a new node
+	 * by evicting other nodes in a random order. The drm_mm_scan should
+	 * pick the first matching hole it finds from the random list. We
+	 * repeat that for different allocation strategies, alignments and
+	 * sizes to try and stress the hole finder.
+	 */
 
-			if (colors_abutt(node))
-				goto out;
+	DRM_RND_STATE(prng, random_seed);
 
-			div64_u64_rem(node->start, node->size, &rem);
-			if (rem) {
-				pr_err("%s colored node misaligned, start=%llx expected alignment=%lld [rem=%lld]\n",
-				       mode->name, node->start, node->size, rem);
-				goto out;
-			}
+	nodes = kunit_vzalloc(test, array_size(size, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
 
-			drm_mm_remove_node(node);
-			kfree(node);
-		}
+	order = kunit_drm_random_order(test, size, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
 
-		cond_resched();
-	}
+	mm = kunit_drm_mm(test, 0, size);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
 
-	ret = 0;
-out:
-	drm_mm_for_each_node_safe(node, nn, &mm) {
-		drm_mm_remove_node(node);
-		kfree(node);
+	for (n = 0; n < size; n++) {
+		err = drm_mm_insert_node(mm, &nodes[n].node, 1);
+		KUNIT_ASSERT_EQ_MSG(test, err, 0, "insert failed, step %d", n);
+	}
+
+	for (n = 1; n <= range_size; n <<= 1) {
+		drm_random_reorder(order, size, &prng);
+		err = evict_something(test, mm, range_start, range_end,
+				      nodes, order, size,
+				      n, 1,
+				      mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0,
+				    "evict_something(size=%u) failed with range [%u, %u]",
+				    n, range_start, range_end);
+	}
+
+	for (n = 1; n <= range_size; n <<= 1) {
+		drm_random_reorder(order, size, &prng);
+		err = evict_something(test, mm, range_start, range_end,
+				      nodes, order, size,
+				      range_size / 2, n,
+				      mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0,
+				    "evict_something(size=%u, alignment=%u) failed with range [%u, %u]",
+				    range_size / 2, n, range_start, range_end);
+	}
+
+	for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
+		unsigned int nsize = (range_size - n + 1) / 2;
+
+		KUNIT_ASSERT_GT(test, nsize, 0);
+
+		drm_random_reorder(order, size, &prng);
+		err = evict_something(test, mm, range_start, range_end,
+				      nodes, order, size,
+				      nsize, n,
+				      mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0,
+				    "evict_something(size=%u, alignment=%u) failed with range [%u, %u]",
+				    nsize, n, range_start, range_end);
 	}
-	drm_mm_takedown(&mm);
-	return ret;
 }
 
-static int evict_color(struct drm_mm *mm,
+static int evict_color(struct kunit *test, struct drm_mm *mm,
 		       u64 range_start, u64 range_end,
 		       struct evict_node *nodes,
 		       unsigned int *order,
@@ -2206,7 +2230,7 @@ static int evict_color(struct drm_mm *mm,
 				    size, alignment, color,
 				    range_start, range_end,
 				    mode->mode);
-	if (!evict_nodes(&scan,
+	if (!evict_nodes(test, &scan,
 			 nodes, order, count, true,
 			 &evict_list))
 		return -EINVAL;
@@ -2215,26 +2239,28 @@ static int evict_color(struct drm_mm *mm,
 	err = drm_mm_insert_node_generic(mm, &tmp, size, alignment, color,
 					 DRM_MM_INSERT_EVICT);
 	if (err) {
-		pr_err("Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n",
-		       size, alignment, color, err);
-		show_scan(&scan);
-		show_holes(mm, 3);
+		kunit_err(test,
+			  "Failed to insert into eviction hole: size=%d, align=%d, color=%lu, err=%d\n",
+			  size, alignment, color, err);
+		show_scan(test, &scan);
+		show_holes(test, mm, 3);
 		return err;
 	}
 
 	if (tmp.start < range_start || tmp.start + tmp.size > range_end) {
-		pr_err("Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
-		       tmp.start, tmp.size, range_start, range_end);
+		kunit_err(test,
+			  "Inserted [address=%llu + %llu] did not fit into the request range [%llu, %llu]\n",
+			  tmp.start, tmp.size, range_start, range_end);
 		err = -EINVAL;
 	}
 
-	if (colors_abutt(&tmp))
+	if (colors_abutt(test, &tmp))
 		err = -EINVAL;
 
-	if (!assert_node(&tmp, mm, size, alignment, color)) {
-		pr_err("Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%llx\n",
-		       tmp.size, size,
-		       alignment, misalignment(&tmp, alignment), tmp.start);
+	if (!check_node(test, &tmp, mm, size, alignment, color)) {
+		kunit_err(test,
+			  "Inserted did not fit the eviction hole: size=%lld [%d], align=%d [rem=%lld], start=%#llx\n",
+			  tmp.size, size, alignment, misalignment(&tmp, alignment), tmp.start);
 		err = -EINVAL;
 	}
 
@@ -2245,239 +2271,152 @@ static int evict_color(struct drm_mm *mm,
 	list_for_each_entry(e, &evict_list, link) {
 		err = drm_mm_reserve_node(mm, &e->node);
 		if (err) {
-			pr_err("Failed to reinsert node after eviction: start=%llx\n",
-			       e->node.start);
+			kunit_err(test, "Failed to reinsert node after eviction: start=%#llx\n",
+				  e->node.start);
 			return err;
 		}
 	}
 
-	cond_resched();
 	return 0;
 }
 
-static int igt_color_evict(void *ignored)
+static void test_color_evict(struct kunit *test)
 {
+	const struct evict_test t = param_to_evict_test((unsigned long)test->param_value);
+	const unsigned int size = t.size;
+	const unsigned int range_size = t.range_size;
+	const unsigned int range_start = t.range_start;
+	const unsigned int range_end = t.range_end;
+	const struct insert_mode *mode = t.mode;
 	DRM_RND_STATE(prng, random_seed);
-	const unsigned int total_size = min(8192u, max_iterations);
-	const struct insert_mode *mode;
 	unsigned long color = 0;
-	struct drm_mm mm;
+	struct drm_mm *mm;
 	struct evict_node *nodes;
-	struct drm_mm_node *node, *next;
 	unsigned int *order, n;
-	int ret, err;
+	int err;
 
-	/* Check that the drm_mm_scan also honours color adjustment when
+	/*
+	 * Check that the drm_mm_scan also honours color adjustment when
 	 * choosing its victims to create a hole. Our color_adjust does not
 	 * allow two nodes to be placed together without an intervening hole
 	 * enlarging the set of victims that must be evicted.
 	 */
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(total_size, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
-
-	order = drm_random_order(total_size, &prng);
-	if (!order)
-		goto err_nodes;
-
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, 2*total_size - 1);
-	mm.color_adjust = separate_adjacent_colors;
-	for (n = 0; n < total_size; n++) {
-		if (!expect_insert(&mm, &nodes[n].node,
-				   1, 0, color++,
-				   &insert_modes[0])) {
-			pr_err("insert failed, step %d\n", n);
-			goto out;
-		}
-	}
-
-	for (mode = evict_modes; mode->name; mode++) {
-		for (n = 1; n <= total_size; n <<= 1) {
-			drm_random_reorder(order, total_size, &prng);
-			err = evict_color(&mm, 0, U64_MAX,
-					  nodes, order, total_size,
-					  n, 1, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u) failed\n",
-				       mode->name, n);
-				goto out;
-			}
-		}
-
-		for (n = 1; n < total_size; n <<= 1) {
-			drm_random_reorder(order, total_size, &prng);
-			err = evict_color(&mm, 0, U64_MAX,
-					  nodes, order, total_size,
-					  total_size/2, n, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u, alignment=%u) failed\n",
-				       mode->name, total_size/2, n);
-				goto out;
-			}
-		}
-
-		for_each_prime_number_from(n, 1, min(total_size, max_prime)) {
-			unsigned int nsize = (total_size - n + 1) / 2;
-
-			DRM_MM_BUG_ON(!nsize);
-
-			drm_random_reorder(order, total_size, &prng);
-			err = evict_color(&mm, 0, U64_MAX,
-					  nodes, order, total_size,
-					  nsize, n, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u, alignment=%u) failed\n",
-				       mode->name, nsize, n);
-				goto out;
-			}
-		}
-
-		cond_resched();
+	nodes = kunit_vzalloc(test, array_size(size, sizeof(*nodes)));
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, nodes);
+
+	order = kunit_drm_random_order(test, size, &prng);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, order);
+
+	mm = kunit_drm_mm(test, 0, 2 * size - 1);
+	KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mm);
+
+	mm->color_adjust = separate_adjacent_colors;
+	for (n = 0; n < size; n++)
+		KUNIT_ASSERT_TRUE_MSG(test,
+				      check_insert(test, mm, &nodes[n].node, 1, 0,
+						   color++, &insert_modes[0]),
+				      "insert failed, step %d", n);
+
+	for (n = 1; n <= range_size; n <<= 1) {
+		drm_random_reorder(order, range_size, &prng);
+		err = evict_color(test, mm, range_start, range_end,
+				  nodes, order, size,
+				  n, 1, color++,
+				  mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0, "evict_color(size=%u) failed for range [%x, %x]",
+				    n, range_start, range_end);
+	}
+
+	for (n = 1; n < range_size; n <<= 1) {
+		drm_random_reorder(order, size, &prng);
+		err = evict_color(test, mm, range_start, range_end,
+				  nodes, order, size,
+				  range_size / 2, n, color++,
+				  mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0,
+				    "evict_color(size=%u, alignment=%u) failed for range [%x, %x]",
+				    size / 2, n, range_start, range_end);
+	}
+
+	for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
+		unsigned int nsize = (range_size - n + 1) / 2;
+
+		KUNIT_ASSERT_GT(test, nsize, 0);
+
+		drm_random_reorder(order, size, &prng);
+		err = evict_color(test, mm, range_start, range_end,
+				  nodes, order, size,
+				  nsize, n, color++,
+				  mode);
+		KUNIT_EXPECT_EQ_MSG(test, err, 0,
+				    "evict_color(size=%u, alignment=%u) failed for range [%x, %x]",
+				    nsize, n, range_start, range_end);
 	}
-
-	ret = 0;
-out:
-	if (ret)
-		show_mm(&mm);
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
 }
 
-static int igt_color_evict_range(void *ignored)
+static const void *evict_gen_params(const void *prev, char *desc)
 {
-	DRM_RND_STATE(prng, random_seed);
-	const unsigned int total_size = 8192;
-	const unsigned int range_size = total_size / 2;
-	const unsigned int range_start = total_size / 4;
-	const unsigned int range_end = range_start + range_size;
-	const struct insert_mode *mode;
-	unsigned long color = 0;
-	struct drm_mm mm;
-	struct evict_node *nodes;
-	struct drm_mm_node *node, *next;
-	unsigned int *order, n;
-	int ret, err;
+	unsigned long param = (unsigned long)prev;
 
-	/* Like igt_color_evict(), but limited to small portion of the full
-	 * drm_mm range.
-	 */
+	if (!prev)
+		kunit_drm_mm_print_params();
 
-	ret = -ENOMEM;
-	nodes = vzalloc(array_size(total_size, sizeof(*nodes)));
-	if (!nodes)
-		goto err;
+	param = mode_ops_gen_param(param,
+				   ARRAY_SIZE(evict_modes),
+				   ARRAY_SIZE(evict_tests));
 
-	order = drm_random_order(total_size, &prng);
-	if (!order)
-		goto err_nodes;
+	if (param_valid(param)) {
+		const struct evict_test t = param_to_evict_test(param);
 
-	ret = -EINVAL;
-	drm_mm_init(&mm, 0, 2*total_size - 1);
-	mm.color_adjust = separate_adjacent_colors;
-	for (n = 0; n < total_size; n++) {
-		if (!expect_insert(&mm, &nodes[n].node,
-				   1, 0, color++,
-				   &insert_modes[0])) {
-			pr_err("insert failed, step %d\n", n);
-			goto out;
-		}
+		sprintf(desc, "size = %llu, [%#llx, %#llx] range_size = %llu, %s",
+			t.size, t.range_start, t.range_end, t.range_size, t.mode->name);
 	}
 
-	for (mode = evict_modes; mode->name; mode++) {
-		for (n = 1; n <= range_size; n <<= 1) {
-			drm_random_reorder(order, range_size, &prng);
-			err = evict_color(&mm, range_start, range_end,
-					  nodes, order, total_size,
-					  n, 1, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u) failed for range [%x, %x]\n",
-				       mode->name, n, range_start, range_end);
-				goto out;
-			}
-		}
-
-		for (n = 1; n < range_size; n <<= 1) {
-			drm_random_reorder(order, total_size, &prng);
-			err = evict_color(&mm, range_start, range_end,
-					  nodes, order, total_size,
-					  range_size/2, n, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n",
-				       mode->name, total_size/2, n, range_start, range_end);
-				goto out;
-			}
-		}
-
-		for_each_prime_number_from(n, 1, min(range_size, max_prime)) {
-			unsigned int nsize = (range_size - n + 1) / 2;
-
-			DRM_MM_BUG_ON(!nsize);
+	return (void *)param;
+}
 
-			drm_random_reorder(order, total_size, &prng);
-			err = evict_color(&mm, range_start, range_end,
-					  nodes, order, total_size,
-					  nsize, n, color++,
-					  mode);
-			if (err) {
-				pr_err("%s evict_color(size=%u, alignment=%u) failed for range [%x, %x]\n",
-				       mode->name, nsize, n, range_start, range_end);
-				goto out;
-			}
-		}
+static struct kunit_case drm_mm_tests[] = {
+	KUNIT_CASE(test_init),
+	KUNIT_CASE(test_debug),
+	KUNIT_CASE_PARAM(test_reserve, reserve_gen_params),
+	KUNIT_CASE_PARAM(test_insert, insert_replace_gen_params),
+	KUNIT_CASE_PARAM(test_replace, insert_replace_gen_params),
+	KUNIT_CASE_PARAM(test_insert_range, insert_range_gen_params),
+	KUNIT_CASE(test_insert_outside_range),
+	KUNIT_CASE_PARAM(test_frag, frag_gen_params),
+	KUNIT_CASE_PARAM(test_align, align_gen_params),
+	KUNIT_CASE_PARAM(test_align_pot, align_pot_gen_params),
+	KUNIT_CASE_PARAM(test_topdown, topdown_bottomup_gen_params),
+	KUNIT_CASE_PARAM(test_bottomup, topdown_bottomup_gen_params),
+	KUNIT_CASE(test_lowest),
+	KUNIT_CASE(test_highest),
+	KUNIT_CASE(test_color_sanity),
+	KUNIT_CASE_PARAM(test_color, color_gen_params),
+	KUNIT_CASE(test_evict_sanity),
+	KUNIT_CASE_PARAM(test_evict, evict_gen_params),
+	KUNIT_CASE_PARAM(test_color_evict, evict_gen_params),
+	{}
+};
 
-		cond_resched();
-	}
+static struct kunit_suite drm_mm_test_suite = {
+	.name = "drm_mm_tests",
+	.test_cases = drm_mm_tests,
+};
 
-	ret = 0;
-out:
-	if (ret)
-		show_mm(&mm);
-	drm_mm_for_each_node_safe(node, next, &mm)
-		drm_mm_remove_node(node);
-	drm_mm_takedown(&mm);
-	kfree(order);
-err_nodes:
-	vfree(nodes);
-err:
-	return ret;
-}
+static struct kunit_suite *drm_mm_test_suite_array[] = { &drm_mm_test_suite, NULL };
 
-#include "drm_selftest.c"
+static struct kunit_suite **drm_mm_test_suites
+	__used __section(".kunit_test_suites") = drm_mm_test_suite_array;
 
 static int __init test_drm_mm_init(void)
 {
-	int err;
-
 	while (!random_seed)
 		random_seed = get_random_int();
 
-	pr_info("Testing DRM range manager (struct drm_mm), with random_seed=0x%x max_iterations=%u max_prime=%u\n",
-		random_seed, max_iterations, max_prime);
-	err = run_selftests(selftests, ARRAY_SIZE(selftests), NULL);
-
-	return err > 0 ? 0 : err;
-}
-
-static void __exit test_drm_mm_exit(void)
-{
+	return 0;
 }
-
 module_init(test_drm_mm_init);
-module_exit(test_drm_mm_exit);
 
 module_param(random_seed, uint, 0400);
 module_param(max_iterations, uint, 0400);
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 09/10] drm: selftests: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

Now that all tests were converted, remove the content that's no longer
used and rename the directory to "test".

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |  17 ---
 drivers/gpu/drm/Makefile                      |   2 +-
 drivers/gpu/drm/i915/Kconfig.debug            |   1 -
 drivers/gpu/drm/selftests/drm_selftest.c      | 109 ------------------
 drivers/gpu/drm/selftests/drm_selftest.h      |  41 -------
 drivers/gpu/drm/{selftests => test}/Makefile  |   0
 .../test-drm_cmdline_parser.c                 |   0
 .../test-drm_damage_helper.c                  |   0
 .../test-drm_dp_mst_helper.c                  |   0
 .../drm/{selftests => test}/test-drm_format.c |   0
 .../test-drm_framebuffer.c                    |   0
 .../gpu/drm/{selftests => test}/test-drm_mm.c |   0
 .../test-drm_plane_helper.c                   |   0
 .../drm/{selftests => test}/test-drm_rect.c   |   0
 14 files changed, 1 insertion(+), 169 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
 rename drivers/gpu/drm/{selftests => test}/Makefile (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_cmdline_parser.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_damage_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_dp_mst_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_format.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_mm.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_plane_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_rect.c (100%)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c567324c96b9..7b18540a1b8a 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -63,23 +63,6 @@ config DRM_DEBUG_MM
 
 	  If in doubt, say "N".
 
-config DRM_DEBUG_SELFTEST
-	tristate "kselftests for DRM"
-	depends on DRM
-	depends on DEBUG_KERNEL
-	select PRIME_NUMBERS
-	select DRM_LIB_RANDOM
-	select DRM_KMS_HELPER
-	select DRM_EXPORT_FOR_TESTS if m
-	default n
-	help
-	  This option provides kernel modules that can be used to run
-	  various selftests on parts of the DRM api. This option is not
-	  useful for distributions or general kernels, but only for kernel
-	  developers working on DRM and associated drivers.
-
-	  If in doubt, say "N".
-
 config DRM_KUNIT_TEST
 	bool "DRM tests" if !KUNIT_ALL_TESTS
 	depends on DRM=y && KUNIT=y
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 550800e81836..6fe8143c43e7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -65,7 +65,7 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
-obj-y += selftests/
+obj-y += test/
 
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index e7fd3e76f8a2..425189f55d37 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -38,7 +38,6 @@ config DRM_I915_DEBUG
 	select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
 	select DRM_DEBUG_MM if DRM=y
 	select DRM_EXPORT_FOR_TESTS if m
-	select DRM_DEBUG_SELFTEST
 	select DMABUF_SELFTESTS
 	select SW_SYNC # signaling validation framework (igt/syncobj*)
 	select DRM_I915_WERROR
diff --git a/drivers/gpu/drm/selftests/drm_selftest.c b/drivers/gpu/drm/selftests/drm_selftest.c
deleted file mode 100644
index e29ed9faef5b..000000000000
--- a/drivers/gpu/drm/selftests/drm_selftest.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <linux/compiler.h>
-
-#define selftest(name, func) __idx_##name,
-enum {
-#include TESTS
-};
-#undef selftest
-
-#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
-static struct drm_selftest {
-	bool enabled;
-	const char *name;
-	int (*func)(void *);
-} selftests[] = {
-#include TESTS
-};
-#undef selftest
-
-/* Embed the line number into the parameter name so that we can order tests */
-#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
-#define selftest_0(n, func, id) \
-module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
-#define selftest(n, func) selftest_0(n, func, param(n))
-#include TESTS
-#undef selftest
-
-static void set_default_test_all(struct drm_selftest *st, unsigned long count)
-{
-	unsigned long i;
-
-	for (i = 0; i < count; i++)
-		if (st[i].enabled)
-			return;
-
-	for (i = 0; i < count; i++)
-		st[i].enabled = true;
-}
-
-static int run_selftests(struct drm_selftest *st,
-			 unsigned long count,
-			 void *data)
-{
-	int err = 0;
-
-	set_default_test_all(st, count);
-
-	/* Tests are listed in natural order in drm_*_selftests.h */
-	for (; count--; st++) {
-		if (!st->enabled)
-			continue;
-
-		pr_debug("drm: Running %s\n", st->name);
-		err = st->func(data);
-		if (err)
-			break;
-	}
-
-	if (WARN(err > 0 || err == -ENOTTY,
-		 "%s returned %d, conflicting with selftest's magic values!\n",
-		 st->name, err))
-		err = -1;
-
-	rcu_barrier();
-	return err;
-}
-
-static int __maybe_unused
-__drm_subtests(const char *caller,
-	       const struct drm_subtest *st,
-	       int count,
-	       void *data)
-{
-	int err;
-
-	for (; count--; st++) {
-		pr_debug("Running %s/%s\n", caller, st->name);
-		err = st->func(data);
-		if (err) {
-			pr_err("%s: %s failed with error %d\n",
-			       caller, st->name, err);
-			return err;
-		}
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/selftests/drm_selftest.h b/drivers/gpu/drm/selftests/drm_selftest.h
deleted file mode 100644
index c784ec02ff53..000000000000
--- a/drivers/gpu/drm/selftests/drm_selftest.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __DRM_SELFTEST_H__
-#define __DRM_SELFTEST_H__
-
-struct drm_subtest {
-	int (*func)(void *data);
-	const char *name;
-};
-
-static int __drm_subtests(const char *caller,
-			  const struct drm_subtest *st,
-			  int count,
-			  void *data);
-#define drm_subtests(T, data) \
-	__drm_subtests(__func__, T, ARRAY_SIZE(T), data)
-
-#define SUBTEST(x) { x, #x }
-
-#endif /* __DRM_SELFTEST_H__ */
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/test/Makefile
similarity index 100%
rename from drivers/gpu/drm/selftests/Makefile
rename to drivers/gpu/drm/test/Makefile
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/test/test-drm_cmdline_parser.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
rename to drivers/gpu/drm/test/test-drm_cmdline_parser.c
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/test/test-drm_damage_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_damage_helper.c
rename to drivers/gpu/drm/test/test-drm_damage_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/test/test-drm_dp_mst_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
rename to drivers/gpu/drm/test/test-drm_dp_mst_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/test/test-drm_format.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_format.c
rename to drivers/gpu/drm/test/test-drm_format.c
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/test/test-drm_framebuffer.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_framebuffer.c
rename to drivers/gpu/drm/test/test-drm_framebuffer.c
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/test/test-drm_mm.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_mm.c
rename to drivers/gpu/drm/test/test-drm_mm.c
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/test/test-drm_plane_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_plane_helper.c
rename to drivers/gpu/drm/test/test-drm_plane_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/test/test-drm_rect.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_rect.c
rename to drivers/gpu/drm/test/test-drm_rect.c
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 09/10] drm: selftests: Convert to KUnit
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

Now that all tests were converted, remove the content that's no longer
used and rename the directory to "test".

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/Kconfig                       |  17 ---
 drivers/gpu/drm/Makefile                      |   2 +-
 drivers/gpu/drm/i915/Kconfig.debug            |   1 -
 drivers/gpu/drm/selftests/drm_selftest.c      | 109 ------------------
 drivers/gpu/drm/selftests/drm_selftest.h      |  41 -------
 drivers/gpu/drm/{selftests => test}/Makefile  |   0
 .../test-drm_cmdline_parser.c                 |   0
 .../test-drm_damage_helper.c                  |   0
 .../test-drm_dp_mst_helper.c                  |   0
 .../drm/{selftests => test}/test-drm_format.c |   0
 .../test-drm_framebuffer.c                    |   0
 .../gpu/drm/{selftests => test}/test-drm_mm.c |   0
 .../test-drm_plane_helper.c                   |   0
 .../drm/{selftests => test}/test-drm_rect.c   |   0
 14 files changed, 1 insertion(+), 169 deletions(-)
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
 delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
 rename drivers/gpu/drm/{selftests => test}/Makefile (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_cmdline_parser.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_damage_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_dp_mst_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_format.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_mm.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_plane_helper.c (100%)
 rename drivers/gpu/drm/{selftests => test}/test-drm_rect.c (100%)

diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c567324c96b9..7b18540a1b8a 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -63,23 +63,6 @@ config DRM_DEBUG_MM
 
 	  If in doubt, say "N".
 
-config DRM_DEBUG_SELFTEST
-	tristate "kselftests for DRM"
-	depends on DRM
-	depends on DEBUG_KERNEL
-	select PRIME_NUMBERS
-	select DRM_LIB_RANDOM
-	select DRM_KMS_HELPER
-	select DRM_EXPORT_FOR_TESTS if m
-	default n
-	help
-	  This option provides kernel modules that can be used to run
-	  various selftests on parts of the DRM api. This option is not
-	  useful for distributions or general kernels, but only for kernel
-	  developers working on DRM and associated drivers.
-
-	  If in doubt, say "N".
-
 config DRM_KUNIT_TEST
 	bool "DRM tests" if !KUNIT_ALL_TESTS
 	depends on DRM=y && KUNIT=y
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index 550800e81836..6fe8143c43e7 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -65,7 +65,7 @@ drm_kms_helper-$(CONFIG_DRM_DP_AUX_CHARDEV) += drm_dp_aux_dev.o
 drm_kms_helper-$(CONFIG_DRM_DP_CEC) += drm_dp_cec.o
 
 obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
-obj-y += selftests/
+obj-y += test/
 
 obj-$(CONFIG_DRM)	+= drm.o
 obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
diff --git a/drivers/gpu/drm/i915/Kconfig.debug b/drivers/gpu/drm/i915/Kconfig.debug
index e7fd3e76f8a2..425189f55d37 100644
--- a/drivers/gpu/drm/i915/Kconfig.debug
+++ b/drivers/gpu/drm/i915/Kconfig.debug
@@ -38,7 +38,6 @@ config DRM_I915_DEBUG
 	select DRM_VGEM # used by igt/prime_vgem (dmabuf interop checks)
 	select DRM_DEBUG_MM if DRM=y
 	select DRM_EXPORT_FOR_TESTS if m
-	select DRM_DEBUG_SELFTEST
 	select DMABUF_SELFTESTS
 	select SW_SYNC # signaling validation framework (igt/syncobj*)
 	select DRM_I915_WERROR
diff --git a/drivers/gpu/drm/selftests/drm_selftest.c b/drivers/gpu/drm/selftests/drm_selftest.c
deleted file mode 100644
index e29ed9faef5b..000000000000
--- a/drivers/gpu/drm/selftests/drm_selftest.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#include <linux/compiler.h>
-
-#define selftest(name, func) __idx_##name,
-enum {
-#include TESTS
-};
-#undef selftest
-
-#define selftest(n, f) [__idx_##n] = { .name = #n, .func = f },
-static struct drm_selftest {
-	bool enabled;
-	const char *name;
-	int (*func)(void *);
-} selftests[] = {
-#include TESTS
-};
-#undef selftest
-
-/* Embed the line number into the parameter name so that we can order tests */
-#define param(n) __PASTE(igt__, __PASTE(__PASTE(__LINE__, __), n))
-#define selftest_0(n, func, id) \
-module_param_named(id, selftests[__idx_##n].enabled, bool, 0400);
-#define selftest(n, func) selftest_0(n, func, param(n))
-#include TESTS
-#undef selftest
-
-static void set_default_test_all(struct drm_selftest *st, unsigned long count)
-{
-	unsigned long i;
-
-	for (i = 0; i < count; i++)
-		if (st[i].enabled)
-			return;
-
-	for (i = 0; i < count; i++)
-		st[i].enabled = true;
-}
-
-static int run_selftests(struct drm_selftest *st,
-			 unsigned long count,
-			 void *data)
-{
-	int err = 0;
-
-	set_default_test_all(st, count);
-
-	/* Tests are listed in natural order in drm_*_selftests.h */
-	for (; count--; st++) {
-		if (!st->enabled)
-			continue;
-
-		pr_debug("drm: Running %s\n", st->name);
-		err = st->func(data);
-		if (err)
-			break;
-	}
-
-	if (WARN(err > 0 || err == -ENOTTY,
-		 "%s returned %d, conflicting with selftest's magic values!\n",
-		 st->name, err))
-		err = -1;
-
-	rcu_barrier();
-	return err;
-}
-
-static int __maybe_unused
-__drm_subtests(const char *caller,
-	       const struct drm_subtest *st,
-	       int count,
-	       void *data)
-{
-	int err;
-
-	for (; count--; st++) {
-		pr_debug("Running %s/%s\n", caller, st->name);
-		err = st->func(data);
-		if (err) {
-			pr_err("%s: %s failed with error %d\n",
-			       caller, st->name, err);
-			return err;
-		}
-	}
-
-	return 0;
-}
diff --git a/drivers/gpu/drm/selftests/drm_selftest.h b/drivers/gpu/drm/selftests/drm_selftest.h
deleted file mode 100644
index c784ec02ff53..000000000000
--- a/drivers/gpu/drm/selftests/drm_selftest.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright © 2016 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
-
-#ifndef __DRM_SELFTEST_H__
-#define __DRM_SELFTEST_H__
-
-struct drm_subtest {
-	int (*func)(void *data);
-	const char *name;
-};
-
-static int __drm_subtests(const char *caller,
-			  const struct drm_subtest *st,
-			  int count,
-			  void *data);
-#define drm_subtests(T, data) \
-	__drm_subtests(__func__, T, ARRAY_SIZE(T), data)
-
-#define SUBTEST(x) { x, #x }
-
-#endif /* __DRM_SELFTEST_H__ */
diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/test/Makefile
similarity index 100%
rename from drivers/gpu/drm/selftests/Makefile
rename to drivers/gpu/drm/test/Makefile
diff --git a/drivers/gpu/drm/selftests/test-drm_cmdline_parser.c b/drivers/gpu/drm/test/test-drm_cmdline_parser.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
rename to drivers/gpu/drm/test/test-drm_cmdline_parser.c
diff --git a/drivers/gpu/drm/selftests/test-drm_damage_helper.c b/drivers/gpu/drm/test/test-drm_damage_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_damage_helper.c
rename to drivers/gpu/drm/test/test-drm_damage_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/test/test-drm_dp_mst_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
rename to drivers/gpu/drm/test/test-drm_dp_mst_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_format.c b/drivers/gpu/drm/test/test-drm_format.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_format.c
rename to drivers/gpu/drm/test/test-drm_format.c
diff --git a/drivers/gpu/drm/selftests/test-drm_framebuffer.c b/drivers/gpu/drm/test/test-drm_framebuffer.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_framebuffer.c
rename to drivers/gpu/drm/test/test-drm_framebuffer.c
diff --git a/drivers/gpu/drm/selftests/test-drm_mm.c b/drivers/gpu/drm/test/test-drm_mm.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_mm.c
rename to drivers/gpu/drm/test/test-drm_mm.c
diff --git a/drivers/gpu/drm/selftests/test-drm_plane_helper.c b/drivers/gpu/drm/test/test-drm_plane_helper.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_plane_helper.c
rename to drivers/gpu/drm/test/test-drm_plane_helper.c
diff --git a/drivers/gpu/drm/selftests/test-drm_rect.c b/drivers/gpu/drm/test/test-drm_rect.c
similarity index 100%
rename from drivers/gpu/drm/selftests/test-drm_rect.c
rename to drivers/gpu/drm/test/test-drm_rect.c
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 10/10] drm: test: Simplify testing on UML with kunit.py
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-17 23:22   ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Brendan Higgins, Daniel Latypov, Daniel Vetter, David Airlie,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Petri Latvala, Arkadiusz Hiler, Michał Winiarski

DRM depends on IOMEM and DMA, introduce an additional Kconfig to pull in
IOMEM and DMA emulation on UML.
Also, add .kunitconfig to simplify running DRM tests with:
./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/.kunitconfig | 3 +++
 drivers/video/Kconfig        | 4 ++++
 2 files changed, 7 insertions(+)
 create mode 100644 drivers/gpu/drm/.kunitconfig

diff --git a/drivers/gpu/drm/.kunitconfig b/drivers/gpu/drm/.kunitconfig
new file mode 100644
index 000000000000..6ec04b4c979d
--- /dev/null
+++ b/drivers/gpu/drm/.kunitconfig
@@ -0,0 +1,3 @@
+CONFIG_KUNIT=y
+CONFIG_DRM=y
+CONFIG_DRM_KUNIT_TEST=y
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 427a993c7f57..0e6028f9b09e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -46,5 +46,9 @@ if FB || SGI_NEWPORT_CONSOLE
 
 endif
 
+config DRM_UML_IO_EMULATION
+	def_bool y if UML && KUNIT
+	select UML_DMA_EMULATION
+	select UML_IOMEM_EMULATION
 
 endmenu
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [RFC 10/10] drm: test: Simplify testing on UML with kunit.py
@ 2022-01-17 23:22   ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-17 23:22 UTC (permalink / raw)
  To: dri-devel, linux-kselftest
  Cc: Michał Winiarski, Thomas Zimmermann, David Airlie,
	Brendan Higgins, Daniel Latypov, Arkadiusz Hiler, Petri Latvala

DRM depends on IOMEM and DMA, introduce an additional Kconfig to pull in
IOMEM and DMA emulation on UML.
Also, add .kunitconfig to simplify running DRM tests with:
./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm

Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
---
 drivers/gpu/drm/.kunitconfig | 3 +++
 drivers/video/Kconfig        | 4 ++++
 2 files changed, 7 insertions(+)
 create mode 100644 drivers/gpu/drm/.kunitconfig

diff --git a/drivers/gpu/drm/.kunitconfig b/drivers/gpu/drm/.kunitconfig
new file mode 100644
index 000000000000..6ec04b4c979d
--- /dev/null
+++ b/drivers/gpu/drm/.kunitconfig
@@ -0,0 +1,3 @@
+CONFIG_KUNIT=y
+CONFIG_DRM=y
+CONFIG_DRM_KUNIT_TEST=y
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
index 427a993c7f57..0e6028f9b09e 100644
--- a/drivers/video/Kconfig
+++ b/drivers/video/Kconfig
@@ -46,5 +46,9 @@ if FB || SGI_NEWPORT_CONSOLE
 
 endif
 
+config DRM_UML_IO_EMULATION
+	def_bool y if UML && KUNIT
+	select UML_DMA_EMULATION
+	select UML_IOMEM_EMULATION
 
 endmenu
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-18 23:58   ` Daniel Latypov
  -1 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-18 23:58 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

 change
On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
>
> KUnit unifies the test structure and provides helper tools that simplify
> the development. Basic use case allows running tests as regular processes,
> leveraging User Mode Linux.
> For example, to execute all DRM unit tests:
> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
>
> For developers - it means that it's easier to run unit tests on the development
> machine, tightening the feedback loop. When using UML, it also simplifies using

Nice, it's neat to see --kunitconfig being useful for having
one-liners for running tests.

> gdb for debug (since the kernel is just a regular process).

Anecdotally, I hear from davidgow@google.com that using gdb and UML
together isn't the nicest experience because of all the SIGSEGV flying
around when emulating paging.
So I'm a bit doubtful about this particular statement, but if you have
tried it out and it works well, then that's good too.

I just think the primary benefit of UML is faster compilation and it
being somewhat lighter than bringing up a VM.

> For CI systems - DRM tests can be moved from being executed on device under
> test (that's also running IGTs and so on) to being executed on buildsystem
> during build (just like checkpatch.pl).
>
> All tests were renamed - IGT prefix is no longer used.
>
> Compared to selftests executed by CI using IGT, there's one functional
> regression - KUnit test runner is not catching WARNs.
> To solve this, we could either go in the similar direction that UBSAN went in:
> 1195505 ("kunit: ubsan integration")

Is the suggestion that all WARN's fail the current KUnit test?
I don't think we can do that.

Some KUnit tests will explicitly want to trigger error paths, so we
could have a lot of false positives.

An alternative is that we can apply the 1195505 to the code paths
we're interested in, e.g.

#include <kunit/test-bug.h>
if (bad_thing()) {
  kunit_fail_current_test("bad_thing happened");
}


I don't have the context to know how cumbersome this would be for the
DRM tests though.
If the answer is we want to catch any and all warnings, then we'd
perhaps want to add something to the tests themselves. And maybe we
should implement that as a KUnit library helper function so that other
tests can use it as well.

> Or we could expand the test runner to catch WARN signature in dmesg.

Ditto from the above, I think we'd wrongly mark some tests as failed
for intentional warnings.

>
> Pastebin to preview the output and execution times:
> https://gitlab.freedesktop.org/-/snippets/4139

I see these take 17-18s to exec the tests in the example snippets.
FYI, if you're not already trying this on top of 5.16, there's recent
changes to make the parsed output more fully realtime as well.
So hopefully that should increase the usability of these tests a bit further.

I only mention that since I wasn't able to apply this series without
conflicts on top of v5.16.

>
> -Michał
>
> Michał Winiarski (10):
>   drm: test-drm_cmdline_parser: Convert to KUnit
>   drm: test-drm_plane_helper: Convert to KUnit
>   drm: test-drm_format: Convert to KUnit
>   drm: test-drm_framebuffer: Convert to KUnit
>   drm: test-drm_damage_helper: Convert to KUnit
>   drm: test-drm_dp_mst_helper: Convert to KUnit
>   drm: test-drm_rect: Convert to KUnit
>   drm: test-drm_mm: Convert to KUnit
>   drm: selftests: Convert to KUnit
>   drm: test: Simplify testing on UML with kunit.py
>
>  drivers/gpu/drm/.kunitconfig                  |    3 +
>  drivers/gpu/drm/Kconfig                       |   22 +-
>  drivers/gpu/drm/Makefile                      |    2 +-
>  drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>  drivers/gpu/drm/selftests/Makefile            |    7 -
>  .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>  drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>  drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>  drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>  .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>  .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>  .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>  drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>  drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>  .../drm/selftests/test-drm_modeset_common.c   |   32 -
>  .../drm/selftests/test-drm_modeset_common.h   |   52 -
>  .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>  drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>  drivers/gpu/drm/test/Makefile                 |    7 +
>  .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>  drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>  drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>  drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>  .../test-drm_framebuffer.c                    |  109 +-
>  drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>  drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>  drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>  drivers/video/Kconfig                         |    4 +
>  29 files changed, 5558 insertions(+), 5727 deletions(-)
>  create mode 100644 drivers/gpu/drm/.kunitconfig
>  delete mode 100644 drivers/gpu/drm/selftests/Makefile
>  delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>  create mode 100644 drivers/gpu/drm/test/Makefile
>  create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>  rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>  create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
>
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-18 23:58   ` Daniel Latypov
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-18 23:58 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

 change
On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
>
> KUnit unifies the test structure and provides helper tools that simplify
> the development. Basic use case allows running tests as regular processes,
> leveraging User Mode Linux.
> For example, to execute all DRM unit tests:
> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
>
> For developers - it means that it's easier to run unit tests on the development
> machine, tightening the feedback loop. When using UML, it also simplifies using

Nice, it's neat to see --kunitconfig being useful for having
one-liners for running tests.

> gdb for debug (since the kernel is just a regular process).

Anecdotally, I hear from davidgow@google.com that using gdb and UML
together isn't the nicest experience because of all the SIGSEGV flying
around when emulating paging.
So I'm a bit doubtful about this particular statement, but if you have
tried it out and it works well, then that's good too.

I just think the primary benefit of UML is faster compilation and it
being somewhat lighter than bringing up a VM.

> For CI systems - DRM tests can be moved from being executed on device under
> test (that's also running IGTs and so on) to being executed on buildsystem
> during build (just like checkpatch.pl).
>
> All tests were renamed - IGT prefix is no longer used.
>
> Compared to selftests executed by CI using IGT, there's one functional
> regression - KUnit test runner is not catching WARNs.
> To solve this, we could either go in the similar direction that UBSAN went in:
> 1195505 ("kunit: ubsan integration")

Is the suggestion that all WARN's fail the current KUnit test?
I don't think we can do that.

Some KUnit tests will explicitly want to trigger error paths, so we
could have a lot of false positives.

An alternative is that we can apply the 1195505 to the code paths
we're interested in, e.g.

#include <kunit/test-bug.h>
if (bad_thing()) {
  kunit_fail_current_test("bad_thing happened");
}


I don't have the context to know how cumbersome this would be for the
DRM tests though.
If the answer is we want to catch any and all warnings, then we'd
perhaps want to add something to the tests themselves. And maybe we
should implement that as a KUnit library helper function so that other
tests can use it as well.

> Or we could expand the test runner to catch WARN signature in dmesg.

Ditto from the above, I think we'd wrongly mark some tests as failed
for intentional warnings.

>
> Pastebin to preview the output and execution times:
> https://gitlab.freedesktop.org/-/snippets/4139

I see these take 17-18s to exec the tests in the example snippets.
FYI, if you're not already trying this on top of 5.16, there's recent
changes to make the parsed output more fully realtime as well.
So hopefully that should increase the usability of these tests a bit further.

I only mention that since I wasn't able to apply this series without
conflicts on top of v5.16.

>
> -Michał
>
> Michał Winiarski (10):
>   drm: test-drm_cmdline_parser: Convert to KUnit
>   drm: test-drm_plane_helper: Convert to KUnit
>   drm: test-drm_format: Convert to KUnit
>   drm: test-drm_framebuffer: Convert to KUnit
>   drm: test-drm_damage_helper: Convert to KUnit
>   drm: test-drm_dp_mst_helper: Convert to KUnit
>   drm: test-drm_rect: Convert to KUnit
>   drm: test-drm_mm: Convert to KUnit
>   drm: selftests: Convert to KUnit
>   drm: test: Simplify testing on UML with kunit.py
>
>  drivers/gpu/drm/.kunitconfig                  |    3 +
>  drivers/gpu/drm/Kconfig                       |   22 +-
>  drivers/gpu/drm/Makefile                      |    2 +-
>  drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>  drivers/gpu/drm/selftests/Makefile            |    7 -
>  .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>  drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>  drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>  drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>  .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>  .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>  .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>  drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>  drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>  .../drm/selftests/test-drm_modeset_common.c   |   32 -
>  .../drm/selftests/test-drm_modeset_common.h   |   52 -
>  .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>  drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>  drivers/gpu/drm/test/Makefile                 |    7 +
>  .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>  drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>  drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>  drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>  .../test-drm_framebuffer.c                    |  109 +-
>  drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>  drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>  drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>  drivers/video/Kconfig                         |    4 +
>  29 files changed, 5558 insertions(+), 5727 deletions(-)
>  create mode 100644 drivers/gpu/drm/.kunitconfig
>  delete mode 100644 drivers/gpu/drm/selftests/Makefile
>  delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>  create mode 100644 drivers/gpu/drm/test/Makefile
>  create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>  rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>  create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
>
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
  2022-01-17 23:22   ` Michał Winiarski
@ 2022-01-19  0:28     ` Daniel Latypov
  -1 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-19  0:28 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
>
> igt_dp_mst_calc_pbn_mode was converted one-to-one,
> igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.
>
> Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
> ---
>  drivers/gpu/drm/selftests/Makefile            |   3 +-
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
>  .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
>  .../drm/selftests/test-drm_modeset_common.h   |   2 -
>  4 files changed, 330 insertions(+), 179 deletions(-)
>
> diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
> index 35f2f40dbaf3..77e37eebf099 100644
> --- a/drivers/gpu/drm/selftests/Makefile
> +++ b/drivers/gpu/drm/selftests/Makefile
> @@ -1,7 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
>                       test-drm_modeset_common.o \
> -                     test-drm_dp_mst_helper.o \
>                       test-drm_rect.o
>
>  obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
> @@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>  obj-$(CONFIG_DRM_KUNIT_TEST) := \
>         test-drm_cmdline_parser.o test-drm_plane_helper.o \
>         test-drm_format.o test-drm_framebuffer.o \
> -       test-drm_damage_helper.o
> +       test-drm_damage_helper.o test-drm_dp_mst_helper.o
> diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> index b6a6dba66b64..630770d30aba 100644
> --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> @@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
>  selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
>  selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
>  selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
> -selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
> -selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
> diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> index 6b4759ed6bfd..d0719f3c5a42 100644
> --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> @@ -3,54 +3,97 @@
>   * Test cases for for the DRM DP MST helpers
>   */
>
> -#define PREFIX_STR "[drm_dp_mst_helper]"
> -
> +#include <kunit/test.h>
>  #include <linux/random.h>
>
>  #include <drm/drm_dp_mst_helper.h>
>  #include <drm/drm_print.h>
>
>  #include "../drm_dp_mst_topology_internal.h"
> -#include "test-drm_modeset_common.h"
>
> -int igt_dp_mst_calc_pbn_mode(void *ignored)
> +struct dp_mst_calc_pbn_mode_test {
> +       int rate;
> +       int bpp;
> +       int expected;
> +       bool dsc;
> +};
> +
> +static void dp_mst_calc_pbn_mode(struct kunit *test)
>  {
> -       int pbn, i;
> -       const struct {
> -               int rate;
> -               int bpp;
> -               int expected;
> -               bool dsc;
> -       } test_params[] = {
> -               { 154000, 30, 689, false },
> -               { 234000, 30, 1047, false },
> -               { 297000, 24, 1063, false },
> -               { 332880, 24, 50, true },
> -               { 324540, 24, 49, true },
> -       };
> +       const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
> +       int pbn;
>
> -       for (i = 0; i < ARRAY_SIZE(test_params); i++) {
> -               pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
> -                                          test_params[i].bpp,
> -                                          test_params[i].dsc);
> -               FAIL(pbn != test_params[i].expected,
> -                    "Expected PBN %d for clock %d bpp %d, got %d\n",
> -                    test_params[i].expected, test_params[i].rate,
> -                    test_params[i].bpp, pbn);
> -       }
> +       pbn = drm_dp_calc_pbn_mode(params->rate,
> +                                  params->bpp,
> +                                  params->dsc);
> +
> +       KUNIT_EXPECT_EQ(test, pbn, params->expected);
> +}
>
> -       return 0;
> +static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
> +       {
> +               .rate = 154000,
> +               .bpp = 30,
> +               .expected = 689,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 234000,
> +               .bpp = 30,
> +               .expected = 1047,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 297000,
> +               .bpp = 24,
> +               .expected = 1063,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 332880,
> +               .bpp = 24,
> +               .expected = 50,
> +               .dsc = true,
> +       },
> +       {
> +               .rate = 324540,
> +               .bpp = 24,
> +               .expected = 49,
> +               .dsc = true,
> +       },
> +};
> +
> +static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
> +                                     char *desc)
> +{
> +       sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
> +               t->rate, t->bpp, t->dsc ? "true" : "false");
>  }
>
> -static bool
> -sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
> -                      const struct drm_dp_sideband_msg_req_body *out)
> +KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
> +
> +static void
> +drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
> +{
> +       struct kunit *test = p->arg;
> +
> +       kunit_err(test, "%pV", vaf);
> +}
> +
> +static void
> +expect_sideband_msg_req_equal(struct kunit *test,
> +                             const struct drm_dp_sideband_msg_req_body *in,
> +                             const struct drm_dp_sideband_msg_req_body *out)
>  {
>         const struct drm_dp_remote_i2c_read_tx *txin, *txout;
> +       struct drm_printer p = {
> +               .printfn = drm_dp_mst_helper_printfn,
> +               .arg = test
> +       };
>         int i;
>
>         if (in->req_type != out->req_type)
> -               return false;
> +               goto fail;

Briefly skimming over this code, it looks like it'd be simpler to have
this function remain unchanged.
There's only the one caller.
It could take on the responsibility of creating the drm_printer and
redirect the printfn to kunit_err, afaik.

Passing in `test` would be useful if we were generating custom error
messages for each of the `return false` lines, which I assume was the
original motivation for doing so?
But looking at this, I'd agree it seems like too much work.

Tangent:
It might have been easier to do that if the kunit assertions returned pass/fail.
E.g. instead of having to do

if (!<long-condition>) {
  KUNIT_FAIL("<long-condition> not met");
  return;
}

if we could do

if(!KUNIT_EXPECT_TRUE(long-condition))
  return;

or if there was a new macro type

KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
from this func on failure


>
>         switch (in->req_type) {
>         /*
> @@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                     IN.num_transactions != OUT.num_transactions ||
>                     IN.port_number != OUT.port_number ||
>                     IN.read_i2c_device_id != OUT.read_i2c_device_id)
> -                       return false;
> +                       goto fail;
>
>                 for (i = 0; i < IN.num_transactions; i++) {
>                         txin = &IN.transactions[i];
> @@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                             txin->num_bytes != txout->num_bytes ||
>                             txin->i2c_transaction_delay !=
>                             txout->i2c_transaction_delay)
> -                               return false;
> +                               goto fail;
>
>                         if (memcmp(txin->bytes, txout->bytes,
>                                    txin->num_bytes) != 0)
> -                               return false;
> +                               goto fail;
>                 }
>                 break;
>  #undef IN
> @@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                 if (IN.dpcd_address != OUT.dpcd_address ||
>                     IN.num_bytes != OUT.num_bytes ||
>                     IN.port_number != OUT.port_number)
> -                       return false;
> +                       goto fail;
>
> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
> +                       goto fail;
> +
> +               break;
>  #undef IN
>  #undef OUT
>
> @@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                 if (IN.port_number != OUT.port_number ||
>                     IN.write_i2c_device_id != OUT.write_i2c_device_id ||
>                     IN.num_bytes != OUT.num_bytes)
> -                       return false;
> +                       goto fail;
>
> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
> +                       goto fail;
> +
> +               break;
>  #undef IN
>  #undef OUT
>
>         default:
> -               return memcmp(in, out, sizeof(*in)) == 0;
> +               if (memcmp(in, out, sizeof(*in)) != 0)
> +                       goto fail;
>         }
>
> -       return true;
> +       return;
> +
> +fail:
> +       drm_printf(&p, "Expected:\n");
> +       drm_dp_dump_sideband_msg_req_body(in, 1, &p);
> +       drm_printf(&p, "Got:\n");
> +       drm_dp_dump_sideband_msg_req_body(out, 1, &p);
> +       KUNIT_FAIL(test, "Encode/decode failed");
> +}
> +
> +struct dp_mst_sideband_msg_req_decode_test {
> +       const struct drm_dp_sideband_msg_req_body req;
> +       const struct drm_dp_sideband_msg_req_body
> +               (*f)(const struct drm_dp_sideband_msg_req_body *in);
> +};
> +
> +const struct drm_dp_sideband_msg_req_body
> +param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
> +{
> +       if (t->f)
> +               return t->f(&t->req);
> +
> +       return t->req;
>  }
>
> -static bool
> -sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
> +static void dp_mst_sideband_msg_req_decode(struct kunit *test)
>  {
> +       const struct drm_dp_sideband_msg_req_body in =
> +               param_to_dp_mst_sideband_msg_req_body(test->param_value);
>         struct drm_dp_sideband_msg_req_body *out;
> -       struct drm_printer p = drm_err_printer(PREFIX_STR);
>         struct drm_dp_sideband_msg_tx *txmsg;
> -       int i, ret;
> -       bool result = true;
> -
> -       out = kzalloc(sizeof(*out), GFP_KERNEL);
> -       if (!out)
> -               return false;
> -
> -       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
> -       if (!txmsg)
> -               return false;
> -
> -       drm_dp_encode_sideband_req(in, txmsg);
> -       ret = drm_dp_decode_sideband_req(txmsg, out);
> -       if (ret < 0) {
> -               drm_printf(&p, "Failed to decode sideband request: %d\n",
> -                          ret);
> -               result = false;
> -               goto out;
> -       }
> +       int i;
>
> -       if (!sideband_msg_req_equal(in, out)) {
> -               drm_printf(&p, "Encode/decode failed, expected:\n");
> -               drm_dp_dump_sideband_msg_req_body(in, 1, &p);
> -               drm_printf(&p, "Got:\n");
> -               drm_dp_dump_sideband_msg_req_body(out, 1, &p);
> -               result = false;
> -               goto out;
> -       }
> +       out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
>
> -       switch (in->req_type) {
> +       txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
> +
> +       drm_dp_encode_sideband_req(&in, txmsg);
> +       KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
> +
> +       expect_sideband_msg_req_equal(test, &in, out);
> +
> +       switch (in.req_type) {
>         case DP_REMOTE_DPCD_WRITE:
>                 kfree(out->u.dpcd_write.bytes);
>                 break;
> @@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>                 kfree(out->u.i2c_write.bytes);
>                 break;
>         }
> -
> -       /* Clear everything but the req_type for the input */
> -       memset(&in->u, 0, sizeof(in->u));
> -
> -out:
> -       kfree(out);
> -       kfree(txmsg);
> -       return result;
>  }
>
> -int igt_dp_mst_sideband_msg_req_decode(void *unused)
> +static u8 data[] = { 0xff, 0x0, 0xdd };
> +
> +const struct drm_dp_sideband_msg_req_body
> +random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
>  {
> -       struct drm_dp_sideband_msg_req_body in = { 0 };
> -       u8 data[] = { 0xff, 0x0, 0xdd };
> -       int i;
> +       struct drm_dp_query_stream_enc_status enc_status = { };
>
> -#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
> -
> -       in.req_type = DP_ENUM_PATH_RESOURCES;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_POWER_UP_PHY;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_POWER_DOWN_PHY;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_ALLOCATE_PAYLOAD;
> -       in.u.allocate_payload.number_sdp_streams = 3;
> -       for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
> -               in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
> -       DO_TEST();
> -       in.u.allocate_payload.port_number = 0xf;
> -       DO_TEST();
> -       in.u.allocate_payload.vcpi = 0x7f;
> -       DO_TEST();
> -       in.u.allocate_payload.pbn = U16_MAX;
> -       DO_TEST();
> -
> -       in.req_type = DP_QUERY_PAYLOAD;
> -       in.u.query_payload.port_number = 0xf;
> -       DO_TEST();
> -       in.u.query_payload.vcpi = 0x7f;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_DPCD_READ;
> -       in.u.dpcd_read.port_number = 0xf;
> -       DO_TEST();
> -       in.u.dpcd_read.dpcd_address = 0xfedcb;
> -       DO_TEST();
> -       in.u.dpcd_read.num_bytes = U8_MAX;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_DPCD_WRITE;
> -       in.u.dpcd_write.port_number = 0xf;
> -       DO_TEST();
> -       in.u.dpcd_write.dpcd_address = 0xfedcb;
> -       DO_TEST();
> -       in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
> -       in.u.dpcd_write.bytes = data;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_I2C_READ;
> -       in.u.i2c_read.port_number = 0xf;
> -       DO_TEST();
> -       in.u.i2c_read.read_i2c_device_id = 0x7f;
> -       DO_TEST();
> -       in.u.i2c_read.num_transactions = 3;
> -       in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
> -       for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
> -               in.u.i2c_read.transactions[i].bytes = data;
> -               in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
> -               in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
> -               in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
> -       }
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_I2C_WRITE;
> -       in.u.i2c_write.port_number = 0xf;
> -       DO_TEST();
> -       in.u.i2c_write.write_i2c_device_id = 0x7f;
> -       DO_TEST();
> -       in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
> -       in.u.i2c_write.bytes = data;
> -       DO_TEST();
> -
> -       in.req_type = DP_QUERY_STREAM_ENC_STATUS;
> -       in.u.enc_status.stream_id = 1;
> -       DO_TEST();
> -       get_random_bytes(in.u.enc_status.client_id,
> -                        sizeof(in.u.enc_status.client_id));
> -       DO_TEST();
> -       in.u.enc_status.stream_event = 3;
> -       DO_TEST();
> -       in.u.enc_status.valid_stream_event = 0;
> -       DO_TEST();
> -       in.u.enc_status.stream_behavior = 3;
> -       DO_TEST();
> -       in.u.enc_status.valid_stream_behavior = 1;
> -       DO_TEST();
> -
> -#undef DO_TEST
> -       return 0;
> +       get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
> +
> +       return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
> +                                                            .u.enc_status = enc_status
> +       };
>  }
> +
> +static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
> +       {
> +               .req = {
> +                       .req_type = DP_ENUM_PATH_RESOURCES,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_POWER_UP_PHY,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_POWER_DOWN_PHY,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.number_sdp_streams = 3,
> +                       .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.vcpi = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.pbn = U16_MAX,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_PAYLOAD,
> +                       .u.query_payload.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_PAYLOAD,
> +                       .u.query_payload.vcpi = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.dpcd_address = 0xfedcb,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.num_bytes = U8_MAX,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.dpcd_address = 0xfedcb,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
> +                       .u.dpcd_write.bytes = data,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.read_i2c_device_id = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.num_transactions = 3,
> +                       .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
> +                       .u.i2c_read.transactions = {
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
> +                       },
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.write_i2c_device_id = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.num_bytes = ARRAY_SIZE(data),
> +                       .u.i2c_write.bytes = data,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_id = 1,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +               },
> +               .f = random_dp_query_enc_client_id,
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_event = 3,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.valid_stream_event = 0,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_behavior = 3,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.valid_stream_behavior = 1,
> +               },
> +       },
> +};
> +
> +KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
> +
> +static struct kunit_case drm_dp_mst_helper_tests[] = {
> +       KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
> +       KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
> +       {}
> +};
> +
> +static struct kunit_suite drm_dp_mst_helper_test_suite = {
> +       .name = "drm_dp_mst_helper_tests",
> +       .test_cases = drm_dp_mst_helper_tests,
> +};
> +
> +kunit_test_suite(drm_dp_mst_helper_test_suite);
> diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> index 1501d99aee2f..c7cc5edc65f1 100644
> --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> @@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
>  int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
>  int igt_drm_rect_clip_scaled_clipped(void *ignored);
>  int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
> -int igt_dp_mst_calc_pbn_mode(void *ignored);
> -int igt_dp_mst_sideband_msg_req_decode(void *ignored);
>
>  #endif
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
@ 2022-01-19  0:28     ` Daniel Latypov
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-19  0:28 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
>
> igt_dp_mst_calc_pbn_mode was converted one-to-one,
> igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.
>
> Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
> ---
>  drivers/gpu/drm/selftests/Makefile            |   3 +-
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
>  .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
>  .../drm/selftests/test-drm_modeset_common.h   |   2 -
>  4 files changed, 330 insertions(+), 179 deletions(-)
>
> diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
> index 35f2f40dbaf3..77e37eebf099 100644
> --- a/drivers/gpu/drm/selftests/Makefile
> +++ b/drivers/gpu/drm/selftests/Makefile
> @@ -1,7 +1,6 @@
>  # SPDX-License-Identifier: GPL-2.0-only
>  test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
>                       test-drm_modeset_common.o \
> -                     test-drm_dp_mst_helper.o \
>                       test-drm_rect.o
>
>  obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
> @@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>  obj-$(CONFIG_DRM_KUNIT_TEST) := \
>         test-drm_cmdline_parser.o test-drm_plane_helper.o \
>         test-drm_format.o test-drm_framebuffer.o \
> -       test-drm_damage_helper.o
> +       test-drm_damage_helper.o test-drm_dp_mst_helper.o
> diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> index b6a6dba66b64..630770d30aba 100644
> --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
> @@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
>  selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
>  selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
>  selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
> -selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
> -selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
> diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> index 6b4759ed6bfd..d0719f3c5a42 100644
> --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> @@ -3,54 +3,97 @@
>   * Test cases for for the DRM DP MST helpers
>   */
>
> -#define PREFIX_STR "[drm_dp_mst_helper]"
> -
> +#include <kunit/test.h>
>  #include <linux/random.h>
>
>  #include <drm/drm_dp_mst_helper.h>
>  #include <drm/drm_print.h>
>
>  #include "../drm_dp_mst_topology_internal.h"
> -#include "test-drm_modeset_common.h"
>
> -int igt_dp_mst_calc_pbn_mode(void *ignored)
> +struct dp_mst_calc_pbn_mode_test {
> +       int rate;
> +       int bpp;
> +       int expected;
> +       bool dsc;
> +};
> +
> +static void dp_mst_calc_pbn_mode(struct kunit *test)
>  {
> -       int pbn, i;
> -       const struct {
> -               int rate;
> -               int bpp;
> -               int expected;
> -               bool dsc;
> -       } test_params[] = {
> -               { 154000, 30, 689, false },
> -               { 234000, 30, 1047, false },
> -               { 297000, 24, 1063, false },
> -               { 332880, 24, 50, true },
> -               { 324540, 24, 49, true },
> -       };
> +       const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
> +       int pbn;
>
> -       for (i = 0; i < ARRAY_SIZE(test_params); i++) {
> -               pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
> -                                          test_params[i].bpp,
> -                                          test_params[i].dsc);
> -               FAIL(pbn != test_params[i].expected,
> -                    "Expected PBN %d for clock %d bpp %d, got %d\n",
> -                    test_params[i].expected, test_params[i].rate,
> -                    test_params[i].bpp, pbn);
> -       }
> +       pbn = drm_dp_calc_pbn_mode(params->rate,
> +                                  params->bpp,
> +                                  params->dsc);
> +
> +       KUNIT_EXPECT_EQ(test, pbn, params->expected);
> +}
>
> -       return 0;
> +static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
> +       {
> +               .rate = 154000,
> +               .bpp = 30,
> +               .expected = 689,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 234000,
> +               .bpp = 30,
> +               .expected = 1047,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 297000,
> +               .bpp = 24,
> +               .expected = 1063,
> +               .dsc = false,
> +       },
> +       {
> +               .rate = 332880,
> +               .bpp = 24,
> +               .expected = 50,
> +               .dsc = true,
> +       },
> +       {
> +               .rate = 324540,
> +               .bpp = 24,
> +               .expected = 49,
> +               .dsc = true,
> +       },
> +};
> +
> +static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
> +                                     char *desc)
> +{
> +       sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
> +               t->rate, t->bpp, t->dsc ? "true" : "false");
>  }
>
> -static bool
> -sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
> -                      const struct drm_dp_sideband_msg_req_body *out)
> +KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
> +
> +static void
> +drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
> +{
> +       struct kunit *test = p->arg;
> +
> +       kunit_err(test, "%pV", vaf);
> +}
> +
> +static void
> +expect_sideband_msg_req_equal(struct kunit *test,
> +                             const struct drm_dp_sideband_msg_req_body *in,
> +                             const struct drm_dp_sideband_msg_req_body *out)
>  {
>         const struct drm_dp_remote_i2c_read_tx *txin, *txout;
> +       struct drm_printer p = {
> +               .printfn = drm_dp_mst_helper_printfn,
> +               .arg = test
> +       };
>         int i;
>
>         if (in->req_type != out->req_type)
> -               return false;
> +               goto fail;

Briefly skimming over this code, it looks like it'd be simpler to have
this function remain unchanged.
There's only the one caller.
It could take on the responsibility of creating the drm_printer and
redirect the printfn to kunit_err, afaik.

Passing in `test` would be useful if we were generating custom error
messages for each of the `return false` lines, which I assume was the
original motivation for doing so?
But looking at this, I'd agree it seems like too much work.

Tangent:
It might have been easier to do that if the kunit assertions returned pass/fail.
E.g. instead of having to do

if (!<long-condition>) {
  KUNIT_FAIL("<long-condition> not met");
  return;
}

if we could do

if(!KUNIT_EXPECT_TRUE(long-condition))
  return;

or if there was a new macro type

KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
from this func on failure


>
>         switch (in->req_type) {
>         /*
> @@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                     IN.num_transactions != OUT.num_transactions ||
>                     IN.port_number != OUT.port_number ||
>                     IN.read_i2c_device_id != OUT.read_i2c_device_id)
> -                       return false;
> +                       goto fail;
>
>                 for (i = 0; i < IN.num_transactions; i++) {
>                         txin = &IN.transactions[i];
> @@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                             txin->num_bytes != txout->num_bytes ||
>                             txin->i2c_transaction_delay !=
>                             txout->i2c_transaction_delay)
> -                               return false;
> +                               goto fail;
>
>                         if (memcmp(txin->bytes, txout->bytes,
>                                    txin->num_bytes) != 0)
> -                               return false;
> +                               goto fail;
>                 }
>                 break;
>  #undef IN
> @@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                 if (IN.dpcd_address != OUT.dpcd_address ||
>                     IN.num_bytes != OUT.num_bytes ||
>                     IN.port_number != OUT.port_number)
> -                       return false;
> +                       goto fail;
>
> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
> +                       goto fail;
> +
> +               break;
>  #undef IN
>  #undef OUT
>
> @@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>                 if (IN.port_number != OUT.port_number ||
>                     IN.write_i2c_device_id != OUT.write_i2c_device_id ||
>                     IN.num_bytes != OUT.num_bytes)
> -                       return false;
> +                       goto fail;
>
> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
> +                       goto fail;
> +
> +               break;
>  #undef IN
>  #undef OUT
>
>         default:
> -               return memcmp(in, out, sizeof(*in)) == 0;
> +               if (memcmp(in, out, sizeof(*in)) != 0)
> +                       goto fail;
>         }
>
> -       return true;
> +       return;
> +
> +fail:
> +       drm_printf(&p, "Expected:\n");
> +       drm_dp_dump_sideband_msg_req_body(in, 1, &p);
> +       drm_printf(&p, "Got:\n");
> +       drm_dp_dump_sideband_msg_req_body(out, 1, &p);
> +       KUNIT_FAIL(test, "Encode/decode failed");
> +}
> +
> +struct dp_mst_sideband_msg_req_decode_test {
> +       const struct drm_dp_sideband_msg_req_body req;
> +       const struct drm_dp_sideband_msg_req_body
> +               (*f)(const struct drm_dp_sideband_msg_req_body *in);
> +};
> +
> +const struct drm_dp_sideband_msg_req_body
> +param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
> +{
> +       if (t->f)
> +               return t->f(&t->req);
> +
> +       return t->req;
>  }
>
> -static bool
> -sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
> +static void dp_mst_sideband_msg_req_decode(struct kunit *test)
>  {
> +       const struct drm_dp_sideband_msg_req_body in =
> +               param_to_dp_mst_sideband_msg_req_body(test->param_value);
>         struct drm_dp_sideband_msg_req_body *out;
> -       struct drm_printer p = drm_err_printer(PREFIX_STR);
>         struct drm_dp_sideband_msg_tx *txmsg;
> -       int i, ret;
> -       bool result = true;
> -
> -       out = kzalloc(sizeof(*out), GFP_KERNEL);
> -       if (!out)
> -               return false;
> -
> -       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
> -       if (!txmsg)
> -               return false;
> -
> -       drm_dp_encode_sideband_req(in, txmsg);
> -       ret = drm_dp_decode_sideband_req(txmsg, out);
> -       if (ret < 0) {
> -               drm_printf(&p, "Failed to decode sideband request: %d\n",
> -                          ret);
> -               result = false;
> -               goto out;
> -       }
> +       int i;
>
> -       if (!sideband_msg_req_equal(in, out)) {
> -               drm_printf(&p, "Encode/decode failed, expected:\n");
> -               drm_dp_dump_sideband_msg_req_body(in, 1, &p);
> -               drm_printf(&p, "Got:\n");
> -               drm_dp_dump_sideband_msg_req_body(out, 1, &p);
> -               result = false;
> -               goto out;
> -       }
> +       out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
>
> -       switch (in->req_type) {
> +       txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
> +
> +       drm_dp_encode_sideband_req(&in, txmsg);
> +       KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
> +
> +       expect_sideband_msg_req_equal(test, &in, out);
> +
> +       switch (in.req_type) {
>         case DP_REMOTE_DPCD_WRITE:
>                 kfree(out->u.dpcd_write.bytes);
>                 break;
> @@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>                 kfree(out->u.i2c_write.bytes);
>                 break;
>         }
> -
> -       /* Clear everything but the req_type for the input */
> -       memset(&in->u, 0, sizeof(in->u));
> -
> -out:
> -       kfree(out);
> -       kfree(txmsg);
> -       return result;
>  }
>
> -int igt_dp_mst_sideband_msg_req_decode(void *unused)
> +static u8 data[] = { 0xff, 0x0, 0xdd };
> +
> +const struct drm_dp_sideband_msg_req_body
> +random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
>  {
> -       struct drm_dp_sideband_msg_req_body in = { 0 };
> -       u8 data[] = { 0xff, 0x0, 0xdd };
> -       int i;
> +       struct drm_dp_query_stream_enc_status enc_status = { };
>
> -#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
> -
> -       in.req_type = DP_ENUM_PATH_RESOURCES;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_POWER_UP_PHY;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_POWER_DOWN_PHY;
> -       in.u.port_num.port_number = 5;
> -       DO_TEST();
> -
> -       in.req_type = DP_ALLOCATE_PAYLOAD;
> -       in.u.allocate_payload.number_sdp_streams = 3;
> -       for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
> -               in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
> -       DO_TEST();
> -       in.u.allocate_payload.port_number = 0xf;
> -       DO_TEST();
> -       in.u.allocate_payload.vcpi = 0x7f;
> -       DO_TEST();
> -       in.u.allocate_payload.pbn = U16_MAX;
> -       DO_TEST();
> -
> -       in.req_type = DP_QUERY_PAYLOAD;
> -       in.u.query_payload.port_number = 0xf;
> -       DO_TEST();
> -       in.u.query_payload.vcpi = 0x7f;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_DPCD_READ;
> -       in.u.dpcd_read.port_number = 0xf;
> -       DO_TEST();
> -       in.u.dpcd_read.dpcd_address = 0xfedcb;
> -       DO_TEST();
> -       in.u.dpcd_read.num_bytes = U8_MAX;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_DPCD_WRITE;
> -       in.u.dpcd_write.port_number = 0xf;
> -       DO_TEST();
> -       in.u.dpcd_write.dpcd_address = 0xfedcb;
> -       DO_TEST();
> -       in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
> -       in.u.dpcd_write.bytes = data;
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_I2C_READ;
> -       in.u.i2c_read.port_number = 0xf;
> -       DO_TEST();
> -       in.u.i2c_read.read_i2c_device_id = 0x7f;
> -       DO_TEST();
> -       in.u.i2c_read.num_transactions = 3;
> -       in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
> -       for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
> -               in.u.i2c_read.transactions[i].bytes = data;
> -               in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
> -               in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
> -               in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
> -       }
> -       DO_TEST();
> -
> -       in.req_type = DP_REMOTE_I2C_WRITE;
> -       in.u.i2c_write.port_number = 0xf;
> -       DO_TEST();
> -       in.u.i2c_write.write_i2c_device_id = 0x7f;
> -       DO_TEST();
> -       in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
> -       in.u.i2c_write.bytes = data;
> -       DO_TEST();
> -
> -       in.req_type = DP_QUERY_STREAM_ENC_STATUS;
> -       in.u.enc_status.stream_id = 1;
> -       DO_TEST();
> -       get_random_bytes(in.u.enc_status.client_id,
> -                        sizeof(in.u.enc_status.client_id));
> -       DO_TEST();
> -       in.u.enc_status.stream_event = 3;
> -       DO_TEST();
> -       in.u.enc_status.valid_stream_event = 0;
> -       DO_TEST();
> -       in.u.enc_status.stream_behavior = 3;
> -       DO_TEST();
> -       in.u.enc_status.valid_stream_behavior = 1;
> -       DO_TEST();
> -
> -#undef DO_TEST
> -       return 0;
> +       get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
> +
> +       return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
> +                                                            .u.enc_status = enc_status
> +       };
>  }
> +
> +static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
> +       {
> +               .req = {
> +                       .req_type = DP_ENUM_PATH_RESOURCES,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_POWER_UP_PHY,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_POWER_DOWN_PHY,
> +                       .u.port_num.port_number = 5,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.number_sdp_streams = 3,
> +                       .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.vcpi = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_ALLOCATE_PAYLOAD,
> +                       .u.allocate_payload.pbn = U16_MAX,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_PAYLOAD,
> +                       .u.query_payload.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_PAYLOAD,
> +                       .u.query_payload.vcpi = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.dpcd_address = 0xfedcb,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_READ,
> +                       .u.dpcd_read.num_bytes = U8_MAX,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.dpcd_address = 0xfedcb,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_DPCD_WRITE,
> +                       .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
> +                       .u.dpcd_write.bytes = data,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.read_i2c_device_id = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_READ,
> +                       .u.i2c_read.num_transactions = 3,
> +                       .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
> +                       .u.i2c_read.transactions = {
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
> +                                 .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
> +                       },
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.port_number = 0xf,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.write_i2c_device_id = 0x7f,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_REMOTE_I2C_WRITE,
> +                       .u.i2c_write.num_bytes = ARRAY_SIZE(data),
> +                       .u.i2c_write.bytes = data,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_id = 1,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +               },
> +               .f = random_dp_query_enc_client_id,
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_event = 3,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.valid_stream_event = 0,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.stream_behavior = 3,
> +               },
> +       },
> +       {
> +               .req = {
> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
> +                       .u.enc_status.valid_stream_behavior = 1,
> +               },
> +       },
> +};
> +
> +KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
> +
> +static struct kunit_case drm_dp_mst_helper_tests[] = {
> +       KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
> +       KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
> +       {}
> +};
> +
> +static struct kunit_suite drm_dp_mst_helper_test_suite = {
> +       .name = "drm_dp_mst_helper_tests",
> +       .test_cases = drm_dp_mst_helper_tests,
> +};
> +
> +kunit_test_suite(drm_dp_mst_helper_test_suite);
> diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> index 1501d99aee2f..c7cc5edc65f1 100644
> --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
> @@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
>  int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
>  int igt_drm_rect_clip_scaled_clipped(void *ignored);
>  int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
> -int igt_dp_mst_calc_pbn_mode(void *ignored);
> -int igt_dp_mst_sideband_msg_req_decode(void *ignored);
>
>  #endif
> --
> 2.34.1
>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
  2022-01-17 23:22 ` Michał Winiarski
@ 2022-01-19 16:11   ` Daniel Vetter
  -1 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2022-01-19 16:11 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: Rodrigo Siqueira, linux-kselftest, Thomas Zimmermann,
	David Airlie, Daniel Latypov, Brendan Higgins, dri-devel,
	Melissa Wen, Arkadiusz Hiler, André Almeida, Petri Latvala

On Tue, Jan 18, 2022 at 12:22:49AM +0100, Michał Winiarski wrote:
> KUnit unifies the test structure and provides helper tools that simplify
> the development. Basic use case allows running tests as regular processes,
> leveraging User Mode Linux.
> For example, to execute all DRM unit tests:
> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
> 
> For developers - it means that it's easier to run unit tests on the development
> machine, tightening the feedback loop. When using UML, it also simplifies using
> gdb for debug (since the kernel is just a regular process).
> For CI systems - DRM tests can be moved from being executed on device under
> test (that's also running IGTs and so on) to being executed on buildsystem
> during build (just like checkpatch.pl).
> 
> All tests were renamed - IGT prefix is no longer used.
> 
> Compared to selftests executed by CI using IGT, there's one functional
> regression - KUnit test runner is not catching WARNs.
> To solve this, we could either go in the similar direction that UBSAN went in:
> 1195505 ("kunit: ubsan integration")
> Or we could expand the test runner to catch WARN signature in dmesg.

I think catching WARN signature in dmesg makes sense, assuming Kunit has a
standard WARN format. It would be nice to be consistent here.

I haven't looked at any details, but yes so much I want to see this done.
I'll cc a bunch of people I've talked with about this conversion,
hopefully I got them all. Maybe they can help with review and getting this
all landed!

Cheers, Daniel

> Pastebin to preview the output and execution times:
> https://gitlab.freedesktop.org/-/snippets/4139
> 
> -Michał
> 
> Michał Winiarski (10):
>   drm: test-drm_cmdline_parser: Convert to KUnit
>   drm: test-drm_plane_helper: Convert to KUnit
>   drm: test-drm_format: Convert to KUnit
>   drm: test-drm_framebuffer: Convert to KUnit
>   drm: test-drm_damage_helper: Convert to KUnit
>   drm: test-drm_dp_mst_helper: Convert to KUnit
>   drm: test-drm_rect: Convert to KUnit
>   drm: test-drm_mm: Convert to KUnit
>   drm: selftests: Convert to KUnit
>   drm: test: Simplify testing on UML with kunit.py
> 
>  drivers/gpu/drm/.kunitconfig                  |    3 +
>  drivers/gpu/drm/Kconfig                       |   22 +-
>  drivers/gpu/drm/Makefile                      |    2 +-
>  drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>  drivers/gpu/drm/selftests/Makefile            |    7 -
>  .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>  drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>  drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>  drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>  .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>  .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>  .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>  drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>  drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>  .../drm/selftests/test-drm_modeset_common.c   |   32 -
>  .../drm/selftests/test-drm_modeset_common.h   |   52 -
>  .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>  drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>  drivers/gpu/drm/test/Makefile                 |    7 +
>  .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>  drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>  drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>  drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>  .../test-drm_framebuffer.c                    |  109 +-
>  drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>  drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>  drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>  drivers/video/Kconfig                         |    4 +
>  29 files changed, 5558 insertions(+), 5727 deletions(-)
>  create mode 100644 drivers/gpu/drm/.kunitconfig
>  delete mode 100644 drivers/gpu/drm/selftests/Makefile
>  delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>  create mode 100644 drivers/gpu/drm/test/Makefile
>  create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>  rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>  create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
> 
> -- 
> 2.34.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-19 16:11   ` Daniel Vetter
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Vetter @ 2022-01-19 16:11 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Latypov,
	Daniel Vetter, David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler,
	André Almeida, Melissa Wen, Rodrigo Siqueira

On Tue, Jan 18, 2022 at 12:22:49AM +0100, Michał Winiarski wrote:
> KUnit unifies the test structure and provides helper tools that simplify
> the development. Basic use case allows running tests as regular processes,
> leveraging User Mode Linux.
> For example, to execute all DRM unit tests:
> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
> 
> For developers - it means that it's easier to run unit tests on the development
> machine, tightening the feedback loop. When using UML, it also simplifies using
> gdb for debug (since the kernel is just a regular process).
> For CI systems - DRM tests can be moved from being executed on device under
> test (that's also running IGTs and so on) to being executed on buildsystem
> during build (just like checkpatch.pl).
> 
> All tests were renamed - IGT prefix is no longer used.
> 
> Compared to selftests executed by CI using IGT, there's one functional
> regression - KUnit test runner is not catching WARNs.
> To solve this, we could either go in the similar direction that UBSAN went in:
> 1195505 ("kunit: ubsan integration")
> Or we could expand the test runner to catch WARN signature in dmesg.

I think catching WARN signature in dmesg makes sense, assuming Kunit has a
standard WARN format. It would be nice to be consistent here.

I haven't looked at any details, but yes so much I want to see this done.
I'll cc a bunch of people I've talked with about this conversion,
hopefully I got them all. Maybe they can help with review and getting this
all landed!

Cheers, Daniel

> Pastebin to preview the output and execution times:
> https://gitlab.freedesktop.org/-/snippets/4139
> 
> -Michał
> 
> Michał Winiarski (10):
>   drm: test-drm_cmdline_parser: Convert to KUnit
>   drm: test-drm_plane_helper: Convert to KUnit
>   drm: test-drm_format: Convert to KUnit
>   drm: test-drm_framebuffer: Convert to KUnit
>   drm: test-drm_damage_helper: Convert to KUnit
>   drm: test-drm_dp_mst_helper: Convert to KUnit
>   drm: test-drm_rect: Convert to KUnit
>   drm: test-drm_mm: Convert to KUnit
>   drm: selftests: Convert to KUnit
>   drm: test: Simplify testing on UML with kunit.py
> 
>  drivers/gpu/drm/.kunitconfig                  |    3 +
>  drivers/gpu/drm/Kconfig                       |   22 +-
>  drivers/gpu/drm/Makefile                      |    2 +-
>  drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>  drivers/gpu/drm/selftests/Makefile            |    7 -
>  .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>  drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>  .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>  drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>  drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>  .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>  .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>  .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>  drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>  drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>  .../drm/selftests/test-drm_modeset_common.c   |   32 -
>  .../drm/selftests/test-drm_modeset_common.h   |   52 -
>  .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>  drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>  drivers/gpu/drm/test/Makefile                 |    7 +
>  .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>  drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>  drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>  drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>  .../test-drm_framebuffer.c                    |  109 +-
>  drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>  drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>  drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>  drivers/video/Kconfig                         |    4 +
>  29 files changed, 5558 insertions(+), 5727 deletions(-)
>  create mode 100644 drivers/gpu/drm/.kunitconfig
>  delete mode 100644 drivers/gpu/drm/selftests/Makefile
>  delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>  delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>  delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>  create mode 100644 drivers/gpu/drm/test/Makefile
>  create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>  rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>  create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>  create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
> 
> -- 
> 2.34.1
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
  2022-01-18 23:58   ` Daniel Latypov
@ 2022-01-20 22:20     ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-20 22:20 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

On 19.01.2022 00:58, Daniel Latypov wrote:
>   change
> On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
> <michal.winiarski@intel.com> wrote:
>>
>> KUnit unifies the test structure and provides helper tools that simplify
>> the development. Basic use case allows running tests as regular processes,
>> leveraging User Mode Linux.
>> For example, to execute all DRM unit tests:
>> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
>> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
>>
>> For developers - it means that it's easier to run unit tests on the development
>> machine, tightening the feedback loop. When using UML, it also simplifies using
> 
> Nice, it's neat to see --kunitconfig being useful for having
> one-liners for running tests.
> 
>> gdb for debug (since the kernel is just a regular process).
> 
> Anecdotally, I hear from davidgow@google.com that using gdb and UML
> together isn't the nicest experience because of all the SIGSEGV flying
> around when emulating paging.
> So I'm a bit doubtful about this particular statement, but if you have
> tried it out and it works well, then that's good too.
> 
> I just think the primary benefit of UML is faster compilation and it
> being somewhat lighter than bringing up a VM.

It was good enough to debug any problems that I accidentally introduced 
during the conversion, but perhaps that was simple enough usecase to not 
encounter SIGSEGVs.

> 
>> For CI systems - DRM tests can be moved from being executed on device under
>> test (that's also running IGTs and so on) to being executed on buildsystem
>> during build (just like checkpatch.pl).
>>
>> All tests were renamed - IGT prefix is no longer used.
>>
>> Compared to selftests executed by CI using IGT, there's one functional
>> regression - KUnit test runner is not catching WARNs.
>> To solve this, we could either go in the similar direction that UBSAN went in:
>> 1195505 ("kunit: ubsan integration")
> 
> Is the suggestion that all WARN's fail the current KUnit test?
> I don't think we can do that.

Yes - that's the suggestion.
The CI used for DRM has a separate "WARN" test state, even if the test 
is PASSing, any WARNs cause the test to end up in this state.
For example:
https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11112/bat-adlp-4/igt@kms_addfb_basic@addfb25-framebuffer-vs-set-tiling.html

> 
> Some KUnit tests will explicitly want to trigger error paths, so we
> could have a lot of false positives.
> 
> An alternative is that we can apply the 1195505 to the code paths
> we're interested in, e.g.
> 
> #include <kunit/test-bug.h>
> if (bad_thing()) {
>    kunit_fail_current_test("bad_thing happened");
> }
> 
> 
> I don't have the context to know how cumbersome this would be for the
> DRM tests though.
> If the answer is we want to catch any and all warnings, then we'd
> perhaps want to add something to the tests themselves. And maybe we
> should implement that as a KUnit library helper function so that other
> tests can use it as well.

I don't thing that would work. IIUC, currently the runner is operating 
on taint - there's a subset of taints that it considers "fatal" 
(including TAINT_WARN).

If we have tests that WARN, perhaps we could introduce extra flag to the 
test state on per-test or per-testsuite level, to mark that the test 
wants to fail-on-warn?
Then we would only fail if the test opted in (or other way around? if 
opt-out makes more sense and we have more tests that actually don't WARN 
as part of their normal test logic).

> 
>> Or we could expand the test runner to catch WARN signature in dmesg.
> 
> Ditto from the above, I think we'd wrongly mark some tests as failed
> for intentional warnings.
> 
>>
>> Pastebin to preview the output and execution times:
>> https://gitlab.freedesktop.org/-/snippets/4139
> 
> I see these take 17-18s to exec the tests in the example snippets.
> FYI, if you're not already trying this on top of 5.16, there's recent
> changes to make the parsed output more fully realtime as well.
> So hopefully that should increase the usability of these tests a bit further.
> 
> I only mention that since I wasn't able to apply this series without
> conflicts on top of v5.16.

It's applied on top of DRM subsystem integration tree (drm-tip):
https://cgit.freedesktop.org/drm-tip
At that time it was already based on v5.16.

Most of that 17-18s is taken by two subtest of drm_mm_tests:

[22:17:19] ============================================================
[22:17:19] ================= drm_mm_tests (1 subtest) =================
[22:17:27] [PASSED] test_insert
[22:17:27] ================== [PASSED] drm_mm_tests ===================
[22:17:27] ============================================================
[22:17:27] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped: 
0, Errors: 0
[22:17:27] Elapsed time: 10.400s total, 0.001s configuring, 2.419s 
building, 7.947s running

[22:17:42] ============================================================
[22:17:42] ================= drm_mm_tests (1 subtest) =================
[22:17:50] [PASSED] test_replace
[22:17:50] ================== [PASSED] drm_mm_tests ===================
[22:17:50] ============================================================
[22:17:50] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped: 
0, Errors: 0
[22:17:50] Elapsed time: 10.272s total, 0.001s configuring, 2.492s 
building, 7.776s running

Their runtime can be controlled with max_prime and max_iterations 
modparams - I left the default values intact, but we can tweak them to 
speed things up if needed.

Thanks!
-Michał

> 
>>
>> -Michał
>>
>> Michał Winiarski (10):
>>    drm: test-drm_cmdline_parser: Convert to KUnit
>>    drm: test-drm_plane_helper: Convert to KUnit
>>    drm: test-drm_format: Convert to KUnit
>>    drm: test-drm_framebuffer: Convert to KUnit
>>    drm: test-drm_damage_helper: Convert to KUnit
>>    drm: test-drm_dp_mst_helper: Convert to KUnit
>>    drm: test-drm_rect: Convert to KUnit
>>    drm: test-drm_mm: Convert to KUnit
>>    drm: selftests: Convert to KUnit
>>    drm: test: Simplify testing on UML with kunit.py
>>
>>   drivers/gpu/drm/.kunitconfig                  |    3 +
>>   drivers/gpu/drm/Kconfig                       |   22 +-
>>   drivers/gpu/drm/Makefile                      |    2 +-
>>   drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>>   drivers/gpu/drm/selftests/Makefile            |    7 -
>>   .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>>   drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>>   .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>>   drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>>   drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>>   .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>>   .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>>   .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>>   drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>>   drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>>   .../drm/selftests/test-drm_modeset_common.c   |   32 -
>>   .../drm/selftests/test-drm_modeset_common.h   |   52 -
>>   .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>>   drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>>   drivers/gpu/drm/test/Makefile                 |    7 +
>>   .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>>   drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>>   drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>>   drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>>   .../test-drm_framebuffer.c                    |  109 +-
>>   drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>>   drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>>   drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>>   drivers/video/Kconfig                         |    4 +
>>   29 files changed, 5558 insertions(+), 5727 deletions(-)
>>   create mode 100644 drivers/gpu/drm/.kunitconfig
>>   delete mode 100644 drivers/gpu/drm/selftests/Makefile
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>>   create mode 100644 drivers/gpu/drm/test/Makefile
>>   create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>>   rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>>   create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
>>
>> --
>> 2.34.1
>>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-20 22:20     ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-20 22:20 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

On 19.01.2022 00:58, Daniel Latypov wrote:
>   change
> On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
> <michal.winiarski@intel.com> wrote:
>>
>> KUnit unifies the test structure and provides helper tools that simplify
>> the development. Basic use case allows running tests as regular processes,
>> leveraging User Mode Linux.
>> For example, to execute all DRM unit tests:
>> ./tools/testing/kunit/kunit.py run --kunitconfig=drivers/gpu/drm
>> (the tool also allows using QEMU instead of UML by adding e.g. --arch=x86_64)
>>
>> For developers - it means that it's easier to run unit tests on the development
>> machine, tightening the feedback loop. When using UML, it also simplifies using
> 
> Nice, it's neat to see --kunitconfig being useful for having
> one-liners for running tests.
> 
>> gdb for debug (since the kernel is just a regular process).
> 
> Anecdotally, I hear from davidgow@google.com that using gdb and UML
> together isn't the nicest experience because of all the SIGSEGV flying
> around when emulating paging.
> So I'm a bit doubtful about this particular statement, but if you have
> tried it out and it works well, then that's good too.
> 
> I just think the primary benefit of UML is faster compilation and it
> being somewhat lighter than bringing up a VM.

It was good enough to debug any problems that I accidentally introduced 
during the conversion, but perhaps that was simple enough usecase to not 
encounter SIGSEGVs.

> 
>> For CI systems - DRM tests can be moved from being executed on device under
>> test (that's also running IGTs and so on) to being executed on buildsystem
>> during build (just like checkpatch.pl).
>>
>> All tests were renamed - IGT prefix is no longer used.
>>
>> Compared to selftests executed by CI using IGT, there's one functional
>> regression - KUnit test runner is not catching WARNs.
>> To solve this, we could either go in the similar direction that UBSAN went in:
>> 1195505 ("kunit: ubsan integration")
> 
> Is the suggestion that all WARN's fail the current KUnit test?
> I don't think we can do that.

Yes - that's the suggestion.
The CI used for DRM has a separate "WARN" test state, even if the test 
is PASSing, any WARNs cause the test to end up in this state.
For example:
https://intel-gfx-ci.01.org/tree/drm-tip/CI_DRM_11112/bat-adlp-4/igt@kms_addfb_basic@addfb25-framebuffer-vs-set-tiling.html

> 
> Some KUnit tests will explicitly want to trigger error paths, so we
> could have a lot of false positives.
> 
> An alternative is that we can apply the 1195505 to the code paths
> we're interested in, e.g.
> 
> #include <kunit/test-bug.h>
> if (bad_thing()) {
>    kunit_fail_current_test("bad_thing happened");
> }
> 
> 
> I don't have the context to know how cumbersome this would be for the
> DRM tests though.
> If the answer is we want to catch any and all warnings, then we'd
> perhaps want to add something to the tests themselves. And maybe we
> should implement that as a KUnit library helper function so that other
> tests can use it as well.

I don't thing that would work. IIUC, currently the runner is operating 
on taint - there's a subset of taints that it considers "fatal" 
(including TAINT_WARN).

If we have tests that WARN, perhaps we could introduce extra flag to the 
test state on per-test or per-testsuite level, to mark that the test 
wants to fail-on-warn?
Then we would only fail if the test opted in (or other way around? if 
opt-out makes more sense and we have more tests that actually don't WARN 
as part of their normal test logic).

> 
>> Or we could expand the test runner to catch WARN signature in dmesg.
> 
> Ditto from the above, I think we'd wrongly mark some tests as failed
> for intentional warnings.
> 
>>
>> Pastebin to preview the output and execution times:
>> https://gitlab.freedesktop.org/-/snippets/4139
> 
> I see these take 17-18s to exec the tests in the example snippets.
> FYI, if you're not already trying this on top of 5.16, there's recent
> changes to make the parsed output more fully realtime as well.
> So hopefully that should increase the usability of these tests a bit further.
> 
> I only mention that since I wasn't able to apply this series without
> conflicts on top of v5.16.

It's applied on top of DRM subsystem integration tree (drm-tip):
https://cgit.freedesktop.org/drm-tip
At that time it was already based on v5.16.

Most of that 17-18s is taken by two subtest of drm_mm_tests:

[22:17:19] ============================================================
[22:17:19] ================= drm_mm_tests (1 subtest) =================
[22:17:27] [PASSED] test_insert
[22:17:27] ================== [PASSED] drm_mm_tests ===================
[22:17:27] ============================================================
[22:17:27] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped: 
0, Errors: 0
[22:17:27] Elapsed time: 10.400s total, 0.001s configuring, 2.419s 
building, 7.947s running

[22:17:42] ============================================================
[22:17:42] ================= drm_mm_tests (1 subtest) =================
[22:17:50] [PASSED] test_replace
[22:17:50] ================== [PASSED] drm_mm_tests ===================
[22:17:50] ============================================================
[22:17:50] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped: 
0, Errors: 0
[22:17:50] Elapsed time: 10.272s total, 0.001s configuring, 2.492s 
building, 7.776s running

Their runtime can be controlled with max_prime and max_iterations 
modparams - I left the default values intact, but we can tweak them to 
speed things up if needed.

Thanks!
-Michał

> 
>>
>> -Michał
>>
>> Michał Winiarski (10):
>>    drm: test-drm_cmdline_parser: Convert to KUnit
>>    drm: test-drm_plane_helper: Convert to KUnit
>>    drm: test-drm_format: Convert to KUnit
>>    drm: test-drm_framebuffer: Convert to KUnit
>>    drm: test-drm_damage_helper: Convert to KUnit
>>    drm: test-drm_dp_mst_helper: Convert to KUnit
>>    drm: test-drm_rect: Convert to KUnit
>>    drm: test-drm_mm: Convert to KUnit
>>    drm: selftests: Convert to KUnit
>>    drm: test: Simplify testing on UML with kunit.py
>>
>>   drivers/gpu/drm/.kunitconfig                  |    3 +
>>   drivers/gpu/drm/Kconfig                       |   22 +-
>>   drivers/gpu/drm/Makefile                      |    2 +-
>>   drivers/gpu/drm/i915/Kconfig.debug            |    1 -
>>   drivers/gpu/drm/selftests/Makefile            |    7 -
>>   .../gpu/drm/selftests/drm_cmdline_selftests.h |   68 -
>>   drivers/gpu/drm/selftests/drm_mm_selftests.h  |   28 -
>>   .../gpu/drm/selftests/drm_modeset_selftests.h |   40 -
>>   drivers/gpu/drm/selftests/drm_selftest.c      |  109 -
>>   drivers/gpu/drm/selftests/drm_selftest.h      |   41 -
>>   .../drm/selftests/test-drm_cmdline_parser.c   | 1141 --------
>>   .../drm/selftests/test-drm_damage_helper.c    |  667 -----
>>   .../drm/selftests/test-drm_dp_mst_helper.c    |  273 --
>>   drivers/gpu/drm/selftests/test-drm_format.c   |  280 --
>>   drivers/gpu/drm/selftests/test-drm_mm.c       | 2487 -----------------
>>   .../drm/selftests/test-drm_modeset_common.c   |   32 -
>>   .../drm/selftests/test-drm_modeset_common.h   |   52 -
>>   .../gpu/drm/selftests/test-drm_plane_helper.c |  223 --
>>   drivers/gpu/drm/selftests/test-drm_rect.c     |  223 --
>>   drivers/gpu/drm/test/Makefile                 |    7 +
>>   .../gpu/drm/test/test-drm_cmdline_parser.c    | 1027 +++++++
>>   drivers/gpu/drm/test/test-drm_damage_helper.c |  667 +++++
>>   drivers/gpu/drm/test/test-drm_dp_mst_helper.c |  429 +++
>>   drivers/gpu/drm/test/test-drm_format.c        |  356 +++
>>   .../test-drm_framebuffer.c                    |  109 +-
>>   drivers/gpu/drm/test/test-drm_mm.c            | 2426 ++++++++++++++++
>>   drivers/gpu/drm/test/test-drm_plane_helper.c  |  312 +++
>>   drivers/gpu/drm/test/test-drm_rect.c          |  249 ++
>>   drivers/video/Kconfig                         |    4 +
>>   29 files changed, 5558 insertions(+), 5727 deletions(-)
>>   create mode 100644 drivers/gpu/drm/.kunitconfig
>>   delete mode 100644 drivers/gpu/drm/selftests/Makefile
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_cmdline_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_mm_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_modeset_selftests.h
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.c
>>   delete mode 100644 drivers/gpu/drm/selftests/drm_selftest.h
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_cmdline_parser.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_damage_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_format.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_mm.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_modeset_common.h
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_plane_helper.c
>>   delete mode 100644 drivers/gpu/drm/selftests/test-drm_rect.c
>>   create mode 100644 drivers/gpu/drm/test/Makefile
>>   create mode 100644 drivers/gpu/drm/test/test-drm_cmdline_parser.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_damage_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_dp_mst_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_format.c
>>   rename drivers/gpu/drm/{selftests => test}/test-drm_framebuffer.c (91%)
>>   create mode 100644 drivers/gpu/drm/test/test-drm_mm.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_plane_helper.c
>>   create mode 100644 drivers/gpu/drm/test/test-drm_rect.c
>>
>> --
>> 2.34.1
>>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
  2022-01-20 22:20     ` Michał Winiarski
@ 2022-01-21  0:20       ` Daniel Latypov
  -1 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-21  0:20 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

On Thu, Jan 20, 2022 at 2:21 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
> > So I'm a bit doubtful about this particular statement, but if you have
> > tried it out and it works well, then that's good too.
> >
> > I just think the primary benefit of UML is faster compilation and it
> > being somewhat lighter than bringing up a VM.
>
> It was good enough to debug any problems that I accidentally introduced
> during the conversion, but perhaps that was simple enough usecase to not
> encounter SIGSEGVs.

Ah, that's good to know.

>
> I don't thing that would work. IIUC, currently the runner is operating
> on taint - there's a subset of taints that it considers "fatal"
> (including TAINT_WARN).
>
> If we have tests that WARN, perhaps we could introduce extra flag to the
> test state on per-test or per-testsuite level, to mark that the test
> wants to fail-on-warn?
> Then we would only fail if the test opted in (or other way around? if
> opt-out makes more sense and we have more tests that actually don't WARN
> as part of their normal test logic).

Yeah, I think this would work.
I chatted with Brendan and David about this and suggested this approach.

This definitely seems useful, so I definitely think we should keep it
in mind, even if we don't get an implementation done in the near
future.

>
> It's applied on top of DRM subsystem integration tree (drm-tip):
> https://cgit.freedesktop.org/drm-tip
> At that time it was already based on v5.16.

Ack, thanks!

I might take another stab at applying the patches locally, but based
on my brief skim over them, everything seemed fine from a KUnit point
of view. It's quite clear you've read over KUnit pretty thoroughly
(e.g. figured out how to create new managed resources, etc.). So I
probably won't have any feedback to give.

>
> Most of that 17-18s is taken by two subtest of drm_mm_tests:
>
> [22:17:19] ============================================================
> [22:17:19] ================= drm_mm_tests (1 subtest) =================
> [22:17:27] [PASSED] test_insert
> [22:17:27] ================== [PASSED] drm_mm_tests ===================
> [22:17:27] ============================================================
> [22:17:27] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped:
> 0, Errors: 0
> [22:17:27] Elapsed time: 10.400s total, 0.001s configuring, 2.419s
> building, 7.947s running
>
> [22:17:42] ============================================================
> [22:17:42] ================= drm_mm_tests (1 subtest) =================
> [22:17:50] [PASSED] test_replace
> [22:17:50] ================== [PASSED] drm_mm_tests ===================
> [22:17:50] ============================================================
> [22:17:50] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped:
> 0, Errors: 0
> [22:17:50] Elapsed time: 10.272s total, 0.001s configuring, 2.492s
> building, 7.776s running
>
> Their runtime can be controlled with max_prime and max_iterations
> modparams - I left the default values intact, but we can tweak them to
> speed things up if needed.

Ah, I was not concerned about test runtime at all.
I was just suggesting that real-time output would be useful if you
didn't have it already.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 00/10] drm: selftests: Convert to KUnit
@ 2022-01-21  0:20       ` Daniel Latypov
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-21  0:20 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

On Thu, Jan 20, 2022 at 2:21 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
> > So I'm a bit doubtful about this particular statement, but if you have
> > tried it out and it works well, then that's good too.
> >
> > I just think the primary benefit of UML is faster compilation and it
> > being somewhat lighter than bringing up a VM.
>
> It was good enough to debug any problems that I accidentally introduced
> during the conversion, but perhaps that was simple enough usecase to not
> encounter SIGSEGVs.

Ah, that's good to know.

>
> I don't thing that would work. IIUC, currently the runner is operating
> on taint - there's a subset of taints that it considers "fatal"
> (including TAINT_WARN).
>
> If we have tests that WARN, perhaps we could introduce extra flag to the
> test state on per-test or per-testsuite level, to mark that the test
> wants to fail-on-warn?
> Then we would only fail if the test opted in (or other way around? if
> opt-out makes more sense and we have more tests that actually don't WARN
> as part of their normal test logic).

Yeah, I think this would work.
I chatted with Brendan and David about this and suggested this approach.

This definitely seems useful, so I definitely think we should keep it
in mind, even if we don't get an implementation done in the near
future.

>
> It's applied on top of DRM subsystem integration tree (drm-tip):
> https://cgit.freedesktop.org/drm-tip
> At that time it was already based on v5.16.

Ack, thanks!

I might take another stab at applying the patches locally, but based
on my brief skim over them, everything seemed fine from a KUnit point
of view. It's quite clear you've read over KUnit pretty thoroughly
(e.g. figured out how to create new managed resources, etc.). So I
probably won't have any feedback to give.

>
> Most of that 17-18s is taken by two subtest of drm_mm_tests:
>
> [22:17:19] ============================================================
> [22:17:19] ================= drm_mm_tests (1 subtest) =================
> [22:17:27] [PASSED] test_insert
> [22:17:27] ================== [PASSED] drm_mm_tests ===================
> [22:17:27] ============================================================
> [22:17:27] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped:
> 0, Errors: 0
> [22:17:27] Elapsed time: 10.400s total, 0.001s configuring, 2.419s
> building, 7.947s running
>
> [22:17:42] ============================================================
> [22:17:42] ================= drm_mm_tests (1 subtest) =================
> [22:17:50] [PASSED] test_replace
> [22:17:50] ================== [PASSED] drm_mm_tests ===================
> [22:17:50] ============================================================
> [22:17:50] Testing complete. Passed: 1, Failed: 0, Crashed: 0, Skipped:
> 0, Errors: 0
> [22:17:50] Elapsed time: 10.272s total, 0.001s configuring, 2.492s
> building, 7.776s running
>
> Their runtime can be controlled with max_prime and max_iterations
> modparams - I left the default values intact, but we can tweak them to
> speed things up if needed.

Ah, I was not concerned about test runtime at all.
I was just suggesting that real-time output would be useful if you
didn't have it already.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
  2022-01-19  0:28     ` Daniel Latypov
@ 2022-01-21  0:48       ` Michał Winiarski
  -1 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-21  0:48 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

On 19.01.2022 01:28, Daniel Latypov wrote:
> On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
> <michal.winiarski@intel.com> wrote:
>>
>> igt_dp_mst_calc_pbn_mode was converted one-to-one,
>> igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.
>>
>> Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
>> ---
>>   drivers/gpu/drm/selftests/Makefile            |   3 +-
>>   .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
>>   .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
>>   .../drm/selftests/test-drm_modeset_common.h   |   2 -
>>   4 files changed, 330 insertions(+), 179 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
>> index 35f2f40dbaf3..77e37eebf099 100644
>> --- a/drivers/gpu/drm/selftests/Makefile
>> +++ b/drivers/gpu/drm/selftests/Makefile
>> @@ -1,7 +1,6 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>>   test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
>>                        test-drm_modeset_common.o \
>> -                     test-drm_dp_mst_helper.o \
>>                        test-drm_rect.o
>>
>>   obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>> @@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>>   obj-$(CONFIG_DRM_KUNIT_TEST) := \
>>          test-drm_cmdline_parser.o test-drm_plane_helper.o \
>>          test-drm_format.o test-drm_framebuffer.o \
>> -       test-drm_damage_helper.o
>> +       test-drm_damage_helper.o test-drm_dp_mst_helper.o
>> diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> index b6a6dba66b64..630770d30aba 100644
>> --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> @@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
>>   selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
>>   selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
>>   selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
>> -selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
>> -selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
>> diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> index 6b4759ed6bfd..d0719f3c5a42 100644
>> --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> @@ -3,54 +3,97 @@
>>    * Test cases for for the DRM DP MST helpers
>>    */
>>
>> -#define PREFIX_STR "[drm_dp_mst_helper]"
>> -
>> +#include <kunit/test.h>
>>   #include <linux/random.h>
>>
>>   #include <drm/drm_dp_mst_helper.h>
>>   #include <drm/drm_print.h>
>>
>>   #include "../drm_dp_mst_topology_internal.h"
>> -#include "test-drm_modeset_common.h"
>>
>> -int igt_dp_mst_calc_pbn_mode(void *ignored)
>> +struct dp_mst_calc_pbn_mode_test {
>> +       int rate;
>> +       int bpp;
>> +       int expected;
>> +       bool dsc;
>> +};
>> +
>> +static void dp_mst_calc_pbn_mode(struct kunit *test)
>>   {
>> -       int pbn, i;
>> -       const struct {
>> -               int rate;
>> -               int bpp;
>> -               int expected;
>> -               bool dsc;
>> -       } test_params[] = {
>> -               { 154000, 30, 689, false },
>> -               { 234000, 30, 1047, false },
>> -               { 297000, 24, 1063, false },
>> -               { 332880, 24, 50, true },
>> -               { 324540, 24, 49, true },
>> -       };
>> +       const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
>> +       int pbn;
>>
>> -       for (i = 0; i < ARRAY_SIZE(test_params); i++) {
>> -               pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
>> -                                          test_params[i].bpp,
>> -                                          test_params[i].dsc);
>> -               FAIL(pbn != test_params[i].expected,
>> -                    "Expected PBN %d for clock %d bpp %d, got %d\n",
>> -                    test_params[i].expected, test_params[i].rate,
>> -                    test_params[i].bpp, pbn);
>> -       }
>> +       pbn = drm_dp_calc_pbn_mode(params->rate,
>> +                                  params->bpp,
>> +                                  params->dsc);
>> +
>> +       KUNIT_EXPECT_EQ(test, pbn, params->expected);
>> +}
>>
>> -       return 0;
>> +static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
>> +       {
>> +               .rate = 154000,
>> +               .bpp = 30,
>> +               .expected = 689,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 234000,
>> +               .bpp = 30,
>> +               .expected = 1047,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 297000,
>> +               .bpp = 24,
>> +               .expected = 1063,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 332880,
>> +               .bpp = 24,
>> +               .expected = 50,
>> +               .dsc = true,
>> +       },
>> +       {
>> +               .rate = 324540,
>> +               .bpp = 24,
>> +               .expected = 49,
>> +               .dsc = true,
>> +       },
>> +};
>> +
>> +static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
>> +                                     char *desc)
>> +{
>> +       sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
>> +               t->rate, t->bpp, t->dsc ? "true" : "false");
>>   }
>>
>> -static bool
>> -sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>> -                      const struct drm_dp_sideband_msg_req_body *out)
>> +KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
>> +
>> +static void
>> +drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
>> +{
>> +       struct kunit *test = p->arg;
>> +
>> +       kunit_err(test, "%pV", vaf);
>> +}
>> +
>> +static void
>> +expect_sideband_msg_req_equal(struct kunit *test,
>> +                             const struct drm_dp_sideband_msg_req_body *in,
>> +                             const struct drm_dp_sideband_msg_req_body *out)
>>   {
>>          const struct drm_dp_remote_i2c_read_tx *txin, *txout;
>> +       struct drm_printer p = {
>> +               .printfn = drm_dp_mst_helper_printfn,
>> +               .arg = test
>> +       };
>>          int i;
>>
>>          if (in->req_type != out->req_type)
>> -               return false;
>> +               goto fail;
> 
> Briefly skimming over this code, it looks like it'd be simpler to have
> this function remain unchanged.
> There's only the one caller.
> It could take on the responsibility of creating the drm_printer and
> redirect the printfn to kunit_err, afaik.
> 
> Passing in `test` would be useful if we were generating custom error
> messages for each of the `return false` lines, which I assume was the
> original motivation for doing so?
> But looking at this, I'd agree it seems like too much work.

Yes, that was the original motivation, but eventually I went back to the 
original code, leaving drm_printer behind.
I agree - I'll leave the function intact.

> 
> Tangent:
> It might have been easier to do that if the kunit assertions returned pass/fail.
> E.g. instead of having to do
> 
> if (!<long-condition>) {
>    KUNIT_FAIL("<long-condition> not met");
>    return;
> }
> 
> if we could do
> 
> if(!KUNIT_EXPECT_TRUE(long-condition))
>    return;
> 
> or if there was a new macro type
> 
> KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
> from this func on failure

This would simplify a bunch of other tests as well.
On the other hand - EXPECT_TRUE returning a value is not something I 
would expect :)

Thanks!
-Michał

> 
> 
>>
>>          switch (in->req_type) {
>>          /*
>> @@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                      IN.num_transactions != OUT.num_transactions ||
>>                      IN.port_number != OUT.port_number ||
>>                      IN.read_i2c_device_id != OUT.read_i2c_device_id)
>> -                       return false;
>> +                       goto fail;
>>
>>                  for (i = 0; i < IN.num_transactions; i++) {
>>                          txin = &IN.transactions[i];
>> @@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                              txin->num_bytes != txout->num_bytes ||
>>                              txin->i2c_transaction_delay !=
>>                              txout->i2c_transaction_delay)
>> -                               return false;
>> +                               goto fail;
>>
>>                          if (memcmp(txin->bytes, txout->bytes,
>>                                     txin->num_bytes) != 0)
>> -                               return false;
>> +                               goto fail;
>>                  }
>>                  break;
>>   #undef IN
>> @@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                  if (IN.dpcd_address != OUT.dpcd_address ||
>>                      IN.num_bytes != OUT.num_bytes ||
>>                      IN.port_number != OUT.port_number)
>> -                       return false;
>> +                       goto fail;
>>
>> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
>> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
>> +                       goto fail;
>> +
>> +               break;
>>   #undef IN
>>   #undef OUT
>>
>> @@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                  if (IN.port_number != OUT.port_number ||
>>                      IN.write_i2c_device_id != OUT.write_i2c_device_id ||
>>                      IN.num_bytes != OUT.num_bytes)
>> -                       return false;
>> +                       goto fail;
>>
>> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
>> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
>> +                       goto fail;
>> +
>> +               break;
>>   #undef IN
>>   #undef OUT
>>
>>          default:
>> -               return memcmp(in, out, sizeof(*in)) == 0;
>> +               if (memcmp(in, out, sizeof(*in)) != 0)
>> +                       goto fail;
>>          }
>>
>> -       return true;
>> +       return;
>> +
>> +fail:
>> +       drm_printf(&p, "Expected:\n");
>> +       drm_dp_dump_sideband_msg_req_body(in, 1, &p);
>> +       drm_printf(&p, "Got:\n");
>> +       drm_dp_dump_sideband_msg_req_body(out, 1, &p);
>> +       KUNIT_FAIL(test, "Encode/decode failed");
>> +}
>> +
>> +struct dp_mst_sideband_msg_req_decode_test {
>> +       const struct drm_dp_sideband_msg_req_body req;
>> +       const struct drm_dp_sideband_msg_req_body
>> +               (*f)(const struct drm_dp_sideband_msg_req_body *in);
>> +};
>> +
>> +const struct drm_dp_sideband_msg_req_body
>> +param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
>> +{
>> +       if (t->f)
>> +               return t->f(&t->req);
>> +
>> +       return t->req;
>>   }
>>
>> -static bool
>> -sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>> +static void dp_mst_sideband_msg_req_decode(struct kunit *test)
>>   {
>> +       const struct drm_dp_sideband_msg_req_body in =
>> +               param_to_dp_mst_sideband_msg_req_body(test->param_value);
>>          struct drm_dp_sideband_msg_req_body *out;
>> -       struct drm_printer p = drm_err_printer(PREFIX_STR);
>>          struct drm_dp_sideband_msg_tx *txmsg;
>> -       int i, ret;
>> -       bool result = true;
>> -
>> -       out = kzalloc(sizeof(*out), GFP_KERNEL);
>> -       if (!out)
>> -               return false;
>> -
>> -       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
>> -       if (!txmsg)
>> -               return false;
>> -
>> -       drm_dp_encode_sideband_req(in, txmsg);
>> -       ret = drm_dp_decode_sideband_req(txmsg, out);
>> -       if (ret < 0) {
>> -               drm_printf(&p, "Failed to decode sideband request: %d\n",
>> -                          ret);
>> -               result = false;
>> -               goto out;
>> -       }
>> +       int i;
>>
>> -       if (!sideband_msg_req_equal(in, out)) {
>> -               drm_printf(&p, "Encode/decode failed, expected:\n");
>> -               drm_dp_dump_sideband_msg_req_body(in, 1, &p);
>> -               drm_printf(&p, "Got:\n");
>> -               drm_dp_dump_sideband_msg_req_body(out, 1, &p);
>> -               result = false;
>> -               goto out;
>> -       }
>> +       out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
>> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
>>
>> -       switch (in->req_type) {
>> +       txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
>> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
>> +
>> +       drm_dp_encode_sideband_req(&in, txmsg);
>> +       KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
>> +
>> +       expect_sideband_msg_req_equal(test, &in, out);
>> +
>> +       switch (in.req_type) {
>>          case DP_REMOTE_DPCD_WRITE:
>>                  kfree(out->u.dpcd_write.bytes);
>>                  break;
>> @@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>>                  kfree(out->u.i2c_write.bytes);
>>                  break;
>>          }
>> -
>> -       /* Clear everything but the req_type for the input */
>> -       memset(&in->u, 0, sizeof(in->u));
>> -
>> -out:
>> -       kfree(out);
>> -       kfree(txmsg);
>> -       return result;
>>   }
>>
>> -int igt_dp_mst_sideband_msg_req_decode(void *unused)
>> +static u8 data[] = { 0xff, 0x0, 0xdd };
>> +
>> +const struct drm_dp_sideband_msg_req_body
>> +random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
>>   {
>> -       struct drm_dp_sideband_msg_req_body in = { 0 };
>> -       u8 data[] = { 0xff, 0x0, 0xdd };
>> -       int i;
>> +       struct drm_dp_query_stream_enc_status enc_status = { };
>>
>> -#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
>> -
>> -       in.req_type = DP_ENUM_PATH_RESOURCES;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_POWER_UP_PHY;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_POWER_DOWN_PHY;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_ALLOCATE_PAYLOAD;
>> -       in.u.allocate_payload.number_sdp_streams = 3;
>> -       for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
>> -               in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
>> -       DO_TEST();
>> -       in.u.allocate_payload.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.allocate_payload.vcpi = 0x7f;
>> -       DO_TEST();
>> -       in.u.allocate_payload.pbn = U16_MAX;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_QUERY_PAYLOAD;
>> -       in.u.query_payload.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.query_payload.vcpi = 0x7f;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_DPCD_READ;
>> -       in.u.dpcd_read.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.dpcd_read.dpcd_address = 0xfedcb;
>> -       DO_TEST();
>> -       in.u.dpcd_read.num_bytes = U8_MAX;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_DPCD_WRITE;
>> -       in.u.dpcd_write.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.dpcd_write.dpcd_address = 0xfedcb;
>> -       DO_TEST();
>> -       in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
>> -       in.u.dpcd_write.bytes = data;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_I2C_READ;
>> -       in.u.i2c_read.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.i2c_read.read_i2c_device_id = 0x7f;
>> -       DO_TEST();
>> -       in.u.i2c_read.num_transactions = 3;
>> -       in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
>> -       for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
>> -               in.u.i2c_read.transactions[i].bytes = data;
>> -               in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
>> -               in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
>> -               in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
>> -       }
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_I2C_WRITE;
>> -       in.u.i2c_write.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.i2c_write.write_i2c_device_id = 0x7f;
>> -       DO_TEST();
>> -       in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
>> -       in.u.i2c_write.bytes = data;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_QUERY_STREAM_ENC_STATUS;
>> -       in.u.enc_status.stream_id = 1;
>> -       DO_TEST();
>> -       get_random_bytes(in.u.enc_status.client_id,
>> -                        sizeof(in.u.enc_status.client_id));
>> -       DO_TEST();
>> -       in.u.enc_status.stream_event = 3;
>> -       DO_TEST();
>> -       in.u.enc_status.valid_stream_event = 0;
>> -       DO_TEST();
>> -       in.u.enc_status.stream_behavior = 3;
>> -       DO_TEST();
>> -       in.u.enc_status.valid_stream_behavior = 1;
>> -       DO_TEST();
>> -
>> -#undef DO_TEST
>> -       return 0;
>> +       get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
>> +
>> +       return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
>> +                                                            .u.enc_status = enc_status
>> +       };
>>   }
>> +
>> +static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ENUM_PATH_RESOURCES,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_POWER_UP_PHY,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_POWER_DOWN_PHY,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.number_sdp_streams = 3,
>> +                       .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.vcpi = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.pbn = U16_MAX,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_PAYLOAD,
>> +                       .u.query_payload.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_PAYLOAD,
>> +                       .u.query_payload.vcpi = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.dpcd_address = 0xfedcb,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.num_bytes = U8_MAX,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.dpcd_address = 0xfedcb,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
>> +                       .u.dpcd_write.bytes = data,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.read_i2c_device_id = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.num_transactions = 3,
>> +                       .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
>> +                       .u.i2c_read.transactions = {
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
>> +                       },
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.write_i2c_device_id = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.num_bytes = ARRAY_SIZE(data),
>> +                       .u.i2c_write.bytes = data,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_id = 1,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +               },
>> +               .f = random_dp_query_enc_client_id,
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_event = 3,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.valid_stream_event = 0,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_behavior = 3,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.valid_stream_behavior = 1,
>> +               },
>> +       },
>> +};
>> +
>> +KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
>> +
>> +static struct kunit_case drm_dp_mst_helper_tests[] = {
>> +       KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
>> +       KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
>> +       {}
>> +};
>> +
>> +static struct kunit_suite drm_dp_mst_helper_test_suite = {
>> +       .name = "drm_dp_mst_helper_tests",
>> +       .test_cases = drm_dp_mst_helper_tests,
>> +};
>> +
>> +kunit_test_suite(drm_dp_mst_helper_test_suite);
>> diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> index 1501d99aee2f..c7cc5edc65f1 100644
>> --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> @@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
>>   int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
>>   int igt_drm_rect_clip_scaled_clipped(void *ignored);
>>   int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
>> -int igt_dp_mst_calc_pbn_mode(void *ignored);
>> -int igt_dp_mst_sideband_msg_req_decode(void *ignored);
>>
>>   #endif
>> --
>> 2.34.1
>>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
@ 2022-01-21  0:48       ` Michał Winiarski
  0 siblings, 0 replies; 35+ messages in thread
From: Michał Winiarski @ 2022-01-21  0:48 UTC (permalink / raw)
  To: Daniel Latypov
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

On 19.01.2022 01:28, Daniel Latypov wrote:
> On Mon, Jan 17, 2022 at 3:24 PM Michał Winiarski
> <michal.winiarski@intel.com> wrote:
>>
>> igt_dp_mst_calc_pbn_mode was converted one-to-one,
>> igt_dp_mst_sideband_msg_req_decode was refactored to parameterized test.
>>
>> Signed-off-by: Michał Winiarski <michal.winiarski@intel.com>
>> ---
>>   drivers/gpu/drm/selftests/Makefile            |   3 +-
>>   .../gpu/drm/selftests/drm_modeset_selftests.h |   2 -
>>   .../drm/selftests/test-drm_dp_mst_helper.c    | 502 ++++++++++++------
>>   .../drm/selftests/test-drm_modeset_common.h   |   2 -
>>   4 files changed, 330 insertions(+), 179 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/selftests/Makefile b/drivers/gpu/drm/selftests/Makefile
>> index 35f2f40dbaf3..77e37eebf099 100644
>> --- a/drivers/gpu/drm/selftests/Makefile
>> +++ b/drivers/gpu/drm/selftests/Makefile
>> @@ -1,7 +1,6 @@
>>   # SPDX-License-Identifier: GPL-2.0-only
>>   test-drm_modeset-$(CONFIG_DRM_DEBUG_SELFTEST) := \
>>                        test-drm_modeset_common.o \
>> -                     test-drm_dp_mst_helper.o \
>>                        test-drm_rect.o
>>
>>   obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>> @@ -9,4 +8,4 @@ obj-$(CONFIG_DRM_DEBUG_SELFTEST) += test-drm_mm.o test-drm_modeset.o
>>   obj-$(CONFIG_DRM_KUNIT_TEST) := \
>>          test-drm_cmdline_parser.o test-drm_plane_helper.o \
>>          test-drm_format.o test-drm_framebuffer.o \
>> -       test-drm_damage_helper.o
>> +       test-drm_damage_helper.o test-drm_dp_mst_helper.o
>> diff --git a/drivers/gpu/drm/selftests/drm_modeset_selftests.h b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> index b6a6dba66b64..630770d30aba 100644
>> --- a/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> +++ b/drivers/gpu/drm/selftests/drm_modeset_selftests.h
>> @@ -10,5 +10,3 @@ selftest(drm_rect_clip_scaled_div_by_zero, igt_drm_rect_clip_scaled_div_by_zero)
>>   selftest(drm_rect_clip_scaled_not_clipped, igt_drm_rect_clip_scaled_not_clipped)
>>   selftest(drm_rect_clip_scaled_clipped, igt_drm_rect_clip_scaled_clipped)
>>   selftest(drm_rect_clip_scaled_signed_vs_unsigned, igt_drm_rect_clip_scaled_signed_vs_unsigned)
>> -selftest(dp_mst_calc_pbn_mode, igt_dp_mst_calc_pbn_mode)
>> -selftest(dp_mst_sideband_msg_req_decode, igt_dp_mst_sideband_msg_req_decode)
>> diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> index 6b4759ed6bfd..d0719f3c5a42 100644
>> --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
>> @@ -3,54 +3,97 @@
>>    * Test cases for for the DRM DP MST helpers
>>    */
>>
>> -#define PREFIX_STR "[drm_dp_mst_helper]"
>> -
>> +#include <kunit/test.h>
>>   #include <linux/random.h>
>>
>>   #include <drm/drm_dp_mst_helper.h>
>>   #include <drm/drm_print.h>
>>
>>   #include "../drm_dp_mst_topology_internal.h"
>> -#include "test-drm_modeset_common.h"
>>
>> -int igt_dp_mst_calc_pbn_mode(void *ignored)
>> +struct dp_mst_calc_pbn_mode_test {
>> +       int rate;
>> +       int bpp;
>> +       int expected;
>> +       bool dsc;
>> +};
>> +
>> +static void dp_mst_calc_pbn_mode(struct kunit *test)
>>   {
>> -       int pbn, i;
>> -       const struct {
>> -               int rate;
>> -               int bpp;
>> -               int expected;
>> -               bool dsc;
>> -       } test_params[] = {
>> -               { 154000, 30, 689, false },
>> -               { 234000, 30, 1047, false },
>> -               { 297000, 24, 1063, false },
>> -               { 332880, 24, 50, true },
>> -               { 324540, 24, 49, true },
>> -       };
>> +       const struct dp_mst_calc_pbn_mode_test *params = test->param_value;
>> +       int pbn;
>>
>> -       for (i = 0; i < ARRAY_SIZE(test_params); i++) {
>> -               pbn = drm_dp_calc_pbn_mode(test_params[i].rate,
>> -                                          test_params[i].bpp,
>> -                                          test_params[i].dsc);
>> -               FAIL(pbn != test_params[i].expected,
>> -                    "Expected PBN %d for clock %d bpp %d, got %d\n",
>> -                    test_params[i].expected, test_params[i].rate,
>> -                    test_params[i].bpp, pbn);
>> -       }
>> +       pbn = drm_dp_calc_pbn_mode(params->rate,
>> +                                  params->bpp,
>> +                                  params->dsc);
>> +
>> +       KUNIT_EXPECT_EQ(test, pbn, params->expected);
>> +}
>>
>> -       return 0;
>> +static const struct dp_mst_calc_pbn_mode_test dp_mst_calc_pbn_mode_tests[] = {
>> +       {
>> +               .rate = 154000,
>> +               .bpp = 30,
>> +               .expected = 689,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 234000,
>> +               .bpp = 30,
>> +               .expected = 1047,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 297000,
>> +               .bpp = 24,
>> +               .expected = 1063,
>> +               .dsc = false,
>> +       },
>> +       {
>> +               .rate = 332880,
>> +               .bpp = 24,
>> +               .expected = 50,
>> +               .dsc = true,
>> +       },
>> +       {
>> +               .rate = 324540,
>> +               .bpp = 24,
>> +               .expected = 49,
>> +               .dsc = true,
>> +       },
>> +};
>> +
>> +static void dp_mst_calc_pbn_mode_desc(const struct dp_mst_calc_pbn_mode_test *t,
>> +                                     char *desc)
>> +{
>> +       sprintf(desc, "rate = %d, bpp = %d, dsc = %s",
>> +               t->rate, t->bpp, t->dsc ? "true" : "false");
>>   }
>>
>> -static bool
>> -sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>> -                      const struct drm_dp_sideband_msg_req_body *out)
>> +KUNIT_ARRAY_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_tests, dp_mst_calc_pbn_mode_desc);
>> +
>> +static void
>> +drm_dp_mst_helper_printfn(struct drm_printer *p, struct va_format *vaf)
>> +{
>> +       struct kunit *test = p->arg;
>> +
>> +       kunit_err(test, "%pV", vaf);
>> +}
>> +
>> +static void
>> +expect_sideband_msg_req_equal(struct kunit *test,
>> +                             const struct drm_dp_sideband_msg_req_body *in,
>> +                             const struct drm_dp_sideband_msg_req_body *out)
>>   {
>>          const struct drm_dp_remote_i2c_read_tx *txin, *txout;
>> +       struct drm_printer p = {
>> +               .printfn = drm_dp_mst_helper_printfn,
>> +               .arg = test
>> +       };
>>          int i;
>>
>>          if (in->req_type != out->req_type)
>> -               return false;
>> +               goto fail;
> 
> Briefly skimming over this code, it looks like it'd be simpler to have
> this function remain unchanged.
> There's only the one caller.
> It could take on the responsibility of creating the drm_printer and
> redirect the printfn to kunit_err, afaik.
> 
> Passing in `test` would be useful if we were generating custom error
> messages for each of the `return false` lines, which I assume was the
> original motivation for doing so?
> But looking at this, I'd agree it seems like too much work.

Yes, that was the original motivation, but eventually I went back to the 
original code, leaving drm_printer behind.
I agree - I'll leave the function intact.

> 
> Tangent:
> It might have been easier to do that if the kunit assertions returned pass/fail.
> E.g. instead of having to do
> 
> if (!<long-condition>) {
>    KUNIT_FAIL("<long-condition> not met");
>    return;
> }
> 
> if we could do
> 
> if(!KUNIT_EXPECT_TRUE(long-condition))
>    return;
> 
> or if there was a new macro type
> 
> KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
> from this func on failure

This would simplify a bunch of other tests as well.
On the other hand - EXPECT_TRUE returning a value is not something I 
would expect :)

Thanks!
-Michał

> 
> 
>>
>>          switch (in->req_type) {
>>          /*
>> @@ -65,7 +108,7 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                      IN.num_transactions != OUT.num_transactions ||
>>                      IN.port_number != OUT.port_number ||
>>                      IN.read_i2c_device_id != OUT.read_i2c_device_id)
>> -                       return false;
>> +                       goto fail;
>>
>>                  for (i = 0; i < IN.num_transactions; i++) {
>>                          txin = &IN.transactions[i];
>> @@ -76,11 +119,11 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                              txin->num_bytes != txout->num_bytes ||
>>                              txin->i2c_transaction_delay !=
>>                              txout->i2c_transaction_delay)
>> -                               return false;
>> +                               goto fail;
>>
>>                          if (memcmp(txin->bytes, txout->bytes,
>>                                     txin->num_bytes) != 0)
>> -                               return false;
>> +                               goto fail;
>>                  }
>>                  break;
>>   #undef IN
>> @@ -92,9 +135,12 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                  if (IN.dpcd_address != OUT.dpcd_address ||
>>                      IN.num_bytes != OUT.num_bytes ||
>>                      IN.port_number != OUT.port_number)
>> -                       return false;
>> +                       goto fail;
>>
>> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
>> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
>> +                       goto fail;
>> +
>> +               break;
>>   #undef IN
>>   #undef OUT
>>
>> @@ -104,55 +150,65 @@ sideband_msg_req_equal(const struct drm_dp_sideband_msg_req_body *in,
>>                  if (IN.port_number != OUT.port_number ||
>>                      IN.write_i2c_device_id != OUT.write_i2c_device_id ||
>>                      IN.num_bytes != OUT.num_bytes)
>> -                       return false;
>> +                       goto fail;
>>
>> -               return memcmp(IN.bytes, OUT.bytes, IN.num_bytes) == 0;
>> +               if (memcmp(IN.bytes, OUT.bytes, IN.num_bytes) != 0)
>> +                       goto fail;
>> +
>> +               break;
>>   #undef IN
>>   #undef OUT
>>
>>          default:
>> -               return memcmp(in, out, sizeof(*in)) == 0;
>> +               if (memcmp(in, out, sizeof(*in)) != 0)
>> +                       goto fail;
>>          }
>>
>> -       return true;
>> +       return;
>> +
>> +fail:
>> +       drm_printf(&p, "Expected:\n");
>> +       drm_dp_dump_sideband_msg_req_body(in, 1, &p);
>> +       drm_printf(&p, "Got:\n");
>> +       drm_dp_dump_sideband_msg_req_body(out, 1, &p);
>> +       KUNIT_FAIL(test, "Encode/decode failed");
>> +}
>> +
>> +struct dp_mst_sideband_msg_req_decode_test {
>> +       const struct drm_dp_sideband_msg_req_body req;
>> +       const struct drm_dp_sideband_msg_req_body
>> +               (*f)(const struct drm_dp_sideband_msg_req_body *in);
>> +};
>> +
>> +const struct drm_dp_sideband_msg_req_body
>> +param_to_dp_mst_sideband_msg_req_body(const struct dp_mst_sideband_msg_req_decode_test *t)
>> +{
>> +       if (t->f)
>> +               return t->f(&t->req);
>> +
>> +       return t->req;
>>   }
>>
>> -static bool
>> -sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>> +static void dp_mst_sideband_msg_req_decode(struct kunit *test)
>>   {
>> +       const struct drm_dp_sideband_msg_req_body in =
>> +               param_to_dp_mst_sideband_msg_req_body(test->param_value);
>>          struct drm_dp_sideband_msg_req_body *out;
>> -       struct drm_printer p = drm_err_printer(PREFIX_STR);
>>          struct drm_dp_sideband_msg_tx *txmsg;
>> -       int i, ret;
>> -       bool result = true;
>> -
>> -       out = kzalloc(sizeof(*out), GFP_KERNEL);
>> -       if (!out)
>> -               return false;
>> -
>> -       txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
>> -       if (!txmsg)
>> -               return false;
>> -
>> -       drm_dp_encode_sideband_req(in, txmsg);
>> -       ret = drm_dp_decode_sideband_req(txmsg, out);
>> -       if (ret < 0) {
>> -               drm_printf(&p, "Failed to decode sideband request: %d\n",
>> -                          ret);
>> -               result = false;
>> -               goto out;
>> -       }
>> +       int i;
>>
>> -       if (!sideband_msg_req_equal(in, out)) {
>> -               drm_printf(&p, "Encode/decode failed, expected:\n");
>> -               drm_dp_dump_sideband_msg_req_body(in, 1, &p);
>> -               drm_printf(&p, "Got:\n");
>> -               drm_dp_dump_sideband_msg_req_body(out, 1, &p);
>> -               result = false;
>> -               goto out;
>> -       }
>> +       out = kunit_kzalloc(test, sizeof(*out), GFP_KERNEL);
>> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, out);
>>
>> -       switch (in->req_type) {
>> +       txmsg = kunit_kzalloc(test, sizeof(*txmsg), GFP_KERNEL);
>> +       KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txmsg);
>> +
>> +       drm_dp_encode_sideband_req(&in, txmsg);
>> +       KUNIT_ASSERT_EQ(test, drm_dp_decode_sideband_req(txmsg, out), 0);
>> +
>> +       expect_sideband_msg_req_equal(test, &in, out);
>> +
>> +       switch (in.req_type) {
>>          case DP_REMOTE_DPCD_WRITE:
>>                  kfree(out->u.dpcd_write.bytes);
>>                  break;
>> @@ -164,110 +220,210 @@ sideband_msg_req_encode_decode(struct drm_dp_sideband_msg_req_body *in)
>>                  kfree(out->u.i2c_write.bytes);
>>                  break;
>>          }
>> -
>> -       /* Clear everything but the req_type for the input */
>> -       memset(&in->u, 0, sizeof(in->u));
>> -
>> -out:
>> -       kfree(out);
>> -       kfree(txmsg);
>> -       return result;
>>   }
>>
>> -int igt_dp_mst_sideband_msg_req_decode(void *unused)
>> +static u8 data[] = { 0xff, 0x0, 0xdd };
>> +
>> +const struct drm_dp_sideband_msg_req_body
>> +random_dp_query_enc_client_id(const struct drm_dp_sideband_msg_req_body *in)
>>   {
>> -       struct drm_dp_sideband_msg_req_body in = { 0 };
>> -       u8 data[] = { 0xff, 0x0, 0xdd };
>> -       int i;
>> +       struct drm_dp_query_stream_enc_status enc_status = { };
>>
>> -#define DO_TEST() FAIL_ON(!sideband_msg_req_encode_decode(&in))
>> -
>> -       in.req_type = DP_ENUM_PATH_RESOURCES;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_POWER_UP_PHY;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_POWER_DOWN_PHY;
>> -       in.u.port_num.port_number = 5;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_ALLOCATE_PAYLOAD;
>> -       in.u.allocate_payload.number_sdp_streams = 3;
>> -       for (i = 0; i < in.u.allocate_payload.number_sdp_streams; i++)
>> -               in.u.allocate_payload.sdp_stream_sink[i] = i + 1;
>> -       DO_TEST();
>> -       in.u.allocate_payload.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.allocate_payload.vcpi = 0x7f;
>> -       DO_TEST();
>> -       in.u.allocate_payload.pbn = U16_MAX;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_QUERY_PAYLOAD;
>> -       in.u.query_payload.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.query_payload.vcpi = 0x7f;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_DPCD_READ;
>> -       in.u.dpcd_read.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.dpcd_read.dpcd_address = 0xfedcb;
>> -       DO_TEST();
>> -       in.u.dpcd_read.num_bytes = U8_MAX;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_DPCD_WRITE;
>> -       in.u.dpcd_write.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.dpcd_write.dpcd_address = 0xfedcb;
>> -       DO_TEST();
>> -       in.u.dpcd_write.num_bytes = ARRAY_SIZE(data);
>> -       in.u.dpcd_write.bytes = data;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_I2C_READ;
>> -       in.u.i2c_read.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.i2c_read.read_i2c_device_id = 0x7f;
>> -       DO_TEST();
>> -       in.u.i2c_read.num_transactions = 3;
>> -       in.u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3;
>> -       for (i = 0; i < in.u.i2c_read.num_transactions; i++) {
>> -               in.u.i2c_read.transactions[i].bytes = data;
>> -               in.u.i2c_read.transactions[i].num_bytes = ARRAY_SIZE(data);
>> -               in.u.i2c_read.transactions[i].i2c_dev_id = 0x7f & ~i;
>> -               in.u.i2c_read.transactions[i].i2c_transaction_delay = 0xf & ~i;
>> -       }
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_REMOTE_I2C_WRITE;
>> -       in.u.i2c_write.port_number = 0xf;
>> -       DO_TEST();
>> -       in.u.i2c_write.write_i2c_device_id = 0x7f;
>> -       DO_TEST();
>> -       in.u.i2c_write.num_bytes = ARRAY_SIZE(data);
>> -       in.u.i2c_write.bytes = data;
>> -       DO_TEST();
>> -
>> -       in.req_type = DP_QUERY_STREAM_ENC_STATUS;
>> -       in.u.enc_status.stream_id = 1;
>> -       DO_TEST();
>> -       get_random_bytes(in.u.enc_status.client_id,
>> -                        sizeof(in.u.enc_status.client_id));
>> -       DO_TEST();
>> -       in.u.enc_status.stream_event = 3;
>> -       DO_TEST();
>> -       in.u.enc_status.valid_stream_event = 0;
>> -       DO_TEST();
>> -       in.u.enc_status.stream_behavior = 3;
>> -       DO_TEST();
>> -       in.u.enc_status.valid_stream_behavior = 1;
>> -       DO_TEST();
>> -
>> -#undef DO_TEST
>> -       return 0;
>> +       get_random_bytes(enc_status.client_id, sizeof(enc_status.client_id));
>> +
>> +       return (const struct drm_dp_sideband_msg_req_body) { .req_type = in->req_type,
>> +                                                            .u.enc_status = enc_status
>> +       };
>>   }
>> +
>> +static const struct dp_mst_sideband_msg_req_decode_test dp_msg_sideband_msg_req_decode_tests[] = {
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ENUM_PATH_RESOURCES,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_POWER_UP_PHY,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_POWER_DOWN_PHY,
>> +                       .u.port_num.port_number = 5,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.number_sdp_streams = 3,
>> +                       .u.allocate_payload.sdp_stream_sink = { 1, 2, 3 },
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.vcpi = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_ALLOCATE_PAYLOAD,
>> +                       .u.allocate_payload.pbn = U16_MAX,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_PAYLOAD,
>> +                       .u.query_payload.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_PAYLOAD,
>> +                       .u.query_payload.vcpi = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.dpcd_address = 0xfedcb,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_READ,
>> +                       .u.dpcd_read.num_bytes = U8_MAX,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.dpcd_address = 0xfedcb,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_DPCD_WRITE,
>> +                       .u.dpcd_write.num_bytes = ARRAY_SIZE(data),
>> +                       .u.dpcd_write.bytes = data,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.read_i2c_device_id = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_READ,
>> +                       .u.i2c_read.num_transactions = 3,
>> +                       .u.i2c_read.num_bytes_read = ARRAY_SIZE(data) * 3,
>> +                       .u.i2c_read.transactions = {
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7f, .i2c_transaction_delay = 0xf, },
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7e, .i2c_transaction_delay = 0xe, },
>> +                               { .bytes = data, .num_bytes = ARRAY_SIZE(data),
>> +                                 .i2c_dev_id = 0x7d, .i2c_transaction_delay = 0xd, },
>> +                       },
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.port_number = 0xf,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.write_i2c_device_id = 0x7f,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_REMOTE_I2C_WRITE,
>> +                       .u.i2c_write.num_bytes = ARRAY_SIZE(data),
>> +                       .u.i2c_write.bytes = data,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_id = 1,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +               },
>> +               .f = random_dp_query_enc_client_id,
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_event = 3,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.valid_stream_event = 0,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.stream_behavior = 3,
>> +               },
>> +       },
>> +       {
>> +               .req = {
>> +                       .req_type = DP_QUERY_STREAM_ENC_STATUS,
>> +                       .u.enc_status.valid_stream_behavior = 1,
>> +               },
>> +       },
>> +};
>> +
>> +KUNIT_ARRAY_PARAM(dp_mst_sideband_msg_req, dp_msg_sideband_msg_req_decode_tests, NULL);
>> +
>> +static struct kunit_case drm_dp_mst_helper_tests[] = {
>> +       KUNIT_CASE_PARAM(dp_mst_calc_pbn_mode, dp_mst_calc_pbn_mode_gen_params),
>> +       KUNIT_CASE_PARAM(dp_mst_sideband_msg_req_decode, dp_mst_sideband_msg_req_gen_params),
>> +       {}
>> +};
>> +
>> +static struct kunit_suite drm_dp_mst_helper_test_suite = {
>> +       .name = "drm_dp_mst_helper_tests",
>> +       .test_cases = drm_dp_mst_helper_tests,
>> +};
>> +
>> +kunit_test_suite(drm_dp_mst_helper_test_suite);
>> diff --git a/drivers/gpu/drm/selftests/test-drm_modeset_common.h b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> index 1501d99aee2f..c7cc5edc65f1 100644
>> --- a/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> +++ b/drivers/gpu/drm/selftests/test-drm_modeset_common.h
>> @@ -20,7 +20,5 @@ int igt_drm_rect_clip_scaled_div_by_zero(void *ignored);
>>   int igt_drm_rect_clip_scaled_not_clipped(void *ignored);
>>   int igt_drm_rect_clip_scaled_clipped(void *ignored);
>>   int igt_drm_rect_clip_scaled_signed_vs_unsigned(void *ignored);
>> -int igt_dp_mst_calc_pbn_mode(void *ignored);
>> -int igt_dp_mst_sideband_msg_req_decode(void *ignored);
>>
>>   #endif
>> --
>> 2.34.1
>>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
  2022-01-21  0:48       ` Michał Winiarski
@ 2022-01-21  1:00         ` Daniel Latypov
  -1 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-21  1:00 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: dri-devel, linux-kselftest, Brendan Higgins, Daniel Vetter,
	David Airlie, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, Petri Latvala, Arkadiusz Hiler

On Thu, Jan 20, 2022 at 4:49 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
> > Tangent:
> > It might have been easier to do that if the kunit assertions returned pass/fail.
> > E.g. instead of having to do
> >
> > if (!<long-condition>) {
> >    KUNIT_FAIL("<long-condition> not met");
> >    return;
> > }
> >
> > if we could do
> >
> > if(!KUNIT_EXPECT_TRUE(long-condition))
> >    return;
> >
> > or if there was a new macro type
> >
> > KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
> > from this func on failure
>
> This would simplify a bunch of other tests as well.
> On the other hand - EXPECT_TRUE returning a value is not something I
> would expect :)

Yeah.
It felt painful to type that out :)

But I felt the same need when looking at converting some other selftests over.
It definitely feels like there's room to make these sorts of helper
functions better.

KTF solved these by allowing asserts to `goto` or `break`, e.g.
https://github.com/oracle/ktf/blob/63c19dead80de9cd654b08120d28a04f24174f4b/kernel/ktf.h#L560

I had floated the idea of KUnit having a
KUNIT_ASSERT_GOTO/KUNIT_ASSERT_RET (return)
macro, but these would add yet another dimension to the macros (EXPECT
vs ASSERT, _MSG vs no _MSG).

But I have some patches out that delete hundreds of lines from the
assert macros along with some others I haven't sent out publicly yet.
Maybe such a thing would be more palatable after those land?

But for now, I think they can either just print enough debug info so
that the failures are obvious (like this does), or they can use
kunit_err() to print out additional info (like you do in other patches
in this series).

>
> Thanks!
> -Michał

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [RFC 06/10] drm: test-drm_dp_mst_helper: Convert to KUnit
@ 2022-01-21  1:00         ` Daniel Latypov
  0 siblings, 0 replies; 35+ messages in thread
From: Daniel Latypov @ 2022-01-21  1:00 UTC (permalink / raw)
  To: Michał Winiarski
  Cc: linux-kselftest, Thomas Zimmermann, David Airlie,
	Brendan Higgins, dri-devel, Arkadiusz Hiler, Petri Latvala

On Thu, Jan 20, 2022 at 4:49 PM Michał Winiarski
<michal.winiarski@intel.com> wrote:
> > Tangent:
> > It might have been easier to do that if the kunit assertions returned pass/fail.
> > E.g. instead of having to do
> >
> > if (!<long-condition>) {
> >    KUNIT_FAIL("<long-condition> not met");
> >    return;
> > }
> >
> > if we could do
> >
> > if(!KUNIT_EXPECT_TRUE(long-condition))
> >    return;
> >
> > or if there was a new macro type
> >
> > KUNIT_EXPECT_RET_TRUE(long-condition); // like ASSERT, but just return
> > from this func on failure
>
> This would simplify a bunch of other tests as well.
> On the other hand - EXPECT_TRUE returning a value is not something I
> would expect :)

Yeah.
It felt painful to type that out :)

But I felt the same need when looking at converting some other selftests over.
It definitely feels like there's room to make these sorts of helper
functions better.

KTF solved these by allowing asserts to `goto` or `break`, e.g.
https://github.com/oracle/ktf/blob/63c19dead80de9cd654b08120d28a04f24174f4b/kernel/ktf.h#L560

I had floated the idea of KUnit having a
KUNIT_ASSERT_GOTO/KUNIT_ASSERT_RET (return)
macro, but these would add yet another dimension to the macros (EXPECT
vs ASSERT, _MSG vs no _MSG).

But I have some patches out that delete hundreds of lines from the
assert macros along with some others I haven't sent out publicly yet.
Maybe such a thing would be more palatable after those land?

But for now, I think they can either just print enough debug info so
that the failures are obvious (like this does), or they can use
kunit_err() to print out additional info (like you do in other patches
in this series).

>
> Thanks!
> -Michał

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2022-01-21  1:00 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-01-17 23:22 [RFC 00/10] drm: selftests: Convert to KUnit Michał Winiarski
2022-01-17 23:22 ` Michał Winiarski
2022-01-17 23:22 ` [RFC 01/10] drm: test-drm_cmdline_parser: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 02/10] drm: test-drm_plane_helper: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 03/10] drm: test-drm_format: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 04/10] drm: test-drm_framebuffer: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 05/10] drm: test-drm_damage_helper: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 06/10] drm: test-drm_dp_mst_helper: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-19  0:28   ` Daniel Latypov
2022-01-19  0:28     ` Daniel Latypov
2022-01-21  0:48     ` Michał Winiarski
2022-01-21  0:48       ` Michał Winiarski
2022-01-21  1:00       ` Daniel Latypov
2022-01-21  1:00         ` Daniel Latypov
2022-01-17 23:22 ` [RFC 07/10] drm: test-drm_rect: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 08/10] drm: test-drm_mm: " Michał Winiarski
2022-01-17 23:22 ` [RFC 09/10] drm: selftests: " Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-17 23:22 ` [RFC 10/10] drm: test: Simplify testing on UML with kunit.py Michał Winiarski
2022-01-17 23:22   ` Michał Winiarski
2022-01-18 23:58 ` [RFC 00/10] drm: selftests: Convert to KUnit Daniel Latypov
2022-01-18 23:58   ` Daniel Latypov
2022-01-20 22:20   ` Michał Winiarski
2022-01-20 22:20     ` Michał Winiarski
2022-01-21  0:20     ` Daniel Latypov
2022-01-21  0:20       ` Daniel Latypov
2022-01-19 16:11 ` Daniel Vetter
2022-01-19 16:11   ` Daniel Vetter

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.