xref: /linux/drivers/gpu/drm/xe/tests/xe_guc_klv_helpers_kunit.c (revision 67f8bc848ee31831336bd478e57d2f993551902e)
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