Some DRM helpers report the state of an object through a drm_printer,
most notably to report which fields of two states differ when comparing
them.

Tests exercising such code paths need to pass a drm_printer as well, and
would rather have its output show up in the KTAP log of the test than
anywhere else, so that a failure comes with the report that caused it.

Add drm_kunit_helper_printer() that returns a drm_printer whose messages
are logged through kunit_log() at the LOGLEVEL_* level requested by the
caller.

Signed-off-by: Maxime Ripard <[email protected]>
---
 drivers/gpu/drm/tests/drm_kunit_helpers.c | 78 +++++++++++++++++++++++++++++++
 include/drm/drm_kunit_helpers.h           |  4 ++
 2 files changed, 82 insertions(+)

diff --git a/drivers/gpu/drm/tests/drm_kunit_helpers.c 
b/drivers/gpu/drm/tests/drm_kunit_helpers.c
index 63d024946500..fad911772ee5 100644
--- a/drivers/gpu/drm/tests/drm_kunit_helpers.c
+++ b/drivers/gpu/drm/tests/drm_kunit_helpers.c
@@ -9,4 +9,5 @@
 #include <drm/drm_kunit_helpers.h>
 #include <drm/drm_managed.h>
+#include <drm/drm_print.h>
 
 #include <kunit/device.h>
@@ -19,4 +20,81 @@
 #define KUNIT_DEVICE_NAME      "drm-kunit-mock-device"
 
+struct drm_printer_ctx {
+       struct drm_printer      p;
+       int                     level;
+       struct kunit            *test;
+};
+
+/*
+ * kunit_log() is a macro that only accepts a compile-time log level,
+ * so the level has to be dispatched to the matching kunit_log() call.
+ */
+static void drm_kunit_printf(struct drm_printer *p, struct va_format *vaf)
+{
+       struct drm_printer_ctx *ctx = p->arg;
+
+       switch (ctx->level) {
+       case LOGLEVEL_EMERG:
+               kunit_log(KERN_EMERG, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_ALERT:
+               kunit_log(KERN_ALERT, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_CRIT:
+               kunit_log(KERN_CRIT, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_ERR:
+               kunit_log(KERN_ERR, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_WARNING:
+               kunit_log(KERN_WARNING, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_NOTICE:
+               kunit_log(KERN_NOTICE, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_DEBUG:
+               kunit_log(KERN_DEBUG, ctx->test, "%pV", vaf);
+               break;
+       case LOGLEVEL_INFO:
+       default:
+               kunit_log(KERN_INFO, ctx->test, "%pV", vaf);
+               break;
+       }
+}
+
+/**
+ * drm_kunit_helper_printer - Creates a &drm_printer logging into a KUnit test 
log
+ * @test: The test context object
+ * @level: The log level to log the messages at, one of the KERN_* constants
+ *
+ * Creates a &struct drm_printer that will log anything printed through
+ * it, using kunit_log(), both to the kernel log at the @level log
+ * level and to the log of the KUnit test @test.
+ *
+ * This is the KUnit counterpart of the drm_print.h printers like
+ * drm_info_printer() or drm_err_printer(), and @level should be the
+ * log level of the printer it replaces.
+ *
+ * Returns:
+ * A pointer to the &drm_printer, or an ERR_PTR() otherwise.
+ */
+struct drm_printer *
+drm_kunit_helper_printer(struct kunit *test, int level)
+{
+       struct drm_printer_ctx *ctx;
+
+       ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
+       if (!ctx)
+               return ERR_PTR(-ENOMEM);
+
+       ctx->level = level;
+       ctx->p.printfn = drm_kunit_printf;
+       ctx->p.arg = ctx;
+       ctx->test = test;
+
+       return &ctx->p;
+}
+EXPORT_SYMBOL_GPL(drm_kunit_helper_printer);
+
 static const struct drm_mode_config_funcs drm_mode_config_funcs = {
        .atomic_check   = drm_atomic_helper_check,
diff --git a/include/drm/drm_kunit_helpers.h b/include/drm/drm_kunit_helpers.h
index e653bc7b1e40..d38614d87678 100644
--- a/include/drm/drm_kunit_helpers.h
+++ b/include/drm/drm_kunit_helpers.h
@@ -16,6 +16,10 @@ struct drm_device;
 struct drm_plane_funcs;
 struct drm_plane_helper_funcs;
+struct drm_printer;
 struct kunit;
 
+struct drm_printer *drm_kunit_helper_printer(struct kunit *test,
+                                            int level);
+
 struct device *drm_kunit_helper_alloc_device(struct kunit *test);
 void drm_kunit_helper_free_device(struct kunit *test, struct device *dev);

-- 
2.55.0

Reply via email to