mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
drm/amd/display: Add KUnit test for HDCP process_output
Expose process_output() as non-static when CONFIG_DRM_AMD_DC_KUNIT_TEST is enabled and add KUnit tests exercising its full branch logic: - property_validate_dwork is always enqueued (delay=0) - callback_dwork is scheduled when callback_needed is set - callback_dwork is cancelled when callback_stop is set - watchdog_timer_dwork is scheduled when watchdog_timer_needed is set - watchdog_timer_dwork is cancelled when watchdog_timer_stop is set - Both dworks are scheduled independently when both flags are set Assisted-by: Copilot:Claude-Sonnet-4.6 Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Hung <alex.hung@amd.com> Signed-off-by: Ivan Lipski <ivan.lipski@amd.com> Tested-by: Dan Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
d28859a470
commit
7a5371e208
|
|
@ -45,8 +45,6 @@
|
|||
* in amdgpu_dm_kms.h file
|
||||
*/
|
||||
|
||||
#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
|
||||
|
||||
#define AMDGPU_DM_MAX_CRTC 6
|
||||
|
||||
#define AMDGPU_DM_MAX_NUM_EDP 2
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "dm_helpers.h"
|
||||
#include <drm/display/drm_hdcp_helper.h>
|
||||
#include "hdcp_psp.h"
|
||||
#include "amdgpu_dm_kunit_helpers.h"
|
||||
|
||||
/*
|
||||
* If the SRM version being loaded is less than or equal to the
|
||||
|
|
@ -158,7 +159,8 @@ static int psp_set_srm(struct psp_context *psp,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void process_output(struct hdcp_workqueue *hdcp_work)
|
||||
STATIC_IFN_KUNIT
|
||||
void process_output(struct hdcp_workqueue *hdcp_work)
|
||||
{
|
||||
struct mod_hdcp_output output = hdcp_work->output;
|
||||
|
||||
|
|
@ -178,6 +180,7 @@ static void process_output(struct hdcp_workqueue *hdcp_work)
|
|||
|
||||
schedule_delayed_work(&hdcp_work->property_validate_dwork, msecs_to_jiffies(0));
|
||||
}
|
||||
EXPORT_IF_KUNIT(process_output);
|
||||
|
||||
static void link_lock(struct hdcp_workqueue *work, bool lock)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -31,12 +31,19 @@
|
|||
#include "hdcp.h"
|
||||
#include "dc.h"
|
||||
#include "dm_cp_psp.h"
|
||||
#include "amdgpu.h"
|
||||
|
||||
/*
|
||||
* Minimal declarations needed by this header.
|
||||
* Full amdgpu/DM definitions come from amdgpu_dm.h included by each .c file.
|
||||
*/
|
||||
#define AMDGPU_DM_MAX_DISPLAY_INDEX 31
|
||||
struct amdgpu_dm_connector;
|
||||
|
||||
struct mod_hdcp;
|
||||
struct mod_hdcp_link;
|
||||
struct mod_hdcp_display;
|
||||
struct cp_psp;
|
||||
struct amdgpu_device;
|
||||
|
||||
struct hdcp_workqueue {
|
||||
struct work_struct cpirq_work;
|
||||
|
|
@ -87,4 +94,8 @@ void hdcp_destroy(struct kobject *kobj, struct hdcp_workqueue *work);
|
|||
|
||||
struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct cp_psp *cp_psp, struct dc *dc);
|
||||
|
||||
#ifdef CONFIG_DRM_AMD_DC_KUNIT_TEST
|
||||
void process_output(struct hdcp_workqueue *hdcp_work);
|
||||
#endif
|
||||
|
||||
#endif /* AMDGPU_DM_AMDGPU_DM_HDCP_H_ */
|
||||
|
|
|
|||
|
|
@ -3,5 +3,10 @@
|
|||
# Makefile for amdgpu_dm KUnit tests.
|
||||
|
||||
ccflags-y += -I$(src)/..
|
||||
ccflags-y += -I$(src)/../..
|
||||
ccflags-y += -I$(src)/../../include
|
||||
ccflags-y += -I$(src)/../../modules/inc
|
||||
ccflags-y += -I$(src)/../../dc
|
||||
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crc_test.o
|
||||
obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_hdcp_test.o
|
||||
|
|
|
|||
|
|
@ -0,0 +1,175 @@
|
|||
// SPDX-License-Identifier: GPL-2.0 OR MIT
|
||||
/*
|
||||
* KUnit tests for amdgpu_dm_hdcp.c
|
||||
*
|
||||
* Copyright 2026 Advanced Micro Devices, Inc.
|
||||
*/
|
||||
|
||||
#include <kunit/test.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include "amdgpu_dm_hdcp.h"
|
||||
|
||||
static void dummy_work_fn(struct work_struct *work) {}
|
||||
|
||||
/* Tests for process_output() */
|
||||
|
||||
/*
|
||||
* Helper: allocate and initialise a minimal hdcp_workqueue sufficient for
|
||||
* process_output() testing. Only the three delayed works accessed by
|
||||
* process_output() are initialised; everything else is zeroed.
|
||||
*/
|
||||
static struct hdcp_workqueue *alloc_test_workqueue(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work;
|
||||
|
||||
work = kunit_kzalloc(test, sizeof(*work), GFP_KERNEL);
|
||||
KUNIT_ASSERT_NOT_NULL(test, work);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* process_output() always schedules property_validate_dwork with delay=0,
|
||||
* which queues the work item directly (bypassing the timer). Use
|
||||
* work_pending() rather than delayed_work_pending() to detect this.
|
||||
*/
|
||||
static void dm_test_process_output_property_validate_always_scheduled(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
/* No flags set: only property_validate_dwork should be enqueued */
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, work_pending(&work->property_validate_dwork.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->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.callback_needed=true must schedule callback_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_callback_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.callback_needed = true;
|
||||
work->output.callback_delay = 500;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->callback_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->callback_dwork);
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.callback_stop=true must cancel a previously scheduled callback_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_callback_stop(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(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));
|
||||
|
||||
work->output.callback_stop = true;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->callback_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.watchdog_timer_needed=true must schedule watchdog_timer_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_watchdog_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.watchdog_timer_needed = true;
|
||||
work->output.watchdog_timer_delay = 1000;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->watchdog_timer_dwork);
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* output.watchdog_timer_stop=true must cancel a previously scheduled
|
||||
* watchdog_timer_dwork.
|
||||
*/
|
||||
static void dm_test_process_output_watchdog_stop(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
/* Pre-schedule watchdog_timer_dwork with a long delay. */
|
||||
schedule_delayed_work(&work->watchdog_timer_dwork, msecs_to_jiffies(10000));
|
||||
KUNIT_ASSERT_TRUE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
work->output.watchdog_timer_stop = true;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_FALSE(test, delayed_work_pending(&work->watchdog_timer_dwork));
|
||||
|
||||
cancel_delayed_work_sync(&work->property_validate_dwork);
|
||||
}
|
||||
|
||||
/*
|
||||
* Both callback_needed and watchdog_timer_needed set: both dworks are
|
||||
* scheduled independently.
|
||||
*/
|
||||
static void dm_test_process_output_callback_and_watchdog_needed(struct kunit *test)
|
||||
{
|
||||
struct hdcp_workqueue *work = alloc_test_workqueue(test);
|
||||
|
||||
work->output.callback_needed = true;
|
||||
work->output.callback_delay = 200;
|
||||
work->output.watchdog_timer_needed = true;
|
||||
work->output.watchdog_timer_delay = 800;
|
||||
|
||||
process_output(work);
|
||||
|
||||
KUNIT_EXPECT_TRUE(test, delayed_work_pending(&work->callback_dwork));
|
||||
KUNIT_EXPECT_TRUE(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 process_output() */
|
||||
|
||||
static struct kunit_case dm_hdcp_test_cases[] = {
|
||||
KUNIT_CASE(dm_test_process_output_property_validate_always_scheduled),
|
||||
KUNIT_CASE(dm_test_process_output_callback_needed),
|
||||
KUNIT_CASE(dm_test_process_output_callback_stop),
|
||||
KUNIT_CASE(dm_test_process_output_watchdog_needed),
|
||||
KUNIT_CASE(dm_test_process_output_watchdog_stop),
|
||||
KUNIT_CASE(dm_test_process_output_callback_and_watchdog_needed),
|
||||
{}
|
||||
};
|
||||
|
||||
static struct kunit_suite dm_hdcp_test_suite = {
|
||||
.name = "amdgpu_dm_hdcp",
|
||||
.test_cases = dm_hdcp_test_cases,
|
||||
};
|
||||
|
||||
kunit_test_suite(dm_hdcp_test_suite);
|
||||
|
||||
MODULE_LICENSE("Dual MIT/GPL");
|
||||
MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_hdcp");
|
||||
MODULE_AUTHOR("AMD");
|
||||
Loading…
Reference in New Issue
Block a user