Add a single KUnit test case for the drm_mode_addfb2 function. Signed-off-by: Carlos Eduardo Gallo Filho <gcarlos@xxxxxxxxxxx> --- drivers/gpu/drm/tests/drm_framebuffer_test.c | 100 ++++++++++++++++++- 1 file changed, 98 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/tests/drm_framebuffer_test.c b/drivers/gpu/drm/tests/drm_framebuffer_test.c index 8eca92fdc645..b8ddd7e34db5 100644 --- a/drivers/gpu/drm/tests/drm_framebuffer_test.c +++ b/drivers/gpu/drm/tests/drm_framebuffer_test.c @@ -10,6 +10,7 @@ #include <drm/drm_device.h> #include <drm/drm_drv.h> #include <drm/drm_mode.h> +#include <drm/drm_file.h> #include <drm/drm_framebuffer.h> #include <drm/drm_fourcc.h> #include <drm/drm_print.h> @@ -343,8 +344,18 @@ static const struct drm_framebuffer_test drm_framebuffer_create_cases[] = { }, }; +/* + * This struct is intended to provide a way to mocked functions communicate + * with the outer test when it can't be achieved by using its return value. In + * this way, the functions that receive the mocked drm_device, for example, can + * grab a reference to @private and actually return something to be used on some + * expectation. Also having the @test member allows doing expectations from + * inside mocked functions. + */ struct drm_mock { struct drm_device dev; + struct drm_file file_priv; + struct kunit *test; void *private; }; @@ -366,13 +377,18 @@ static int drm_framebuffer_test_init(struct kunit *test) { struct drm_mock *mock; struct drm_device *dev; + struct drm_file *file_priv; + struct drm_driver *driver; mock = kunit_kzalloc(test, sizeof(*mock), GFP_KERNEL); KUNIT_ASSERT_NOT_ERR_OR_NULL(test, mock); dev = &mock->dev; + file_priv = &mock->file_priv; - dev->driver = kunit_kzalloc(test, sizeof(*dev->driver), GFP_KERNEL); - KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev->driver); + driver = kunit_kzalloc(test, sizeof(*dev->driver), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, driver); + driver->driver_features = DRIVER_MODESET; + dev->driver = driver; idr_init_base(&dev->mode_config.object_idr, 1); mutex_init(&dev->mode_config.fb_lock); @@ -384,6 +400,9 @@ static int drm_framebuffer_test_init(struct kunit *test) dev->mode_config.max_height = MAX_HEIGHT; dev->mode_config.funcs = &mock_config_funcs; + mutex_init(&file_priv->fbs_lock); + INIT_LIST_HEAD(&file_priv->fbs); + test->priv = mock; return 0; } @@ -392,8 +411,10 @@ static void drm_framebuffer_test_exit(struct kunit *test) { struct drm_mock *mock = test->priv; struct drm_device *dev = &mock->dev; + struct drm_file *file_priv = &mock->file_priv; mutex_destroy(&dev->mode_config.fb_lock); + mutex_destroy(&file_priv->fbs_lock); } static void drm_test_framebuffer_create(struct kunit *test) @@ -656,7 +677,82 @@ static void drm_test_framebuffer_free(struct kunit *test) KUNIT_EXPECT_PTR_EQ(test, obj, NULL); } +static struct drm_framebuffer * +fb_create_addfb2_mock(struct drm_device *dev, struct drm_file *file_priv, + const struct drm_mode_fb_cmd2 *cmd) +{ + struct drm_mock *mock = container_of(dev, typeof(*mock), dev); + struct drm_framebuffer *fb; + struct kunit *test = mock->test; + + fb = kunit_kzalloc(test, sizeof(*fb), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fb); + + fb->base.id = 1; + + mock->private = fb; + return fb; +} + +static struct drm_mode_config_funcs config_funcs_addfb2_mock = { + .fb_create = fb_create_addfb2_mock, +}; + +static void drm_test_framebuffer_addfb2(struct kunit *test) +{ + struct drm_mock *mock = test->priv; + struct drm_device *dev = &mock->dev; + struct drm_file *file_priv = &mock->file_priv; + struct drm_framebuffer *fb = NULL; + int ret; + + /* A valid cmd */ + struct drm_mode_fb_cmd2 cmd = { + .width = 600, .height = 600, + .pixel_format = DRM_FORMAT_ABGR8888, + .handles = { 1, 0, 0 }, .pitches = { 4 * 600, 0, 0 }, + }; + + mock->test = test; + dev->mode_config.funcs = &config_funcs_addfb2_mock; + + /* Must fail due to missing DRIVER_MODESET support */ + ret = drm_mode_addfb2(dev, &cmd, file_priv); + KUNIT_EXPECT_EQ(test, ret, -EOPNOTSUPP); + KUNIT_ASSERT_PTR_EQ(test, mock->private, NULL); + + /* Set DRIVER_MODESET support */ + dev->driver_features = dev->driver->driver_features; + + /* + * Set an invalid cmd to trigger a fail on the + * drm_internal_framebuffer_create function + */ + cmd.width = 0; + ret = drm_mode_addfb2(dev, &cmd, file_priv); + KUNIT_EXPECT_EQ(test, ret, -EINVAL); + KUNIT_ASSERT_PTR_EQ(test, mock->private, NULL); + cmd.width = 600; /* restore to a valid value */ + + ret = drm_mode_addfb2(dev, &cmd, file_priv); + KUNIT_EXPECT_EQ(test, ret, 0); + + /* The fb_create_addfb2_mock set fb id to 1 */ + KUNIT_EXPECT_EQ(test, cmd.fb_id, 1); + + fb = mock->private; + + /* The fb must be properly added to the file_priv->fbs list */ + KUNIT_EXPECT_PTR_EQ(test, file_priv->fbs.prev, &fb->filp_head); + KUNIT_EXPECT_PTR_EQ(test, file_priv->fbs.next, &fb->filp_head); + + /* There must be just one fb on the list */ + KUNIT_EXPECT_PTR_EQ(test, fb->filp_head.prev, &file_priv->fbs); + KUNIT_EXPECT_PTR_EQ(test, fb->filp_head.next, &file_priv->fbs); +} + static struct kunit_case drm_framebuffer_tests[] = { + KUNIT_CASE(drm_test_framebuffer_addfb2), KUNIT_CASE(drm_test_framebuffer_cleanup), KUNIT_CASE(drm_test_framebuffer_free), KUNIT_CASE(drm_test_framebuffer_init), -- 2.41.0