1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright 2022 Advanced Micro Devices, Inc. 4 */ 5 6 #define pr_fmt(fmt) "drm_exec: " fmt 7 8 #include <kunit/test.h> 9 10 #include <linux/module.h> 11 #include <linux/prime_numbers.h> 12 13 #include <drm/drm_exec.h> 14 #include <drm/drm_device.h> 15 #include <drm/drm_drv.h> 16 #include <drm/drm_gem.h> 17 #include <drm/drm_kunit_helpers.h> 18 19 struct drm_exec_priv { 20 struct device *dev; 21 struct drm_device *drm; 22 }; 23 24 static int drm_exec_test_init(struct kunit *test) 25 { 26 struct drm_exec_priv *priv; 27 28 priv = kunit_kzalloc(test, sizeof(*priv), GFP_KERNEL); 29 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv); 30 31 test->priv = priv; 32 33 priv->dev = drm_kunit_helper_alloc_device(test); 34 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->dev); 35 36 priv->drm = __drm_kunit_helper_alloc_drm_device(test, priv->dev, sizeof(*priv->drm), 0, 37 DRIVER_MODESET); 38 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, priv->drm); 39 40 return 0; 41 } 42 43 static void sanitycheck(struct kunit *test) 44 { 45 struct drm_exec exec; 46 47 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 48 drm_exec_fini(&exec); 49 KUNIT_SUCCEED(test); 50 } 51 52 static void test_lock(struct kunit *test) 53 { 54 struct drm_exec_priv *priv = test->priv; 55 struct drm_gem_object gobj = { }; 56 struct drm_exec exec; 57 int ret; 58 59 drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); 60 61 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 62 drm_exec_until_all_locked(&exec) { 63 ret = drm_exec_lock_obj(&exec, &gobj); 64 drm_exec_retry_on_contention(&exec); 65 KUNIT_EXPECT_EQ(test, ret, 0); 66 if (ret) 67 break; 68 } 69 drm_exec_fini(&exec); 70 } 71 72 static void test_lock_unlock(struct kunit *test) 73 { 74 struct drm_exec_priv *priv = test->priv; 75 struct drm_gem_object gobj = { }; 76 struct drm_exec exec; 77 int ret; 78 79 drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); 80 81 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 82 drm_exec_until_all_locked(&exec) { 83 ret = drm_exec_lock_obj(&exec, &gobj); 84 drm_exec_retry_on_contention(&exec); 85 KUNIT_EXPECT_EQ(test, ret, 0); 86 if (ret) 87 break; 88 89 drm_exec_unlock_obj(&exec, &gobj); 90 ret = drm_exec_lock_obj(&exec, &gobj); 91 drm_exec_retry_on_contention(&exec); 92 KUNIT_EXPECT_EQ(test, ret, 0); 93 if (ret) 94 break; 95 } 96 drm_exec_fini(&exec); 97 } 98 99 static void test_duplicates(struct kunit *test) 100 { 101 struct drm_exec_priv *priv = test->priv; 102 struct drm_gem_object gobj = { }; 103 struct drm_exec exec; 104 int ret; 105 106 drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); 107 108 drm_exec_init(&exec, DRM_EXEC_IGNORE_DUPLICATES, 0); 109 drm_exec_until_all_locked(&exec) { 110 ret = drm_exec_lock_obj(&exec, &gobj); 111 drm_exec_retry_on_contention(&exec); 112 KUNIT_EXPECT_EQ(test, ret, 0); 113 if (ret) 114 break; 115 116 ret = drm_exec_lock_obj(&exec, &gobj); 117 drm_exec_retry_on_contention(&exec); 118 KUNIT_EXPECT_EQ(test, ret, 0); 119 if (ret) 120 break; 121 } 122 drm_exec_unlock_obj(&exec, &gobj); 123 drm_exec_fini(&exec); 124 } 125 126 static void test_prepare(struct kunit *test) 127 { 128 struct drm_exec_priv *priv = test->priv; 129 struct drm_gem_object gobj = { }; 130 struct drm_exec exec; 131 int ret; 132 133 drm_gem_private_object_init(priv->drm, &gobj, PAGE_SIZE); 134 135 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 136 drm_exec_until_all_locked(&exec) { 137 ret = drm_exec_prepare_obj(&exec, &gobj, 1); 138 drm_exec_retry_on_contention(&exec); 139 KUNIT_EXPECT_EQ(test, ret, 0); 140 if (ret) 141 break; 142 } 143 drm_exec_fini(&exec); 144 145 drm_gem_private_object_fini(&gobj); 146 } 147 148 static void test_prepare_array(struct kunit *test) 149 { 150 struct drm_exec_priv *priv = test->priv; 151 struct drm_gem_object *gobj1; 152 struct drm_gem_object *gobj2; 153 struct drm_gem_object *array[] = { 154 (gobj1 = kunit_kzalloc(test, sizeof(*gobj1), GFP_KERNEL)), 155 (gobj2 = kunit_kzalloc(test, sizeof(*gobj2), GFP_KERNEL)), 156 }; 157 struct drm_exec exec; 158 int ret; 159 160 if (!gobj1 || !gobj2) { 161 KUNIT_FAIL(test, "Failed to allocate GEM objects.\n"); 162 return; 163 } 164 165 drm_gem_private_object_init(priv->drm, gobj1, PAGE_SIZE); 166 drm_gem_private_object_init(priv->drm, gobj2, PAGE_SIZE); 167 168 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 169 drm_exec_until_all_locked(&exec) 170 ret = drm_exec_prepare_array(&exec, array, ARRAY_SIZE(array), 171 1); 172 KUNIT_EXPECT_EQ(test, ret, 0); 173 drm_exec_fini(&exec); 174 175 drm_gem_private_object_fini(gobj1); 176 drm_gem_private_object_fini(gobj2); 177 } 178 179 static void test_multiple_loops(struct kunit *test) 180 { 181 struct drm_exec exec; 182 183 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 184 drm_exec_until_all_locked(&exec) 185 { 186 break; 187 } 188 drm_exec_fini(&exec); 189 190 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 191 drm_exec_until_all_locked(&exec) 192 { 193 break; 194 } 195 drm_exec_fini(&exec); 196 KUNIT_SUCCEED(test); 197 } 198 199 static struct kunit_case drm_exec_tests[] = { 200 KUNIT_CASE(sanitycheck), 201 KUNIT_CASE(test_lock), 202 KUNIT_CASE(test_lock_unlock), 203 KUNIT_CASE(test_duplicates), 204 KUNIT_CASE(test_prepare), 205 KUNIT_CASE(test_prepare_array), 206 KUNIT_CASE(test_multiple_loops), 207 {} 208 }; 209 210 static struct kunit_suite drm_exec_test_suite = { 211 .name = "drm_exec", 212 .init = drm_exec_test_init, 213 .test_cases = drm_exec_tests, 214 }; 215 216 kunit_test_suite(drm_exec_test_suite); 217 218 MODULE_AUTHOR("AMD"); 219 MODULE_DESCRIPTION("Kunit test for drm_exec functions"); 220 MODULE_LICENSE("GPL and additional rights"); 221