From: Alex Hung <[email protected]> [WHAT] Add KUnit coverage using a DRM-managed connector fixture.
Tests cover show() mapping immediate-disable to 0 and reporting an active ABM level, and store() handling the disable mapping, the forbidden update, invalid text, and out-of-range input. show() writes through a page-backed buffer because sysfs_emit() requires one. Assisted-by: Copilot:Claude-Opus-4.8 Reviewed-by: Bhawanpreet Lakha <[email protected]> Signed-off-by: Alex Hung <[email protected]> Signed-off-by: George Zhang <[email protected]> --- .../display/amdgpu_dm/amdgpu_dm_backlight.c | 16 +- .../display/amdgpu_dm/amdgpu_dm_backlight.h | 8 + .../tests/amdgpu_dm_backlight_test.c | 177 ++++++++++++++++++ 3 files changed, 195 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c index 859cbce2cdaf..373ef4d217f1 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.c @@ -611,9 +611,10 @@ EXPORT_IF_KUNIT(amdgpu_dm_setup_backlight_device); * carefully. */ -static ssize_t panel_power_savings_show(struct device *device, - struct device_attribute *attr, - char *buf) +STATIC_IFN_KUNIT +ssize_t panel_power_savings_show(struct device *device, + struct device_attribute *attr, + char *buf) { struct drm_connector *connector = dev_get_drvdata(device); struct drm_device *dev = connector->dev; @@ -627,10 +628,12 @@ static ssize_t panel_power_savings_show(struct device *device, return sysfs_emit(buf, "%u\n", val); } +EXPORT_IF_KUNIT(panel_power_savings_show); -static ssize_t panel_power_savings_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) +STATIC_IFN_KUNIT +ssize_t panel_power_savings_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count) { struct drm_connector *connector = dev_get_drvdata(device); struct drm_device *dev = connector->dev; @@ -660,6 +663,7 @@ static ssize_t panel_power_savings_store(struct device *device, return count; } +EXPORT_IF_KUNIT(panel_power_savings_store); static DEVICE_ATTR_RW(panel_power_savings); diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h index 7b417c79980f..07b75064847c 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_backlight.h @@ -30,6 +30,8 @@ struct backlight_device; struct backlight_properties; struct dc_link; struct dc_stream_state; +struct device; +struct device_attribute; struct drm_connector; struct attribute_group; @@ -56,6 +58,12 @@ struct dc_stream_state *dm_find_stream_with_link(struct amdgpu_display_manager * int amdgpu_dm_backlight_update_status(struct backlight_device *bd); u32 amdgpu_dm_backlight_get_level(struct amdgpu_display_manager *dm, int bl_idx); int amdgpu_dm_backlight_get_brightness(struct backlight_device *bd); +ssize_t panel_power_savings_show(struct device *device, + struct device_attribute *attr, + char *buf); +ssize_t panel_power_savings_store(struct device *device, + struct device_attribute *attr, + const char *buf, size_t count); int get_brightness_range(const struct amdgpu_dm_backlight_caps *caps, unsigned int *min, unsigned int *max); void convert_custom_brightness(const struct amdgpu_dm_backlight_caps *caps, diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c index 5a2c32d53487..b74bbbc7f56f 100644 --- a/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/tests/amdgpu_dm_backlight_test.c @@ -8,6 +8,11 @@ #include <kunit/test.h> #include <linux/backlight.h> +#include <drm/drm_atomic_helper.h> +#include <drm/drm_connector.h> +#include <drm/drm_mode_config.h> +#include <drm/drm_property.h> + #include "dc.h" #include "dc_dmub_srv.h" #include "amdgpu.h" @@ -458,6 +463,171 @@ static void dm_test_register_backlight_device_negative_index(struct kunit *test) KUNIT_EXPECT_NULL(test, adev->dm.backlight_dev[0]); } +static struct drm_connector *setup_panel_power_savings_connector(struct kunit *test, + struct device **device_out, + struct dm_connector_state **state_out) +{ + struct dm_connector_state *state; + struct drm_connector *connector; + struct amdgpu_device *adev; + struct device *device; + int ret; + + adev = dm_kunit_alloc_adev(test); + ret = drmm_mode_config_init(&adev->ddev); + KUNIT_ASSERT_EQ(test, ret, 0); + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); + state = kunit_kzalloc(test, sizeof(*state), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, state); + + connector->dev = &adev->ddev; + connector->state = &state->base; + dev_set_drvdata(device, connector); + *device_out = device; + *state_out = state; + + return connector; +} + +static void dm_test_free_sysfs_buf(void *data) +{ + free_page((unsigned long)data); +} + +static char *dm_test_alloc_sysfs_buf(struct kunit *test) +{ + char *buf; + + buf = (char *)get_zeroed_page(GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, buf); + KUNIT_ASSERT_EQ(test, kunit_add_action_or_reset(test, dm_test_free_sysfs_buf, buf), 0); + + return buf; +} + +/* Tests for panel_power_savings_show()/panel_power_savings_store() */ + +/** + * dm_test_panel_power_savings_show_maps_disable_to_zero - Test show output + * @test: The KUnit test context + */ +static void dm_test_panel_power_savings_show_maps_disable_to_zero(struct kunit *test) +{ + struct dm_connector_state *state; + struct device *device; + char *buf; + + setup_panel_power_savings_connector(test, &device, &state); + buf = dm_test_alloc_sysfs_buf(test); + state->abm_level = ABM_LEVEL_IMMEDIATE_DISABLE; + + KUNIT_EXPECT_EQ(test, panel_power_savings_show(device, NULL, buf), 2); + KUNIT_EXPECT_STREQ(test, buf, "0\n"); +} + +/** + * dm_test_panel_power_savings_show_reports_level - Test show output for active level + * @test: The KUnit test context + * + * When abm_level is not the immediate-disable sentinel, show() reports the + * raw level value. + */ +static void dm_test_panel_power_savings_show_reports_level(struct kunit *test) +{ + struct dm_connector_state *state; + struct device *device; + char *buf; + + setup_panel_power_savings_connector(test, &device, &state); + buf = dm_test_alloc_sysfs_buf(test); + state->abm_level = 3; + + KUNIT_EXPECT_EQ(test, panel_power_savings_show(device, NULL, buf), 2); + KUNIT_EXPECT_STREQ(test, buf, "3\n"); +} + +/** + * dm_test_panel_power_savings_store_sets_disable - Test zero maps to disable + * @test: The KUnit test context + */ +static void dm_test_panel_power_savings_store_sets_disable(struct kunit *test) +{ + struct dm_connector_state *state; + struct device *device; + size_t count = strlen("0"); + + setup_panel_power_savings_connector(test, &device, &state); + + KUNIT_EXPECT_EQ(test, panel_power_savings_store(device, NULL, "0", count), + (ssize_t)count); + KUNIT_EXPECT_EQ(test, state->abm_level, ABM_LEVEL_IMMEDIATE_DISABLE); +} + +/** + * dm_test_panel_power_savings_store_forbidden - Test forbidden update + * @test: The KUnit test context + */ +static void dm_test_panel_power_savings_store_forbidden(struct kunit *test) +{ + struct dm_connector_state *state; + struct device *device; + + setup_panel_power_savings_connector(test, &device, &state); + state->abm_sysfs_forbidden = true; + + KUNIT_EXPECT_EQ(test, panel_power_savings_store(device, NULL, "1", 1), -EBUSY); +} + +/** + * dm_test_panel_power_savings_store_rejects_invalid_text - Test parse failure + * @test: The KUnit test context + */ +static void dm_test_panel_power_savings_store_rejects_invalid_text(struct kunit *test) +{ + struct drm_connector *connector; + struct drm_device *drm; + struct device *device; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL); + device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); + + connector->dev = drm; + dev_set_drvdata(device, connector); + + KUNIT_EXPECT_LT(test, panel_power_savings_store(device, NULL, "bad", 3), 0); +} + +/** + * dm_test_panel_power_savings_store_rejects_out_of_range - Test range failure + * @test: The KUnit test context + */ +static void dm_test_panel_power_savings_store_rejects_out_of_range(struct kunit *test) +{ + struct drm_connector *connector; + struct drm_device *drm; + struct device *device; + + connector = kunit_kzalloc(test, sizeof(*connector), GFP_KERNEL); + drm = kunit_kzalloc(test, sizeof(*drm), GFP_KERNEL); + device = kunit_kzalloc(test, sizeof(*device), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, connector); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, drm); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, device); + + connector->dev = drm; + dev_set_drvdata(device, connector); + + KUNIT_EXPECT_EQ(test, panel_power_savings_store(device, NULL, "5", 1), -EINVAL); +} + /* Tests for amdgpu_dm_backlight_get_device_index() */ /** @@ -1636,6 +1806,13 @@ static struct kunit_case dm_backlight_test_cases[] = { KUNIT_CASE(dm_test_backlight_get_brightness_uses_device_index), /* amdgpu_dm_register_backlight_device */ KUNIT_CASE(dm_test_register_backlight_device_negative_index), + /* panel_power_savings_show / store */ + KUNIT_CASE(dm_test_panel_power_savings_show_maps_disable_to_zero), + KUNIT_CASE(dm_test_panel_power_savings_show_reports_level), + KUNIT_CASE(dm_test_panel_power_savings_store_sets_disable), + KUNIT_CASE(dm_test_panel_power_savings_store_forbidden), + KUNIT_CASE(dm_test_panel_power_savings_store_rejects_invalid_text), + KUNIT_CASE(dm_test_panel_power_savings_store_rejects_out_of_range), /* amdgpu_dm_backlight_get_device_index */ KUNIT_CASE(dm_test_backlight_device_index_matches_second), KUNIT_CASE(dm_test_backlight_device_index_missing_fallback), -- 2.55.0
