* [PATCH v3 01/20] drm/tests: helpers: Move the helper header to include/drm
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers Maxime Ripard
` (19 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
We'll need to use those helpers from drivers too, so let's move it to a
more visible location.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_client_modeset_test.c | 3 +--
drivers/gpu/drm/tests/drm_kunit_helpers.c | 3 +--
drivers/gpu/drm/tests/drm_modes_test.c | 3 +--
drivers/gpu/drm/tests/drm_probe_helper_test.c | 3 +--
{drivers/gpu/drm/tests => include/drm}/drm_kunit_helpers.h | 0
5 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 52929536a158..ed2f62e92fea 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -8,12 +8,11 @@
#include <drm/drm_connector.h>
#include <drm/drm_edid.h>
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
#include <drm/drm_modeset_helper_vtables.h>
#include <drm/drm_probe_helper.h>
-#include "drm_kunit_helpers.h"
-
struct drm_client_modeset_test_priv {
struct drm_device *drm;
struct drm_connector connector;
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 8c738384a992..6600a4db3158 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -1,14 +1,13 @@
// SPDX-License-Identifier: GPL-2.0
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
#include <kunit/resource.h>
#include <linux/device.h>
-#include "drm_kunit_helpers.h"
-
struct kunit_dev {
struct drm_device base;
};
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
index 9358a885c58b..3953e478c4d0 100644
--- a/drivers/gpu/drm/tests/drm_modes_test.c
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -4,14 +4,13 @@
*/
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_modes.h>
#include <kunit/test.h>
#include <linux/units.h>
-#include "drm_kunit_helpers.h"
-
struct drm_test_modes_priv {
struct drm_device *drm;
};
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
index 7e938258c742..1f3941c150ae 100644
--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -7,6 +7,7 @@
#include <drm/drm_connector.h>
#include <drm/drm_device.h>
#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
#include <drm/drm_mode.h>
#include <drm/drm_modes.h>
#include <drm/drm_modeset_helper_vtables.h>
@@ -14,8 +15,6 @@
#include <kunit/test.h>
-#include "drm_kunit_helpers.h"
-
struct drm_probe_helper_test_priv {
struct drm_device *drm;
struct drm_connector connector;
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
similarity index 100%
rename from drivers/gpu/drm/tests/drm_kunit_helpers.h
rename to include/drm/drm_kunit_helpers.h
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 01/20] drm/tests: helpers: Move the helper header to include/drm Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 13:57 ` Maíra Canal
2022-12-01 15:11 ` [PATCH v3 03/20] drm/tests: helpers: Document drm_kunit_device_init() Maxime Ripard
` (18 subsequent siblings)
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
Driver-specific tests will need access to the helpers without pulling
every DRM framework test. Let's create an intermediate Kconfig options
for the helpers.
Suggested-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/Kconfig | 7 +++++++
drivers/gpu/drm/Makefile | 2 +-
drivers/gpu/drm/tests/Makefile | 4 +++-
3 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index 315cbdf61979..9f019cd053e1 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -63,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
bytes per callsite, the .data costs can be substantial, and
are therefore configurable.
+config DRM_KUNIT_TEST_HELPERS
+ tristate
+ depends on DRM && KUNIT
+ help
+ KUnit Helpers for KMS drivers.
+
config DRM_KUNIT_TEST
tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
depends on DRM && KUNIT
@@ -73,6 +79,7 @@ config DRM_KUNIT_TEST
select DRM_KMS_HELPER
select DRM_BUDDY
select DRM_EXPORT_FOR_TESTS if m
+ select DRM_KUNIT_TEST_HELPERS
default KUNIT_ALL_TESTS
help
This builds unit tests for DRM. This option is not useful for
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index f92cd7892711..8d61fbdfdfac 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -125,7 +125,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
# Drivers and the rest
#
-obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
+obj-y += tests/
obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index 94fe546d937d..ef14bd481139 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -1,5 +1,8 @@
# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
+ drm_kunit_helpers.o
+
obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_buddy_test.o \
drm_cmdline_parser_test.o \
@@ -9,7 +12,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_format_helper_test.o \
drm_format_test.o \
drm_framebuffer_test.o \
- drm_kunit_helpers.o \
drm_mm_test.o \
drm_modes_test.o \
drm_plane_helper_test.o \
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers
2022-12-01 15:11 ` [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers Maxime Ripard
@ 2022-12-07 13:57 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:57 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Driver-specific tests will need access to the helpers without pulling
> every DRM framework test. Let's create an intermediate Kconfig options
> for the helpers.
>
> Suggested-by: Maíra Canal <mcanal@igalia.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/Kconfig | 7 +++++++
> drivers/gpu/drm/Makefile | 2 +-
> drivers/gpu/drm/tests/Makefile | 4 +++-
> 3 files changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 315cbdf61979..9f019cd053e1 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -63,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
> bytes per callsite, the .data costs can be substantial, and
> are therefore configurable.
>
> +config DRM_KUNIT_TEST_HELPERS
> + tristate
> + depends on DRM && KUNIT
> + help
> + KUnit Helpers for KMS drivers.
> +
> config DRM_KUNIT_TEST
> tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
> depends on DRM && KUNIT
> @@ -73,6 +79,7 @@ config DRM_KUNIT_TEST
> select DRM_KMS_HELPER
> select DRM_BUDDY
> select DRM_EXPORT_FOR_TESTS if m
> + select DRM_KUNIT_TEST_HELPERS
> default KUNIT_ALL_TESTS
> help
> This builds unit tests for DRM. This option is not useful for
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index f92cd7892711..8d61fbdfdfac 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -125,7 +125,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
> # Drivers and the rest
> #
>
> -obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
> +obj-y += tests/
>
> obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
> obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> index 94fe546d937d..ef14bd481139 100644
> --- a/drivers/gpu/drm/tests/Makefile
> +++ b/drivers/gpu/drm/tests/Makefile
> @@ -1,5 +1,8 @@
> # SPDX-License-Identifier: GPL-2.0
>
> +obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
> + drm_kunit_helpers.o
> +
> obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_buddy_test.o \
> drm_cmdline_parser_test.o \
> @@ -9,7 +12,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_format_helper_test.o \
> drm_format_test.o \
> drm_framebuffer_test.o \
> - drm_kunit_helpers.o \
> drm_mm_test.o \
> drm_modes_test.o \
> drm_plane_helper_test.o \
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers
@ 2022-12-07 13:57 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:57 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
Maíra Canal, Javier Martinez Canillas, dri-devel,
linux-kernel, linaro-mm-sig, Brendan Higgins, David Gow,
linux-media, kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> Driver-specific tests will need access to the helpers without pulling
> every DRM framework test. Let's create an intermediate Kconfig options
> for the helpers.
>
> Suggested-by: Maíra Canal <mcanal@igalia.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/Kconfig | 7 +++++++
> drivers/gpu/drm/Makefile | 2 +-
> drivers/gpu/drm/tests/Makefile | 4 +++-
> 3 files changed, 11 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 315cbdf61979..9f019cd053e1 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -63,6 +63,12 @@ config DRM_USE_DYNAMIC_DEBUG
> bytes per callsite, the .data costs can be substantial, and
> are therefore configurable.
>
> +config DRM_KUNIT_TEST_HELPERS
> + tristate
> + depends on DRM && KUNIT
> + help
> + KUnit Helpers for KMS drivers.
> +
> config DRM_KUNIT_TEST
> tristate "KUnit tests for DRM" if !KUNIT_ALL_TESTS
> depends on DRM && KUNIT
> @@ -73,6 +79,7 @@ config DRM_KUNIT_TEST
> select DRM_KMS_HELPER
> select DRM_BUDDY
> select DRM_EXPORT_FOR_TESTS if m
> + select DRM_KUNIT_TEST_HELPERS
> default KUNIT_ALL_TESTS
> help
> This builds unit tests for DRM. This option is not useful for
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index f92cd7892711..8d61fbdfdfac 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -125,7 +125,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
> # Drivers and the rest
> #
>
> -obj-$(CONFIG_DRM_KUNIT_TEST) += tests/
> +obj-y += tests/
>
> obj-$(CONFIG_DRM_MIPI_DBI) += drm_mipi_dbi.o
> obj-$(CONFIG_DRM_MIPI_DSI) += drm_mipi_dsi.o
> diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
> index 94fe546d937d..ef14bd481139 100644
> --- a/drivers/gpu/drm/tests/Makefile
> +++ b/drivers/gpu/drm/tests/Makefile
> @@ -1,5 +1,8 @@
> # SPDX-License-Identifier: GPL-2.0
>
> +obj-$(CONFIG_DRM_KUNIT_TEST_HELPERS) += \
> + drm_kunit_helpers.o
> +
> obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_buddy_test.o \
> drm_cmdline_parser_test.o \
> @@ -9,7 +12,6 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
> drm_format_helper_test.o \
> drm_format_test.o \
> drm_framebuffer_test.o \
> - drm_kunit_helpers.o \
> drm_mm_test.o \
> drm_modes_test.o \
> drm_plane_helper_test.o \
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v3 03/20] drm/tests: helpers: Document drm_kunit_device_init()
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 01/20] drm/tests: helpers: Move the helper header to include/drm Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 02/20] drm/tests: Introduce a config option for the KUnit helpers Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL Maxime Ripard
` (17 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
Commit 44a3928324e9 ("drm/tests: Add Kunit Helpers") introduced the
drm_kunit_device_init() function but didn't document it properly. Add
that documentation.
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 6600a4db3158..9ed3cfc2ac03 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -35,6 +35,23 @@ static void dev_free(struct kunit_resource *res)
root_device_unregister(dev);
}
+/**
+ * drm_kunit_device_init - Allocates a mock DRM device for KUnit tests
+ * @test: The test context object
+ * @features: Mocked DRM device driver features
+ * @name: Name of the struct &device to allocate
+ *
+ * This function allocates a new struct &device, creates a struct
+ * &drm_driver and will create a struct &drm_device using both.
+ *
+ * The device and driver are tied to the @test context and will get
+ * cleaned at the end of the test. The drm_device is allocated through
+ * devm_drm_dev_alloc() and will thus be freed through a device-managed
+ * resource.
+ *
+ * Returns:
+ * A pointer to the new drm_device, or an ERR_PTR() otherwise.
+ */
struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name)
{
struct kunit_dev *kdev;
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (2 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 03/20] drm/tests: helpers: Document drm_kunit_device_init() Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 13:59 ` Maíra Canal
2022-12-01 15:11 ` [PATCH v3 05/20] drm/tests: helpers: Rename the device init helper Maxime Ripard
` (16 subsequent siblings)
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
drm_kunit_device_init() among other things will allocate a device and
wrap around root_device_register. This function is exported with
EXPORT_SYMBOL_GPL, so we can't really change the license.
Fixes: 199557fab925 ("drm/tests: helpers: Add missing export")
Suggested-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 9ed3cfc2ac03..4fe131141718 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -82,7 +82,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
return drm;
}
-EXPORT_SYMBOL(drm_kunit_device_init);
+EXPORT_SYMBOL_GPL(drm_kunit_device_init);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL
2022-12-01 15:11 ` [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL Maxime Ripard
@ 2022-12-07 13:59 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:59 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
Maíra Canal, Javier Martinez Canillas, dri-devel,
linux-kernel, linaro-mm-sig, Brendan Higgins, David Gow,
linux-media, kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> drm_kunit_device_init() among other things will allocate a device and
> wrap around root_device_register. This function is exported with
> EXPORT_SYMBOL_GPL, so we can't really change the license.
>
> Fixes: 199557fab925 ("drm/tests: helpers: Add missing export")
> Suggested-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/tests/drm_kunit_helpers.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> index 9ed3cfc2ac03..4fe131141718 100644
> --- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
> +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> @@ -82,7 +82,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
>
> return drm;
> }
> -EXPORT_SYMBOL(drm_kunit_device_init);
> +EXPORT_SYMBOL_GPL(drm_kunit_device_init);
>
> MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
> MODULE_LICENSE("GPL");
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL
@ 2022-12-07 13:59 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:59 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> drm_kunit_device_init() among other things will allocate a device and
> wrap around root_device_register. This function is exported with
> EXPORT_SYMBOL_GPL, so we can't really change the license.
>
> Fixes: 199557fab925 ("drm/tests: helpers: Add missing export")
> Suggested-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/tests/drm_kunit_helpers.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> index 9ed3cfc2ac03..4fe131141718 100644
> --- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
> +++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
> @@ -82,7 +82,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
>
> return drm;
> }
> -EXPORT_SYMBOL(drm_kunit_device_init);
> +EXPORT_SYMBOL_GPL(drm_kunit_device_init);
>
> MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
> MODULE_LICENSE("GPL");
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v3 05/20] drm/tests: helpers: Rename the device init helper
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (3 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 04/20] drm/tests: helpers: Switch to EXPORT_SYMBOL_GPL Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 06/20] drm/tests: helpers: Remove the name parameter Maxime Ripard
` (15 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The name doesn't really fit the conventions for the other helpers in
DRM/KMS, so let's rename it to make it obvious that we allocate a new
DRM device.
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_client_modeset_test.c | 3 ++-
drivers/gpu/drm/tests/drm_kunit_helpers.c | 8 +++++---
drivers/gpu/drm/tests/drm_modes_test.c | 3 ++-
drivers/gpu/drm/tests/drm_probe_helper_test.c | 5 +++--
include/drm/drm_kunit_helpers.h | 5 ++++-
5 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index ed2f62e92fea..6cdf08f582ce 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -59,7 +59,8 @@ static int drm_client_modeset_test_init(struct kunit *test)
test->priv = priv;
- priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-client-modeset-test");
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET,
+ "drm-client-modeset-test");
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 4fe131141718..e718073ba6e9 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -36,7 +36,7 @@ static void dev_free(struct kunit_resource *res)
}
/**
- * drm_kunit_device_init - Allocates a mock DRM device for KUnit tests
+ * drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
* @test: The test context object
* @features: Mocked DRM device driver features
* @name: Name of the struct &device to allocate
@@ -52,7 +52,9 @@ static void dev_free(struct kunit_resource *res)
* Returns:
* A pointer to the new drm_device, or an ERR_PTR() otherwise.
*/
-struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name)
+struct drm_device *
+drm_kunit_helper_alloc_drm_device(struct kunit *test,
+ u32 features, char *name)
{
struct kunit_dev *kdev;
struct drm_device *drm;
@@ -82,7 +84,7 @@ struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char
return drm;
}
-EXPORT_SYMBOL_GPL(drm_kunit_device_init);
+EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_drm_device);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
index 3953e478c4d0..6723089dff9f 100644
--- a/drivers/gpu/drm/tests/drm_modes_test.c
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -22,7 +22,8 @@ static int drm_test_modes_init(struct kunit *test)
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv);
- priv->drm = drm_kunit_device_init(test, DRIVER_MODESET, "drm-modes-test");
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET,
+ "drm-modes-test");
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
test->priv = priv;
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
index 1f3941c150ae..85236ff4744f 100644
--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -39,8 +39,9 @@ static int drm_probe_helper_test_init(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, priv);
test->priv = priv;
- priv->drm = drm_kunit_device_init(test, DRIVER_MODESET | DRIVER_ATOMIC,
- "drm-probe-helper-test");
+ priv->drm = drm_kunit_helper_alloc_drm_device(test,
+ DRIVER_MODESET | DRIVER_ATOMIC,
+ "drm-probe-helper-test");
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
connector = &priv->connector;
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index 20ab6eec4c89..e9870c7911fe 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -6,6 +6,9 @@
struct drm_device;
struct kunit;
-struct drm_device *drm_kunit_device_init(struct kunit *test, u32 features, char *name);
+struct drm_device *
+drm_kunit_helper_alloc_drm_device(struct kunit *test,
+ u32 features,
+ char *name);
#endif // DRM_KUNIT_HELPERS_H_
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 06/20] drm/tests: helpers: Remove the name parameter
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (4 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 05/20] drm/tests: helpers: Rename the device init helper Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 07/20] drm/tests: helpers: Create the device in another function Maxime Ripard
` (14 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The device name isn't really useful, we can just define it instead of
exposing it in the API.
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_client_modeset_test.c | 3 +--
drivers/gpu/drm/tests/drm_kunit_helpers.c | 7 ++++---
drivers/gpu/drm/tests/drm_modes_test.c | 3 +--
drivers/gpu/drm/tests/drm_probe_helper_test.c | 3 +--
include/drm/drm_kunit_helpers.h | 3 +--
5 files changed, 8 insertions(+), 11 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 6cdf08f582ce..4d475ae6dbb6 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -59,8 +59,7 @@ static int drm_client_modeset_test_init(struct kunit *test)
test->priv = priv;
- priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET,
- "drm-client-modeset-test");
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index e718073ba6e9..ec33fcbd092d 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -8,6 +8,8 @@
#include <linux/device.h>
+#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
+
struct kunit_dev {
struct drm_device base;
};
@@ -39,7 +41,6 @@ static void dev_free(struct kunit_resource *res)
* drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
* @test: The test context object
* @features: Mocked DRM device driver features
- * @name: Name of the struct &device to allocate
*
* This function allocates a new struct &device, creates a struct
* &drm_driver and will create a struct &drm_device using both.
@@ -54,7 +55,7 @@ static void dev_free(struct kunit_resource *res)
*/
struct drm_device *
drm_kunit_helper_alloc_drm_device(struct kunit *test,
- u32 features, char *name)
+ u32 features)
{
struct kunit_dev *kdev;
struct drm_device *drm;
@@ -62,7 +63,7 @@ drm_kunit_helper_alloc_drm_device(struct kunit *test,
struct device *dev;
int ret;
- dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, name);
+ dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, KUNIT_DEVICE_NAME);
if (!dev)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
index 6723089dff9f..35965ad86188 100644
--- a/drivers/gpu/drm/tests/drm_modes_test.c
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -22,8 +22,7 @@ static int drm_test_modes_init(struct kunit *test)
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv);
- priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET,
- "drm-modes-test");
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
test->priv = priv;
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
index 85236ff4744f..be61a92b79d2 100644
--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -40,8 +40,7 @@ static int drm_probe_helper_test_init(struct kunit *test)
test->priv = priv;
priv->drm = drm_kunit_helper_alloc_drm_device(test,
- DRIVER_MODESET | DRIVER_ATOMIC,
- "drm-probe-helper-test");
+ DRIVER_MODESET | DRIVER_ATOMIC);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
connector = &priv->connector;
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index e9870c7911fe..6c12b1426ba0 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -8,7 +8,6 @@ struct kunit;
struct drm_device *
drm_kunit_helper_alloc_drm_device(struct kunit *test,
- u32 features,
- char *name);
+ u32 features);
#endif // DRM_KUNIT_HELPERS_H_
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 07/20] drm/tests: helpers: Create the device in another function
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (5 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 06/20] drm/tests: helpers: Remove the name parameter Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 08/20] drm/tests: helpers: Switch to a platform_device Maxime Ripard
` (13 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
We'll need in some tests to control when the device needs to be added
and removed, so let's split the device creation from the DRM device
creation function.
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_client_modeset_test.c | 14 ++++++-
drivers/gpu/drm/tests/drm_kunit_helpers.c | 56 +++++++++++++++----------
drivers/gpu/drm/tests/drm_modes_test.c | 15 ++++++-
drivers/gpu/drm/tests/drm_probe_helper_test.c | 14 ++++++-
include/drm/drm_kunit_helpers.h | 5 ++-
5 files changed, 77 insertions(+), 27 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 4d475ae6dbb6..053dbc0106d9 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -15,6 +15,7 @@
struct drm_client_modeset_test_priv {
struct drm_device *drm;
+ struct device *dev;
struct drm_connector connector;
};
@@ -59,7 +60,10 @@ static int drm_client_modeset_test_init(struct kunit *test)
test->priv = priv;
- priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET);
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev, DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
@@ -76,6 +80,13 @@ static int drm_client_modeset_test_init(struct kunit *test)
return 0;
}
+static void drm_client_modeset_test_exit(struct kunit *test)
+{
+ struct drm_client_modeset_test_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
static void drm_test_pick_cmdline_res_1920_1080_60(struct kunit *test)
{
struct drm_client_modeset_test_priv *priv = test->priv;
@@ -175,6 +186,7 @@ static struct kunit_case drm_test_pick_cmdline_tests[] = {
static struct kunit_suite drm_test_pick_cmdline_test_suite = {
.name = "drm_test_pick_cmdline",
.init = drm_client_modeset_test_init,
+ .exit = drm_client_modeset_test_exit,
.test_cases = drm_test_pick_cmdline_tests
};
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index ec33fcbd092d..4bf98bd0a8c6 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -17,36 +17,51 @@ struct kunit_dev {
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
-static int dev_init(struct kunit_resource *res, void *ptr)
+/**
+ * drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
+ * @test: The test context object
+ *
+ * This allocates a fake struct &device to create a mock for a KUnit
+ * test.
+ *
+ * Callers need to make sure drm_kunit_helper_free_device() on the
+ * device when done.
+ *
+ * Returns:
+ * A pointer to the new device, or an ERR_PTR() otherwise.
+ */
+struct device *drm_kunit_helper_alloc_device(struct kunit *test)
{
- char *name = ptr;
- struct device *dev;
-
- dev = root_device_register(name);
- if (IS_ERR(dev))
- return PTR_ERR(dev);
-
- res->data = dev;
- return 0;
+ return root_device_register(KUNIT_DEVICE_NAME);
}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
-static void dev_free(struct kunit_resource *res)
+/**
+ * drm_kunit_helper_free_device - Frees a mock device
+ * @test: The test context object
+ * @dev: The device to free
+ *
+ * Frees a device allocated with drm_kunit_helper_alloc_device().
+ */
+void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
{
- struct device *dev = res->data;
-
root_device_unregister(dev);
}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
/**
* drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
* @test: The test context object
+ * @dev: The parent device object
* @features: Mocked DRM device driver features
*
- * This function allocates a new struct &device, creates a struct
- * &drm_driver and will create a struct &drm_device using both.
+ * This function creates a struct &drm_driver and will create a struct
+ * &drm_device from @dev and that driver.
*
- * The device and driver are tied to the @test context and will get
- * cleaned at the end of the test. The drm_device is allocated through
+ * @dev should be allocated using drm_kunit_helper_alloc_device().
+ *
+ * The driver is tied to the @test context and will get cleaned at the
+ * end of the test. The drm_device is allocated through
* devm_drm_dev_alloc() and will thus be freed through a device-managed
* resource.
*
@@ -54,19 +69,14 @@ static void dev_free(struct kunit_resource *res)
* A pointer to the new drm_device, or an ERR_PTR() otherwise.
*/
struct drm_device *
-drm_kunit_helper_alloc_drm_device(struct kunit *test,
+drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
u32 features)
{
struct kunit_dev *kdev;
struct drm_device *drm;
struct drm_driver *driver;
- struct device *dev;
int ret;
- dev = kunit_alloc_resource(test, dev_init, dev_free, GFP_KERNEL, KUNIT_DEVICE_NAME);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
if (!driver)
return ERR_PTR(-ENOMEM);
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
index 35965ad86188..d1e9f3c0433a 100644
--- a/drivers/gpu/drm/tests/drm_modes_test.c
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -13,6 +13,7 @@
struct drm_test_modes_priv {
struct drm_device *drm;
+ struct device *dev;
};
static int drm_test_modes_init(struct kunit *test)
@@ -22,7 +23,11 @@ static int drm_test_modes_init(struct kunit *test)
priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, priv);
- priv->drm = drm_kunit_helper_alloc_drm_device(test, DRIVER_MODESET);
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
test->priv = priv;
@@ -30,6 +35,13 @@ static int drm_test_modes_init(struct kunit *test)
return 0;
}
+static void drm_test_modes_exit(struct kunit *test)
+{
+ struct drm_test_modes_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
static void drm_test_modes_analog_tv_ntsc_480i(struct kunit *test)
{
struct drm_test_modes_priv *priv = test->priv;
@@ -135,6 +147,7 @@ static struct kunit_case drm_modes_analog_tv_tests[] = {
static struct kunit_suite drm_modes_analog_tv_test_suite = {
.name = "drm_modes_analog_tv",
.init = drm_test_modes_init,
+ .exit = drm_test_modes_exit,
.test_cases = drm_modes_analog_tv_tests,
};
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
index be61a92b79d2..63a3bd1a6e4d 100644
--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -17,6 +17,7 @@
struct drm_probe_helper_test_priv {
struct drm_device *drm;
+ struct device *dev;
struct drm_connector connector;
};
@@ -39,7 +40,10 @@ static int drm_probe_helper_test_init(struct kunit *test)
KUNIT_ASSERT_NOT_NULL(test, priv);
test->priv = priv;
- priv->drm = drm_kunit_helper_alloc_drm_device(test,
+ priv->dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
+
+ priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev,
DRIVER_MODESET | DRIVER_ATOMIC);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
@@ -55,6 +59,13 @@ static int drm_probe_helper_test_init(struct kunit *test)
return 0;
}
+static void drm_probe_helper_test_exit(struct kunit *test)
+{
+ struct drm_probe_helper_test_priv *priv = test->priv;
+
+ drm_kunit_helper_free_device(test, priv->dev);
+}
+
typedef struct drm_display_mode *(*expected_mode_func_t)(struct drm_device *);
struct drm_connector_helper_tv_get_modes_test {
@@ -195,6 +206,7 @@ static struct kunit_case drm_test_connector_helper_tv_get_modes_tests[] = {
static struct kunit_suite drm_test_connector_helper_tv_get_modes_suite = {
.name = "drm_connector_helper_tv_get_modes",
.init = drm_probe_helper_test_init,
+ .exit = drm_probe_helper_test_exit,
.test_cases = drm_test_connector_helper_tv_get_modes_tests,
};
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index 6c12b1426ba0..b4277fe92c38 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -6,8 +6,11 @@
struct drm_device;
struct kunit;
+struct device *drm_kunit_helper_alloc_device(struct kunit *test);
+void drm_kunit_helper_free_device(struct kunit *test, struct device *dev);
+
struct drm_device *
-drm_kunit_helper_alloc_drm_device(struct kunit *test,
+drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
u32 features);
#endif // DRM_KUNIT_HELPERS_H_
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 08/20] drm/tests: helpers: Switch to a platform_device
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (6 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 07/20] drm/tests: helpers: Create the device in another function Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 09/20] drm/tests: helpers: Make sure the device is bound Maxime Ripard
` (12 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The device managed resources are ran if the device has bus, which is not
the case of a root_device.
Let's use a platform_device instead.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 16 ++++++++++++++--
1 file changed, 14 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 4bf98bd0a8c6..b66ce779511b 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -7,6 +7,7 @@
#include <kunit/resource.h>
#include <linux/device.h>
+#include <linux/platform_device.h>
#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
@@ -32,7 +33,16 @@ static const struct drm_mode_config_funcs drm_mode_config_funcs = {
*/
struct device *drm_kunit_helper_alloc_device(struct kunit *test)
{
- return root_device_register(KUNIT_DEVICE_NAME);
+ struct platform_device *pdev;
+ int ret;
+
+ pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
+
+ ret = platform_device_add(pdev);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return &pdev->dev;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
@@ -45,7 +55,9 @@ EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
*/
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
{
- root_device_unregister(dev);
+ struct platform_device *pdev = to_platform_device(dev);
+
+ platform_device_unregister(pdev);
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 09/20] drm/tests: helpers: Make sure the device is bound
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (7 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 08/20] drm/tests: helpers: Switch to a platform_device Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 10/20] drm/tests: helpers: Allow for a custom device struct to be allocated Maxime Ripard
` (11 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The device managed resources are freed when the device is detached, so
it has to be bound in the first place.
Let's create a fake driver that we will bind to our fake device to
benefit from the device managed cleanups in our tests.
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 26 +++++++++++++++++++++++++-
1 file changed, 25 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index b66ce779511b..9bfd3cb9cde1 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -18,12 +18,32 @@ struct kunit_dev {
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
+static int fake_probe(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static int fake_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static struct platform_driver fake_platform_driver = {
+ .probe = fake_probe,
+ .remove = fake_remove,
+ .driver = {
+ .name = KUNIT_DEVICE_NAME,
+ },
+};
+
/**
* drm_kunit_helper_alloc_device - Allocate a mock device for a KUnit test
* @test: The test context object
*
* This allocates a fake struct &device to create a mock for a KUnit
- * test.
+ * test. The device will also be bound to a fake driver. It will thus be
+ * able to leverage the usual infrastructure and most notably the
+ * device-managed resources just like a "real" device.
*
* Callers need to make sure drm_kunit_helper_free_device() on the
* device when done.
@@ -36,6 +56,9 @@ struct device *drm_kunit_helper_alloc_device(struct kunit *test)
struct platform_device *pdev;
int ret;
+ ret = platform_driver_register(&fake_platform_driver);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
@@ -58,6 +81,7 @@ void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
platform_device_unregister(pdev);
+ platform_driver_unregister(&fake_platform_driver);
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 10/20] drm/tests: helpers: Allow for a custom device struct to be allocated
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (8 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 09/20] drm/tests: helpers: Make sure the device is bound Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 11/20] drm/tests: helpers: Allow to pass a custom drm_driver Maxime Ripard
` (10 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The current helper to allocate a DRM device doesn't allow for any
subclassing by drivers, which is going to be troublesome as we work on
getting some kunit testing on atomic modesetting code.
Let's use a similar pattern to the other allocation helpers by providing
the structure size and offset as arguments.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_client_modeset_test.c | 4 ++-
drivers/gpu/drm/tests/drm_kunit_helpers.c | 40 ++++++-------------------
drivers/gpu/drm/tests/drm_modes_test.c | 5 ++--
drivers/gpu/drm/tests/drm_probe_helper_test.c | 5 ++--
include/drm/drm_kunit_helpers.h | 32 ++++++++++++++++++--
5 files changed, 48 insertions(+), 38 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_client_modeset_test.c b/drivers/gpu/drm/tests/drm_client_modeset_test.c
index 053dbc0106d9..416a279b6dae 100644
--- a/drivers/gpu/drm/tests/drm_client_modeset_test.c
+++ b/drivers/gpu/drm/tests/drm_client_modeset_test.c
@@ -63,7 +63,9 @@ static int drm_client_modeset_test_init(struct kunit *test)
priv->dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
- priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev, DRIVER_MODESET);
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
ret = drmm_connector_init(priv->drm, &priv->connector,
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 9bfd3cb9cde1..b5485ab8fbf9 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -11,10 +11,6 @@
#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
-struct kunit_dev {
- struct drm_device base;
-};
-
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
@@ -85,32 +81,14 @@ void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
-/**
- * drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
- * @test: The test context object
- * @dev: The parent device object
- * @features: Mocked DRM device driver features
- *
- * This function creates a struct &drm_driver and will create a struct
- * &drm_device from @dev and that driver.
- *
- * @dev should be allocated using drm_kunit_helper_alloc_device().
- *
- * The driver is tied to the @test context and will get cleaned at the
- * end of the test. The drm_device is allocated through
- * devm_drm_dev_alloc() and will thus be freed through a device-managed
- * resource.
- *
- * Returns:
- * A pointer to the new drm_device, or an ERR_PTR() otherwise.
- */
struct drm_device *
-drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
- u32 features)
+__drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
+ size_t size, size_t offset,
+ u32 features)
{
- struct kunit_dev *kdev;
struct drm_device *drm;
struct drm_driver *driver;
+ void *container;
int ret;
driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
@@ -118,11 +96,11 @@ drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
return ERR_PTR(-ENOMEM);
driver->driver_features = features;
- kdev = devm_drm_dev_alloc(dev, driver, struct kunit_dev, base);
- if (IS_ERR(kdev))
- return ERR_CAST(kdev);
+ container = __devm_drm_dev_alloc(dev, driver, size, offset);
+ if (IS_ERR(container))
+ return ERR_CAST(container);
- drm = &kdev->base;
+ drm = container + offset;
drm->mode_config.funcs = &drm_mode_config_funcs;
ret = drmm_mode_config_init(drm);
@@ -131,7 +109,7 @@ drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
return drm;
}
-EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_drm_device);
+EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tests/drm_modes_test.c b/drivers/gpu/drm/tests/drm_modes_test.c
index d1e9f3c0433a..bc4aa2ce78be 100644
--- a/drivers/gpu/drm/tests/drm_modes_test.c
+++ b/drivers/gpu/drm/tests/drm_modes_test.c
@@ -26,8 +26,9 @@ static int drm_test_modes_init(struct kunit *test)
priv->dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
- priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev,
- DRIVER_MODESET);
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
test->priv = priv;
diff --git a/drivers/gpu/drm/tests/drm_probe_helper_test.c b/drivers/gpu/drm/tests/drm_probe_helper_test.c
index 63a3bd1a6e4d..e5bd967fe8af 100644
--- a/drivers/gpu/drm/tests/drm_probe_helper_test.c
+++ b/drivers/gpu/drm/tests/drm_probe_helper_test.c
@@ -43,8 +43,9 @@ static int drm_probe_helper_test_init(struct kunit *test)
priv->dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev);
- priv->drm = drm_kunit_helper_alloc_drm_device(test, priv->dev,
- DRIVER_MODESET | DRIVER_ATOMIC);
+ priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev,
+ sizeof(*priv->drm), 0,
+ DRIVER_MODESET | DRIVER_ATOMIC);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm);
connector = &priv->connector;
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index b4277fe92c38..df99fda95e89 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -10,7 +10,35 @@ struct device *drm_kunit_helper_alloc_device(struct kunit *test);
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev);
struct drm_device *
-drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
- u32 features);
+__drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
+ size_t size, size_t offset,
+ u32 features);
+
+/**
+ * drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
+ * @_test: The test context object
+ * @_dev: The parent device object
+ * @_type: the type of the struct which contains struct &drm_device
+ * @_member: the name of the &drm_device within @_type.
+ * @_features: Mocked DRM device driver features
+ *
+ * This function creates a struct &drm_driver and will create a struct
+ * &drm_device from @_dev and that driver.
+ *
+ * @_dev should be allocated using drm_kunit_helper_alloc_device().
+ *
+ * The driver is tied to the @_test context and will get cleaned at the
+ * end of the test. The drm_device is allocated through
+ * devm_drm_dev_alloc() and will thus be freed through a device-managed
+ * resource.
+ *
+ * Returns:
+ * A pointer to the new drm_device, or an ERR_PTR() otherwise.
+ */
+#define drm_kunit_helper_alloc_drm_device(_test, _dev, _type, _member, _feat) \
+ ((_type *)__drm_kunit_helper_alloc_drm_device(_test, _dev, \
+ sizeof(_type), \
+ offsetof(_type, _member), \
+ _feat))
#endif // DRM_KUNIT_HELPERS_H_
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 11/20] drm/tests: helpers: Allow to pass a custom drm_driver
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (9 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 10/20] drm/tests: helpers: Allow for a custom device struct to be allocated Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 12/20] drm/tests: Add a test for DRM managed actions Maxime Ripard
` (9 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
Some tests will need to provide their own drm_driver instead of relying
on the dumb one in the helpers, so let's create a helper that allows to
do so.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/drm_kunit_helpers.c | 15 +++------
include/drm/drm_kunit_helpers.h | 51 +++++++++++++++++++++++++++++--
2 files changed, 54 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index b5485ab8fbf9..e98b4150f556 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -82,20 +82,15 @@ void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
struct drm_device *
-__drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
- size_t size, size_t offset,
- u32 features)
+__drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
+ struct device *dev,
+ size_t size, size_t offset,
+ const struct drm_driver *driver)
{
struct drm_device *drm;
- struct drm_driver *driver;
void *container;
int ret;
- driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
- if (!driver)
- return ERR_PTR(-ENOMEM);
-
- driver->driver_features = features;
container = __devm_drm_dev_alloc(dev, driver, size, offset);
if (IS_ERR(container))
return ERR_CAST(container);
@@ -109,7 +104,7 @@ __drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
return drm;
}
-EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device);
+EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL");
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index df99fda95e89..ed013fdcc1ff 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -3,6 +3,8 @@
#ifndef DRM_KUNIT_HELPERS_H_
#define DRM_KUNIT_HELPERS_H_
+#include <kunit/test.h>
+
struct drm_device;
struct kunit;
@@ -10,9 +12,54 @@ struct device *drm_kunit_helper_alloc_device(struct kunit *test);
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev);
struct drm_device *
-__drm_kunit_helper_alloc_drm_device(struct kunit *test, struct device *dev,
+__drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
+ struct device *dev,
+ size_t size, size_t offset,
+ const struct drm_driver *driver);
+
+/**
+ * drm_kunit_helper_alloc_drm_device_with_driver - Allocates a mock DRM device for KUnit tests
+ * @_test: The test context object
+ * @_dev: The parent device object
+ * @_type: the type of the struct which contains struct &drm_device
+ * @_member: the name of the &drm_device within @_type.
+ * @_drv: Mocked DRM device driver features
+ *
+ * This function creates a struct &drm_device from @_dev and @_drv.
+ *
+ * @_dev should be allocated using drm_kunit_helper_alloc_device().
+ *
+ * The driver is tied to the @_test context and will get cleaned at the
+ * end of the test. The drm_device is allocated through
+ * devm_drm_dev_alloc() and will thus be freed through a device-managed
+ * resource.
+ *
+ * Returns:
+ * A pointer to the new drm_device, or an ERR_PTR() otherwise.
+ */
+#define drm_kunit_helper_alloc_drm_device_with_driver(_test, _dev, _type, _member, _drv) \
+ ((_type *)__drm_kunit_helper_alloc_drm_device_with_driver(_test, _dev, \
+ sizeof(_type), \
+ offsetof(_type, _member), \
+ _drv))
+
+static inline struct drm_device *
+__drm_kunit_helper_alloc_drm_device(struct kunit *test,
+ struct device *dev,
size_t size, size_t offset,
- u32 features);
+ u32 features)
+{
+ struct drm_driver *driver;
+
+ driver = kunit_kzalloc(test, sizeof(*driver), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, driver);
+
+ driver->driver_features = features;
+
+ return __drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
+ size, offset,
+ driver);
+}
/**
* drm_kunit_helper_alloc_drm_device - Allocates a mock DRM device for KUnit tests
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 12/20] drm/tests: Add a test for DRM managed actions
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (10 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 11/20] drm/tests: helpers: Allow to pass a custom drm_driver Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 13/20] drm/vc4: Move HVS state to main header Maxime Ripard
` (8 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
DRM-managed actions are supposed to be ran whenever the device is
released. Let's introduce a basic unit test to make sure it happens.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/tests/Makefile | 1 +
drivers/gpu/drm/tests/drm_managed_test.c | 71 ++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+)
diff --git a/drivers/gpu/drm/tests/Makefile b/drivers/gpu/drm/tests/Makefile
index ef14bd481139..aaf357e29c65 100644
--- a/drivers/gpu/drm/tests/Makefile
+++ b/drivers/gpu/drm/tests/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_DRM_KUNIT_TEST) += \
drm_format_helper_test.o \
drm_format_test.o \
drm_framebuffer_test.o \
+ drm_managed_test.o \
drm_mm_test.o \
drm_modes_test.o \
drm_plane_helper_test.o \
diff --git a/drivers/gpu/drm/tests/drm_managed_test.c b/drivers/gpu/drm/tests/drm_managed_test.c
new file mode 100644
index 000000000000..1652dca11d30
--- /dev/null
+++ b/drivers/gpu/drm/tests/drm_managed_test.c
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_managed.h>
+
+#include <kunit/resource.h>
+
+#include <linux/device.h>
+
+/* Ought to be enough for anybody */
+#define TEST_TIMEOUT_MS 100
+
+struct managed_test_priv {
+ bool action_done;
+ wait_queue_head_t action_wq;
+};
+
+static void drm_action(struct drm_device *drm, void *ptr)
+{
+ struct managed_test_priv *priv = ptr;
+
+ priv->action_done = true;
+ wake_up_interruptible(&priv->action_wq);
+}
+
+static void drm_test_managed_run_action(struct kunit *test)
+{
+ struct managed_test_priv *priv;
+ struct drm_device *drm;
+ struct device *dev;
+ int ret;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv);
+ init_waitqueue_head(&priv->action_wq);
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ drm = __drm_kunit_helper_alloc_drm_device(test, dev, sizeof(*drm), 0, DRIVER_MODESET);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm);
+
+ ret = drmm_add_action_or_reset(drm, drm_action, priv);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ ret = drm_dev_register(drm, 0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, dev);
+
+ ret = wait_event_interruptible_timeout(priv->action_wq, priv->action_done,
+ msecs_to_jiffies(TEST_TIMEOUT_MS));
+ KUNIT_EXPECT_GT(test, ret, 0);
+}
+
+static struct kunit_case drm_managed_tests[] = {
+ KUNIT_CASE(drm_test_managed_run_action),
+ {}
+};
+
+static struct kunit_suite drm_managed_test_suite = {
+ .name = "drm-test-managed",
+ .test_cases = drm_managed_tests
+};
+
+kunit_test_suite(drm_managed_test_suite);
+
+MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
+MODULE_LICENSE("GPL");
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 13/20] drm/vc4: Move HVS state to main header
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (11 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 12/20] drm/tests: Add a test for DRM managed actions Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 14/20] drm/vc4: crtc: Introduce a lower-level crtc init helper Maxime Ripard
` (7 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
In order to introduce unit tests for the HVS state computation, we'll
need access to the vc4_hvs_state struct definition and its associated
helpers.
Let's move them in our driver header.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_drv.h | 23 +++++++++++++++++++++++
drivers/gpu/drm/vc4/vc4_kms.c | 25 +++----------------------
2 files changed, 26 insertions(+), 22 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 6af615c2eb65..051c2e3b6d43 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -355,6 +355,29 @@ struct vc4_hvs {
bool vc5_hdmi_enable_4096by2160;
};
+#define HVS_NUM_CHANNELS 3
+
+struct vc4_hvs_state {
+ struct drm_private_state base;
+ unsigned long core_clock_rate;
+
+ struct {
+ unsigned in_use: 1;
+ unsigned long fifo_load;
+ struct drm_crtc_commit *pending_commit;
+ } fifo_state[HVS_NUM_CHANNELS];
+};
+
+static inline struct vc4_hvs_state *
+to_vc4_hvs_state(const struct drm_private_state *priv)
+{
+ return container_of(priv, struct vc4_hvs_state, base);
+}
+
+struct vc4_hvs_state *vc4_hvs_get_global_state(struct drm_atomic_state *state);
+struct vc4_hvs_state *vc4_hvs_get_old_global_state(const struct drm_atomic_state *state);
+struct vc4_hvs_state *vc4_hvs_get_new_global_state(const struct drm_atomic_state *state);
+
struct vc4_plane {
struct drm_plane base;
};
diff --git a/drivers/gpu/drm/vc4/vc4_kms.c b/drivers/gpu/drm/vc4/vc4_kms.c
index 7282545c54a1..53d9f30460cf 100644
--- a/drivers/gpu/drm/vc4/vc4_kms.c
+++ b/drivers/gpu/drm/vc4/vc4_kms.c
@@ -25,8 +25,6 @@
#include "vc4_drv.h"
#include "vc4_regs.h"
-#define HVS_NUM_CHANNELS 3
-
struct vc4_ctm_state {
struct drm_private_state base;
struct drm_color_ctm *ctm;
@@ -39,23 +37,6 @@ to_vc4_ctm_state(const struct drm_private_state *priv)
return container_of(priv, struct vc4_ctm_state, base);
}
-struct vc4_hvs_state {
- struct drm_private_state base;
- unsigned long core_clock_rate;
-
- struct {
- unsigned in_use: 1;
- unsigned long fifo_load;
- struct drm_crtc_commit *pending_commit;
- } fifo_state[HVS_NUM_CHANNELS];
-};
-
-static struct vc4_hvs_state *
-to_vc4_hvs_state(const struct drm_private_state *priv)
-{
- return container_of(priv, struct vc4_hvs_state, base);
-}
-
struct vc4_load_tracker_state {
struct drm_private_state base;
u64 hvs_load;
@@ -191,7 +172,7 @@ vc4_ctm_commit(struct vc4_dev *vc4, struct drm_atomic_state *state)
VC4_SET_FIELD(ctm_state->fifo, SCALER_OLEDOFFS_DISPFIFO));
}
-static struct vc4_hvs_state *
+struct vc4_hvs_state *
vc4_hvs_get_new_global_state(const struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
@@ -204,7 +185,7 @@ vc4_hvs_get_new_global_state(const struct drm_atomic_state *state)
return to_vc4_hvs_state(priv_state);
}
-static struct vc4_hvs_state *
+struct vc4_hvs_state *
vc4_hvs_get_old_global_state(const struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
@@ -217,7 +198,7 @@ vc4_hvs_get_old_global_state(const struct drm_atomic_state *state)
return to_vc4_hvs_state(priv_state);
}
-static struct vc4_hvs_state *
+struct vc4_hvs_state *
vc4_hvs_get_global_state(struct drm_atomic_state *state)
{
struct vc4_dev *vc4 = to_vc4_dev(state->dev);
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 14/20] drm/vc4: crtc: Introduce a lower-level crtc init helper
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (12 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 13/20] drm/vc4: Move HVS state to main header Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 15/20] drm/vc4: crtc: Make encoder lookup helper public Maxime Ripard
` (6 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The current vc4_crtc_init() helper assumes that we will be using
hardware planes and calls vc4_plane_init().
While it's a reasonable assumption, we'll want to mock the plane and
thus provide our own. Let's create a helper that will take the plane as
an argument.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 70 ++++++++++++++++++++++++++++++------------
drivers/gpu/drm/vc4/vc4_drv.h | 6 ++++
2 files changed, 57 insertions(+), 19 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 333529ed3a0d..5f7f50add46e 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -1286,31 +1286,38 @@ static void vc4_set_crtc_possible_masks(struct drm_device *drm,
}
}
-int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
- struct vc4_crtc *vc4_crtc,
- const struct vc4_crtc_data *data,
- const struct drm_crtc_funcs *crtc_funcs,
- const struct drm_crtc_helper_funcs *crtc_helper_funcs,
- bool feeds_txp)
+/**
+ * __vc4_crtc_init - Initializes a CRTC
+ * @drm: DRM Device
+ * @pdev: CRTC Platform Device
+ * @vc4_crtc: CRTC Object to Initialize
+ * @data: Configuration data associated with this CRTC
+ * @primary_plane: Primary plane for CRTC
+ * @crtc_funcs: Callbacks for the new CRTC
+ * @crtc_helper_funcs: Helper Callbacks for the new CRTC
+ * @feeds_txp: Is this CRTC connected to the TXP?
+ *
+ * Initializes our private CRTC structure. This function is mostly
+ * relevant for KUnit testing, all other users should use
+ * vc4_crtc_init() instead.
+ *
+ * Returns:
+ * 0 on success, a negative error code on failure.
+ */
+int __vc4_crtc_init(struct drm_device *drm,
+ struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc,
+ const struct vc4_crtc_data *data,
+ struct drm_plane *primary_plane,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp)
{
struct vc4_dev *vc4 = to_vc4_dev(drm);
struct drm_crtc *crtc = &vc4_crtc->base;
- struct drm_plane *primary_plane;
unsigned int i;
int ret;
- /* For now, we create just the primary and the legacy cursor
- * planes. We should be able to stack more planes on easily,
- * but to do that we would need to compute the bandwidth
- * requirement of the plane configuration, and reject ones
- * that will take too much.
- */
- primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
- if (IS_ERR(primary_plane)) {
- dev_err(drm->dev, "failed to construct primary plane\n");
- return PTR_ERR(primary_plane);
- }
-
vc4_crtc->data = data;
vc4_crtc->pdev = pdev;
vc4_crtc->feeds_txp = feeds_txp;
@@ -1342,6 +1349,31 @@ int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
return 0;
}
+int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc,
+ const struct vc4_crtc_data *data,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp)
+{
+ struct drm_plane *primary_plane;
+
+ /* For now, we create just the primary and the legacy cursor
+ * planes. We should be able to stack more planes on easily,
+ * but to do that we would need to compute the bandwidth
+ * requirement of the plane configuration, and reject ones
+ * that will take too much.
+ */
+ primary_plane = vc4_plane_init(drm, DRM_PLANE_TYPE_PRIMARY, 0);
+ if (IS_ERR(primary_plane)) {
+ dev_err(drm->dev, "failed to construct primary plane\n");
+ return PTR_ERR(primary_plane);
+ }
+
+ return __vc4_crtc_init(drm, pdev, vc4_crtc, data, primary_plane,
+ crtc_funcs, crtc_helper_funcs, feeds_txp);
+}
+
static int vc4_crtc_bind(struct device *dev, struct device *master, void *data)
{
struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 051c2e3b6d43..cd2002fff115 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -888,6 +888,12 @@ int vc4_bo_debugfs_init(struct drm_minor *minor);
/* vc4_crtc.c */
extern struct platform_driver vc4_crtc_driver;
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc);
+int __vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
+ struct vc4_crtc *vc4_crtc, const struct vc4_crtc_data *data,
+ struct drm_plane *primary_plane,
+ const struct drm_crtc_funcs *crtc_funcs,
+ const struct drm_crtc_helper_funcs *crtc_helper_funcs,
+ bool feeds_txp);
int vc4_crtc_init(struct drm_device *drm, struct platform_device *pdev,
struct vc4_crtc *vc4_crtc, const struct vc4_crtc_data *data,
const struct drm_crtc_funcs *crtc_funcs,
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 15/20] drm/vc4: crtc: Make encoder lookup helper public
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (13 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 14/20] drm/vc4: crtc: Introduce a lower-level crtc init helper Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 16/20] drm/vc4: hvs: Provide a function to initialize the HVS structure Maxime Ripard
` (5 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
We'll need a function that looks up an encoder by its vc4_encoder_type.
Such a function is already present in the CRTC code, so let's make it
public so that we can reuse it in the unit tests.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 17 +----------------
drivers/gpu/drm/vc4/vc4_drv.h | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 16 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 5f7f50add46e..195d2b61839d 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -486,21 +486,6 @@ static int vc4_crtc_disable(struct drm_crtc *crtc,
return 0;
}
-static struct drm_encoder *vc4_crtc_get_encoder_by_type(struct drm_crtc *crtc,
- enum vc4_encoder_type type)
-{
- struct drm_encoder *encoder;
-
- drm_for_each_encoder(encoder, crtc->dev) {
- struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
-
- if (vc4_encoder->type == type)
- return encoder;
- }
-
- return NULL;
-}
-
int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
{
struct drm_device *drm = crtc->dev;
@@ -536,7 +521,7 @@ int vc4_crtc_disable_at_boot(struct drm_crtc *crtc)
pv_data = vc4_crtc_to_vc4_pv_data(vc4_crtc);
encoder_type = pv_data->encoder_types[encoder_sel];
- encoder = vc4_crtc_get_encoder_by_type(crtc, encoder_type);
+ encoder = vc4_find_encoder_by_type(drm, encoder_type);
if (WARN_ON(!encoder))
return 0;
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index cd2002fff115..54352db48476 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -495,6 +495,22 @@ to_vc4_encoder(const struct drm_encoder *encoder)
return container_of(encoder, struct vc4_encoder, base);
}
+static inline
+struct drm_encoder *vc4_find_encoder_by_type(struct drm_device *drm,
+ enum vc4_encoder_type type)
+{
+ struct drm_encoder *encoder;
+
+ drm_for_each_encoder(encoder, drm) {
+ struct vc4_encoder *vc4_encoder = to_vc4_encoder(encoder);
+
+ if (vc4_encoder->type == type)
+ return encoder;
+ }
+
+ return NULL;
+}
+
struct vc4_crtc_data {
const char *name;
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 16/20] drm/vc4: hvs: Provide a function to initialize the HVS structure
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (14 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 15/20] drm/vc4: crtc: Make encoder lookup helper public Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-01 15:11 ` [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure Maxime Ripard
` (4 subsequent siblings)
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
We'll need to initialize the HVS structure without a backing device to
create a mock we'll use for testing.
Split the structure initialization part into a separate function.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_drv.h | 1 +
drivers/gpu/drm/vc4/vc4_hvs.c | 81 +++++++++++++++++++++++++------------------
2 files changed, 48 insertions(+), 34 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 54352db48476..e0be7a81a24a 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -1009,6 +1009,7 @@ void vc4_irq_reset(struct drm_device *dev);
/* vc4_hvs.c */
extern struct platform_driver vc4_hvs_driver;
+struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev);
void vc4_hvs_stop_channel(struct vc4_hvs *hvs, unsigned int output);
int vc4_hvs_get_fifo_from_output(struct vc4_hvs *hvs, unsigned int output);
u8 vc4_hvs_get_fifo_frame_count(struct vc4_hvs *hvs, unsigned int fifo);
diff --git a/drivers/gpu/drm/vc4/vc4_hvs.c b/drivers/gpu/drm/vc4/vc4_hvs.c
index c4453a5ae163..94c29f8547bb 100644
--- a/drivers/gpu/drm/vc4/vc4_hvs.c
+++ b/drivers/gpu/drm/vc4/vc4_hvs.c
@@ -768,22 +768,60 @@ int vc4_hvs_debugfs_init(struct drm_minor *minor)
return 0;
}
-static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+struct vc4_hvs *__vc4_hvs_alloc(struct vc4_dev *vc4, struct platform_device *pdev)
{
- struct platform_device *pdev = to_platform_device(dev);
- struct drm_device *drm = dev_get_drvdata(master);
- struct vc4_dev *vc4 = to_vc4_dev(drm);
- struct vc4_hvs *hvs = NULL;
- int ret;
- u32 dispctrl;
- u32 reg;
+ struct drm_device *drm = &vc4->base;
+ struct vc4_hvs *hvs;
hvs = drmm_kzalloc(drm, sizeof(*hvs), GFP_KERNEL);
if (!hvs)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
+
hvs->vc4 = vc4;
hvs->pdev = pdev;
+ spin_lock_init(&hvs->mm_lock);
+
+ /* Set up the HVS display list memory manager. We never
+ * overwrite the setup from the bootloader (just 128b out of
+ * our 16K), since we don't want to scramble the screen when
+ * transitioning from the firmware's boot setup to runtime.
+ */
+ drm_mm_init(&hvs->dlist_mm,
+ HVS_BOOTLOADER_DLIST_END,
+ (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
+
+ /* Set up the HVS LBM memory manager. We could have some more
+ * complicated data structure that allowed reuse of LBM areas
+ * between planes when they don't overlap on the screen, but
+ * for now we just allocate globally.
+ */
+ if (!vc4->is_vc5)
+ /* 48k words of 2x12-bit pixels */
+ drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
+ else
+ /* 60k words of 4x12-bit pixels */
+ drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
+
+ vc4->hvs = hvs;
+
+ return hvs;
+}
+
+static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct vc4_dev *vc4 = to_vc4_dev(drm);
+ struct vc4_hvs *hvs = NULL;
+ int ret;
+ u32 dispctrl;
+ u32 reg;
+
+ hvs = __vc4_hvs_alloc(vc4, NULL);
+ if (IS_ERR(hvs))
+ return PTR_ERR(hvs);
+
hvs->regs = vc4_ioremap_regs(pdev, 0);
if (IS_ERR(hvs->regs))
return PTR_ERR(hvs->regs);
@@ -835,29 +873,6 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
else
hvs->dlist = hvs->regs + SCALER5_DLIST_START;
- spin_lock_init(&hvs->mm_lock);
-
- /* Set up the HVS display list memory manager. We never
- * overwrite the setup from the bootloader (just 128b out of
- * our 16K), since we don't want to scramble the screen when
- * transitioning from the firmware's boot setup to runtime.
- */
- drm_mm_init(&hvs->dlist_mm,
- HVS_BOOTLOADER_DLIST_END,
- (SCALER_DLIST_SIZE >> 2) - HVS_BOOTLOADER_DLIST_END);
-
- /* Set up the HVS LBM memory manager. We could have some more
- * complicated data structure that allowed reuse of LBM areas
- * between planes when they don't overlap on the screen, but
- * for now we just allocate globally.
- */
- if (!vc4->is_vc5)
- /* 48k words of 2x12-bit pixels */
- drm_mm_init(&hvs->lbm_mm, 0, 48 * 1024);
- else
- /* 60k words of 4x12-bit pixels */
- drm_mm_init(&hvs->lbm_mm, 0, 60 * 1024);
-
/* Upload filter kernels. We only have the one for now, so we
* keep it around for the lifetime of the driver.
*/
@@ -867,8 +882,6 @@ static int vc4_hvs_bind(struct device *dev, struct device *master, void *data)
if (ret)
return ret;
- vc4->hvs = hvs;
-
reg = HVS_READ(SCALER_DISPECTRL);
reg &= ~SCALER_DISPECTRL_DSP2_MUX_MASK;
HVS_WRITE(SCALER_DISPECTRL,
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (15 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 16/20] drm/vc4: hvs: Provide a function to initialize the HVS structure Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 14:08 ` Maíra Canal
2022-12-01 15:11 ` [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register Maxime Ripard
` (3 subsequent siblings)
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
In order to test the current atomic_check hooks we need to have a DRM
device that has roughly the same capabilities and layout that the actual
hardware. We'll also need a bunch of functions to create arbitrary
atomic states.
Let's create some helpers to create a device that behaves like the real
one, and some helpers to maintain the atomic state we want to check.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/Kconfig | 16 +++
drivers/gpu/drm/vc4/Makefile | 6 +
drivers/gpu/drm/vc4/tests/.kunitconfig | 13 ++
drivers/gpu/drm/vc4/tests/vc4_mock.c | 200 ++++++++++++++++++++++++++++
drivers/gpu/drm/vc4/tests/vc4_mock.h | 60 +++++++++
drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c | 41 ++++++
drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 99 ++++++++++++++
drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 47 +++++++
drivers/gpu/drm/vc4/vc4_crtc.c | 20 +--
drivers/gpu/drm/vc4/vc4_drv.c | 4 +-
drivers/gpu/drm/vc4/vc4_drv.h | 16 +++
drivers/gpu/drm/vc4/vc4_txp.c | 2 +-
12 files changed, 511 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
index 246305d17a52..f423941c028d 100644
--- a/drivers/gpu/drm/vc4/Kconfig
+++ b/drivers/gpu/drm/vc4/Kconfig
@@ -34,3 +34,19 @@ config DRM_VC4_HDMI_CEC
help
Choose this option if you have a Broadcom VC4 GPU
and want to use CEC.
+
+config DRM_VC4_KUNIT_TEST
+ bool "KUnit tests for VC4" if !KUNIT_ALL_TESTS
+ depends on DRM_VC4 && KUNIT
+ select DRM_KUNIT_TEST_HELPERS
+ default KUNIT_ALL_TESTS
+ help
+ This builds unit tests for the VC4 DRM/KMS driver. This option is
+ not useful for distributions or general kernels, but only for kernel
+ developers working on the VC4 driver.
+
+ For more information on KUnit and unit tests in general,
+ please refer to the KUnit documentation in
+ Documentation/dev-tools/kunit/.
+
+ If in doubt, say "N".
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index d0163e18e9ca..f974a8c80e2f 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -25,6 +25,12 @@ vc4-y := \
vc4_validate.o \
vc4_validate_shaders.o
+vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
+ tests/vc4_mock.o \
+ tests/vc4_mock_crtc.o \
+ tests/vc4_mock_output.o \
+ tests/vc4_mock_plane.o
+
vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
obj-$(CONFIG_DRM_VC4) += vc4.o
diff --git a/drivers/gpu/drm/vc4/tests/.kunitconfig b/drivers/gpu/drm/vc4/tests/.kunitconfig
new file mode 100644
index 000000000000..b503e9036c7f
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/.kunitconfig
@@ -0,0 +1,13 @@
+CONFIG_ARCH_BCM=y
+CONFIG_ARCH_BCM2835=y
+CONFIG_BCM2835_MBOX=y
+CONFIG_KUNIT=y
+CONFIG_DRM=y
+CONFIG_DRM_VC4=y
+CONFIG_DRM_VC4_KUNIT_TEST=y
+CONFIG_MAILBOX=y
+CONFIG_RASPBERRYPI_FIRMWARE=y
+CONFIG_SND=y
+CONFIG_SND_SOC=y
+CONFIG_SOUND=y
+CONFIG_COMMON_CLK=y
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c
new file mode 100644
index 000000000000..a4bed26af32f
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_drv.h>
+#include <drm/drm_kunit_helpers.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+struct vc4_mock_output_desc {
+ enum vc4_encoder_type vc4_encoder_type;
+ unsigned int encoder_type;
+ unsigned int connector_type;
+};
+
+#define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \
+ { \
+ .vc4_encoder_type = _vc4_type, \
+ .encoder_type = _etype, \
+ .connector_type = _ctype, \
+ }
+
+struct vc4_mock_pipe_desc {
+ const struct vc4_crtc_data *data;
+ const struct vc4_mock_output_desc *outputs;
+ unsigned int noutputs;
+};
+
+#define VC4_MOCK_CRTC_DESC(_data, ...) \
+ { \
+ .data = _data, \
+ .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \
+ .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \
+ sizeof(struct vc4_mock_output_desc), \
+ }
+
+#define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \
+ VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__)
+
+struct vc4_mock_desc {
+ const struct vc4_mock_pipe_desc *pipes;
+ unsigned int npipes;
+};
+
+#define VC4_MOCK_DESC(...) \
+ { \
+ .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \
+ .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \
+ sizeof(struct vc4_mock_pipe_desc), \
+ }
+
+static const struct vc4_mock_desc vc4_mock =
+ VC4_MOCK_DESC(
+ VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
+ DRM_MODE_ENCODER_VIRTUAL,
+ DRM_MODE_CONNECTOR_WRITEBACK)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
+ DRM_MODE_ENCODER_DPI,
+ DRM_MODE_CONNECTOR_DPI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
+ DRM_MODE_ENCODER_TVDAC,
+ DRM_MODE_CONNECTOR_Composite)),
+);
+
+static const struct vc4_mock_desc vc5_mock =
+ VC4_MOCK_DESC(
+ VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
+ DRM_MODE_ENCODER_VIRTUAL,
+ DRM_MODE_CONNECTOR_WRITEBACK)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI),
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
+ DRM_MODE_ENCODER_DPI,
+ DRM_MODE_CONNECTOR_DPI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
+ DRM_MODE_ENCODER_DSI,
+ DRM_MODE_CONNECTOR_DSI)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
+ DRM_MODE_ENCODER_TVDAC,
+ DRM_MODE_CONNECTOR_Composite)),
+ VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data,
+ VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1,
+ DRM_MODE_ENCODER_TMDS,
+ DRM_MODE_CONNECTOR_HDMIA)),
+);
+
+static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
+ const struct vc4_mock_pipe_desc *pipe)
+{
+ struct vc4_dummy_plane *dummy_plane;
+ struct drm_plane *plane;
+ struct vc4_dummy_crtc *dummy_crtc;
+ struct drm_crtc *crtc;
+ unsigned int i;
+
+ dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+
+ plane = &dummy_plane->plane.base;
+ dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
+
+ crtc = &dummy_crtc->crtc.base;
+ for (i = 0; i < pipe->noutputs; i++) {
+ const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i];
+ struct vc4_dummy_output *dummy_output;
+
+ dummy_output = vc4_dummy_output(test, drm, crtc,
+ mock_output->vc4_encoder_type,
+ mock_output->encoder_type,
+ mock_output->connector_type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
+ }
+
+ return 0;
+}
+
+static int __build_mock(struct kunit *test, struct drm_device *drm,
+ const struct vc4_mock_desc *mock)
+{
+ unsigned int i;
+
+ for (i = 0; i < mock->npipes; i++) {
+ const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i];
+ int ret;
+
+ ret = __build_one_pipe(test, drm, pipe);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ return 0;
+}
+
+static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
+{
+ struct drm_device *drm;
+ const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver;
+ const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock;
+ struct vc4_dev *vc4;
+ struct device *dev;
+ int ret;
+
+ dev = drm_kunit_helper_alloc_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
+
+ vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
+ struct vc4_dev, base,
+ drv);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ vc4->dev = dev;
+ vc4->is_vc5 = is_vc5;
+
+ vc4->hvs = __vc4_hvs_alloc(vc4, NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs);
+
+ drm = &vc4->base;
+ ret = __build_mock(test, drm, desc);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = vc4_kms_load(drm);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_dev_register(drm, 0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return vc4;
+}
+
+struct vc4_dev *vc4_mock_device(struct kunit *test)
+{
+ return __mock_device(test, false);
+}
+
+struct vc4_dev *vc5_mock_device(struct kunit *test)
+{
+ return __mock_device(test, true);
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
new file mode 100644
index 000000000000..ace5b2e00f4a
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef VC4_MOCK_H_
+#define VC4_MOCK_H_
+
+#include "../vc4_drv.h"
+
+static inline
+struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_encoder *encoder)
+{
+ struct drm_crtc *crtc;
+
+ KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1);
+
+ drm_for_each_crtc(crtc, drm)
+ if (encoder->possible_crtcs & drm_crtc_mask(crtc))
+ return crtc;
+
+ return NULL;
+}
+
+struct vc4_dummy_plane {
+ struct vc4_plane plane;
+};
+
+struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
+ struct drm_device *drm,
+ enum drm_plane_type type);
+
+struct vc4_dummy_crtc {
+ struct vc4_crtc crtc;
+};
+
+struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_plane *plane,
+ const struct vc4_crtc_data *data);
+
+struct vc4_dummy_output {
+ struct vc4_encoder encoder;
+ struct drm_connector connector;
+};
+
+struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ enum vc4_encoder_type vc4_encoder_type,
+ unsigned int kms_encoder_type,
+ unsigned int connector_type);
+
+struct vc4_dev *vc4_mock_device(struct kunit *test);
+struct vc4_dev *vc5_mock_device(struct kunit *test);
+
+int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
+ enum vc4_encoder_type type,
+ struct drm_atomic_state *state);
+
+#endif // VC4_MOCK_H_
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
new file mode 100644
index 000000000000..5d12d7beef0e
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
@@ -0,0 +1,41 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_crtc_helper_funcs vc4_dummy_crtc_helper_funcs = {
+ .atomic_check = vc4_crtc_atomic_check,
+};
+
+static const struct drm_crtc_funcs vc4_dummy_crtc_funcs = {
+ .atomic_destroy_state = vc4_crtc_destroy_state,
+ .atomic_duplicate_state = vc4_crtc_duplicate_state,
+ .reset = vc4_crtc_reset,
+};
+
+struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_plane *plane,
+ const struct vc4_crtc_data *data)
+{
+ struct vc4_dummy_crtc *dummy_crtc;
+ struct vc4_crtc *vc4_crtc;
+ int ret;
+
+ dummy_crtc = kunit_kzalloc(test, sizeof(*dummy_crtc), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
+
+ vc4_crtc = &dummy_crtc->crtc;
+ ret = __vc4_crtc_init(drm, NULL,
+ vc4_crtc, data, plane,
+ &vc4_dummy_crtc_funcs,
+ &vc4_dummy_crtc_helper_funcs,
+ false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return dummy_crtc;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
new file mode 100644
index 000000000000..cb16ab4451f7
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_connector.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_encoder.h>
+#include <drm/drm_modeset_helper_vtables.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs = {
+};
+
+static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .reset = drm_atomic_helper_connector_reset,
+};
+
+struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
+ struct drm_device *drm,
+ struct drm_crtc *crtc,
+ enum vc4_encoder_type vc4_encoder_type,
+ unsigned int kms_encoder_type,
+ unsigned int connector_type)
+{
+ struct vc4_dummy_output *dummy_output;
+ struct drm_connector *conn;
+ struct drm_encoder *enc;
+ int ret;
+
+ dummy_output = kunit_kzalloc(test, sizeof(*dummy_output), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
+ dummy_output->encoder.type = vc4_encoder_type;
+
+ enc = &dummy_output->encoder.base;
+ ret = drmm_encoder_init(drm, enc,
+ NULL,
+ kms_encoder_type,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ enc->possible_crtcs = drm_crtc_mask(crtc);
+
+ conn = &dummy_output->connector;
+ ret = drmm_connector_init(drm, conn,
+ &vc4_dummy_connector_funcs,
+ connector_type,
+ NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_connector_helper_add(conn, &vc4_dummy_connector_helper_funcs);
+ drm_connector_attach_encoder(conn, enc);
+
+ return dummy_output;
+}
+
+static const struct drm_display_mode default_mode = {
+ DRM_SIMPLE_MODE(640, 480, 64, 48)
+};
+
+int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
+ enum vc4_encoder_type type,
+ struct drm_atomic_state *state)
+{
+ struct vc4_dummy_output *output;
+ struct drm_connector *conn;
+ struct drm_connector_state *conn_state;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+ struct drm_crtc_state *crtc_state;
+ int ret;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ output = container_of(encoder, struct vc4_dummy_output, encoder.base);
+ conn = &output->connector;
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ crtc_state->active = true;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
new file mode 100644
index 000000000000..62b18f5f41db
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane.h>
+
+#include <kunit/test.h>
+
+#include "vc4_mock.h"
+
+static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
+};
+
+static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
+ .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
+ .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
+ .reset = drm_atomic_helper_plane_reset,
+};
+
+static const uint32_t vc4_dummy_plane_formats[] = {
+ DRM_FORMAT_XRGB8888,
+};
+
+struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
+ struct drm_device *drm,
+ enum drm_plane_type type)
+{
+ struct vc4_dummy_plane *dummy_plane;
+ struct drm_plane *plane;
+
+ dummy_plane = drmm_universal_plane_alloc(drm,
+ struct vc4_dummy_plane, plane.base,
+ 0,
+ &vc4_dummy_plane_funcs,
+ vc4_dummy_plane_formats,
+ ARRAY_SIZE(vc4_dummy_plane_formats),
+ NULL,
+ DRM_PLANE_TYPE_PRIMARY,
+ NULL);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
+
+ plane = &dummy_plane->plane.base;
+ drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs);
+
+ return dummy_plane;
+}
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 195d2b61839d..7d1a696477ce 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -675,8 +675,8 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
}
}
-static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
- struct drm_atomic_state *state)
+int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state)
{
struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
crtc);
@@ -1116,7 +1116,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
.get_scanout_position = vc4_crtc_get_scanout_position,
};
-static const struct vc4_pv_data bcm2835_pv0_data = {
+const struct vc4_pv_data bcm2835_pv0_data = {
.base = {
.name = "pixelvalve-0",
.debugfs_name = "crtc0_regs",
@@ -1131,7 +1131,7 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
},
};
-static const struct vc4_pv_data bcm2835_pv1_data = {
+const struct vc4_pv_data bcm2835_pv1_data = {
.base = {
.name = "pixelvalve-1",
.debugfs_name = "crtc1_regs",
@@ -1146,7 +1146,7 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
},
};
-static const struct vc4_pv_data bcm2835_pv2_data = {
+const struct vc4_pv_data bcm2835_pv2_data = {
.base = {
.name = "pixelvalve-2",
.debugfs_name = "crtc2_regs",
@@ -1161,7 +1161,7 @@ static const struct vc4_pv_data bcm2835_pv2_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv0_data = {
+const struct vc4_pv_data bcm2711_pv0_data = {
.base = {
.name = "pixelvalve-0",
.debugfs_name = "crtc0_regs",
@@ -1176,7 +1176,7 @@ static const struct vc4_pv_data bcm2711_pv0_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv1_data = {
+const struct vc4_pv_data bcm2711_pv1_data = {
.base = {
.name = "pixelvalve-1",
.debugfs_name = "crtc1_regs",
@@ -1191,7 +1191,7 @@ static const struct vc4_pv_data bcm2711_pv1_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv2_data = {
+const struct vc4_pv_data bcm2711_pv2_data = {
.base = {
.name = "pixelvalve-2",
.debugfs_name = "crtc2_regs",
@@ -1205,7 +1205,7 @@ static const struct vc4_pv_data bcm2711_pv2_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv3_data = {
+const struct vc4_pv_data bcm2711_pv3_data = {
.base = {
.name = "pixelvalve-3",
.debugfs_name = "crtc3_regs",
@@ -1219,7 +1219,7 @@ static const struct vc4_pv_data bcm2711_pv3_data = {
},
};
-static const struct vc4_pv_data bcm2711_pv4_data = {
+const struct vc4_pv_data bcm2711_pv4_data = {
.base = {
.name = "pixelvalve-4",
.debugfs_name = "crtc4_regs",
diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
index 5990d8f8c363..3b0ae2c3e33c 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.c
+++ b/drivers/gpu/drm/vc4/vc4_drv.c
@@ -196,7 +196,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
};
-static const struct drm_driver vc4_drm_driver = {
+const struct drm_driver vc4_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM |
@@ -225,7 +225,7 @@ static const struct drm_driver vc4_drm_driver = {
.patchlevel = DRIVER_PATCHLEVEL,
};
-static const struct drm_driver vc5_drm_driver = {
+const struct drm_driver vc5_drm_driver = {
.driver_features = (DRIVER_MODESET |
DRIVER_ATOMIC |
DRIVER_GEM),
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index e0be7a81a24a..418f4f308e36 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -24,6 +24,9 @@
struct drm_device;
struct drm_gem_object;
+extern const struct drm_driver vc4_drm_driver;
+extern const struct drm_driver vc5_drm_driver;
+
/* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
* this.
*/
@@ -523,6 +526,8 @@ struct vc4_crtc_data {
int hvs_output;
};
+extern const struct vc4_crtc_data vc4_txp_crtc_data;
+
struct vc4_pv_data {
struct vc4_crtc_data base;
@@ -535,6 +540,15 @@ struct vc4_pv_data {
enum vc4_encoder_type encoder_types[4];
};
+extern const struct vc4_pv_data bcm2835_pv0_data;
+extern const struct vc4_pv_data bcm2835_pv1_data;
+extern const struct vc4_pv_data bcm2835_pv2_data;
+extern const struct vc4_pv_data bcm2711_pv0_data;
+extern const struct vc4_pv_data bcm2711_pv1_data;
+extern const struct vc4_pv_data bcm2711_pv2_data;
+extern const struct vc4_pv_data bcm2711_pv3_data;
+extern const struct vc4_pv_data bcm2711_pv4_data;
+
struct vc4_crtc {
struct drm_crtc base;
struct platform_device *pdev;
@@ -920,6 +934,8 @@ int vc4_page_flip(struct drm_crtc *crtc,
struct drm_pending_vblank_event *event,
uint32_t flags,
struct drm_modeset_acquire_ctx *ctx);
+int vc4_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_atomic_state *state);
struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
void vc4_crtc_destroy_state(struct drm_crtc *crtc,
struct drm_crtc_state *state);
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index 4f7ce5d3e8ad..2b69454b8534 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -479,7 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-static const struct vc4_crtc_data vc4_txp_crtc_data = {
+const struct vc4_crtc_data vc4_txp_crtc_data = {
.name = "txp",
.debugfs_name = "txp_regs",
.hvs_available_channels = BIT(2),
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure
2022-12-01 15:11 ` [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure Maxime Ripard
@ 2022-12-07 14:08 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:08 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> In order to test the current atomic_check hooks we need to have a DRM
> device that has roughly the same capabilities and layout that the actual
> hardware. We'll also need a bunch of functions to create arbitrary
> atomic states.
>
> Let's create some helpers to create a device that behaves like the real
> one, and some helpers to maintain the atomic state we want to check.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
But it would be nice if you could fix the checkpatch problems in the
vc4/tests folder.
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Kconfig | 16 +++
> drivers/gpu/drm/vc4/Makefile | 6 +
> drivers/gpu/drm/vc4/tests/.kunitconfig | 13 ++
> drivers/gpu/drm/vc4/tests/vc4_mock.c | 200 ++++++++++++++++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 60 +++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c | 41 ++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 99 ++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 47 +++++++
> drivers/gpu/drm/vc4/vc4_crtc.c | 20 +--
> drivers/gpu/drm/vc4/vc4_drv.c | 4 +-
> drivers/gpu/drm/vc4/vc4_drv.h | 16 +++
> drivers/gpu/drm/vc4/vc4_txp.c | 2 +-
> 12 files changed, 511 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
> index 246305d17a52..f423941c028d 100644
> --- a/drivers/gpu/drm/vc4/Kconfig
> +++ b/drivers/gpu/drm/vc4/Kconfig
> @@ -34,3 +34,19 @@ config DRM_VC4_HDMI_CEC
> help
> Choose this option if you have a Broadcom VC4 GPU
> and want to use CEC.
> +
> +config DRM_VC4_KUNIT_TEST
> + bool "KUnit tests for VC4" if !KUNIT_ALL_TESTS
> + depends on DRM_VC4 && KUNIT
> + select DRM_KUNIT_TEST_HELPERS
> + default KUNIT_ALL_TESTS
> + help
> + This builds unit tests for the VC4 DRM/KMS driver. This option is
> + not useful for distributions or general kernels, but only for kernel
> + developers working on the VC4 driver.
> +
> + For more information on KUnit and unit tests in general,
> + please refer to the KUnit documentation in
> + Documentation/dev-tools/kunit/.
> +
> + If in doubt, say "N".
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index d0163e18e9ca..f974a8c80e2f 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -25,6 +25,12 @@ vc4-y := \
> vc4_validate.o \
> vc4_validate_shaders.o
>
> +vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> + tests/vc4_mock.o \
> + tests/vc4_mock_crtc.o \
> + tests/vc4_mock_output.o \
> + tests/vc4_mock_plane.o
> +
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> obj-$(CONFIG_DRM_VC4) += vc4.o
> diff --git a/drivers/gpu/drm/vc4/tests/.kunitconfig b/drivers/gpu/drm/vc4/tests/.kunitconfig
> new file mode 100644
> index 000000000000..b503e9036c7f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/.kunitconfig
> @@ -0,0 +1,13 @@
> +CONFIG_ARCH_BCM=y
> +CONFIG_ARCH_BCM2835=y
> +CONFIG_BCM2835_MBOX=y
> +CONFIG_KUNIT=y
> +CONFIG_DRM=y
> +CONFIG_DRM_VC4=y
> +CONFIG_DRM_VC4_KUNIT_TEST=y
> +CONFIG_MAILBOX=y
> +CONFIG_RASPBERRYPI_FIRMWARE=y
> +CONFIG_SND=y
> +CONFIG_SND_SOC=y
> +CONFIG_SOUND=y
> +CONFIG_COMMON_CLK=y
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> new file mode 100644
> index 000000000000..a4bed26af32f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_kunit_helpers.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +struct vc4_mock_output_desc {
> + enum vc4_encoder_type vc4_encoder_type;
> + unsigned int encoder_type;
> + unsigned int connector_type;
> +};
> +
> +#define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \
> + { \
> + .vc4_encoder_type = _vc4_type, \
> + .encoder_type = _etype, \
> + .connector_type = _ctype, \
> + }
> +
> +struct vc4_mock_pipe_desc {
> + const struct vc4_crtc_data *data;
> + const struct vc4_mock_output_desc *outputs;
> + unsigned int noutputs;
> +};
> +
> +#define VC4_MOCK_CRTC_DESC(_data, ...) \
> + { \
> + .data = _data, \
> + .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \
> + .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_output_desc), \
> + }
> +
> +#define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \
> + VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__)
> +
> +struct vc4_mock_desc {
> + const struct vc4_mock_pipe_desc *pipes;
> + unsigned int npipes;
> +};
> +
> +#define VC4_MOCK_DESC(...) \
> + { \
> + .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \
> + .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_pipe_desc), \
> + }
> +
> +static const struct vc4_mock_desc vc4_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> +);
> +
> +static const struct vc4_mock_desc vc5_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> +);
> +
> +static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_pipe_desc *pipe)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct drm_crtc *crtc;
> + unsigned int i;
> +
> + dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
> +
> + crtc = &dummy_crtc->crtc.base;
> + for (i = 0; i < pipe->noutputs; i++) {
> + const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i];
> + struct vc4_dummy_output *dummy_output;
> +
> + dummy_output = vc4_dummy_output(test, drm, crtc,
> + mock_output->vc4_encoder_type,
> + mock_output->encoder_type,
> + mock_output->connector_type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + }
> +
> + return 0;
> +}
> +
> +static int __build_mock(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_desc *mock)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < mock->npipes; i++) {
> + const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i];
> + int ret;
> +
> + ret = __build_one_pipe(test, drm, pipe);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + return 0;
> +}
> +
> +static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
> +{
> + struct drm_device *drm;
> + const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver;
> + const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock;
> + struct vc4_dev *vc4;
> + struct device *dev;
> + int ret;
> +
> + dev = drm_kunit_helper_alloc_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
> +
> + vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
> + struct vc4_dev, base,
> + drv);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + vc4->dev = dev;
> + vc4->is_vc5 = is_vc5;
> +
> + vc4->hvs = __vc4_hvs_alloc(vc4, NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs);
> +
> + drm = &vc4->base;
> + ret = __build_mock(test, drm, desc);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_kms_load(drm);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_dev_register(drm, 0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return vc4;
> +}
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, false);
> +}
> +
> +struct vc4_dev *vc5_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, true);
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> new file mode 100644
> index 000000000000..ace5b2e00f4a
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef VC4_MOCK_H_
> +#define VC4_MOCK_H_
> +
> +#include "../vc4_drv.h"
> +
> +static inline
> +struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_encoder *encoder)
> +{
> + struct drm_crtc *crtc;
> +
> + KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1);
> +
> + drm_for_each_crtc(crtc, drm)
> + if (encoder->possible_crtcs & drm_crtc_mask(crtc))
> + return crtc;
> +
> + return NULL;
> +}
> +
> +struct vc4_dummy_plane {
> + struct vc4_plane plane;
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type);
> +
> +struct vc4_dummy_crtc {
> + struct vc4_crtc crtc;
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data);
> +
> +struct vc4_dummy_output {
> + struct vc4_encoder encoder;
> + struct drm_connector connector;
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type);
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test);
> +struct vc4_dev *vc5_mock_device(struct kunit *test);
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state);
> +
> +#endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> new file mode 100644
> index 000000000000..5d12d7beef0e
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> @@ -0,0 +1,41 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_crtc_helper_funcs vc4_dummy_crtc_helper_funcs = {
> + .atomic_check = vc4_crtc_atomic_check,
> +};
> +
> +static const struct drm_crtc_funcs vc4_dummy_crtc_funcs = {
> + .atomic_destroy_state = vc4_crtc_destroy_state,
> + .atomic_duplicate_state = vc4_crtc_duplicate_state,
> + .reset = vc4_crtc_reset,
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data)
> +{
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct vc4_crtc *vc4_crtc;
> + int ret;
> +
> + dummy_crtc = kunit_kzalloc(test, sizeof(*dummy_crtc), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
> +
> + vc4_crtc = &dummy_crtc->crtc;
> + ret = __vc4_crtc_init(drm, NULL,
> + vc4_crtc, data, plane,
> + &vc4_dummy_crtc_funcs,
> + &vc4_dummy_crtc_helper_funcs,
> + false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return dummy_crtc;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> new file mode 100644
> index 000000000000..cb16ab4451f7
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs = {
> +};
> +
> +static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .reset = drm_atomic_helper_connector_reset,
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type)
> +{
> + struct vc4_dummy_output *dummy_output;
> + struct drm_connector *conn;
> + struct drm_encoder *enc;
> + int ret;
> +
> + dummy_output = kunit_kzalloc(test, sizeof(*dummy_output), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + dummy_output->encoder.type = vc4_encoder_type;
> +
> + enc = &dummy_output->encoder.base;
> + ret = drmm_encoder_init(drm, enc,
> + NULL,
> + kms_encoder_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + enc->possible_crtcs = drm_crtc_mask(crtc);
> +
> + conn = &dummy_output->connector;
> + ret = drmm_connector_init(drm, conn,
> + &vc4_dummy_connector_funcs,
> + connector_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_connector_helper_add(conn, &vc4_dummy_connector_helper_funcs);
> + drm_connector_attach_encoder(conn, enc);
> +
> + return dummy_output;
> +}
> +
> +static const struct drm_display_mode default_mode = {
> + DRM_SIMPLE_MODE(640, 480, 64, 48)
> +};
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state)
> +{
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_connector_state *conn_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state->active = true;
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> new file mode 100644
> index 000000000000..62b18f5f41db
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
> +};
> +
> +static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .reset = drm_atomic_helper_plane_reset,
> +};
> +
> +static const uint32_t vc4_dummy_plane_formats[] = {
> + DRM_FORMAT_XRGB8888,
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> +
> + dummy_plane = drmm_universal_plane_alloc(drm,
> + struct vc4_dummy_plane, plane.base,
> + 0,
> + &vc4_dummy_plane_funcs,
> + vc4_dummy_plane_formats,
> + ARRAY_SIZE(vc4_dummy_plane_formats),
> + NULL,
> + DRM_PLANE_TYPE_PRIMARY,
> + NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs);
> +
> + return dummy_plane;
> +}
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 195d2b61839d..7d1a696477ce 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -675,8 +675,8 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
> }
> }
>
> -static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> - struct drm_atomic_state *state)
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> {
> struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> crtc);
> @@ -1116,7 +1116,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
> .get_scanout_position = vc4_crtc_get_scanout_position,
> };
>
> -static const struct vc4_pv_data bcm2835_pv0_data = {
> +const struct vc4_pv_data bcm2835_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1131,7 +1131,7 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv1_data = {
> +const struct vc4_pv_data bcm2835_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1146,7 +1146,7 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv2_data = {
> +const struct vc4_pv_data bcm2835_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1161,7 +1161,7 @@ static const struct vc4_pv_data bcm2835_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv0_data = {
> +const struct vc4_pv_data bcm2711_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1176,7 +1176,7 @@ static const struct vc4_pv_data bcm2711_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv1_data = {
> +const struct vc4_pv_data bcm2711_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1191,7 +1191,7 @@ static const struct vc4_pv_data bcm2711_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv2_data = {
> +const struct vc4_pv_data bcm2711_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1205,7 +1205,7 @@ static const struct vc4_pv_data bcm2711_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv3_data = {
> +const struct vc4_pv_data bcm2711_pv3_data = {
> .base = {
> .name = "pixelvalve-3",
> .debugfs_name = "crtc3_regs",
> @@ -1219,7 +1219,7 @@ static const struct vc4_pv_data bcm2711_pv3_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv4_data = {
> +const struct vc4_pv_data bcm2711_pv4_data = {
> .base = {
> .name = "pixelvalve-4",
> .debugfs_name = "crtc4_regs",
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 5990d8f8c363..3b0ae2c3e33c 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -196,7 +196,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
> DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
> };
>
> -static const struct drm_driver vc4_drm_driver = {
> +const struct drm_driver vc4_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM |
> @@ -225,7 +225,7 @@ static const struct drm_driver vc4_drm_driver = {
> .patchlevel = DRIVER_PATCHLEVEL,
> };
>
> -static const struct drm_driver vc5_drm_driver = {
> +const struct drm_driver vc5_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index e0be7a81a24a..418f4f308e36 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -24,6 +24,9 @@
> struct drm_device;
> struct drm_gem_object;
>
> +extern const struct drm_driver vc4_drm_driver;
> +extern const struct drm_driver vc5_drm_driver;
> +
> /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
> * this.
> */
> @@ -523,6 +526,8 @@ struct vc4_crtc_data {
> int hvs_output;
> };
>
> +extern const struct vc4_crtc_data vc4_txp_crtc_data;
> +
> struct vc4_pv_data {
> struct vc4_crtc_data base;
>
> @@ -535,6 +540,15 @@ struct vc4_pv_data {
> enum vc4_encoder_type encoder_types[4];
> };
>
> +extern const struct vc4_pv_data bcm2835_pv0_data;
> +extern const struct vc4_pv_data bcm2835_pv1_data;
> +extern const struct vc4_pv_data bcm2835_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv0_data;
> +extern const struct vc4_pv_data bcm2711_pv1_data;
> +extern const struct vc4_pv_data bcm2711_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv3_data;
> +extern const struct vc4_pv_data bcm2711_pv4_data;
> +
> struct vc4_crtc {
> struct drm_crtc base;
> struct platform_device *pdev;
> @@ -920,6 +934,8 @@ int vc4_page_flip(struct drm_crtc *crtc,
> struct drm_pending_vblank_event *event,
> uint32_t flags,
> struct drm_modeset_acquire_ctx *ctx);
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state);
> struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
> void vc4_crtc_destroy_state(struct drm_crtc *crtc,
> struct drm_crtc_state *state);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 4f7ce5d3e8ad..2b69454b8534 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -479,7 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> -static const struct vc4_crtc_data vc4_txp_crtc_data = {
> +const struct vc4_crtc_data vc4_txp_crtc_data = {
> .name = "txp",
> .debugfs_name = "txp_regs",
> .hvs_available_channels = BIT(2),
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure
@ 2022-12-07 14:08 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:08 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
linux-kernel, dri-devel, Javier Martinez Canillas, linaro-mm-sig,
Brendan Higgins, David Gow, linux-media, Maíra Canal,
kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> In order to test the current atomic_check hooks we need to have a DRM
> device that has roughly the same capabilities and layout that the actual
> hardware. We'll also need a bunch of functions to create arbitrary
> atomic states.
>
> Let's create some helpers to create a device that behaves like the real
> one, and some helpers to maintain the atomic state we want to check.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
But it would be nice if you could fix the checkpatch problems in the
vc4/tests folder.
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Kconfig | 16 +++
> drivers/gpu/drm/vc4/Makefile | 6 +
> drivers/gpu/drm/vc4/tests/.kunitconfig | 13 ++
> drivers/gpu/drm/vc4/tests/vc4_mock.c | 200 ++++++++++++++++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 60 +++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c | 41 ++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 99 ++++++++++++++
> drivers/gpu/drm/vc4/tests/vc4_mock_plane.c | 47 +++++++
> drivers/gpu/drm/vc4/vc4_crtc.c | 20 +--
> drivers/gpu/drm/vc4/vc4_drv.c | 4 +-
> drivers/gpu/drm/vc4/vc4_drv.h | 16 +++
> drivers/gpu/drm/vc4/vc4_txp.c | 2 +-
> 12 files changed, 511 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Kconfig b/drivers/gpu/drm/vc4/Kconfig
> index 246305d17a52..f423941c028d 100644
> --- a/drivers/gpu/drm/vc4/Kconfig
> +++ b/drivers/gpu/drm/vc4/Kconfig
> @@ -34,3 +34,19 @@ config DRM_VC4_HDMI_CEC
> help
> Choose this option if you have a Broadcom VC4 GPU
> and want to use CEC.
> +
> +config DRM_VC4_KUNIT_TEST
> + bool "KUnit tests for VC4" if !KUNIT_ALL_TESTS
> + depends on DRM_VC4 && KUNIT
> + select DRM_KUNIT_TEST_HELPERS
> + default KUNIT_ALL_TESTS
> + help
> + This builds unit tests for the VC4 DRM/KMS driver. This option is
> + not useful for distributions or general kernels, but only for kernel
> + developers working on the VC4 driver.
> +
> + For more information on KUnit and unit tests in general,
> + please refer to the KUnit documentation in
> + Documentation/dev-tools/kunit/.
> +
> + If in doubt, say "N".
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index d0163e18e9ca..f974a8c80e2f 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -25,6 +25,12 @@ vc4-y := \
> vc4_validate.o \
> vc4_validate_shaders.o
>
> +vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> + tests/vc4_mock.o \
> + tests/vc4_mock_crtc.o \
> + tests/vc4_mock_output.o \
> + tests/vc4_mock_plane.o
> +
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> obj-$(CONFIG_DRM_VC4) += vc4.o
> diff --git a/drivers/gpu/drm/vc4/tests/.kunitconfig b/drivers/gpu/drm/vc4/tests/.kunitconfig
> new file mode 100644
> index 000000000000..b503e9036c7f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/.kunitconfig
> @@ -0,0 +1,13 @@
> +CONFIG_ARCH_BCM=y
> +CONFIG_ARCH_BCM2835=y
> +CONFIG_BCM2835_MBOX=y
> +CONFIG_KUNIT=y
> +CONFIG_DRM=y
> +CONFIG_DRM_VC4=y
> +CONFIG_DRM_VC4_KUNIT_TEST=y
> +CONFIG_MAILBOX=y
> +CONFIG_RASPBERRYPI_FIRMWARE=y
> +CONFIG_SND=y
> +CONFIG_SND_SOC=y
> +CONFIG_SOUND=y
> +CONFIG_COMMON_CLK=y
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.c b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> new file mode 100644
> index 000000000000..a4bed26af32f
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.c
> @@ -0,0 +1,200 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_drv.h>
> +#include <drm/drm_kunit_helpers.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +struct vc4_mock_output_desc {
> + enum vc4_encoder_type vc4_encoder_type;
> + unsigned int encoder_type;
> + unsigned int connector_type;
> +};
> +
> +#define VC4_MOCK_OUTPUT_DESC(_vc4_type, _etype, _ctype) \
> + { \
> + .vc4_encoder_type = _vc4_type, \
> + .encoder_type = _etype, \
> + .connector_type = _ctype, \
> + }
> +
> +struct vc4_mock_pipe_desc {
> + const struct vc4_crtc_data *data;
> + const struct vc4_mock_output_desc *outputs;
> + unsigned int noutputs;
> +};
> +
> +#define VC4_MOCK_CRTC_DESC(_data, ...) \
> + { \
> + .data = _data, \
> + .outputs = (struct vc4_mock_output_desc[]) { __VA_ARGS__ }, \
> + .noutputs = sizeof((struct vc4_mock_output_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_output_desc), \
> + }
> +
> +#define VC4_MOCK_PIXELVALVE_DESC(_data, ...) \
> + VC4_MOCK_CRTC_DESC(&(_data)->base, __VA_ARGS__)
> +
> +struct vc4_mock_desc {
> + const struct vc4_mock_pipe_desc *pipes;
> + unsigned int npipes;
> +};
> +
> +#define VC4_MOCK_DESC(...) \
> + { \
> + .pipes = (struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }, \
> + .npipes = sizeof((struct vc4_mock_pipe_desc[]) { __VA_ARGS__ }) / \
> + sizeof(struct vc4_mock_pipe_desc), \
> + }
> +
> +static const struct vc4_mock_desc vc4_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2835_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> +);
> +
> +static const struct vc4_mock_desc vc5_mock =
> + VC4_MOCK_DESC(
> + VC4_MOCK_CRTC_DESC(&vc4_txp_crtc_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_TXP,
> + DRM_MODE_ENCODER_VIRTUAL,
> + DRM_MODE_CONNECTOR_WRITEBACK)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv0_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI0,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI),
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DPI,
> + DRM_MODE_ENCODER_DPI,
> + DRM_MODE_CONNECTOR_DPI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv1_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_DSI1,
> + DRM_MODE_ENCODER_DSI,
> + DRM_MODE_CONNECTOR_DSI)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv2_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI0,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv3_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_VEC,
> + DRM_MODE_ENCODER_TVDAC,
> + DRM_MODE_CONNECTOR_Composite)),
> + VC4_MOCK_PIXELVALVE_DESC(&bcm2711_pv4_data,
> + VC4_MOCK_OUTPUT_DESC(VC4_ENCODER_TYPE_HDMI1,
> + DRM_MODE_ENCODER_TMDS,
> + DRM_MODE_CONNECTOR_HDMIA)),
> +);
> +
> +static int __build_one_pipe(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_pipe_desc *pipe)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct drm_crtc *crtc;
> + unsigned int i;
> +
> + dummy_plane = vc4_dummy_plane(test, drm, DRM_PLANE_TYPE_PRIMARY);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + dummy_crtc = vc4_mock_pv(test, drm, plane, pipe->data);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_crtc);
> +
> + crtc = &dummy_crtc->crtc.base;
> + for (i = 0; i < pipe->noutputs; i++) {
> + const struct vc4_mock_output_desc *mock_output = &pipe->outputs[i];
> + struct vc4_dummy_output *dummy_output;
> +
> + dummy_output = vc4_dummy_output(test, drm, crtc,
> + mock_output->vc4_encoder_type,
> + mock_output->encoder_type,
> + mock_output->connector_type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + }
> +
> + return 0;
> +}
> +
> +static int __build_mock(struct kunit *test, struct drm_device *drm,
> + const struct vc4_mock_desc *mock)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < mock->npipes; i++) {
> + const struct vc4_mock_pipe_desc *pipe = &mock->pipes[i];
> + int ret;
> +
> + ret = __build_one_pipe(test, drm, pipe);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + return 0;
> +}
> +
> +static struct vc4_dev *__mock_device(struct kunit *test, bool is_vc5)
> +{
> + struct drm_device *drm;
> + const struct drm_driver *drv = is_vc5 ? &vc5_drm_driver : &vc4_drm_driver;
> + const struct vc4_mock_desc *desc = is_vc5 ? &vc5_mock : &vc4_mock;
> + struct vc4_dev *vc4;
> + struct device *dev;
> + int ret;
> +
> + dev = drm_kunit_helper_alloc_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
> +
> + vc4 = drm_kunit_helper_alloc_drm_device_with_driver(test, dev,
> + struct vc4_dev, base,
> + drv);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + vc4->dev = dev;
> + vc4->is_vc5 = is_vc5;
> +
> + vc4->hvs = __vc4_hvs_alloc(vc4, NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4->hvs);
> +
> + drm = &vc4->base;
> + ret = __build_mock(test, drm, desc);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_kms_load(drm);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_dev_register(drm, 0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return vc4;
> +}
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, false);
> +}
> +
> +struct vc4_dev *vc5_mock_device(struct kunit *test)
> +{
> + return __mock_device(test, true);
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> new file mode 100644
> index 000000000000..ace5b2e00f4a
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -0,0 +1,60 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef VC4_MOCK_H_
> +#define VC4_MOCK_H_
> +
> +#include "../vc4_drv.h"
> +
> +static inline
> +struct drm_crtc *vc4_find_crtc_for_encoder(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_encoder *encoder)
> +{
> + struct drm_crtc *crtc;
> +
> + KUNIT_ASSERT_EQ(test, hweight32(encoder->possible_crtcs), 1);
> +
> + drm_for_each_crtc(crtc, drm)
> + if (encoder->possible_crtcs & drm_crtc_mask(crtc))
> + return crtc;
> +
> + return NULL;
> +}
> +
> +struct vc4_dummy_plane {
> + struct vc4_plane plane;
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type);
> +
> +struct vc4_dummy_crtc {
> + struct vc4_crtc crtc;
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data);
> +
> +struct vc4_dummy_output {
> + struct vc4_encoder encoder;
> + struct drm_connector connector;
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type);
> +
> +struct vc4_dev *vc4_mock_device(struct kunit *test);
> +struct vc4_dev *vc5_mock_device(struct kunit *test);
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state);
> +
> +#endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> new file mode 100644
> index 000000000000..5d12d7beef0e
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_crtc.c
> @@ -0,0 +1,41 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_crtc_helper_funcs vc4_dummy_crtc_helper_funcs = {
> + .atomic_check = vc4_crtc_atomic_check,
> +};
> +
> +static const struct drm_crtc_funcs vc4_dummy_crtc_funcs = {
> + .atomic_destroy_state = vc4_crtc_destroy_state,
> + .atomic_duplicate_state = vc4_crtc_duplicate_state,
> + .reset = vc4_crtc_reset,
> +};
> +
> +struct vc4_dummy_crtc *vc4_mock_pv(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_plane *plane,
> + const struct vc4_crtc_data *data)
> +{
> + struct vc4_dummy_crtc *dummy_crtc;
> + struct vc4_crtc *vc4_crtc;
> + int ret;
> +
> + dummy_crtc = kunit_kzalloc(test, sizeof(*dummy_crtc), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, dummy_crtc);
> +
> + vc4_crtc = &dummy_crtc->crtc;
> + ret = __vc4_crtc_init(drm, NULL,
> + vc4_crtc, data, plane,
> + &vc4_dummy_crtc_funcs,
> + &vc4_dummy_crtc_helper_funcs,
> + false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return dummy_crtc;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> new file mode 100644
> index 000000000000..cb16ab4451f7
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -0,0 +1,99 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_connector.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_encoder.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_connector_helper_funcs vc4_dummy_connector_helper_funcs = {
> +};
> +
> +static const struct drm_connector_funcs vc4_dummy_connector_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .reset = drm_atomic_helper_connector_reset,
> +};
> +
> +struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> + struct drm_device *drm,
> + struct drm_crtc *crtc,
> + enum vc4_encoder_type vc4_encoder_type,
> + unsigned int kms_encoder_type,
> + unsigned int connector_type)
> +{
> + struct vc4_dummy_output *dummy_output;
> + struct drm_connector *conn;
> + struct drm_encoder *enc;
> + int ret;
> +
> + dummy_output = kunit_kzalloc(test, sizeof(*dummy_output), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_output);
> + dummy_output->encoder.type = vc4_encoder_type;
> +
> + enc = &dummy_output->encoder.base;
> + ret = drmm_encoder_init(drm, enc,
> + NULL,
> + kms_encoder_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + enc->possible_crtcs = drm_crtc_mask(crtc);
> +
> + conn = &dummy_output->connector;
> + ret = drmm_connector_init(drm, conn,
> + &vc4_dummy_connector_funcs,
> + connector_type,
> + NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_connector_helper_add(conn, &vc4_dummy_connector_helper_funcs);
> + drm_connector_attach_encoder(conn, enc);
> +
> + return dummy_output;
> +}
> +
> +static const struct drm_display_mode default_mode = {
> + DRM_SIMPLE_MODE(640, 480, 64, 48)
> +};
> +
> +int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> + enum vc4_encoder_type type,
> + struct drm_atomic_state *state)
> +{
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_connector_state *conn_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + struct drm_crtc_state *crtc_state;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, crtc);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, &default_mode);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + crtc_state->active = true;
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> new file mode 100644
> index 000000000000..62b18f5f41db
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_plane.c
> @@ -0,0 +1,47 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "vc4_mock.h"
> +
> +static const struct drm_plane_helper_funcs vc4_dummy_plane_helper_funcs = {
> +};
> +
> +static const struct drm_plane_funcs vc4_dummy_plane_funcs = {
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .reset = drm_atomic_helper_plane_reset,
> +};
> +
> +static const uint32_t vc4_dummy_plane_formats[] = {
> + DRM_FORMAT_XRGB8888,
> +};
> +
> +struct vc4_dummy_plane *vc4_dummy_plane(struct kunit *test,
> + struct drm_device *drm,
> + enum drm_plane_type type)
> +{
> + struct vc4_dummy_plane *dummy_plane;
> + struct drm_plane *plane;
> +
> + dummy_plane = drmm_universal_plane_alloc(drm,
> + struct vc4_dummy_plane, plane.base,
> + 0,
> + &vc4_dummy_plane_funcs,
> + vc4_dummy_plane_formats,
> + ARRAY_SIZE(vc4_dummy_plane_formats),
> + NULL,
> + DRM_PLANE_TYPE_PRIMARY,
> + NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dummy_plane);
> +
> + plane = &dummy_plane->plane.base;
> + drm_plane_helper_add(plane, &vc4_dummy_plane_helper_funcs);
> +
> + return dummy_plane;
> +}
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 195d2b61839d..7d1a696477ce 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -675,8 +675,8 @@ void vc4_crtc_get_margins(struct drm_crtc_state *state,
> }
> }
>
> -static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> - struct drm_atomic_state *state)
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state)
> {
> struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state,
> crtc);
> @@ -1116,7 +1116,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
> .get_scanout_position = vc4_crtc_get_scanout_position,
> };
>
> -static const struct vc4_pv_data bcm2835_pv0_data = {
> +const struct vc4_pv_data bcm2835_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1131,7 +1131,7 @@ static const struct vc4_pv_data bcm2835_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv1_data = {
> +const struct vc4_pv_data bcm2835_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1146,7 +1146,7 @@ static const struct vc4_pv_data bcm2835_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2835_pv2_data = {
> +const struct vc4_pv_data bcm2835_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1161,7 +1161,7 @@ static const struct vc4_pv_data bcm2835_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv0_data = {
> +const struct vc4_pv_data bcm2711_pv0_data = {
> .base = {
> .name = "pixelvalve-0",
> .debugfs_name = "crtc0_regs",
> @@ -1176,7 +1176,7 @@ static const struct vc4_pv_data bcm2711_pv0_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv1_data = {
> +const struct vc4_pv_data bcm2711_pv1_data = {
> .base = {
> .name = "pixelvalve-1",
> .debugfs_name = "crtc1_regs",
> @@ -1191,7 +1191,7 @@ static const struct vc4_pv_data bcm2711_pv1_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv2_data = {
> +const struct vc4_pv_data bcm2711_pv2_data = {
> .base = {
> .name = "pixelvalve-2",
> .debugfs_name = "crtc2_regs",
> @@ -1205,7 +1205,7 @@ static const struct vc4_pv_data bcm2711_pv2_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv3_data = {
> +const struct vc4_pv_data bcm2711_pv3_data = {
> .base = {
> .name = "pixelvalve-3",
> .debugfs_name = "crtc3_regs",
> @@ -1219,7 +1219,7 @@ static const struct vc4_pv_data bcm2711_pv3_data = {
> },
> };
>
> -static const struct vc4_pv_data bcm2711_pv4_data = {
> +const struct vc4_pv_data bcm2711_pv4_data = {
> .base = {
> .name = "pixelvalve-4",
> .debugfs_name = "crtc4_regs",
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.c b/drivers/gpu/drm/vc4/vc4_drv.c
> index 5990d8f8c363..3b0ae2c3e33c 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.c
> +++ b/drivers/gpu/drm/vc4/vc4_drv.c
> @@ -196,7 +196,7 @@ static const struct drm_ioctl_desc vc4_drm_ioctls[] = {
> DRM_IOCTL_DEF_DRV(VC4_PERFMON_GET_VALUES, vc4_perfmon_get_values_ioctl, DRM_RENDER_ALLOW),
> };
>
> -static const struct drm_driver vc4_drm_driver = {
> +const struct drm_driver vc4_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM |
> @@ -225,7 +225,7 @@ static const struct drm_driver vc4_drm_driver = {
> .patchlevel = DRIVER_PATCHLEVEL,
> };
>
> -static const struct drm_driver vc5_drm_driver = {
> +const struct drm_driver vc5_drm_driver = {
> .driver_features = (DRIVER_MODESET |
> DRIVER_ATOMIC |
> DRIVER_GEM),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index e0be7a81a24a..418f4f308e36 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -24,6 +24,9 @@
> struct drm_device;
> struct drm_gem_object;
>
> +extern const struct drm_driver vc4_drm_driver;
> +extern const struct drm_driver vc5_drm_driver;
> +
> /* Don't forget to update vc4_bo.c: bo_type_names[] when adding to
> * this.
> */
> @@ -523,6 +526,8 @@ struct vc4_crtc_data {
> int hvs_output;
> };
>
> +extern const struct vc4_crtc_data vc4_txp_crtc_data;
> +
> struct vc4_pv_data {
> struct vc4_crtc_data base;
>
> @@ -535,6 +540,15 @@ struct vc4_pv_data {
> enum vc4_encoder_type encoder_types[4];
> };
>
> +extern const struct vc4_pv_data bcm2835_pv0_data;
> +extern const struct vc4_pv_data bcm2835_pv1_data;
> +extern const struct vc4_pv_data bcm2835_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv0_data;
> +extern const struct vc4_pv_data bcm2711_pv1_data;
> +extern const struct vc4_pv_data bcm2711_pv2_data;
> +extern const struct vc4_pv_data bcm2711_pv3_data;
> +extern const struct vc4_pv_data bcm2711_pv4_data;
> +
> struct vc4_crtc {
> struct drm_crtc base;
> struct platform_device *pdev;
> @@ -920,6 +934,8 @@ int vc4_page_flip(struct drm_crtc *crtc,
> struct drm_pending_vblank_event *event,
> uint32_t flags,
> struct drm_modeset_acquire_ctx *ctx);
> +int vc4_crtc_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_state *state);
> struct drm_crtc_state *vc4_crtc_duplicate_state(struct drm_crtc *crtc);
> void vc4_crtc_destroy_state(struct drm_crtc *crtc,
> struct drm_crtc_state *state);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 4f7ce5d3e8ad..2b69454b8534 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -479,7 +479,7 @@ static irqreturn_t vc4_txp_interrupt(int irq, void *data)
> return IRQ_HANDLED;
> }
>
> -static const struct vc4_crtc_data vc4_txp_crtc_data = {
> +const struct vc4_crtc_data vc4_txp_crtc_data = {
> .name = "txp",
> .debugfs_name = "txp_regs",
> .hvs_available_channels = BIT(2),
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (16 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 17/20] drm/vc4: tests: Introduce a mocking infrastructure Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 14:26 ` Maíra Canal
2022-12-01 15:11 ` [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing Maxime Ripard
` (2 subsequent siblings)
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
Accessing a register when running under kunit is a bad idea since our
device is completely mocked.
Fail the current test if we ever access any of our hardware registers.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/vc4_crtc.c | 13 +++++++++++--
drivers/gpu/drm/vc4/vc4_dpi.c | 13 +++++++++++--
drivers/gpu/drm/vc4/vc4_drv.h | 29 +++++++++++++++++++++++++----
drivers/gpu/drm/vc4/vc4_dsi.c | 9 ++++++++-
drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 ++++
drivers/gpu/drm/vc4/vc4_txp.c | 13 +++++++++++--
drivers/gpu/drm/vc4/vc4_vec.c | 13 +++++++++++--
7 files changed, 81 insertions(+), 13 deletions(-)
diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 7d1a696477ce..a1a3465948c4 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -50,8 +50,17 @@
#define HVS_FIFO_LATENCY_PIX 6
-#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
-#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
+#define CRTC_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vc4_crtc->regs + (offset)); \
+ } while (0)
+
+#define CRTC_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vc4_crtc->regs + (offset)); \
+ })
static const struct debugfs_reg32 crtc_regs[] = {
VC4_REG32(PV_CONTROL),
diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
index 1f8f44b7b5a5..0edf3c4c98c8 100644
--- a/drivers/gpu/drm/vc4/vc4_dpi.c
+++ b/drivers/gpu/drm/vc4/vc4_dpi.c
@@ -103,8 +103,17 @@ to_vc4_dpi(struct drm_encoder *encoder)
return container_of(encoder, struct vc4_dpi, encoder.base);
}
-#define DPI_READ(offset) readl(dpi->regs + (offset))
-#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
+#define DPI_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(dpi->regs + (offset)); \
+ })
+
+#define DPI_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, dpi->regs + (offset)); \
+ } while (0)
static const struct debugfs_reg32 dpi_regs[] = {
VC4_REG32(DPI_C),
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
index 418f4f308e36..78fda5332cb3 100644
--- a/drivers/gpu/drm/vc4/vc4_drv.h
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
@@ -19,6 +19,8 @@
#include <drm/drm_mm.h>
#include <drm/drm_modeset_lock.h>
+#include <kunit/test-bug.h>
+
#include "uapi/drm/vc4_drm.h"
struct drm_device;
@@ -645,10 +647,29 @@ to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
return container_of(crtc_state, struct vc4_crtc_state, base);
}
-#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
-#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
-#define HVS_READ(offset) readl(hvs->regs + offset)
-#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
+#define V3D_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vc4->v3d->regs + (offset)); \
+ })
+
+#define V3D_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vc4->v3d->regs + (offset)); \
+ } while (0)
+
+#define HVS_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(hvs->regs + (offset)); \
+ })
+
+#define HVS_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, hvs->regs + (offset)); \
+ } while (0)
#define VC4_REG32(reg) { .name = #reg, .offset = reg }
diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
index 878e05d79e81..2c9cb27903a0 100644
--- a/drivers/gpu/drm/vc4/vc4_dsi.c
+++ b/drivers/gpu/drm/vc4/vc4_dsi.c
@@ -617,6 +617,8 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
dma_cookie_t cookie;
int ret;
+ kunit_fail_current_test("Accessing a register in a unit test!\n");
+
/* DSI0 should be able to write normally. */
if (!chan) {
writel(val, dsi->regs + offset);
@@ -645,7 +647,12 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
DRM_ERROR("Failed to wait for DMA: %d\n", ret);
}
-#define DSI_READ(offset) readl(dsi->regs + (offset))
+#define DSI_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(dsi->regs + (offset)); \
+ })
+
#define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
#define DSI_PORT_READ(offset) \
DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
index 48db438550b1..b04b2fc8d831 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
+++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
@@ -456,6 +456,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
+ kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
+
if (reg >= variant->num_registers) {
dev_warn(&hdmi->pdev->dev,
"Invalid register ID %u\n", reg);
@@ -486,6 +488,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
+ kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
+
if (reg >= variant->num_registers) {
dev_warn(&hdmi->pdev->dev,
"Invalid register ID %u\n", reg);
diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
index 2b69454b8534..ef5cab2a3aa9 100644
--- a/drivers/gpu/drm/vc4/vc4_txp.c
+++ b/drivers/gpu/drm/vc4/vc4_txp.c
@@ -145,8 +145,17 @@
/* Number of lines received and committed to memory. */
#define TXP_PROGRESS 0x10
-#define TXP_READ(offset) readl(txp->regs + (offset))
-#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
+#define TXP_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(txp->regs + (offset)); \
+ })
+
+#define TXP_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, txp->regs + (offset)); \
+ } while (0)
struct vc4_txp {
struct vc4_crtc base;
diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
index e270a4099be3..f589ab918f4d 100644
--- a/drivers/gpu/drm/vc4/vc4_vec.c
+++ b/drivers/gpu/drm/vc4/vc4_vec.c
@@ -207,8 +207,17 @@ struct vc4_vec {
struct debugfs_regset32 regset;
};
-#define VEC_READ(offset) readl(vec->regs + (offset))
-#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
+#define VEC_READ(offset) \
+ ({ \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ readl(vec->regs + (offset)); \
+ })
+
+#define VEC_WRITE(offset, val) \
+ do { \
+ kunit_fail_current_test("Accessing a register in a unit test!\n"); \
+ writel(val, vec->regs + (offset)); \
+ } while (0)
static inline struct vc4_vec *
encoder_to_vc4_vec(struct drm_encoder *encoder)
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
2022-12-01 15:11 ` [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register Maxime Ripard
@ 2022-12-07 14:26 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:26 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Accessing a register when running under kunit is a bad idea since our
> device is completely mocked.
>
> Fail the current test if we ever access any of our hardware registers.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit: I believe that macros with multiple statements should
be enclosed in a do-while block [1], even READ macros. I saw that you
enclosed the WRITE macros on a do-while block, but not the READ macros.
[1]
https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/vc4_crtc.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_dpi.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_drv.h | 29 +++++++++++++++++++++++++----
> drivers/gpu/drm/vc4/vc4_dsi.c | 9 ++++++++-
> drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 ++++
> drivers/gpu/drm/vc4/vc4_txp.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_vec.c | 13 +++++++++++--
> 7 files changed, 81 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 7d1a696477ce..a1a3465948c4 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -50,8 +50,17 @@
>
> #define HVS_FIFO_LATENCY_PIX 6
>
> -#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
> -#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
> +#define CRTC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4_crtc->regs + (offset)); \
> + } while (0)
> +
> +#define CRTC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4_crtc->regs + (offset)); \
> + })
>
> static const struct debugfs_reg32 crtc_regs[] = {
> VC4_REG32(PV_CONTROL),
> diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
> index 1f8f44b7b5a5..0edf3c4c98c8 100644
> --- a/drivers/gpu/drm/vc4/vc4_dpi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dpi.c
> @@ -103,8 +103,17 @@ to_vc4_dpi(struct drm_encoder *encoder)
> return container_of(encoder, struct vc4_dpi, encoder.base);
> }
>
> -#define DPI_READ(offset) readl(dpi->regs + (offset))
> -#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
> +#define DPI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dpi->regs + (offset)); \
> + })
> +
> +#define DPI_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, dpi->regs + (offset)); \
> + } while (0)
>
> static const struct debugfs_reg32 dpi_regs[] = {
> VC4_REG32(DPI_C),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index 418f4f308e36..78fda5332cb3 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -19,6 +19,8 @@
> #include <drm/drm_mm.h>
> #include <drm/drm_modeset_lock.h>
>
> +#include <kunit/test-bug.h>
> +
> #include "uapi/drm/vc4_drm.h"
>
> struct drm_device;
> @@ -645,10 +647,29 @@ to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
> return container_of(crtc_state, struct vc4_crtc_state, base);
> }
>
> -#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
> -#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
> -#define HVS_READ(offset) readl(hvs->regs + offset)
> -#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
> +#define V3D_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4->v3d->regs + (offset)); \
> + })
> +
> +#define V3D_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4->v3d->regs + (offset)); \
> + } while (0)
> +
> +#define HVS_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(hvs->regs + (offset)); \
> + })
> +
> +#define HVS_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, hvs->regs + (offset)); \
> + } while (0)
>
> #define VC4_REG32(reg) { .name = #reg, .offset = reg }
>
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index 878e05d79e81..2c9cb27903a0 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -617,6 +617,8 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> dma_cookie_t cookie;
> int ret;
>
> + kunit_fail_current_test("Accessing a register in a unit test!\n");
> +
> /* DSI0 should be able to write normally. */
> if (!chan) {
> writel(val, dsi->regs + offset);
> @@ -645,7 +647,12 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> DRM_ERROR("Failed to wait for DMA: %d\n", ret);
> }
>
> -#define DSI_READ(offset) readl(dsi->regs + (offset))
> +#define DSI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dsi->regs + (offset)); \
> + })
> +
> #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
> #define DSI_PORT_READ(offset) \
> DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> index 48db438550b1..b04b2fc8d831 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> @@ -456,6 +456,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> @@ -486,6 +488,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 2b69454b8534..ef5cab2a3aa9 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -145,8 +145,17 @@
> /* Number of lines received and committed to memory. */
> #define TXP_PROGRESS 0x10
>
> -#define TXP_READ(offset) readl(txp->regs + (offset))
> -#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
> +#define TXP_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(txp->regs + (offset)); \
> + })
> +
> +#define TXP_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, txp->regs + (offset)); \
> + } while (0)
>
> struct vc4_txp {
> struct vc4_crtc base;
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> index e270a4099be3..f589ab918f4d 100644
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> @@ -207,8 +207,17 @@ struct vc4_vec {
> struct debugfs_regset32 regset;
> };
>
> -#define VEC_READ(offset) readl(vec->regs + (offset))
> -#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
> +#define VEC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vec->regs + (offset)); \
> + })
> +
> +#define VEC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vec->regs + (offset)); \
> + } while (0)
>
> static inline struct vc4_vec *
> encoder_to_vc4_vec(struct drm_encoder *encoder)
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
@ 2022-12-07 14:26 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:26 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
linux-kernel, dri-devel, Javier Martinez Canillas, linaro-mm-sig,
Brendan Higgins, David Gow, linux-media, Maíra Canal,
kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> Accessing a register when running under kunit is a bad idea since our
> device is completely mocked.
>
> Fail the current test if we ever access any of our hardware registers.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit: I believe that macros with multiple statements should
be enclosed in a do-while block [1], even READ macros. I saw that you
enclosed the WRITE macros on a do-while block, but not the READ macros.
[1]
https://www.kernel.org/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/vc4_crtc.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_dpi.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_drv.h | 29 +++++++++++++++++++++++++----
> drivers/gpu/drm/vc4/vc4_dsi.c | 9 ++++++++-
> drivers/gpu/drm/vc4/vc4_hdmi_regs.h | 4 ++++
> drivers/gpu/drm/vc4/vc4_txp.c | 13 +++++++++++--
> drivers/gpu/drm/vc4/vc4_vec.c | 13 +++++++++++--
> 7 files changed, 81 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
> index 7d1a696477ce..a1a3465948c4 100644
> --- a/drivers/gpu/drm/vc4/vc4_crtc.c
> +++ b/drivers/gpu/drm/vc4/vc4_crtc.c
> @@ -50,8 +50,17 @@
>
> #define HVS_FIFO_LATENCY_PIX 6
>
> -#define CRTC_WRITE(offset, val) writel(val, vc4_crtc->regs + (offset))
> -#define CRTC_READ(offset) readl(vc4_crtc->regs + (offset))
> +#define CRTC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4_crtc->regs + (offset)); \
> + } while (0)
> +
> +#define CRTC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4_crtc->regs + (offset)); \
> + })
>
> static const struct debugfs_reg32 crtc_regs[] = {
> VC4_REG32(PV_CONTROL),
> diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c
> index 1f8f44b7b5a5..0edf3c4c98c8 100644
> --- a/drivers/gpu/drm/vc4/vc4_dpi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dpi.c
> @@ -103,8 +103,17 @@ to_vc4_dpi(struct drm_encoder *encoder)
> return container_of(encoder, struct vc4_dpi, encoder.base);
> }
>
> -#define DPI_READ(offset) readl(dpi->regs + (offset))
> -#define DPI_WRITE(offset, val) writel(val, dpi->regs + (offset))
> +#define DPI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dpi->regs + (offset)); \
> + })
> +
> +#define DPI_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, dpi->regs + (offset)); \
> + } while (0)
>
> static const struct debugfs_reg32 dpi_regs[] = {
> VC4_REG32(DPI_C),
> diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
> index 418f4f308e36..78fda5332cb3 100644
> --- a/drivers/gpu/drm/vc4/vc4_drv.h
> +++ b/drivers/gpu/drm/vc4/vc4_drv.h
> @@ -19,6 +19,8 @@
> #include <drm/drm_mm.h>
> #include <drm/drm_modeset_lock.h>
>
> +#include <kunit/test-bug.h>
> +
> #include "uapi/drm/vc4_drm.h"
>
> struct drm_device;
> @@ -645,10 +647,29 @@ to_vc4_crtc_state(const struct drm_crtc_state *crtc_state)
> return container_of(crtc_state, struct vc4_crtc_state, base);
> }
>
> -#define V3D_READ(offset) readl(vc4->v3d->regs + offset)
> -#define V3D_WRITE(offset, val) writel(val, vc4->v3d->regs + offset)
> -#define HVS_READ(offset) readl(hvs->regs + offset)
> -#define HVS_WRITE(offset, val) writel(val, hvs->regs + offset)
> +#define V3D_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vc4->v3d->regs + (offset)); \
> + })
> +
> +#define V3D_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vc4->v3d->regs + (offset)); \
> + } while (0)
> +
> +#define HVS_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(hvs->regs + (offset)); \
> + })
> +
> +#define HVS_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, hvs->regs + (offset)); \
> + } while (0)
>
> #define VC4_REG32(reg) { .name = #reg, .offset = reg }
>
> diff --git a/drivers/gpu/drm/vc4/vc4_dsi.c b/drivers/gpu/drm/vc4/vc4_dsi.c
> index 878e05d79e81..2c9cb27903a0 100644
> --- a/drivers/gpu/drm/vc4/vc4_dsi.c
> +++ b/drivers/gpu/drm/vc4/vc4_dsi.c
> @@ -617,6 +617,8 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> dma_cookie_t cookie;
> int ret;
>
> + kunit_fail_current_test("Accessing a register in a unit test!\n");
> +
> /* DSI0 should be able to write normally. */
> if (!chan) {
> writel(val, dsi->regs + offset);
> @@ -645,7 +647,12 @@ dsi_dma_workaround_write(struct vc4_dsi *dsi, u32 offset, u32 val)
> DRM_ERROR("Failed to wait for DMA: %d\n", ret);
> }
>
> -#define DSI_READ(offset) readl(dsi->regs + (offset))
> +#define DSI_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(dsi->regs + (offset)); \
> + })
> +
> #define DSI_WRITE(offset, val) dsi_dma_workaround_write(dsi, offset, val)
> #define DSI_PORT_READ(offset) \
> DSI_READ(dsi->variant->port ? DSI1_##offset : DSI0_##offset)
> diff --git a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> index 48db438550b1..b04b2fc8d831 100644
> --- a/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> +++ b/drivers/gpu/drm/vc4/vc4_hdmi_regs.h
> @@ -456,6 +456,8 @@ static inline u32 vc4_hdmi_read(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> @@ -486,6 +488,8 @@ static inline void vc4_hdmi_write(struct vc4_hdmi *hdmi,
>
> WARN_ON(pm_runtime_status_suspended(&hdmi->pdev->dev));
>
> + kunit_fail_current_test("Accessing an HDMI register in a unit test!\n");
> +
> if (reg >= variant->num_registers) {
> dev_warn(&hdmi->pdev->dev,
> "Invalid register ID %u\n", reg);
> diff --git a/drivers/gpu/drm/vc4/vc4_txp.c b/drivers/gpu/drm/vc4/vc4_txp.c
> index 2b69454b8534..ef5cab2a3aa9 100644
> --- a/drivers/gpu/drm/vc4/vc4_txp.c
> +++ b/drivers/gpu/drm/vc4/vc4_txp.c
> @@ -145,8 +145,17 @@
> /* Number of lines received and committed to memory. */
> #define TXP_PROGRESS 0x10
>
> -#define TXP_READ(offset) readl(txp->regs + (offset))
> -#define TXP_WRITE(offset, val) writel(val, txp->regs + (offset))
> +#define TXP_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(txp->regs + (offset)); \
> + })
> +
> +#define TXP_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, txp->regs + (offset)); \
> + } while (0)
>
> struct vc4_txp {
> struct vc4_crtc base;
> diff --git a/drivers/gpu/drm/vc4/vc4_vec.c b/drivers/gpu/drm/vc4/vc4_vec.c
> index e270a4099be3..f589ab918f4d 100644
> --- a/drivers/gpu/drm/vc4/vc4_vec.c
> +++ b/drivers/gpu/drm/vc4/vc4_vec.c
> @@ -207,8 +207,17 @@ struct vc4_vec {
> struct debugfs_regset32 regset;
> };
>
> -#define VEC_READ(offset) readl(vec->regs + (offset))
> -#define VEC_WRITE(offset, val) writel(val, vec->regs + (offset))
> +#define VEC_READ(offset) \
> + ({ \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + readl(vec->regs + (offset)); \
> + })
> +
> +#define VEC_WRITE(offset, val) \
> + do { \
> + kunit_fail_current_test("Accessing a register in a unit test!\n"); \
> + writel(val, vec->regs + (offset)); \
> + } while (0)
>
> static inline struct vc4_vec *
> encoder_to_vc4_vec(struct drm_encoder *encoder)
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
2022-12-07 14:26 ` Maíra Canal
@ 2022-12-07 16:11 ` Maxime Ripard
-1 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-07 16:11 UTC (permalink / raw)
To: Maíra Canal
Cc: Maarten Lankhorst, Daniel Vetter, Thomas Zimmermann,
David Airlie, David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
[-- Attachment #1: Type: text/plain, Size: 937 bytes --]
Hi Maíra,
Thanks for your review!
On Wed, Dec 07, 2022 at 11:26:13AM -0300, Maíra Canal wrote:
> On 12/1/22 12:11, Maxime Ripard wrote:
> > Accessing a register when running under kunit is a bad idea since our
> > device is completely mocked.
> >
> > Fail the current test if we ever access any of our hardware registers.
> >
> > Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> > Signed-off-by: Maxime Ripard <maxime@cerno.tech>
>
> Reviewed-by: Maíra Canal <mcanal@igalia.com>
>
> Just a small nit: I believe that macros with multiple statements should be
> enclosed in a do-while block [1], even READ macros. I saw that you enclosed
> the WRITE macros on a do-while block, but not the READ macros.
This is on purpose: do-while blocks don't return a value, but ({ ... })
blocks do. So we can do a write macros with a do-while, but can't for
read since we expect to get a value back.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register
@ 2022-12-07 16:11 ` Maxime Ripard
0 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-07 16:11 UTC (permalink / raw)
To: Maíra Canal
Cc: linux-kselftest, Thomas Zimmermann, Dave Stevenson,
Greg Kroah-Hartman, Javier Martinez Canillas, dri-devel,
linux-kernel, linaro-mm-sig, Brendan Higgins, David Gow,
linux-media, Maíra Canal, kunit-dev
[-- Attachment #1: Type: text/plain, Size: 937 bytes --]
Hi Maíra,
Thanks for your review!
On Wed, Dec 07, 2022 at 11:26:13AM -0300, Maíra Canal wrote:
> On 12/1/22 12:11, Maxime Ripard wrote:
> > Accessing a register when running under kunit is a bad idea since our
> > device is completely mocked.
> >
> > Fail the current test if we ever access any of our hardware registers.
> >
> > Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> > Signed-off-by: Maxime Ripard <maxime@cerno.tech>
>
> Reviewed-by: Maíra Canal <mcanal@igalia.com>
>
> Just a small nit: I believe that macros with multiple statements should be
> enclosed in a do-while block [1], even READ macros. I saw that you enclosed
> the WRITE macros on a do-while block, but not the READ macros.
This is on purpose: do-while blocks don't return a value, but ({ ... })
blocks do. So we can do a write macros with a do-while, but can't for
read since we expect to get a value back.
Maxime
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (17 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 18/20] drm/vc4: tests: Fail the current test if we access a register Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 14:24 ` Maíra Canal
2022-12-01 15:11 ` [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section Maxime Ripard
2022-12-08 8:58 ` [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
The HVS to PixelValve muxing code is fairly error prone and has a bunch
of arbitrary constraints due to the hardware setup.
Let's create a test suite that makes sure that the possible combinations
work and the invalid ones don't.
Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
drivers/gpu/drm/vc4/Makefile | 3 +-
drivers/gpu/drm/vc4/tests/vc4_mock.h | 9 +-
drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 49 +-
drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 1039 ++++++++++++++++++++++++
4 files changed, 1091 insertions(+), 9 deletions(-)
diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
index f974a8c80e2f..c41f89a15a55 100644
--- a/drivers/gpu/drm/vc4/Makefile
+++ b/drivers/gpu/drm/vc4/Makefile
@@ -29,7 +29,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
tests/vc4_mock.o \
tests/vc4_mock_crtc.o \
tests/vc4_mock_output.o \
- tests/vc4_mock_plane.o
+ tests/vc4_mock_plane.o \
+ tests/vc4_test_pv_muxing.o
vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
index ace5b2e00f4a..db8e9a141ef8 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
@@ -53,8 +53,11 @@ struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
struct vc4_dev *vc4_mock_device(struct kunit *test);
struct vc4_dev *vc5_mock_device(struct kunit *test);
-int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
- enum vc4_encoder_type type,
- struct drm_atomic_state *state);
+int vc4_mock_atomic_add_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type);
+int vc4_mock_atomic_del_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type);
#endif // VC4_MOCK_H_
diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
index cb16ab4451f7..8d33be828d9a 100644
--- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
+++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
@@ -61,16 +61,17 @@ static const struct drm_display_mode default_mode = {
DRM_SIMPLE_MODE(640, 480, 64, 48)
};
-int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
- enum vc4_encoder_type type,
- struct drm_atomic_state *state)
+int vc4_mock_atomic_add_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
{
+ struct drm_device *drm = state->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
struct vc4_dummy_output *output;
struct drm_connector *conn;
- struct drm_connector_state *conn_state;
struct drm_encoder *encoder;
struct drm_crtc *crtc;
- struct drm_crtc_state *crtc_state;
int ret;
encoder = vc4_find_encoder_by_type(drm, type);
@@ -97,3 +98,41 @@ int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
return 0;
}
+
+int vc4_mock_atomic_del_output(struct kunit *test,
+ struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
+{
+ struct drm_device *drm = state->dev;
+ struct drm_connector_state *conn_state;
+ struct drm_crtc_state *crtc_state;
+ struct vc4_dummy_output *output;
+ struct drm_connector *conn;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+ int ret;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
+
+ crtc_state->active = false;
+
+ ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ output = container_of(encoder, struct vc4_dummy_output, encoder.base);
+ conn = &output->connector;
+ conn_state = drm_atomic_get_connector_state(state, conn);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
+
+ ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
new file mode 100644
index 000000000000..ae0bd0f81698
--- /dev/null
+++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
@@ -0,0 +1,1039 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_atomic_state_helper.h>
+#include <drm/drm_atomic_uapi.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_fourcc.h>
+#include <drm/drm_kunit_helpers.h>
+#include <drm/drm_mode.h>
+#include <drm/drm_modeset_helper_vtables.h>
+#include <drm/drm_plane.h>
+
+#include <kunit/test.h>
+
+#include "../vc4_drv.h"
+
+#include "vc4_mock.h"
+
+struct pv_muxing_priv {
+ struct vc4_dev *vc4;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+};
+
+static bool check_fifo_conflict(struct kunit *test,
+ const struct drm_atomic_state *state)
+{
+ struct vc4_hvs_state *hvs_state;
+ unsigned int used_fifos = 0;
+ unsigned int i;
+
+ hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hvs_state);
+
+ for (i = 0; i < HVS_NUM_CHANNELS; i++) {
+ if (!hvs_state->fifo_state[i].in_use)
+ continue;
+
+ KUNIT_EXPECT_FALSE(test, used_fifos & BIT(i));
+ used_fifos |= BIT(i);
+ }
+
+ return true;
+}
+
+struct encoder_constraint {
+ enum vc4_encoder_type type;
+ unsigned int *channels;
+ size_t nchannels;
+};
+
+#define ENCODER_CONSTRAINT(_type, ...) \
+ { \
+ .type = _type, \
+ .channels = (unsigned int[]) { __VA_ARGS__ }, \
+ .nchannels = sizeof((unsigned int[]) { __VA_ARGS__ }) / \
+ sizeof(unsigned int), \
+ }
+
+static bool __check_encoder_constraints(const struct encoder_constraint *constraints,
+ size_t nconstraints,
+ enum vc4_encoder_type type,
+ unsigned int channel)
+{
+ unsigned int i;
+
+ for (i = 0; i < nconstraints; i++) {
+ const struct encoder_constraint *constraint = &constraints[i];
+ unsigned int j;
+
+ if (constraint->type != type)
+ continue;
+
+ for (j = 0; j < constraint->nchannels; j++) {
+ unsigned int _channel = constraint->channels[j];
+
+ if (channel != _channel)
+ continue;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static const struct encoder_constraint vc4_encoder_constraints[] = {
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2),
+};
+
+static const struct encoder_constraint vc5_encoder_constraints[] = {
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2),
+ ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2),
+};
+
+static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
+{
+ return __check_encoder_constraints(vc4_encoder_constraints,
+ ARRAY_SIZE(vc4_encoder_constraints),
+ type, channel);
+}
+
+static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
+{
+ return __check_encoder_constraints(vc5_encoder_constraints,
+ ARRAY_SIZE(vc5_encoder_constraints),
+ type, channel);
+}
+
+static struct vc4_crtc_state *
+get_vc4_crtc_state_for_encoder(struct kunit *test,
+ const struct drm_atomic_state *state,
+ enum vc4_encoder_type type)
+{
+ struct drm_device *drm = state->dev;
+ struct drm_crtc_state *new_crtc_state;
+ struct drm_encoder *encoder;
+ struct drm_crtc *crtc;
+
+ encoder = vc4_find_encoder_by_type(drm, type);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
+
+ crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
+
+ new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
+ if (!new_crtc_state)
+ return NULL;
+
+ return to_vc4_crtc_state(new_crtc_state);
+}
+
+static bool check_channel_for_encoder(struct kunit *test,
+ const struct drm_atomic_state *state,
+ enum vc4_encoder_type type,
+ bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
+{
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int channel;
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state, type);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_EXPECT_NE(test, channel, VC4_HVS_CHANNEL_DISABLED);
+
+ KUNIT_EXPECT_TRUE(test, new_hvs_state->fifo_state[channel].in_use);
+
+ KUNIT_EXPECT_TRUE(test, check_fn(type, channel));
+
+ return true;
+}
+
+struct pv_muxing_param {
+ const char *name;
+ struct vc4_dev *(*mock_fn)(struct kunit *test);
+ bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel);
+ enum vc4_encoder_type *encoders;
+ size_t nencoders;
+};
+
+static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc)
+{
+ strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
+}
+
+#define PV_MUXING_TEST(_name, _mock_fn, _check_fn, ...) \
+ { \
+ .name = _name, \
+ .mock_fn = &_mock_fn, \
+ .check_fn = &_check_fn, \
+ .encoders = (enum vc4_encoder_type[]) { __VA_ARGS__ }, \
+ .nencoders = sizeof((enum vc4_encoder_type[]) { __VA_ARGS__ }) / \
+ sizeof(enum vc4_encoder_type), \
+ }
+
+#define VC4_PV_MUXING_TEST(_name, ...) \
+ PV_MUXING_TEST(_name, vc4_mock_device, check_vc4_encoder_constraints, __VA_ARGS__)
+
+#define VC5_PV_MUXING_TEST(_name, ...) \
+ PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__)
+
+static const struct pv_muxing_param vc4_test_pv_muxing_params[] = {
+ VC4_PV_MUXING_TEST("1 output: DSI0",
+ VC4_ENCODER_TYPE_DSI0),
+ VC4_PV_MUXING_TEST("1 output: DPI",
+ VC4_ENCODER_TYPE_DPI),
+ VC4_PV_MUXING_TEST("1 output: HDMI0",
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("1 output: VEC",
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("1 output: DSI1",
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("1 output: TXP",
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, VEC",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, VEC",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: DPI, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("2 outputs: VEC, TXP",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+};
+
+KUNIT_ARRAY_PARAM(vc4_test_pv_muxing,
+ vc4_test_pv_muxing_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params[] = {
+ VC4_PV_MUXING_TEST("DPI/DSI0 Conflict",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI0),
+ VC4_PV_MUXING_TEST("TXP/DSI1 Conflict",
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC4_PV_MUXING_TEST("HDMI0/VEC Conflict",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, HDMI0, DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+};
+
+KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid,
+ vc4_test_pv_muxing_invalid_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc5_test_pv_muxing_params[] = {
+ VC5_PV_MUXING_TEST("1 output: DPI",
+ VC4_ENCODER_TYPE_DPI),
+ VC5_PV_MUXING_TEST("1 output: DSI0",
+ VC4_ENCODER_TYPE_DSI0),
+ VC5_PV_MUXING_TEST("1 output: DSI1",
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("1 output: HDMI0",
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("1 output: HDMI1",
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("1 output: VEC",
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, VEC",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, VEC",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, VEC",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI1, VEC",
+ VC4_ENCODER_TYPE_HDMI1,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP",
+ VC4_ENCODER_TYPE_HDMI1,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("2 outputs: TXP, VEC",
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_VEC),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DPI, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+};
+
+KUNIT_ARRAY_PARAM(vc5_test_pv_muxing,
+ vc5_test_pv_muxing_params,
+ vc4_test_pv_muxing_desc);
+
+static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params[] = {
+ VC5_PV_MUXING_TEST("DPI/DSI0 Conflict",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DPI,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+ VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1",
+ VC4_ENCODER_TYPE_DSI0,
+ VC4_ENCODER_TYPE_VEC,
+ VC4_ENCODER_TYPE_TXP,
+ VC4_ENCODER_TYPE_DSI1,
+ VC4_ENCODER_TYPE_HDMI0,
+ VC4_ENCODER_TYPE_HDMI1),
+};
+
+KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid,
+ vc5_test_pv_muxing_invalid_params,
+ vc4_test_pv_muxing_desc);
+
+static void drm_vc4_test_pv_muxing(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ const struct pv_muxing_priv *priv = test->priv;
+ struct drm_atomic_state *state = priv->state;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_EQ(test, ret, 0);
+
+ KUNIT_EXPECT_TRUE(test,
+ check_fifo_conflict(test, state));
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
+ params->check_fn));
+ }
+}
+
+static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ const struct pv_muxing_priv *priv = test->priv;
+ struct drm_atomic_state *state = priv->state;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < params->nencoders; i++) {
+ enum vc4_encoder_type enc_type = params->encoders[i];
+
+ ret = vc4_mock_atomic_add_output(test, state, enc_type);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+ }
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_EXPECT_LT(test, ret, 0);
+}
+
+static int vc4_pv_muxing_test_init(struct kunit *test)
+{
+ const struct pv_muxing_param *params = test->param_value;
+ struct drm_atomic_state *state;
+ struct pv_muxing_priv *priv;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+
+ priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, priv);
+ test->priv = priv;
+
+ vc4 = params->mock_fn(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+ priv->vc4 = vc4;
+
+ drm_modeset_acquire_init(&priv->ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &priv->ctx;
+
+ priv->state = state;
+
+ return 0;
+}
+
+static void vc4_pv_muxing_test_exit(struct kunit *test)
+{
+ struct pv_muxing_priv *priv = test->priv;
+ struct vc4_dev *vc4 = priv->vc4;
+ struct drm_device *drm = &vc4->base;
+ struct drm_atomic_state *state = priv->state;
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&priv->ctx);
+ drm_modeset_acquire_fini(&priv->ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static struct kunit_case vc4_pv_muxing_tests[] = {
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
+ vc4_test_pv_muxing_gen_params),
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
+ vc4_test_pv_muxing_invalid_gen_params),
+ {}
+};
+
+static struct kunit_suite vc4_pv_muxing_test_suite = {
+ .name = "vc4-pv-muxing-combinations",
+ .init = vc4_pv_muxing_test_init,
+ .exit = vc4_pv_muxing_test_exit,
+ .test_cases = vc4_pv_muxing_tests,
+};
+
+static struct kunit_case vc5_pv_muxing_tests[] = {
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
+ vc5_test_pv_muxing_gen_params),
+ KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
+ vc5_test_pv_muxing_invalid_gen_params),
+ {}
+};
+
+static struct kunit_suite vc5_pv_muxing_test_suite = {
+ .name = "vc5-pv-muxing-combinations",
+ .init = vc4_pv_muxing_test_init,
+ .exit = vc4_pv_muxing_test_exit,
+ .test_cases = vc5_pv_muxing_tests,
+};
+
+/* See
+ * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/
+ * and
+ * https://lore.kernel.org/dri-devel/20200917121623.42023-1-maxime@cerno.tech/
+ */
+static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int hdmi0_channel;
+ unsigned int hdmi1_channel;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ hdmi0_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi0_channel].in_use);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
+
+ KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct vc4_hvs_state *new_hvs_state;
+ unsigned int old_hdmi0_channel;
+ unsigned int old_hdmi1_channel;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ old_hdmi0_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, old_hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi0_channel].in_use);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
+
+ old_hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, old_hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi1_channel].in_use);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_hvs_state = vc4_hvs_get_new_global_state(state);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI1);
+
+ if (new_vc4_crtc_state) {
+ unsigned int hdmi1_channel;
+
+ hdmi1_channel = new_vc4_crtc_state->assigned_channel;
+ KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
+ KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
+
+ KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
+ }
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static void
+drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
+{
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_atomic_state *state;
+ struct vc4_crtc_state *new_vc4_crtc_state;
+ struct drm_device *drm;
+ struct vc4_dev *vc4;
+ int ret;
+
+ vc4 = vc5_mock_device(test);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ drm = &vc4->base;
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_helper_swap_state(state, false);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ drm_atomic_state_put(state);
+
+ state = drm_atomic_state_alloc(drm);
+ KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
+
+ state->acquire_ctx = &ctx;
+
+ ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ ret = drm_atomic_check_only(state);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
+ VC4_ENCODER_TYPE_HDMI0);
+ KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
+
+ drm_atomic_state_put(state);
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+ drm_dev_unregister(drm);
+ drm_kunit_helper_free_device(test, vc4->dev);
+}
+
+static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
+ KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
+ {}
+};
+
+static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
+ .name = "vc5-pv-muxing-bugs",
+ .test_cases = vc5_pv_muxing_bugs_tests,
+};
+
+kunit_test_suites(
+ &vc4_pv_muxing_test_suite,
+ &vc5_pv_muxing_test_suite,
+ &vc5_pv_muxing_bugs_test_suite
+);
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing
2022-12-01 15:11 ` [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing Maxime Ripard
@ 2022-12-07 14:24 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:24 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
linux-kernel, dri-devel, Javier Martinez Canillas, linaro-mm-sig,
Brendan Higgins, David Gow, linux-media, Maíra Canal,
kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> The HVS to PixelValve muxing code is fairly error prone and has a bunch
> of arbitrary constraints due to the hardware setup.
>
> Let's create a test suite that makes sure that the possible combinations
> work and the invalid ones don't.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Makefile | 3 +-
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 9 +-
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 49 +-
> drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 1039 ++++++++++++++++++++++++
> 4 files changed, 1091 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index f974a8c80e2f..c41f89a15a55 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -29,7 +29,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> tests/vc4_mock.o \
> tests/vc4_mock_crtc.o \
> tests/vc4_mock_output.o \
> - tests/vc4_mock_plane.o
> + tests/vc4_mock_plane.o \
> + tests/vc4_test_pv_muxing.o
>
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> index ace5b2e00f4a..db8e9a141ef8 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -53,8 +53,11 @@ struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> struct vc4_dev *vc4_mock_device(struct kunit *test);
> struct vc4_dev *vc5_mock_device(struct kunit *test);
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state);
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
>
> #endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> index cb16ab4451f7..8d33be828d9a 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -61,16 +61,17 @@ static const struct drm_display_mode default_mode = {
> DRM_SIMPLE_MODE(640, 480, 64, 48)
> };
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state)
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> {
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> struct vc4_dummy_output *output;
> struct drm_connector *conn;
> - struct drm_connector_state *conn_state;
> struct drm_encoder *encoder;
> struct drm_crtc *crtc;
> - struct drm_crtc_state *crtc_state;
> int ret;
>
> encoder = vc4_find_encoder_by_type(drm, type);
> @@ -97,3 +98,41 @@ int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
>
> return 0;
> }
> +
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + crtc_state->active = false;
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> new file mode 100644
> index 000000000000..ae0bd0f81698
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> @@ -0,0 +1,1039 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_kunit_helpers.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "../vc4_drv.h"
> +
> +#include "vc4_mock.h"
> +
> +struct pv_muxing_priv {
> + struct vc4_dev *vc4;
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> +};
> +
> +static bool check_fifo_conflict(struct kunit *test,
> + const struct drm_atomic_state *state)
> +{
> + struct vc4_hvs_state *hvs_state;
> + unsigned int used_fifos = 0;
> + unsigned int i;
> +
> + hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hvs_state);
> +
> + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
> + if (!hvs_state->fifo_state[i].in_use)
> + continue;
> +
> + KUNIT_EXPECT_FALSE(test, used_fifos & BIT(i));
> + used_fifos |= BIT(i);
> + }
> +
> + return true;
> +}
> +
> +struct encoder_constraint {
> + enum vc4_encoder_type type;
> + unsigned int *channels;
> + size_t nchannels;
> +};
> +
> +#define ENCODER_CONSTRAINT(_type, ...) \
> + { \
> + .type = _type, \
> + .channels = (unsigned int[]) { __VA_ARGS__ }, \
> + .nchannels = sizeof((unsigned int[]) { __VA_ARGS__ }) / \
> + sizeof(unsigned int), \
> + }
> +
> +static bool __check_encoder_constraints(const struct encoder_constraint *constraints,
> + size_t nconstraints,
> + enum vc4_encoder_type type,
> + unsigned int channel)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < nconstraints; i++) {
> + const struct encoder_constraint *constraint = &constraints[i];
> + unsigned int j;
> +
> + if (constraint->type != type)
> + continue;
> +
> + for (j = 0; j < constraint->nchannels; j++) {
> + unsigned int _channel = constraint->channels[j];
> +
> + if (channel != _channel)
> + continue;
> +
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static const struct encoder_constraint vc4_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2),
> +};
> +
> +static const struct encoder_constraint vc5_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2),
> +};
> +
> +static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc4_encoder_constraints,
> + ARRAY_SIZE(vc4_encoder_constraints),
> + type, channel);
> +}
> +
> +static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc5_encoder_constraints,
> + ARRAY_SIZE(vc5_encoder_constraints),
> + type, channel);
> +}
> +
> +static struct vc4_crtc_state *
> +get_vc4_crtc_state_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_crtc_state *new_crtc_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> + if (!new_crtc_state)
> + return NULL;
> +
> + return to_vc4_crtc_state(new_crtc_state);
> +}
> +
> +static bool check_channel_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type,
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
> +{
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int channel;
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state, type);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_EXPECT_NE(test, channel, VC4_HVS_CHANNEL_DISABLED);
> +
> + KUNIT_EXPECT_TRUE(test, new_hvs_state->fifo_state[channel].in_use);
> +
> + KUNIT_EXPECT_TRUE(test, check_fn(type, channel));
> +
> + return true;
> +}
> +
> +struct pv_muxing_param {
> + const char *name;
> + struct vc4_dev *(*mock_fn)(struct kunit *test);
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel);
> + enum vc4_encoder_type *encoders;
> + size_t nencoders;
> +};
> +
> +static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc)
> +{
> + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
> +}
> +
> +#define PV_MUXING_TEST(_name, _mock_fn, _check_fn, ...) \
> + { \
> + .name = _name, \
> + .mock_fn = &_mock_fn, \
> + .check_fn = &_check_fn, \
> + .encoders = (enum vc4_encoder_type[]) { __VA_ARGS__ }, \
> + .nencoders = sizeof((enum vc4_encoder_type[]) { __VA_ARGS__ }) / \
> + sizeof(enum vc4_encoder_type), \
> + }
> +
> +#define VC4_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc4_mock_device, check_vc4_encoder_constraints, __VA_ARGS__)
> +
> +#define VC5_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__)
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_params[] = {
> + VC4_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC4_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("1 output: TXP",
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, TXP",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing,
> + vc4_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params[] = {
> + VC4_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("TXP/DSI1 Conflict",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("HDMI0/VEC Conflict",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_params[] = {
> + VC5_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC5_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("1 output: HDMI1",
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, VEC",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, VEC",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, VEC",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: TXP, VEC",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing,
> + vc5_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params[] = {
> + VC5_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static void drm_vc4_test_pv_muxing(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + KUNIT_EXPECT_TRUE(test,
> + check_fifo_conflict(test, state));
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
> + params->check_fn));
> + }
> +}
> +
> +static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_LT(test, ret, 0);
> +}
> +
> +static int vc4_pv_muxing_test_init(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + struct drm_atomic_state *state;
> + struct pv_muxing_priv *priv;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> +
> + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, priv);
> + test->priv = priv;
> +
> + vc4 = params->mock_fn(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> + priv->vc4 = vc4;
> +
> + drm_modeset_acquire_init(&priv->ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &priv->ctx;
> +
> + priv->state = state;
> +
> + return 0;
> +}
> +
> +static void vc4_pv_muxing_test_exit(struct kunit *test)
> +{
> + struct pv_muxing_priv *priv = test->priv;
> + struct vc4_dev *vc4 = priv->vc4;
> + struct drm_device *drm = &vc4->base;
> + struct drm_atomic_state *state = priv->state;
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&priv->ctx);
> + drm_modeset_acquire_fini(&priv->ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc4_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc4_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc4_pv_muxing_test_suite = {
> + .name = "vc4-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc4_pv_muxing_tests,
> +};
> +
> +static struct kunit_case vc5_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc5_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_test_suite = {
> + .name = "vc5-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc5_pv_muxing_tests,
> +};
> +
> +/* See
> + * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/
> + * and
> + * https://lore.kernel.org/dri-devel/20200917121623.42023-1-maxime@cerno.tech/
> + */
> +static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int hdmi0_channel;
> + unsigned int hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi0_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int old_hdmi0_channel;
> + unsigned int old_hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi0_channel].in_use);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi1_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> +
> + if (new_vc4_crtc_state) {
> + unsigned int hdmi1_channel;
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
> + }
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void
> +drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
> + .name = "vc5-pv-muxing-bugs",
> + .test_cases = vc5_pv_muxing_bugs_tests,
> +};
> +
> +kunit_test_suites(
> + &vc4_pv_muxing_test_suite,
> + &vc5_pv_muxing_test_suite,
> + &vc5_pv_muxing_bugs_test_suite
> +);
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing
@ 2022-12-07 14:24 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 14:24 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, Maíra Canal,
linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> The HVS to PixelValve muxing code is fairly error prone and has a bunch
> of arbitrary constraints due to the hardware setup.
>
> Let's create a test suite that makes sure that the possible combinations
> work and the invalid ones don't.
>
> Reviewed-by: Javier Martinez Canillas <javierm@redhat.com>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Best Regards,
- Maíra Canal
> ---
> drivers/gpu/drm/vc4/Makefile | 3 +-
> drivers/gpu/drm/vc4/tests/vc4_mock.h | 9 +-
> drivers/gpu/drm/vc4/tests/vc4_mock_output.c | 49 +-
> drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c | 1039 ++++++++++++++++++++++++
> 4 files changed, 1091 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/gpu/drm/vc4/Makefile b/drivers/gpu/drm/vc4/Makefile
> index f974a8c80e2f..c41f89a15a55 100644
> --- a/drivers/gpu/drm/vc4/Makefile
> +++ b/drivers/gpu/drm/vc4/Makefile
> @@ -29,7 +29,8 @@ vc4-$(CONFIG_DRM_VC4_KUNIT_TEST) += \
> tests/vc4_mock.o \
> tests/vc4_mock_crtc.o \
> tests/vc4_mock_output.o \
> - tests/vc4_mock_plane.o
> + tests/vc4_mock_plane.o \
> + tests/vc4_test_pv_muxing.o
>
> vc4-$(CONFIG_DEBUG_FS) += vc4_debugfs.o
>
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock.h b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> index ace5b2e00f4a..db8e9a141ef8 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock.h
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock.h
> @@ -53,8 +53,11 @@ struct vc4_dummy_output *vc4_dummy_output(struct kunit *test,
> struct vc4_dev *vc4_mock_device(struct kunit *test);
> struct vc4_dev *vc5_mock_device(struct kunit *test);
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state);
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type);
>
> #endif // VC4_MOCK_H_
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> index cb16ab4451f7..8d33be828d9a 100644
> --- a/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> +++ b/drivers/gpu/drm/vc4/tests/vc4_mock_output.c
> @@ -61,16 +61,17 @@ static const struct drm_display_mode default_mode = {
> DRM_SIMPLE_MODE(640, 480, 64, 48)
> };
>
> -int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
> - enum vc4_encoder_type type,
> - struct drm_atomic_state *state)
> +int vc4_mock_atomic_add_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> {
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> struct vc4_dummy_output *output;
> struct drm_connector *conn;
> - struct drm_connector_state *conn_state;
> struct drm_encoder *encoder;
> struct drm_crtc *crtc;
> - struct drm_crtc_state *crtc_state;
> int ret;
>
> encoder = vc4_find_encoder_by_type(drm, type);
> @@ -97,3 +98,41 @@ int vc4_mock_atomic_add_output(struct kunit *test, struct drm_device *drm,
>
> return 0;
> }
> +
> +int vc4_mock_atomic_del_output(struct kunit *test,
> + struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_connector_state *conn_state;
> + struct drm_crtc_state *crtc_state;
> + struct vc4_dummy_output *output;
> + struct drm_connector *conn;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> + int ret;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + crtc_state = drm_atomic_get_crtc_state(state, crtc);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc_state);
> +
> + crtc_state->active = false;
> +
> + ret = drm_atomic_set_mode_for_crtc(crtc_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + output = container_of(encoder, struct vc4_dummy_output, encoder.base);
> + conn = &output->connector;
> + conn_state = drm_atomic_get_connector_state(state, conn);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, conn_state);
> +
> + ret = drm_atomic_set_crtc_for_connector(conn_state, NULL);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + return 0;
> +}
> diff --git a/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> new file mode 100644
> index 000000000000..ae0bd0f81698
> --- /dev/null
> +++ b/drivers/gpu/drm/vc4/tests/vc4_test_pv_muxing.c
> @@ -0,0 +1,1039 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <drm/drm_atomic.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_atomic_state_helper.h>
> +#include <drm/drm_atomic_uapi.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_drv.h>
> +#include <drm/drm_fourcc.h>
> +#include <drm/drm_kunit_helpers.h>
> +#include <drm/drm_mode.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane.h>
> +
> +#include <kunit/test.h>
> +
> +#include "../vc4_drv.h"
> +
> +#include "vc4_mock.h"
> +
> +struct pv_muxing_priv {
> + struct vc4_dev *vc4;
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> +};
> +
> +static bool check_fifo_conflict(struct kunit *test,
> + const struct drm_atomic_state *state)
> +{
> + struct vc4_hvs_state *hvs_state;
> + unsigned int used_fifos = 0;
> + unsigned int i;
> +
> + hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, hvs_state);
> +
> + for (i = 0; i < HVS_NUM_CHANNELS; i++) {
> + if (!hvs_state->fifo_state[i].in_use)
> + continue;
> +
> + KUNIT_EXPECT_FALSE(test, used_fifos & BIT(i));
> + used_fifos |= BIT(i);
> + }
> +
> + return true;
> +}
> +
> +struct encoder_constraint {
> + enum vc4_encoder_type type;
> + unsigned int *channels;
> + size_t nchannels;
> +};
> +
> +#define ENCODER_CONSTRAINT(_type, ...) \
> + { \
> + .type = _type, \
> + .channels = (unsigned int[]) { __VA_ARGS__ }, \
> + .nchannels = sizeof((unsigned int[]) { __VA_ARGS__ }) / \
> + sizeof(unsigned int), \
> + }
> +
> +static bool __check_encoder_constraints(const struct encoder_constraint *constraints,
> + size_t nconstraints,
> + enum vc4_encoder_type type,
> + unsigned int channel)
> +{
> + unsigned int i;
> +
> + for (i = 0; i < nconstraints; i++) {
> + const struct encoder_constraint *constraint = &constraints[i];
> + unsigned int j;
> +
> + if (constraint->type != type)
> + continue;
> +
> + for (j = 0; j < constraint->nchannels; j++) {
> + unsigned int _channel = constraint->channels[j];
> +
> + if (channel != _channel)
> + continue;
> +
> + return true;
> + }
> + }
> +
> + return false;
> +}
> +
> +static const struct encoder_constraint vc4_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 2),
> +};
> +
> +static const struct encoder_constraint vc5_encoder_constraints[] = {
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DPI, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI0, 0),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_VEC, 1),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_TXP, 0, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_DSI1, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI0, 0, 1, 2),
> + ENCODER_CONSTRAINT(VC4_ENCODER_TYPE_HDMI1, 0, 1, 2),
> +};
> +
> +static bool check_vc4_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc4_encoder_constraints,
> + ARRAY_SIZE(vc4_encoder_constraints),
> + type, channel);
> +}
> +
> +static bool check_vc5_encoder_constraints(enum vc4_encoder_type type, unsigned int channel)
> +{
> + return __check_encoder_constraints(vc5_encoder_constraints,
> + ARRAY_SIZE(vc5_encoder_constraints),
> + type, channel);
> +}
> +
> +static struct vc4_crtc_state *
> +get_vc4_crtc_state_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type)
> +{
> + struct drm_device *drm = state->dev;
> + struct drm_crtc_state *new_crtc_state;
> + struct drm_encoder *encoder;
> + struct drm_crtc *crtc;
> +
> + encoder = vc4_find_encoder_by_type(drm, type);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, encoder);
> +
> + crtc = vc4_find_crtc_for_encoder(test, drm, encoder);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, crtc);
> +
> + new_crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> + if (!new_crtc_state)
> + return NULL;
> +
> + return to_vc4_crtc_state(new_crtc_state);
> +}
> +
> +static bool check_channel_for_encoder(struct kunit *test,
> + const struct drm_atomic_state *state,
> + enum vc4_encoder_type type,
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel))
> +{
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int channel;
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state, type);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_EXPECT_NE(test, channel, VC4_HVS_CHANNEL_DISABLED);
> +
> + KUNIT_EXPECT_TRUE(test, new_hvs_state->fifo_state[channel].in_use);
> +
> + KUNIT_EXPECT_TRUE(test, check_fn(type, channel));
> +
> + return true;
> +}
> +
> +struct pv_muxing_param {
> + const char *name;
> + struct vc4_dev *(*mock_fn)(struct kunit *test);
> + bool (*check_fn)(enum vc4_encoder_type type, unsigned int channel);
> + enum vc4_encoder_type *encoders;
> + size_t nencoders;
> +};
> +
> +static void vc4_test_pv_muxing_desc(const struct pv_muxing_param *t, char *desc)
> +{
> + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE);
> +}
> +
> +#define PV_MUXING_TEST(_name, _mock_fn, _check_fn, ...) \
> + { \
> + .name = _name, \
> + .mock_fn = &_mock_fn, \
> + .check_fn = &_check_fn, \
> + .encoders = (enum vc4_encoder_type[]) { __VA_ARGS__ }, \
> + .nencoders = sizeof((enum vc4_encoder_type[]) { __VA_ARGS__ }) / \
> + sizeof(enum vc4_encoder_type), \
> + }
> +
> +#define VC4_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc4_mock_device, check_vc4_encoder_constraints, __VA_ARGS__)
> +
> +#define VC5_PV_MUXING_TEST(_name, ...) \
> + PV_MUXING_TEST(_name, vc5_mock_device, check_vc5_encoder_constraints, __VA_ARGS__)
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_params[] = {
> + VC4_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC4_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("1 output: TXP",
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, DSI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, DSI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("2 outputs: VEC, TXP",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, HDMI0, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing,
> + vc4_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc4_test_pv_muxing_invalid_params[] = {
> + VC4_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC4_PV_MUXING_TEST("TXP/DSI1 Conflict",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC4_PV_MUXING_TEST("HDMI0/VEC Conflict",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, HDMI0, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC4_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_params[] = {
> + VC5_PV_MUXING_TEST("1 output: DPI",
> + VC4_ENCODER_TYPE_DPI),
> + VC5_PV_MUXING_TEST("1 output: DSI0",
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("1 output: DSI1",
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("1 output: HDMI0",
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("1 output: HDMI1",
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("1 output: VEC",
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, VEC",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DPI, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, VEC",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI0, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, VEC",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, TXP",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("2 outputs: DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, VEC",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, TXP",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, VEC",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("2 outputs: HDMI1, TXP",
> + VC4_ENCODER_TYPE_HDMI1,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("2 outputs: TXP, VEC",
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_VEC),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, TXP",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DPI, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, TXP",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, VEC, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("3 outputs: DSI0, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing,
> + vc5_test_pv_muxing_params,
> + vc4_test_pv_muxing_desc);
> +
> +static const struct pv_muxing_param vc5_test_pv_muxing_invalid_params[] = {
> + VC5_PV_MUXING_TEST("DPI/DSI0 Conflict",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DPI, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DPI,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> + VC5_PV_MUXING_TEST("More than 3 outputs: DSI0, VEC, TXP, DSI1, HDMI0, HDMI1",
> + VC4_ENCODER_TYPE_DSI0,
> + VC4_ENCODER_TYPE_VEC,
> + VC4_ENCODER_TYPE_TXP,
> + VC4_ENCODER_TYPE_DSI1,
> + VC4_ENCODER_TYPE_HDMI0,
> + VC4_ENCODER_TYPE_HDMI1),
> +};
> +
> +KUNIT_ARRAY_PARAM(vc5_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_params,
> + vc4_test_pv_muxing_desc);
> +
> +static void drm_vc4_test_pv_muxing(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + KUNIT_EXPECT_TRUE(test,
> + check_fifo_conflict(test, state));
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + KUNIT_EXPECT_TRUE(test, check_channel_for_encoder(test, state, enc_type,
> + params->check_fn));
> + }
> +}
> +
> +static void drm_vc4_test_pv_muxing_invalid(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + const struct pv_muxing_priv *priv = test->priv;
> + struct drm_atomic_state *state = priv->state;
> + unsigned int i;
> + int ret;
> +
> + for (i = 0; i < params->nencoders; i++) {
> + enum vc4_encoder_type enc_type = params->encoders[i];
> +
> + ret = vc4_mock_atomic_add_output(test, state, enc_type);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> + }
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_EXPECT_LT(test, ret, 0);
> +}
> +
> +static int vc4_pv_muxing_test_init(struct kunit *test)
> +{
> + const struct pv_muxing_param *params = test->param_value;
> + struct drm_atomic_state *state;
> + struct pv_muxing_priv *priv;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> +
> + priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL);
> + KUNIT_ASSERT_NOT_NULL(test, priv);
> + test->priv = priv;
> +
> + vc4 = params->mock_fn(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> + priv->vc4 = vc4;
> +
> + drm_modeset_acquire_init(&priv->ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &priv->ctx;
> +
> + priv->state = state;
> +
> + return 0;
> +}
> +
> +static void vc4_pv_muxing_test_exit(struct kunit *test)
> +{
> + struct pv_muxing_priv *priv = test->priv;
> + struct vc4_dev *vc4 = priv->vc4;
> + struct drm_device *drm = &vc4->base;
> + struct drm_atomic_state *state = priv->state;
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&priv->ctx);
> + drm_modeset_acquire_fini(&priv->ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc4_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc4_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc4_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc4_pv_muxing_test_suite = {
> + .name = "vc4-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc4_pv_muxing_tests,
> +};
> +
> +static struct kunit_case vc5_pv_muxing_tests[] = {
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing,
> + vc5_test_pv_muxing_gen_params),
> + KUNIT_CASE_PARAM(drm_vc4_test_pv_muxing_invalid,
> + vc5_test_pv_muxing_invalid_gen_params),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_test_suite = {
> + .name = "vc5-pv-muxing-combinations",
> + .init = vc4_pv_muxing_test_init,
> + .exit = vc4_pv_muxing_test_exit,
> + .test_cases = vc5_pv_muxing_tests,
> +};
> +
> +/* See
> + * https://lore.kernel.org/all/3e113525-aa89-b1e2-56b7-ca55bd41d057@samsung.com/
> + * and
> + * https://lore.kernel.org/dri-devel/20200917121623.42023-1-maxime@cerno.tech/
> + */
> +static void drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int hdmi0_channel;
> + unsigned int hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi0_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_NE(test, hdmi0_channel, hdmi1_channel);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void drm_test_vc5_pv_muxing_bugs_stable_fifo(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct vc4_hvs_state *new_hvs_state;
> + unsigned int old_hdmi0_channel;
> + unsigned int old_hdmi1_channel;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi0_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi0_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi0_channel].in_use);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_NOT_NULL(test, new_vc4_crtc_state);
> +
> + old_hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, old_hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[old_hdmi1_channel].in_use);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_del_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_hvs_state = vc4_hvs_get_new_global_state(state);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, new_hvs_state);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI1);
> +
> + if (new_vc4_crtc_state) {
> + unsigned int hdmi1_channel;
> +
> + hdmi1_channel = new_vc4_crtc_state->assigned_channel;
> + KUNIT_ASSERT_NE(test, hdmi1_channel, VC4_HVS_CHANNEL_DISABLED);
> + KUNIT_ASSERT_TRUE(test, new_hvs_state->fifo_state[hdmi1_channel].in_use);
> +
> + KUNIT_EXPECT_EQ(test, old_hdmi1_channel, hdmi1_channel);
> + }
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static void
> +drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state(struct kunit *test)
> +{
> + struct drm_modeset_acquire_ctx ctx;
> + struct drm_atomic_state *state;
> + struct vc4_crtc_state *new_vc4_crtc_state;
> + struct drm_device *drm;
> + struct vc4_dev *vc4;
> + int ret;
> +
> + vc4 = vc5_mock_device(test);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vc4);
> +
> + drm_modeset_acquire_init(&ctx, 0);
> +
> + drm = &vc4->base;
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_helper_swap_state(state, false);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + drm_atomic_state_put(state);
> +
> + state = drm_atomic_state_alloc(drm);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state);
> +
> + state->acquire_ctx = &ctx;
> +
> + ret = vc4_mock_atomic_add_output(test, state, VC4_ENCODER_TYPE_HDMI1);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + ret = drm_atomic_check_only(state);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + new_vc4_crtc_state = get_vc4_crtc_state_for_encoder(test, state,
> + VC4_ENCODER_TYPE_HDMI0);
> + KUNIT_EXPECT_NULL(test, new_vc4_crtc_state);
> +
> + drm_atomic_state_put(state);
> + drm_modeset_drop_locks(&ctx);
> + drm_modeset_acquire_fini(&ctx);
> + drm_dev_unregister(drm);
> + drm_kunit_helper_free_device(test, vc4->dev);
> +}
> +
> +static struct kunit_case vc5_pv_muxing_bugs_tests[] = {
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_subsequent_crtc_enable_too_many_crtc_state),
> + KUNIT_CASE(drm_test_vc5_pv_muxing_bugs_stable_fifo),
> + {}
> +};
> +
> +static struct kunit_suite vc5_pv_muxing_bugs_test_suite = {
> + .name = "vc5-pv-muxing-bugs",
> + .test_cases = vc5_pv_muxing_bugs_tests,
> +};
> +
> +kunit_test_suites(
> + &vc4_pv_muxing_test_suite,
> + &vc5_pv_muxing_test_suite,
> + &vc5_pv_muxing_bugs_test_suite
> +);
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (18 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 19/20] drm/vc4: tests: Add unit test suite for the PV muxing Maxime Ripard
@ 2022-12-01 15:11 ` Maxime Ripard
2022-12-07 13:55 ` Maíra Canal
2022-12-08 8:58 ` [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
20 siblings, 1 reply; 36+ messages in thread
From: Maxime Ripard @ 2022-12-01 15:11 UTC (permalink / raw)
To: Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, Maxime Ripard, linux-kselftest, kunit-dev,
Maíra Canal, linux-media
Now that we have VC4-specific tests in place, let's document them
properly.
Signed-off-by: Maxime Ripard <maxime@cerno.tech>
---
Documentation/gpu/vc4.rst | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/Documentation/gpu/vc4.rst b/Documentation/gpu/vc4.rst
index 5df1d98b9544..a2375f1584e6 100644
--- a/Documentation/gpu/vc4.rst
+++ b/Documentation/gpu/vc4.rst
@@ -54,6 +54,22 @@ VEC (Composite TV out) encoder
.. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
:doc: VC4 SDTV module
+KUnit Tests
+===========
+
+The VC4 Driver uses KUnit to perform driver-specific unit and
+integration tests.
+
+These tests are using a mock driver and can be ran using the
+command::
+ ./tools/testing/kunit/kunit.py run \
+ --kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
+ --cross_compile aarch64-linux-gnu- --arch arm64
+
+Parts of the driver that are currently covered by tests are:
+ * The HVS to PixelValve dynamic FIFO assignment, for the BCM2835-7
+ and BCM2711.
+
Memory Management and 3D Command Submission
===========================================
--
b4 0.10.1
^ permalink raw reply related [flat|nested] 36+ messages in thread
* Re: [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section
2022-12-01 15:11 ` [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section Maxime Ripard
@ 2022-12-07 13:55 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:55 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: David Gow, Dave Stevenson, Greg Kroah-Hartman, Maíra Canal,
Javier Martinez Canillas, dri-devel, linux-kernel, linaro-mm-sig,
Brendan Higgins, linux-kselftest, kunit-dev, linux-media
On 12/1/22 12:11, Maxime Ripard wrote:
> Now that we have VC4-specific tests in place, let's document them
> properly.
>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit below.
> ---
> Documentation/gpu/vc4.rst | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/Documentation/gpu/vc4.rst b/Documentation/gpu/vc4.rst
> index 5df1d98b9544..a2375f1584e6 100644
> --- a/Documentation/gpu/vc4.rst
> +++ b/Documentation/gpu/vc4.rst
> @@ -54,6 +54,22 @@ VEC (Composite TV out) encoder
> .. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
> :doc: VC4 SDTV module
>
> +KUnit Tests
> +===========
> +
> +The VC4 Driver uses KUnit to perform driver-specific unit and
> +integration tests.
> +
> +These tests are using a mock driver and can be ran using the
> +command::
> + ./tools/testing/kunit/kunit.py run \
> + --kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
> + --cross_compile aarch64-linux-gnu- --arch arm64
I believe you could use a code block here, like:
.. code-block:: bash
$ ./tools/testing/kunit/kunit.py run \
--kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
--cross_compile aarch64-linux-gnu- --arch arm64
You could also mention that you can run the tests with --arch arm.
Best Regards,
- Maíra Canal
> +
> +Parts of the driver that are currently covered by tests are:
> + * The HVS to PixelValve dynamic FIFO assignment, for the BCM2835-7
> + and BCM2711.
> +
> Memory Management and 3D Command Submission
> ===========================================
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section
@ 2022-12-07 13:55 ` Maíra Canal
0 siblings, 0 replies; 36+ messages in thread
From: Maíra Canal @ 2022-12-07 13:55 UTC (permalink / raw)
To: Maxime Ripard, Maxime Ripard, Maarten Lankhorst, Daniel Vetter,
Thomas Zimmermann, David Airlie
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
Maíra Canal, Javier Martinez Canillas, dri-devel,
linux-kernel, linaro-mm-sig, Brendan Higgins, David Gow,
linux-media, kunit-dev
On 12/1/22 12:11, Maxime Ripard wrote:
> Now that we have VC4-specific tests in place, let's document them
> properly.
>
> Signed-off-by: Maxime Ripard <maxime@cerno.tech>
Reviewed-by: Maíra Canal <mcanal@igalia.com>
Just a small nit below.
> ---
> Documentation/gpu/vc4.rst | 16 ++++++++++++++++
> 1 file changed, 16 insertions(+)
>
> diff --git a/Documentation/gpu/vc4.rst b/Documentation/gpu/vc4.rst
> index 5df1d98b9544..a2375f1584e6 100644
> --- a/Documentation/gpu/vc4.rst
> +++ b/Documentation/gpu/vc4.rst
> @@ -54,6 +54,22 @@ VEC (Composite TV out) encoder
> .. kernel-doc:: drivers/gpu/drm/vc4/vc4_vec.c
> :doc: VC4 SDTV module
>
> +KUnit Tests
> +===========
> +
> +The VC4 Driver uses KUnit to perform driver-specific unit and
> +integration tests.
> +
> +These tests are using a mock driver and can be ran using the
> +command::
> + ./tools/testing/kunit/kunit.py run \
> + --kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
> + --cross_compile aarch64-linux-gnu- --arch arm64
I believe you could use a code block here, like:
.. code-block:: bash
$ ./tools/testing/kunit/kunit.py run \
--kunitconfig=drivers/gpu/drm/vc4/tests/.kunitconfig \
--cross_compile aarch64-linux-gnu- --arch arm64
You could also mention that you can run the tests with --arch arm.
Best Regards,
- Maíra Canal
> +
> +Parts of the driver that are currently covered by tests are:
> + * The HVS to PixelValve dynamic FIFO assignment, for the BCM2835-7
> + and BCM2711.
> +
> Memory Management and 3D Command Submission
> ===========================================
>
>
^ permalink raw reply [flat|nested] 36+ messages in thread
* Re: [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4
2022-12-01 15:11 [PATCH v3 00/20] drm: Introduce Kunit Tests to VC4 Maxime Ripard
` (19 preceding siblings ...)
2022-12-01 15:11 ` [PATCH v3 20/20] Documentation: gpu: vc4: Add KUnit Tests Section Maxime Ripard
@ 2022-12-08 8:58 ` Maxime Ripard
20 siblings, 0 replies; 36+ messages in thread
From: Maxime Ripard @ 2022-12-08 8:58 UTC (permalink / raw)
To: Maarten Lankhorst, David Airlie, Daniel Vetter, Maxime Ripard,
Maxime Ripard, Thomas Zimmermann
Cc: linux-kselftest, Dave Stevenson, Greg Kroah-Hartman,
Ma��ra Canal, linux-kernel, dri-devel,
Javier Martinez Canillas, linaro-mm-sig, Brendan Higgins,
David Gow, linux-media, Ma��ra Canal, kunit-dev
On Thu, 01 Dec 2022 16:11:31 +0100, Maxime Ripard wrote:
> This series introduce Kunit tests to the vc4 KMS driver, but unlike what we
> have been doing so far in KMS, it actually tests the atomic modesetting code.
>
> In order to do so, I've had to improve a fair bit on the Kunit helpers already
> found in the tree in order to register a full blown and somewhat functional KMS
> driver.
>
> [...]
Applied to drm/drm-misc (drm-misc-next).
Thanks!
Maxime
^ permalink raw reply [flat|nested] 36+ messages in thread