1 // SPDX-License-Identifier: GPL-2.0 AND MIT 2 /* 3 * Copyright © 2026 Intel Corporation 4 */ 5 6 #include <kunit/test.h> 7 #include <kunit/test-bug.h> 8 9 #define TEST_KEY (GUC_KLV_RESERVED_RANGE_START + 0x3de) 10 #define TEST_GROUP_KEY (GUC_KLV_RESERVED_RANGE_START + 0x3f0) 11 #define TEST_PAD 0xdeadbeef 12 13 static bool fake_is_group_key(u16 key) 14 { 15 return is_reserved_key(key) && key >= TEST_GROUP_KEY; 16 } 17 18 static void test_count(struct kunit *test) 19 { 20 u32 value = 0x12345678; 21 u16 key = TEST_KEY; 22 u32 klvs[] = { 23 PREP_GUC_KLV(key + 0, 0), 24 PREP_GUC_KLV(key + 1, 1), value, 25 PREP_GUC_KLV(key + 2, 2), value, value, 26 PREP_GUC_KLV(key + 3, 0), 27 0, /* padding */ 28 }; 29 30 KUNIT_EXPECT_EQ(test, 0, xe_guc_klv_count(klvs, 0)); 31 KUNIT_EXPECT_EQ(test, 1, xe_guc_klv_count(klvs, 1)); 32 KUNIT_EXPECT_GT(test, 0, xe_guc_klv_count(klvs, 2)); 33 KUNIT_EXPECT_EQ(test, 2, xe_guc_klv_count(klvs, 3)); 34 KUNIT_EXPECT_GT(test, 0, xe_guc_klv_count(klvs, 4)); 35 KUNIT_EXPECT_GT(test, 0, xe_guc_klv_count(klvs, 5)); 36 KUNIT_EXPECT_EQ(test, 3, xe_guc_klv_count(klvs, 6)); 37 KUNIT_EXPECT_EQ(test, 4, xe_guc_klv_count(klvs, 7)); 38 39 /* 0 is treated as reserved KLV { KEY=0, LEN=0 } */ 40 KUNIT_EXPECT_EQ(test, 5, xe_guc_klv_count(klvs, 8)); 41 } 42 43 static void test_encode_u32(struct kunit *test) 44 { 45 u32 *fail = ERR_PTR(-ENOMEM); 46 u32 value = 0x12345678; 47 u16 key = TEST_KEY; 48 u32 klvs[16]; 49 50 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 51 52 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), xe_guc_klv_encode_u32(klvs, 0, key, value)); 53 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), xe_guc_klv_encode_u32(klvs, 1, key, value)); 54 55 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe_guc_klv_encode_u32(klvs, 2, key, value)); 56 KUNIT_EXPECT_EQ(test, klvs[0], PREP_GUC_KLV(key, 1)); 57 KUNIT_EXPECT_EQ(test, klvs[1], value); 58 KUNIT_EXPECT_EQ(test, klvs[2], TEST_PAD); 59 KUNIT_EXPECT_PTR_EQ(test, &klvs[2], xe_guc_klv_encode_u32(klvs, 2, key, value)); 60 KUNIT_EXPECT_PTR_EQ(test, 61 xe_guc_klv_encode_u32(klvs, 2, key, value), 62 xe_guc_klv_encode_u32(klvs, ARRAY_SIZE(klvs), key, value)); 63 64 KUNIT_ASSERT_PTR_EQ(test, fail, xe_guc_klv_encode_u32(fail, ARRAY_SIZE(klvs), key, value)); 65 } 66 67 static void test_encode_u64(struct kunit *test) 68 { 69 u64 value = 0x123456789abcdef0; 70 u32 *fail = ERR_PTR(-ENOMEM); 71 u16 key = TEST_KEY; 72 u32 klvs[16]; 73 74 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 75 76 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), xe_guc_klv_encode_u64(klvs, 0, key, value)); 77 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), xe_guc_klv_encode_u64(klvs, 1, key, value)); 78 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), xe_guc_klv_encode_u64(klvs, 2, key, value)); 79 80 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe_guc_klv_encode_u64(klvs, 3, key, value)); 81 KUNIT_EXPECT_EQ(test, klvs[0], PREP_GUC_KLV(key, 2)); 82 KUNIT_EXPECT_EQ(test, klvs[1], lower_32_bits(value)); 83 KUNIT_EXPECT_EQ(test, klvs[2], upper_32_bits(value)); 84 KUNIT_EXPECT_EQ(test, klvs[3], TEST_PAD); 85 KUNIT_EXPECT_PTR_EQ(test, &klvs[3], xe_guc_klv_encode_u64(klvs, 3, key, value)); 86 KUNIT_EXPECT_PTR_EQ(test, 87 xe_guc_klv_encode_u64(klvs, 3, key, value), 88 xe_guc_klv_encode_u64(klvs, ARRAY_SIZE(klvs), key, value)); 89 90 KUNIT_ASSERT_PTR_EQ(test, fail, xe_guc_klv_encode_u64(fail, ARRAY_SIZE(klvs), key, value)); 91 } 92 93 static u32 str_klv_size(const char *string) 94 { 95 return GUC_KLV_LEN_MIN + to_num_dwords(strlen(string) + 1); 96 } 97 98 static void test_encode_string(struct kunit *test) 99 { 100 size_t longest_str = to_num_bytes(FIELD_MAX(GUC_KLV_0_LEN)) - 1; 101 u32 avail = GUC_KLV_LEN_MIN + FIELD_MAX(GUC_KLV_0_LEN) + 1; 102 const char *string = "abcdefghijklmnopqrstvwxyz"; 103 u16 key = TEST_KEY; 104 u32 *klvs; 105 u32 *next; 106 char *buf; 107 u32 n; 108 109 klvs = kunit_kcalloc(test, avail, sizeof(u32), GFP_KERNEL); 110 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, klvs); 111 112 buf = kunit_kzalloc(test, longest_str + 2, GFP_KERNEL); 113 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); 114 115 /* empty string, no space, must fail */ 116 for (n = 0; n < str_klv_size(""); n++) { 117 klvs[0] = TEST_PAD; 118 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), 119 xe_guc_klv_encode_string(klvs, n, key, "")); 120 KUNIT_EXPECT_EQ(test, klvs[0], TEST_PAD); 121 } 122 123 /* empty string, must pass */ 124 KUNIT_EXPECT_PTR_EQ(test, klvs + str_klv_size(""), 125 xe_guc_klv_encode_string(klvs, str_klv_size(""), key, "")); 126 KUNIT_EXPECT_PTR_EQ(test, klvs + str_klv_size(""), 127 xe_guc_klv_encode_string(klvs, avail, key, "")); 128 129 /* demo string, no space, must fail */ 130 for (n = 0; n < str_klv_size(string); n++) { 131 klvs[0] = TEST_PAD; 132 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), 133 xe_guc_klv_encode_string(klvs, n, key, string)); 134 KUNIT_EXPECT_EQ(test, klvs[0], TEST_PAD); 135 } 136 137 /* different string len, must pass */ 138 for (n = 0; n <= strlen(string); n++) { 139 strscpy(buf, string, n + 1); 140 kunit_info(test, "%u: '%s'\n", n, buf); 141 KUNIT_ASSERT_EQ(test, n, strlen(buf)); 142 memset32(klvs, TEST_PAD, avail); 143 144 next = xe_guc_klv_encode_string(klvs, str_klv_size(buf), key, buf); 145 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, next); 146 KUNIT_EXPECT_PTR_EQ(test, next, klvs + str_klv_size(buf)); 147 KUNIT_EXPECT_STREQ_MSG(test, buf, (char *)(klvs + GUC_KLV_LEN_MIN), "n=%u", n); 148 kunit_info(test, "%u: %*ph\n", n, (int)to_num_bytes(next - klvs), klvs); 149 KUNIT_EXPECT_NE(test, *(next - 1), TEST_PAD); 150 KUNIT_ASSERT_EQ(test, *next, TEST_PAD); 151 152 /* bigger buf doesn't matter */ 153 KUNIT_EXPECT_PTR_EQ(test, 154 xe_guc_klv_encode_string(klvs, str_klv_size(buf), key, buf), 155 xe_guc_klv_encode_string(klvs, avail, key, buf)); 156 } 157 158 /* don't crash if already failed */ 159 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-EROFS), 160 xe_guc_klv_encode_string(ERR_PTR(-EROFS), avail, key, "")); 161 162 /* too long string, must fail */ 163 memset(buf, 'X', longest_str + 1); 164 buf[longest_str + 1] = '\0'; 165 KUNIT_EXPECT_LT(test, longest_str, strlen(buf)); 166 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-E2BIG), 167 xe_guc_klv_encode_string(klvs, avail, key, buf)); 168 169 /* longest string, should pass */ 170 buf[longest_str] = '\0'; 171 KUNIT_EXPECT_EQ(test, longest_str, strlen(buf)); 172 KUNIT_EXPECT_PTR_EQ(test, klvs + str_klv_size(buf), 173 xe_guc_klv_encode_string(klvs, avail, key, buf)); 174 } 175 176 struct some_object { 177 u32 value1; 178 u64 value2; 179 } __packed; 180 181 static u32 *obj_raw_encoder(u32 *klvs, u32 avail, const void *arg) 182 { 183 const struct some_object *obj = arg; 184 size_t sz = sizeof(*obj); 185 u32 dwords = to_num_dwords(sz); 186 187 if (IS_ERR(klvs)) 188 return klvs; 189 if (dwords > avail) 190 return ERR_PTR(-ENOSPC); 191 memcpy(klvs, obj, sz); 192 return klvs + dwords; 193 } 194 195 static u32 *obj_klv_encoder(u32 *klvs, u32 avail, const void *arg) 196 { 197 const struct some_object *obj = arg; 198 u32 *end = klvs + avail; 199 200 klvs = xe_guc_klv_encode_u32(klvs, end - klvs, TEST_KEY + 1, obj->value1); 201 klvs = xe_guc_klv_encode_u64(klvs, end - klvs, TEST_KEY + 2, obj->value2); 202 return klvs; 203 } 204 205 static u32 *obj_nested_encoder(u32 *klvs, u32 avail, const void *arg) 206 { 207 u32 *end = klvs + avail; 208 209 klvs = xe_guc_klv_encode_object(klvs, end - klvs, TEST_GROUP_KEY + 1, 210 arg, obj_klv_encoder); 211 klvs = xe_guc_klv_encode_object(klvs, end - klvs, TEST_GROUP_KEY + 2, 212 arg, obj_klv_encoder); 213 return klvs; 214 } 215 216 static void test_encode_object_raw(struct kunit *test) 217 { 218 const struct some_object obj = { 219 .value1 = 0xdead1234, 220 .value2 = 0xdead87654321dead, 221 }; 222 u32 payload = to_num_dwords(sizeof(obj)); 223 u32 *err = ERR_PTR(-ENOSPC); 224 u16 key = TEST_KEY; 225 u32 klvs[16]; 226 u32 n; 227 228 /* too small, must fail */ 229 for (n = 0; n < GUC_KLV_LEN_MIN + payload; n++) { 230 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 231 KUNIT_EXPECT_PTR_EQ_MSG(test, ERR_PTR(-ENOSPC), 232 xe_guc_klv_encode_object(klvs, n, key, &obj, 233 obj_raw_encoder), 234 "buf size=%u dwords", n); 235 } 236 237 /* must pass */ 238 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 239 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, 240 xe_guc_klv_encode_object(klvs, GUC_KLV_LEN_MIN + payload, 241 key, &obj, obj_raw_encoder)); 242 KUNIT_EXPECT_EQ(test, klvs[0], PREP_GUC_KLV(key, payload)); 243 KUNIT_EXPECT_MEMEQ(test, &klvs[1], &obj, sizeof(obj)); 244 245 /* already failed, must fail */ 246 KUNIT_ASSERT_PTR_EQ(test, err, 247 xe_guc_klv_encode_object(err, ARRAY_SIZE(klvs), key, 248 &obj, obj_raw_encoder)); 249 } 250 251 static void test_encode_object_klv(struct kunit *test) 252 { 253 const struct some_object obj = { 254 .value1 = 0xdead1234, 255 .value2 = 0xdead87654321dead, 256 }; 257 u16 key = TEST_GROUP_KEY; 258 u32 payload = 0; 259 u32 klvs[16]; 260 u32 n; 261 262 payload += GUC_KLV_LEN_MIN + to_num_dwords(sizeof(obj.value1)); 263 payload += GUC_KLV_LEN_MIN + to_num_dwords(sizeof(obj.value2)); 264 265 /* too small, must fail */ 266 for (n = 0; n < GUC_KLV_LEN_MIN + payload; n++) { 267 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 268 KUNIT_EXPECT_PTR_EQ_MSG(test, ERR_PTR(-ENOSPC), 269 xe_guc_klv_encode_object(klvs, n, key, &obj, 270 obj_klv_encoder), 271 "buf size=%u dwords", n); 272 } 273 274 /* must pass */ 275 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 276 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, 277 xe_guc_klv_encode_object(klvs, GUC_KLV_LEN_MIN + payload, 278 key, &obj, obj_klv_encoder)); 279 KUNIT_EXPECT_EQ(test, klvs[0], PREP_GUC_KLV(key, payload)); 280 KUNIT_EXPECT_EQ(test, klvs[1], PREP_GUC_KLV(TEST_KEY + 1, 1)); 281 KUNIT_EXPECT_EQ(test, klvs[2], obj.value1); 282 KUNIT_EXPECT_EQ(test, klvs[3], PREP_GUC_KLV(TEST_KEY + 2, 2)); 283 KUNIT_EXPECT_EQ(test, klvs[4], lower_32_bits(obj.value2)); 284 KUNIT_EXPECT_EQ(test, klvs[5], upper_32_bits(obj.value2)); 285 KUNIT_EXPECT_EQ(test, klvs[6], TEST_PAD); 286 } 287 288 static void test_encode_object_nested(struct kunit *test) 289 { 290 const struct some_object obj = { 291 .value1 = 0xdead1234, 292 .value2 = 0xdead87654321dead, 293 }; 294 u16 key = TEST_GROUP_KEY; 295 u32 payload = 0; 296 u32 klvs[16]; 297 u32 n; 298 299 payload += GUC_KLV_LEN_MIN; 300 payload += GUC_KLV_LEN_MIN + to_num_dwords(sizeof(obj.value1)); 301 payload += GUC_KLV_LEN_MIN + to_num_dwords(sizeof(obj.value2)); 302 payload *= 2; 303 304 /* too small, must fail */ 305 for (n = 0; n < GUC_KLV_LEN_MIN + payload; n++) { 306 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 307 KUNIT_EXPECT_PTR_EQ_MSG(test, ERR_PTR(-ENOSPC), 308 xe_guc_klv_encode_object(klvs, n, key, &obj, 309 obj_nested_encoder), 310 "buf size=%u dwords", n); 311 } 312 313 /* must pass */ 314 memset32(klvs, TEST_PAD, ARRAY_SIZE(klvs)); 315 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, 316 xe_guc_klv_encode_object(klvs, GUC_KLV_LEN_MIN + payload, 317 key, &obj, obj_nested_encoder)); 318 KUNIT_EXPECT_EQ(test, klvs[0], PREP_GUC_KLV(key, payload)); 319 KUNIT_EXPECT_EQ(test, klvs[1], PREP_GUC_KLV(TEST_GROUP_KEY + 1, 5)); 320 KUNIT_EXPECT_EQ(test, klvs[2], PREP_GUC_KLV(TEST_KEY + 1, 1)); 321 KUNIT_EXPECT_EQ(test, klvs[3], obj.value1); 322 KUNIT_EXPECT_EQ(test, klvs[4], PREP_GUC_KLV(TEST_KEY + 2, 2)); 323 KUNIT_EXPECT_EQ(test, klvs[5], lower_32_bits(obj.value2)); 324 KUNIT_EXPECT_EQ(test, klvs[6], upper_32_bits(obj.value2)); 325 KUNIT_EXPECT_EQ(test, klvs[7], PREP_GUC_KLV(TEST_GROUP_KEY + 2, 5)); 326 KUNIT_EXPECT_EQ(test, klvs[8], PREP_GUC_KLV(TEST_KEY + 1, 1)); 327 KUNIT_EXPECT_EQ(test, klvs[9], obj.value1); 328 KUNIT_EXPECT_EQ(test, klvs[10], PREP_GUC_KLV(TEST_KEY + 2, 2)); 329 KUNIT_EXPECT_EQ(test, klvs[11], lower_32_bits(obj.value2)); 330 KUNIT_EXPECT_EQ(test, klvs[12], upper_32_bits(obj.value2)); 331 KUNIT_EXPECT_EQ(test, klvs[13], TEST_PAD); 332 } 333 334 static u32 *obj_echo_encoder(u32 *klvs, u32 avail, const void *arg) 335 { 336 return ERR_CAST(arg); 337 } 338 339 static void test_encode_object_basic(struct kunit *test) 340 { 341 u32 longest = GUC_KLV_LEN_MIN + FIELD_MAX(GUC_KLV_0_LEN); 342 u32 avail = GUC_KLV_LEN_MIN + longest; 343 u16 key = TEST_GROUP_KEY; 344 u32 *klvs; 345 346 klvs = kunit_kcalloc(test, avail, sizeof(u32), GFP_KERNEL); 347 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, klvs); 348 349 /* smallest */ 350 KUNIT_EXPECT_PTR_EQ(test, klvs + GUC_KLV_LEN_MIN, 351 xe_guc_klv_encode_object(klvs, avail, key, 352 klvs + GUC_KLV_LEN_MIN, 353 obj_echo_encoder)); 354 /* largest */ 355 KUNIT_EXPECT_PTR_EQ(test, klvs + longest, 356 xe_guc_klv_encode_object(klvs, avail, key, 357 klvs + longest, 358 obj_echo_encoder)); 359 /* already failed */ 360 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-EROFS), 361 xe_guc_klv_encode_object(ERR_PTR(-EROFS), avail, key, 362 klvs + GUC_KLV_LEN_MIN, 363 obj_echo_encoder)); 364 /* encoding error */ 365 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-EUCLEAN), 366 xe_guc_klv_encode_object(klvs, avail, key, 367 ERR_PTR(-EUCLEAN), 368 obj_echo_encoder)); 369 /* no space */ 370 KUNIT_EXPECT_PTR_EQ(test, ERR_PTR(-ENOSPC), 371 xe_guc_klv_encode_object(klvs, 0, key, 372 klvs + GUC_KLV_LEN_MIN, 373 obj_echo_encoder)); 374 } 375 376 static void __drm_printfn_kunit(struct drm_printer *p, struct va_format *vaf) 377 { 378 struct kunit *test = p->arg; 379 380 kunit_info(test, "%pV", vaf); 381 } 382 383 static struct drm_printer drm_kunit_printer(void) 384 { 385 struct drm_printer p = { 386 .printfn = __drm_printfn_kunit, 387 .arg = kunit_get_current_test(), 388 }; 389 return p; 390 } 391 392 static void test_print(struct kunit *test) 393 { 394 struct drm_printer p = drm_kunit_printer(); 395 u32 zeros[] = { 0, 0, 0, /* padding */ }; 396 u32 klvs[] = { 397 PREP_GUC_KLV(GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_KEY, 0), 398 PREP_GUC_KLV(GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY, 1), 1234, 399 PREP_GUC_KLV(GUC_KLV_VF_CFG_GGTT_SIZE_KEY, 2), 0x4000, 0x0123, 400 PREP_GUC_KLV(TEST_KEY, 3), 1, 2, 3, 401 PREP_GUC_KLV(TEST_GROUP_KEY, 5), 402 PREP_GUC_KLV(TEST_KEY + 1, 1), 1, 403 PREP_GUC_KLV(TEST_KEY + 2, 2), 1, 2, 404 }; 405 406 kunit_activate_static_stub(test, is_group_key, fake_is_group_key); 407 xe_guc_klv_print(zeros, ARRAY_SIZE(zeros), &p); 408 xe_guc_klv_print(klvs, ARRAY_SIZE(klvs), &p); 409 } 410 411 static struct kunit_case guc_klv_helpers_test_cases[] = { 412 KUNIT_CASE(test_count), 413 KUNIT_CASE(test_encode_u32), 414 KUNIT_CASE(test_encode_u64), 415 KUNIT_CASE(test_encode_string), 416 KUNIT_CASE(test_encode_object_raw), 417 KUNIT_CASE(test_encode_object_klv), 418 KUNIT_CASE(test_encode_object_nested), 419 KUNIT_CASE(test_encode_object_basic), 420 KUNIT_CASE(test_print), 421 {} 422 }; 423 424 static struct kunit_suite guc_klv_helpers_suite = { 425 .name = "guc_klv_helpers", 426 .test_cases = guc_klv_helpers_test_cases, 427 }; 428 429 kunit_test_suite(guc_klv_helpers_suite); 430