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 { 184 __label__ drm_exec_retry; 185 186 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 187 drm_exec_until_all_locked(&exec) 188 { 189 break; 190 } 191 drm_exec_fini(&exec); 192 } 193 194 { 195 __label__ drm_exec_retry; 196 197 drm_exec_init(&exec, DRM_EXEC_INTERRUPTIBLE_WAIT, 0); 198 drm_exec_until_all_locked(&exec) 199 { 200 break; 201 } 202 drm_exec_fini(&exec); 203 } 204 KUNIT_SUCCEED(test); 205 } 206 207 static struct kunit_case drm_exec_tests[] = { 208 KUNIT_CASE(sanitycheck), 209 KUNIT_CASE(test_lock), 210 KUNIT_CASE(test_lock_unlock), 211 KUNIT_CASE(test_duplicates), 212 KUNIT_CASE(test_prepare), 213 KUNIT_CASE(test_prepare_array), 214 KUNIT_CASE(test_multiple_loops), 215 {} 216 }; 217 218 static struct kunit_suite drm_exec_test_suite = { 219 .name = "drm_exec", 220 .init = drm_exec_test_init, 221 .test_cases = drm_exec_tests, 222 }; 223 224 kunit_test_suite(drm_exec_test_suite); 225 226 MODULE_AUTHOR("AMD"); 227 MODULE_DESCRIPTION("Kunit test for drm_exec functions"); 228 MODULE_LICENSE("GPL and additional rights"); 229