[PATCH 08/49] drm/amd/display: Add KUnit tests for watchdog and cpirq events

Fangzhi Zuo <[email protected]>
Newsgroups org.freedesktop.lists.amd-gfx
Message-ID <[email protected]>
From: Bhawanpreet Lakha <[email protected]>

Verify event_watchdog_timer() cancels its pending watchdog_dwork
and runs process_output(), and that event_cpirq() runs
process_output() without arming the callback or watchdog timers.
Both release the work-queue mutex on return.

Reviewed-by: Alex Hung <[email protected]>
Signed-off-by: Bhawanpreet Lakha <[email protected]>
Signed-off-by: Fangzhi Zuo <[email protected]>
Tested-by: Dan Wheeler <[email protected]>
---
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.c    |   8 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |   2 +
 .../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c     | 132 ++++++++++++++++++
 3 files changed, 140 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
index 622d9c275c3a..896668c92888 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
@@ -517,7 +517,8 @@ void event_property_validate(struct work_struct *work)
 }
 EXPORT_IF_KUNIT(event_property_validate);
 
-static void event_watchdog_timer(struct work_struct *work)
+STATIC_IFN_KUNIT
+void event_watchdog_timer(struct work_struct *work)
 {
 	struct hdcp_workqueue *hdcp_work;
 
@@ -535,8 +536,10 @@ static void event_watchdog_timer(struct work_struct *work)
 
 	process_output(hdcp_work);
 }
+EXPORT_IF_KUNIT(event_watchdog_timer);
 
-static void event_cpirq(struct work_struct *work)
+STATIC_IFN_KUNIT
+void event_cpirq(struct work_struct *work)
 {
 	struct hdcp_workqueue *hdcp_work;
 
@@ -548,6 +551,7 @@ static void event_cpirq(struct work_struct *work)
 
 	process_output(hdcp_work);
 }
