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

Reply via email to