summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBhawanpreet Lakha <bhawanpreet.lakha@amd.com>2026-07-10 16:12:55 -0400
committerAlex Deucher <alexander.deucher@amd.com>2026-07-28 18:58:39 -0400
commit3c729afe2f9a319e0852de9af460f94d1207ce1a (patch)
tree4fc43a89918367ab1077578fab0faa66e3060a5f
parent560ef68fec09a6fa92539eb99976e020e26148c6 (diff)
downloadlinux-next-3c729afe2f9a319e0852de9af460f94d1207ce1a.tar.gz
linux-next-3c729afe2f9a319e0852de9af460f94d1207ce1a.zip
drm/amd/display: Add KUnit tests for hdcp_destroy
Verify hdcp_destroy() cancels each link's delayed works, removes the SRM sysfs file and frees the workqueue and SRM buffers. Cover both a populated work-queue and the zero-link / NULL-SRM path. Reviewed-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Bhawanpreet Lakha <bhawanpreet.lakha@amd.com> Signed-off-by: Fangzhi Zuo <jerry.zuo@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c1
-rw-r--r--drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_hdcp_test.c122
2 files changed, 123 insertions, 0 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 896668c92888..e704b6b7fc0b 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
@@ -568,6 +568,7 @@ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *hdcp_work)
kfree(hdcp_work->srm_temp);
kfree(hdcp_work);
}
+EXPORT_IF_KUNIT(hdcp_destroy);
static bool enable_assr(void *handle, struct dc_link *link)
{
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 a4097a4aec26..5eace7fa4100 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
@@ -7,6 +7,9 @@
#include <kunit/test.h>
#include <linux/workqueue.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+#include <linux/sysfs.h>
#include "amdgpu.h"
#include "amdgpu_dm.h"
@@ -1007,6 +1010,122 @@ static void dm_test_hdcp_create_workqueue_zero_max_links_returns_null(struct kun
/* End of tests for hdcp_create_workqueue() */
+/* Tests for hdcp_destroy() */
+
+static ssize_t test_srm_bin_read(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr, char *buffer,
+ loff_t pos, size_t count)
+{
+ return 0;
+}
+
+static ssize_t test_srm_bin_write(struct file *filp, struct kobject *kobj,
+ const struct bin_attribute *bin_attr, char *buffer,
+ loff_t pos, size_t count)
+{
+ return count;
+}
+
+/**
+ * setup_destroy_sysfs - create a kobject with the SRM bin file attached
+ * @test: KUnit test context
+ * @work: workqueue whose attr will be registered
+ *
+ * hdcp_destroy() calls sysfs_remove_bin_file() on the first entry's attr, so
+ * a real kobject with the bin file created is required. Returns the kobject,
+ * which the caller must kobject_put() after hdcp_destroy() has run.
+ */
+static struct kobject *setup_destroy_sysfs(struct kunit *test,
+ struct hdcp_workqueue *work)
+{
+ struct kobject *kobj;
+ int ret;
+
+ kobj = kobject_create_and_add("amdgpu_dm_hdcp_test", NULL);
+ KUNIT_ASSERT_NOT_NULL(test, kobj);
+
+ sysfs_bin_attr_init(&work->attr);
+ work->attr.attr.name = "hdcp_srm";
+ work->attr.attr.mode = 0664;
+ work->attr.size = 16;
+ work->attr.read = test_srm_bin_read;
+ work->attr.write = test_srm_bin_write;
+
+ ret = sysfs_create_bin_file(kobj, &work->attr);
+ KUNIT_ASSERT_EQ(test, ret, 0);
+
+ return kobj;
+}
+
+/**
+ * dm_test_hdcp_destroy_frees_and_removes_sysfs - full teardown path
+ * @test: KUnit test context
+ *
+ * hdcp_destroy() must cancel every link's delayed works, remove the SRM
+ * sysfs bin file and free srm, srm_temp and the workqueue itself. The
+ * workqueue and SRM buffers use kzalloc() (not kunit-managed) because
+ * hdcp_destroy() frees them; KASAN/kmemleak validate there is no leak or
+ * use-after-free.
+ */
+static void dm_test_hdcp_destroy_frees_and_removes_sysfs(struct kunit *test)
+{
+ struct hdcp_workqueue *work;
+ struct kobject *kobj;
+
+ work = kzalloc_obj(*work);
+ KUNIT_ASSERT_NOT_NULL(test, work);
+
+ work->max_link = 1;
+ 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);
+
+ work->srm = kzalloc(16, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, work->srm);
+ work->srm_temp = kzalloc(16, GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, work->srm_temp);
+
+ kobj = setup_destroy_sysfs(test, work);
+
+ /* Pre-schedule a delayed work to exercise the cancel path. */
+ schedule_delayed_work(&work->callback_dwork, msecs_to_jiffies(10000));
+ KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->callback_dwork));
+
+ hdcp_destroy(kobj, work);
+
+ /* work is freed by hdcp_destroy(); only the kobject remains. */
+ kobject_put(kobj);
+}
+
+/**
+ * dm_test_hdcp_destroy_zero_links_null_srm - teardown with no links or SRM
+ * @test: KUnit test context
+ *
+ * With max_link == 0 the cancel loop is skipped, and NULL srm/srm_temp make
+ * the kfree() calls no-ops. hdcp_destroy() must still remove the sysfs bin
+ * file and free the workqueue without crashing.
+ */
+static void dm_test_hdcp_destroy_zero_links_null_srm(struct kunit *test)
+{
+ struct hdcp_workqueue *work;
+ struct kobject *kobj;
+
+ work = kzalloc_obj(*work);
+ KUNIT_ASSERT_NOT_NULL(test, work);
+
+ work->max_link = 0;
+ work->srm = NULL;
+ work->srm_temp = NULL;
+
+ kobj = setup_destroy_sysfs(test, work);
+
+ hdcp_destroy(kobj, work);
+
+ kobject_put(kobj);
+}
+
+/* End of tests for hdcp_destroy() */
+
/* Tests for link_lock() */
/**
@@ -1373,6 +1492,9 @@ static struct kunit_case dm_hdcp_test_cases[] = {
KUNIT_CASE(dm_test_hdcp_update_display_disable_resets_status_and_cancels_validate),
/* hdcp_create_workqueue() */
KUNIT_CASE(dm_test_hdcp_create_workqueue_zero_max_links_returns_null),
+ /* hdcp_destroy() */
+ KUNIT_CASE(dm_test_hdcp_destroy_frees_and_removes_sysfs),
+ KUNIT_CASE(dm_test_hdcp_destroy_zero_links_null_srm),
/* link_lock() */
KUNIT_CASE(dm_test_link_lock_locks_and_unlocks_all_links),
KUNIT_CASE(dm_test_link_lock_zero_links_is_noop),