From: Alex Hung <[email protected]> Add amdgpu_dm_services_test.c with KUnit coverage for five functions in amdgpu_dm_services.c:
- dm_get_elapse_time_in_ns(): four arithmetic cases covering zero delta, positive delta, ULLONG_MAX span, and unsigned wraparound. - dm_perf_trace_timestamp(): one case verifying the function dereferences ctx->perf_trace safely (the tracepoint is a no-op without an attached probe). - dm_trace_smu_enter(): two cases for the empty stub with NULL ctx and with non-zero parameters. - dm_trace_smu_exit(): three cases for the empty stub covering success, failure, and a non-zero response value. - dm_query_extended_brightness_caps(): four guard-clause cases (NULL ctx, NULL caps, NULL ctx->driver_context, NULL ctx with LCD2) plus two success cases covering the LCD1 slot with luminance data copy and a non-LCD1 display using the second backlight slot with zero data points. Assisted-by: Copilot:Claude-Opus-4.8 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: Chenyu Chen <[email protected]> --- .../display/amdgpu_dm/amdgpu_dm_services.c | 6 + .../drm/amd/display/amdgpu_dm/tests/Makefile | 1 + .../amdgpu_dm/tests/amdgpu_dm_services_test.c | 313 ++++++++++++++++++ 3 files changed, 320 insertions(+) create mode 100644 drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c index 0fdcf70256cc..6c0464754ed8 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_services.c @@ -36,6 +36,7 @@ #include "amdgpu_dm_irq.h" #include "amdgpu_pm.h" #include "amdgpu_dm_trace.h" +#include "amdgpu_dm_kunit_helpers.h" unsigned long long dm_get_elapse_time_in_ns(struct dc_context *ctx, @@ -44,6 +45,7 @@ { return current_time_stamp - last_time_stamp; } +EXPORT_IF_KUNIT(dm_get_elapse_time_in_ns); void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc_context *ctx) { @@ -53,14 +55,17 @@ void dm_perf_trace_timestamp(const char *func_name, unsigned int line, struct dc &ctx->perf_trace->last_entry_write, func_name, line); } +EXPORT_IF_KUNIT(dm_perf_trace_timestamp); void dm_trace_smu_enter(uint32_t msg_id, uint32_t param_in, unsigned int delay, struct dc_context *ctx) { } +EXPORT_IF_KUNIT(dm_trace_smu_enter); void dm_trace_smu_exit(bool success, uint32_t response, struct dc_context *ctx) { } +EXPORT_IF_KUNIT(dm_trace_smu_exit); /**** power component interfaces ****/ @@ -90,3 +95,4 @@ bool dm_query_extended_brightness_caps(struct dc_context *ctx, sizeof(struct dm_bl_data_point) * pCaps->num_data_points); return true; } +EXPORT_IF_KUNIT(dm_query_extended_brightness_caps); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile index cde8f7748bc5..364b4f3c783f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/Makefile @@ -28,3 +28,4 @@ obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_mst_types_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_pp_smu_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_test.o obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_crtc_test.o +obj-$(CONFIG_DRM_AMD_DC_KUNIT_TEST) += amdgpu_dm_services_test.o diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c new file mode 100644 index 000000000000..e48bac7fb024 --- /dev/null +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_services_test.c @@ -0,0 +1,313 @@ +// SPDX-License-Identifier: GPL-2.0 OR MIT +/* + * KUnit tests for amdgpu_dm_services.c + * + * Copyright 2026 Advanced Micro Devices, Inc. + */ + +#include <kunit/test.h> + +#include "dc.h" +#include "amdgpu.h" +#include "amdgpu_mode.h" +#include "amdgpu_dm.h" +#include "dm_services.h" +#include "dm_services_types.h" + +/* Tests for dm_get_elapse_time_in_ns() */ + +/** + * dm_test_get_elapse_time_zero_delta - Test Get elapse time zero delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_zero_delta(struct kunit *test) +{ + unsigned long long ts = 1000000ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, ts, ts), 0ULL); +} + +/** + * dm_test_get_elapse_time_positive_delta - Test Get elapse time positive delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_positive_delta(struct kunit *test) +{ + unsigned long long current_ts = 5000000ULL; + unsigned long long last_ts = 1000000ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + 4000000ULL); +} + +/** + * dm_test_get_elapse_time_large_delta - Test Get elapse time large delta + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_large_delta(struct kunit *test) +{ + unsigned long long current_ts = ULLONG_MAX; + unsigned long long last_ts = 0ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + ULLONG_MAX); +} + +/** + * dm_test_get_elapse_time_wraparound - Test Get elapse time wraparound + * @test: The KUnit test context + */ +static void dm_test_get_elapse_time_wraparound(struct kunit *test) +{ + /* Unsigned wraparound: result = ULLONG_MAX - last + current + 1 */ + unsigned long long current_ts = 5ULL; + unsigned long long last_ts = ULLONG_MAX - 4ULL; + + KUNIT_EXPECT_EQ(test, dm_get_elapse_time_in_ns(NULL, current_ts, last_ts), + 10ULL); +} + +/* Tests for dm_perf_trace_timestamp() */ + +/** + * dm_test_perf_trace_timestamp_basic - Test Perf trace timestamp basic + * @test: The KUnit test context + * + * The tracepoint is a no-op without an attached probe, so this verifies the + * function dereferences ctx->perf_trace safely and does not crash. + */ +static void dm_test_perf_trace_timestamp_basic(struct kunit *test) +{ + struct dc_context *ctx; + + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx); + ctx->perf_trace = kunit_kzalloc(test, sizeof(*ctx->perf_trace), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, ctx->perf_trace); + + ctx->perf_trace->read_count = 10; + ctx->perf_trace->write_count = 20; + + dm_perf_trace_timestamp(__func__, __LINE__, ctx); +} + +/* Tests for dm_trace_smu_enter() */ + +/** + * dm_test_trace_smu_enter_null_ctx - Test Trace smu enter null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_enter_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash with NULL ctx */ + dm_trace_smu_enter(0, 0, 0, NULL); +} + +/** + * dm_test_trace_smu_enter_with_params - Test Trace smu enter with params + * @test: The KUnit test context + */ +static void dm_test_trace_smu_enter_with_params(struct kunit *test) +{ + /* Exercise non-zero msg_id, param_in, and delay */ + dm_trace_smu_enter(0xFF, 0x12345678, 1000, NULL); +} + +/* Tests for dm_trace_smu_exit() */ + +/** + * dm_test_trace_smu_exit_success_null_ctx - Test Trace smu exit success null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_success_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash on success path with NULL ctx */ + dm_trace_smu_exit(true, 0x0, NULL); +} + +/** + * dm_test_trace_smu_exit_failure_null_ctx - Test Trace smu exit failure null ctx + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_failure_null_ctx(struct kunit *test) +{ + /* Empty stub — must not crash on failure path with NULL ctx */ + dm_trace_smu_exit(false, 0x0, NULL); +} + +/** + * dm_test_trace_smu_exit_with_response - Test Trace smu exit with response + * @test: The KUnit test context + */ +static void dm_test_trace_smu_exit_with_response(struct kunit *test) +{ + /* Exercise non-zero response value */ + dm_trace_smu_exit(true, 0xDEADBEEF, NULL); +} + +/* Tests for dm_query_extended_brightness_caps() */ + +/** + * dm_test_query_brightness_caps_null_ctx - Test Query brightness caps null ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_ctx(struct kunit *test) +{ + struct dm_acpi_atif_backlight_caps caps = {}; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(NULL, AcpiDisplayType_LCD1, &caps)); +} + +/** + * dm_test_query_brightness_caps_null_caps - Test Query brightness caps null caps + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_caps(struct kunit *test) +{ + struct dc_context ctx = {}; + + ctx.driver_context = (void *)0x1; /* non-NULL sentinel */ + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, NULL)); +} + +/** + * dm_test_query_brightness_caps_null_driver_ctx - Test Query brightness caps null driver ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_null_driver_ctx(struct kunit *test) +{ + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + ctx.driver_context = NULL; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, &caps)); +} + +/** + * dm_test_query_brightness_caps_lcd2_null_ctx - Test Query brightness caps lcd2 null ctx + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_lcd2_null_ctx(struct kunit *test) +{ + struct dm_acpi_atif_backlight_caps caps = {}; + + KUNIT_EXPECT_FALSE(test, + dm_query_extended_brightness_caps(NULL, AcpiDisplayType_LCD2, &caps)); +} + +/** + * dm_test_query_brightness_caps_lcd1_success - Test Query brightness caps lcd1 success + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_lcd1_success(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_dm_backlight_caps *source_caps; + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + source_caps = &adev->dm.backlight_caps[0]; + source_caps->caps_valid = true; + source_caps->min_input_signal = 12; + source_caps->max_input_signal = 240; + source_caps->ac_level = 80; + source_caps->dc_level = 40; + source_caps->data_points = 2; + source_caps->luminance_data[0].luminance = 10; + source_caps->luminance_data[0].input_signal = 22; + source_caps->luminance_data[1].luminance = 90; + source_caps->luminance_data[1].input_signal = 200; + ctx.driver_context = adev; + + KUNIT_EXPECT_TRUE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_LCD1, &caps)); + KUNIT_EXPECT_EQ(test, caps.num_data_points, 2); + KUNIT_EXPECT_EQ(test, caps.max_input_signal, 240); + KUNIT_EXPECT_EQ(test, caps.min_input_signal, 12); + KUNIT_EXPECT_EQ(test, caps.ac_level_percentage, 80); + KUNIT_EXPECT_EQ(test, caps.dc_level_percentage, 40); + KUNIT_EXPECT_EQ(test, caps.data_points[0].luminance, 10); + KUNIT_EXPECT_EQ(test, caps.data_points[0].signal_level, 22); + KUNIT_EXPECT_EQ(test, caps.data_points[1].luminance, 90); + KUNIT_EXPECT_EQ(test, caps.data_points[1].signal_level, 200); +} + +/** + * dm_test_query_brightness_caps_non_lcd1_uses_second_slot - Test Query brightness caps non lcd1 uses second slot + * @test: The KUnit test context + */ +static void dm_test_query_brightness_caps_non_lcd1_uses_second_slot(struct kunit *test) +{ + struct amdgpu_device *adev; + struct amdgpu_dm_backlight_caps *source_caps; + struct dc_context ctx = {}; + struct dm_acpi_atif_backlight_caps caps = {}; + + adev = kunit_kzalloc(test, sizeof(*adev), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, adev); + + adev->dm.backlight_caps[0].caps_valid = true; + adev->dm.backlight_caps[0].min_input_signal = 1; + adev->dm.backlight_caps[0].max_input_signal = 2; + source_caps = &adev->dm.backlight_caps[1]; + source_caps->caps_valid = true; + source_caps->min_input_signal = 33; + source_caps->max_input_signal = 199; + source_caps->ac_level = 70; + source_caps->dc_level = 30; + source_caps->data_points = 0; + ctx.driver_context = adev; + + KUNIT_EXPECT_TRUE(test, + dm_query_extended_brightness_caps(&ctx, AcpiDisplayType_DFP1, &caps)); + KUNIT_EXPECT_EQ(test, caps.num_data_points, 0); + KUNIT_EXPECT_EQ(test, caps.max_input_signal, 199); + KUNIT_EXPECT_EQ(test, caps.min_input_signal, 33); + KUNIT_EXPECT_EQ(test, caps.ac_level_percentage, 70); + KUNIT_EXPECT_EQ(test, caps.dc_level_percentage, 30); + KUNIT_EXPECT_EQ(test, caps.data_points[0].luminance, 0); + KUNIT_EXPECT_EQ(test, caps.data_points[0].signal_level, 0); +} + +static struct kunit_case amdgpu_dm_services_test_cases[] = { + /* dm_get_elapse_time_in_ns */ + KUNIT_CASE(dm_test_get_elapse_time_zero_delta), + KUNIT_CASE(dm_test_get_elapse_time_positive_delta), + KUNIT_CASE(dm_test_get_elapse_time_large_delta), + KUNIT_CASE(dm_test_get_elapse_time_wraparound), + /* dm_perf_trace_timestamp */ + KUNIT_CASE(dm_test_perf_trace_timestamp_basic), + /* dm_trace_smu_enter */ + KUNIT_CASE(dm_test_trace_smu_enter_null_ctx), + KUNIT_CASE(dm_test_trace_smu_enter_with_params), + /* dm_trace_smu_exit */ + KUNIT_CASE(dm_test_trace_smu_exit_success_null_ctx), + KUNIT_CASE(dm_test_trace_smu_exit_failure_null_ctx), + KUNIT_CASE(dm_test_trace_smu_exit_with_response), + /* dm_query_extended_brightness_caps */ + KUNIT_CASE(dm_test_query_brightness_caps_null_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_null_caps), + KUNIT_CASE(dm_test_query_brightness_caps_null_driver_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_lcd2_null_ctx), + KUNIT_CASE(dm_test_query_brightness_caps_lcd1_success), + KUNIT_CASE(dm_test_query_brightness_caps_non_lcd1_uses_second_slot), + {} +}; + +static struct kunit_suite amdgpu_dm_services_test_suite = { + .name = "amdgpu_dm_services", + .test_cases = amdgpu_dm_services_test_cases, +}; + +kunit_test_suite(amdgpu_dm_services_test_suite); + +MODULE_DESCRIPTION("KUnit tests for amdgpu_dm_services"); +MODULE_LICENSE("Dual MIT/GPL"); -- 2.43.0