+EXPORT_IF_KUNIT(event_cpirq);
 
 void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
 {
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index 57c534efbc71..a2b08bec58b5 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -116,6 +116,8 @@ void hdcp_update_display_encryption_control(struct hdcp_workqueue *hdcp_work,
 void event_property_update(struct work_struct *work);
 void event_property_validate(struct work_struct *work);
 void event_callback(struct work_struct *work);
+void event_watchdog_timer(struct work_struct *work);
+void event_cpirq(struct work_struct *work);
 void link_lock(struct hdcp_workqueue *work, bool lock);
 void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index,
 			 struct amdgpu_dm_connector *aconnector);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
index 6f5cae0960e1..a4097a4aec26 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c
@@ -748,6 +748,132 @@ static void dm_test_event_property_validate_no_update_when_unchanged(struct kuni
 
 /* End of tests for event_property_validate() */
 
+/* Tests for event_watchdog_timer() */
+
+/**
+ * dm_test_event_watchdog_timer_cancels_watchdog_dwork - watchdog work is cancelled
+ * @test: KUnit test context
+ *
+ * event_watchdog_timer() must cancel a previously scheduled
+ * watchdog_timer_dwork. With no active hdcp display,
+ * mod_hdcp_process_event() leaves output cleared so the watchdog is not
+ * requeued and watchdog_timer_dwork ends up not pending.
+ */
+static void dm_test_event_watchdog_timer_cancels_watchdog_dwork(struct kunit *test)
+{
+	struct hdcp_workqueue *work = alloc_test_workqueue_for_callback(test);
+
+	/* Pre-schedule watchdog_timer_dwork with a long delay so it won't fire. */
+	schedule_delayed_work(&work->watchdog_timer_dwork, msecs_to_jiffies(10000));
+	KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
+
+	event_watchdog_timer(&work->watchdog_timer_dwork.work);
+
+	KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->watchdog_timer_dwork));
+
+	cancel_delayed_work_sync(&work->callback_dwork);
+	cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+	cancel_delayed_work_sync(&work->property_validate_dwork);
+}
+
+/**
+ * dm_test_event_watchdog_timer_schedules_property_validate - process_output() runs
+ * @test: KUnit test context
+ *
+ * event_watchdog_timer() finishes by calling process_output(), which always
+ * enqueues property_validate_dwork with delay=0. Verifying it is pending
+ * proves the handler reached process_output() and released the mutex.
+ */
+static void dm_test_event_watchdog_timer_schedules_property_validate(struct kunit *test)
+{
+	struct hdcp_workqueue *work = alloc_test_workqueue_for_callback(test);
+
+	event_watchdog_timer(&work->watchdog_timer_dwork.work);
+
+	KUNIT_EXPECT_TRUE(test, work_pending(&work->property_validate_dwork.work));
+	/* Mutex must be released after the guard scope exits. */
+	KUNIT_EXPECT_FALSE(test, mutex_is_locked(&work->mutex));
+
+	cancel_delayed_work_sync(&work->callback_dwork);
+	cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+	cancel_delayed_work_sync(&work->property_validate_dwork);
+}
+
+/* End of tests for event_watchdog_timer() */
+
+/* Tests for event_cpirq() */
+
+/**
+ * alloc_test_workqueue_for_cpirq - workqueue ready for event_cpirq()
+ * @test: KUnit test context for managed allocation
+ *
+ * Allocates a minimal hdcp_workqueue with its mutex, cpirq_work and the
+ * three delayed works initialised, as required by the guard(mutex) and
+ * process_output() usage inside event_cpirq().
+ */
+static struct hdcp_workqueue *alloc_test_workqueue_for_cpirq(struct kunit *test)
+{
+	struct hdcp_workqueue *work;
+
+	work = kunit_kzalloc(test, sizeof(*work), GFP_KERNEL);
+	KUNIT_ASSERT_NOT_NULL(test, work);
+
+	mutex_init(&work->mutex);
+	INIT_WORK(&work->cpirq_work, dummy_work_fn);
+	INIT_DELAYED_WORK(&work->callback_dwork, dummy_work_fn);
+	INIT_DELAYED_WORK(&work->watchdog_timer_dwork, dummy_work_fn);
+	INIT_DELAYED_WORK(&work->property_validate_dwork, dummy_work_fn);
+
+	return work;
+}
+
+/**
+ * dm_test_event_cpirq_schedules_property_validate - process_output() runs
+ * @test: KUnit test context
+ *
+ * event_cpirq() finishes by calling process_output(), which always
+ * enqueues property_validate_dwork with delay=0. Verifying it is pending
+ * proves the handler reached process_output() and released the mutex.
+ */
+static void dm_test_event_cpirq_schedules_property_validate(struct kunit *test)
+{
+	struct hdcp_workqueue *work = alloc_test_workqueue_for_cpirq(test);
+
+	event_cpirq(&work->cpirq_work);
+
+	KUNIT_EXPECT_TRUE(test, work_pending(&work->property_validate_dwork.work));
+	/* Mutex must be released after the guard scope exits. */
+	KUNIT_EXPECT_FALSE(test, mutex_is_locked(&work->mutex));
+
+	cancel_delayed_work_sync(&work->callback_dwork);
+	cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+	cancel_delayed_work_sync(&work->property_validate_dwork);
+}
+
+/**
+ * dm_test_event_cpirq_leaves_callback_and_watchdog_idle - only validate is queued
+ * @test: KUnit test context
+ *
+ * With no active hdcp display, mod_hdcp_process_event() leaves output
+ * cleared, so event_cpirq() must not schedule callback_dwork or
+ * watchdog_timer_dwork; only property_validate_dwork is enqueued.
+ */
+static void dm_test_event_cpirq_leaves_callback_and_watchdog_idle(struct kunit *test)
+{
+	struct hdcp_workqueue *work = alloc_test_workqueue_for_cpirq(test);
+
+	event_cpirq(&work->cpirq_work);
+
+	KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->callback_dwork));
+	KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->watchdog_timer_dwork));
+
+	cancel_delayed_work_sync(&work->callback_dwork);
+	cancel_delayed_work_sync(&work->watchdog_timer_dwork);
+	cancel_delayed_work_sync(&work->property_validate_dwork);
+}
+
+/* End of tests for event_cpirq() */
+
 /* Tests for hdcp_handle_cpirq() */
 
 /**
@@ -1233,6 +1359,12 @@ static struct kunit_case dm_hdcp_test_cases[] = {
 	KUNIT_CASE(dm_test_event_property_validate_skips_null_state),
 	KUNIT_CASE(dm_test_event_property_validate_updates_on_status_change),
 	KUNIT_CASE(dm_test_event_property_validate_no_update_when_unchanged),
+	/* event_watchdog_timer() */
+	KUNIT_CASE(dm_test_event_watchdog_timer_cancels_watchdog_dwork),
+	KUNIT_CASE(dm_test_event_watchdog_timer_schedules_property_validate),
+	/* event_cpirq() */
+	KUNIT_CASE(dm_test_event_cpirq_schedules_property_validate),
+	KUNIT_CASE(dm_test_event_cpirq_leaves_callback_and_watchdog_idle),
 	/* hdcp_handle_cpirq() */
 	KUNIT_CASE(dm_test_hdcp_handle_cpirq_schedules_work),
 	KUNIT_CASE(dm_test_hdcp_handle_cpirq_selects_link_index),
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.