From: Bhawanpreet Lakha <[email protected]>

Verify event_callback() cancels a pending callback_dwork and then
runs process_output(), which re-arms property_validate_dwork, and
that the work-queue mutex is released 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    |  4 +-
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |  1 +
 .../amdgpu_dm/tests/amdgpu_dm_hdcp_test.c     | 78 +++++++++++++++++++
 3 files changed, 82 insertions(+), 1 deletion(-)

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 f786c0a85425..34f70e517dc6 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
@@ -384,7 +384,8 @@ void hdcp_handle_cpirq(struct hdcp_workqueue *hdcp_work, 
unsigned int link_index
 }
 EXPORT_IF_KUNIT(hdcp_handle_cpirq);
 
-static void event_callback(struct work_struct *work)
+STATIC_IFN_KUNIT
+void event_callback(struct work_struct *work)
 {
        struct hdcp_workqueue *hdcp_work;
 
@@ -400,6 +401,7 @@ static void event_callback(struct work_struct *work)
 
        process_output(hdcp_work);
 }
+EXPORT_IF_KUNIT(event_callback);
 
 STATIC_IFN_KUNIT
 void event_property_update(struct work_struct *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 69a50e081c56..4b8ba743f9d8 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
@@ -114,6 +114,7 @@ void hdcp_update_display_encryption_control(struct 
hdcp_workqueue *hdcp_work,
                                            unsigned int conn_index,
                                            bool enable_encryption);
 void event_property_update(struct work_struct *work);
+void event_callback(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 e6d03199187b..e0386030b35e 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
@@ -501,6 +501,81 @@ static void 
dm_test_event_property_update_skips_null_connector(struct kunit *tes
 
 /* End of tests for event_property_update() */
 
+/* Tests for event_callback() */
+
+/**
+ * alloc_test_workqueue_for_callback - workqueue ready for event_callback()
+ * @test: KUnit test context for managed allocation
+ *
+ * Allocates a minimal hdcp_workqueue with its mutex and the three delayed
+ * works initialised, as required by the guard(mutex), cancel_delayed_work()
+ * and process_output() usage inside event_callback().
+ */
+static struct hdcp_workqueue *alloc_test_workqueue_for_callback(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_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_callback_cancels_callback_dwork - callback work is cancelled
+ * @test: KUnit test context
+ *
+ * event_callback() must cancel a previously scheduled callback_dwork. With
+ * no active hdcp display, mod_hdcp_process_event() leaves output cleared so
+ * the callback is not requeued and callback_dwork ends up not pending.
+ */
+static void dm_test_event_callback_cancels_callback_dwork(struct kunit *test)
+{
+       struct hdcp_workqueue *work = alloc_test_workqueue_for_callback(test);
+
+       /* Pre-schedule callback_dwork with a long delay so it won't fire. */
+       schedule_delayed_work(&work->callback_dwork, msecs_to_jiffies(10000));
+       KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->callback_dwork));
+
+       event_callback(&work->callback_dwork.work);
+
+       KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->callback_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_callback_schedules_property_validate - process_output() runs
+ * @test: KUnit test context
+ *
+ * event_callback() finishes by calling process_output(), which always
+ * enqueues property_validate_dwork with delay=0. Verifying it is pending
+ * proves event_callback() reached process_output() and released the mutex.
+ */
+static void dm_test_event_callback_schedules_property_validate(struct kunit 
*test)
+{
+       struct hdcp_workqueue *work = alloc_test_workqueue_for_callback(test);
+
+       event_callback(&work->callback_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_callback() */
+
 /* Tests for hdcp_handle_cpirq() */
 
 /**
@@ -977,6 +1052,9 @@ static struct kunit_case dm_hdcp_test_cases[] = {
        KUNIT_CASE(dm_test_process_output_watchdog_stop_and_needed_requeues),
        /* event_property_update() */
        KUNIT_CASE(dm_test_event_property_update_skips_null_connector),
+       /* event_callback() */
+       KUNIT_CASE(dm_test_event_callback_cancels_callback_dwork),
+       KUNIT_CASE(dm_test_event_callback_schedules_property_validate),
        /* 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

Reply via email to