xref: /linux/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c (revision 333f7de560e1196034b67db16916b10a0c529e1d)
1 // SPDX-License-Identifier: BSD-3-Clause
2 /* Copyright (C) 2022 Microchip Technology Inc. and its subsidiaries.
3  * Microchip VCAP API kunit test suite
4  */
5 
6 #include <kunit/test.h>
7 #include "vcap_api.h"
8 #include "vcap_api_client.h"
9 #include "vcap_api_debugfs.h"
10 #include "vcap_model_kunit.h"
11 
12 /* First we have the test infrastructure that emulates the platform
13  * implementation
14  */
15 #define TEST_BUF_CNT 100
16 #define TEST_BUF_SZ  350
17 #define STREAMWSIZE 64
18 
19 static u32 test_updateaddr[STREAMWSIZE] = {};
20 static int test_updateaddridx;
21 static int test_cache_erase_count;
22 static u32 test_init_start;
23 static u32 test_init_count;
24 static u32 test_hw_counter_id;
25 static struct vcap_cache_data test_hw_cache;
26 static struct net_device test_netdev = {};
27 static int test_move_addr;
28 static int test_move_offset;
29 static int test_move_count;
30 static char test_pr_buffer[TEST_BUF_CNT][TEST_BUF_SZ];
31 static int test_pr_bufferidx;
32 static int test_pr_idx;
33 
34 /* Callback used by the VCAP API */
35 static enum vcap_keyfield_set test_val_keyset(struct net_device *ndev,
36 					      struct vcap_admin *admin,
37 					      struct vcap_rule *rule,
38 					      struct vcap_keyset_list *kslist,
39 					      u16 l3_proto)
40 {
41 	int idx;
42 
43 	if (kslist->cnt > 0) {
44 		switch (admin->vtype) {
45 		case VCAP_TYPE_IS0:
46 			for (idx = 0; idx < kslist->cnt; idx++) {
47 				if (kslist->keysets[idx] == VCAP_KFS_ETAG)
48 					return kslist->keysets[idx];
49 				if (kslist->keysets[idx] ==
50 				    VCAP_KFS_PURE_5TUPLE_IP4)
51 					return kslist->keysets[idx];
52 				if (kslist->keysets[idx] ==
53 				    VCAP_KFS_NORMAL_5TUPLE_IP4)
54 					return kslist->keysets[idx];
55 				if (kslist->keysets[idx] ==
56 				    VCAP_KFS_NORMAL_7TUPLE)
57 					return kslist->keysets[idx];
58 			}
59 			break;
60 		case VCAP_TYPE_IS2:
61 			for (idx = 0; idx < kslist->cnt; idx++) {
62 				if (kslist->keysets[idx] == VCAP_KFS_MAC_ETYPE)
63 					return kslist->keysets[idx];
64 				if (kslist->keysets[idx] == VCAP_KFS_ARP)
65 					return kslist->keysets[idx];
66 				if (kslist->keysets[idx] == VCAP_KFS_IP_7TUPLE)
67 					return kslist->keysets[idx];
68 			}
69 			break;
70 		default:
71 			pr_info("%s:%d: no validation for VCAP %d\n",
72 				__func__, __LINE__, admin->vtype);
73 			break;
74 		}
75 	}
76 	return -EINVAL;
77 }
78 
79 /* Callback used by the VCAP API */
80 static void test_add_def_fields(struct net_device *ndev,
81 				struct vcap_admin *admin,
82 				struct vcap_rule *rule)
83 {
84 	if (admin->vinst == 0 || admin->vinst == 2)
85 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
86 				      VCAP_BIT_1);
87 	else
88 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
89 				      VCAP_BIT_0);
90 }
91 
92 /* Callback used by the VCAP API */
93 static void test_cache_erase(struct vcap_admin *admin)
94 {
95 	if (test_cache_erase_count) {
96 		memset(admin->cache.keystream, 0, test_cache_erase_count);
97 		memset(admin->cache.maskstream, 0, test_cache_erase_count);
98 		memset(admin->cache.actionstream, 0, test_cache_erase_count);
99 		test_cache_erase_count = 0;
100 	}
101 }
102 
103 /* Callback used by the VCAP API */
104 static void test_cache_init(struct net_device *ndev, struct vcap_admin *admin,
105 			    u32 start, u32 count)
106 {
107 	test_init_start = start;
108 	test_init_count = count;
109 }
110 
111 /* Callback used by the VCAP API */
112 static void test_cache_read(struct net_device *ndev, struct vcap_admin *admin,
113 			    enum vcap_selection sel, u32 start, u32 count)
114 {
115 	u32 *keystr, *mskstr, *actstr;
116 	int idx;
117 
118 	pr_debug("%s:%d: %d %d\n", __func__, __LINE__, start, count);
119 	switch (sel) {
120 	case VCAP_SEL_ENTRY:
121 		keystr = &admin->cache.keystream[start];
122 		mskstr = &admin->cache.maskstream[start];
123 		for (idx = 0; idx < count; ++idx) {
124 			pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__,
125 				 __LINE__, start + idx, keystr[idx]);
126 		}
127 		for (idx = 0; idx < count; ++idx) {
128 			/* Invert the mask before decoding starts */
129 			mskstr[idx] = ~mskstr[idx];
130 			pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__,
131 				 __LINE__, start + idx, mskstr[idx]);
132 		}
133 		break;
134 	case VCAP_SEL_ACTION:
135 		actstr = &admin->cache.actionstream[start];
136 		for (idx = 0; idx < count; ++idx) {
137 			pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__,
138 				 __LINE__, start + idx, actstr[idx]);
139 		}
140 		break;
141 	case VCAP_SEL_COUNTER:
142 		pr_debug("%s:%d\n", __func__, __LINE__);
143 		test_hw_counter_id = start;
144 		admin->cache.counter = test_hw_cache.counter;
145 		admin->cache.sticky = test_hw_cache.sticky;
146 		break;
147 	case VCAP_SEL_ALL:
148 		pr_debug("%s:%d\n", __func__, __LINE__);
149 		break;
150 	}
151 }
152 
153 /* Callback used by the VCAP API */
154 static void test_cache_write(struct net_device *ndev, struct vcap_admin *admin,
155 			     enum vcap_selection sel, u32 start, u32 count)
156 {
157 	u32 *keystr, *mskstr, *actstr;
158 	int idx;
159 
160 	switch (sel) {
161 	case VCAP_SEL_ENTRY:
162 		keystr = &admin->cache.keystream[start];
163 		mskstr = &admin->cache.maskstream[start];
164 		for (idx = 0; idx < count; ++idx) {
165 			pr_debug("%s:%d: keydata[%02d]: 0x%08x\n", __func__,
166 				 __LINE__, start + idx, keystr[idx]);
167 		}
168 		for (idx = 0; idx < count; ++idx) {
169 			/* Invert the mask before encoding starts */
170 			mskstr[idx] = ~mskstr[idx];
171 			pr_debug("%s:%d: mskdata[%02d]: 0x%08x\n", __func__,
172 				 __LINE__, start + idx, mskstr[idx]);
173 		}
174 		break;
175 	case VCAP_SEL_ACTION:
176 		actstr = &admin->cache.actionstream[start];
177 		for (idx = 0; idx < count; ++idx) {
178 			pr_debug("%s:%d: actdata[%02d]: 0x%08x\n", __func__,
179 				 __LINE__, start + idx, actstr[idx]);
180 		}
181 		break;
182 	case VCAP_SEL_COUNTER:
183 		pr_debug("%s:%d\n", __func__, __LINE__);
184 		test_hw_counter_id = start;
185 		test_hw_cache.counter = admin->cache.counter;
186 		test_hw_cache.sticky = admin->cache.sticky;
187 		break;
188 	case VCAP_SEL_ALL:
189 		pr_err("%s:%d: cannot write all streams at once\n",
190 		       __func__, __LINE__);
191 		break;
192 	}
193 }
194 
195 /* Callback used by the VCAP API */
196 static void test_cache_update(struct net_device *ndev, struct vcap_admin *admin,
197 			      enum vcap_command cmd,
198 			      enum vcap_selection sel, u32 addr)
199 {
200 	if (test_updateaddridx < ARRAY_SIZE(test_updateaddr))
201 		test_updateaddr[test_updateaddridx] = addr;
202 	else
203 		pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
204 		       test_updateaddridx);
205 	test_updateaddridx++;
206 }
207 
208 static void test_cache_move(struct net_device *ndev, struct vcap_admin *admin,
209 			    u32 addr, int offset, int count)
210 {
211 	test_move_addr = addr;
212 	test_move_offset = offset;
213 	test_move_count = count;
214 }
215 
216 /* Provide port information via a callback interface */
217 static int vcap_test_port_info(struct net_device *ndev,
218 			       struct vcap_admin *admin,
219 			       struct vcap_output_print *out)
220 {
221 	return 0;
222 }
223 
224 static const struct vcap_operations test_callbacks = {
225 	.validate_keyset = test_val_keyset,
226 	.add_default_fields = test_add_def_fields,
227 	.cache_erase = test_cache_erase,
228 	.cache_write = test_cache_write,
229 	.cache_read = test_cache_read,
230 	.init = test_cache_init,
231 	.update = test_cache_update,
232 	.move = test_cache_move,
233 	.port_info = vcap_test_port_info,
234 };
235 
236 static struct vcap_control test_vctrl = {
237 	.vcaps = kunit_test_vcaps,
238 	.stats = &kunit_test_vcap_stats,
239 	.ops = &test_callbacks,
240 };
241 
242 static void vcap_test_api_init(struct vcap_admin *admin)
243 {
244 	/* Initialize the shared objects */
245 	INIT_LIST_HEAD(&test_vctrl.list);
246 	mutex_init(&test_vctrl.lock);
247 	INIT_LIST_HEAD(&admin->list);
248 	INIT_LIST_HEAD(&admin->rules);
249 	INIT_LIST_HEAD(&admin->enabled);
250 	admin->vctrl = &test_vctrl;
251 	list_add_tail(&admin->list, &test_vctrl.list);
252 	memset(test_updateaddr, 0, sizeof(test_updateaddr));
253 	test_updateaddridx = 0;
254 	test_pr_bufferidx = 0;
255 	test_pr_idx = 0;
256 }
257 
258 /* callback used by the show_admin function */
259 static __printf(2, 3)
260 int test_prf(void *out, const char *fmt, ...)
261 {
262 	static char test_buffer[TEST_BUF_SZ];
263 	va_list args;
264 	int idx, cnt;
265 
266 	if (test_pr_bufferidx >= TEST_BUF_CNT) {
267 		pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
268 		       test_pr_bufferidx);
269 		return 0;
270 	}
271 
272 	va_start(args, fmt);
273 	cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args);
274 	va_end(args);
275 
276 	for (idx = 0; idx < cnt; ++idx) {
277 		test_pr_buffer[test_pr_bufferidx][test_pr_idx] =
278 			test_buffer[idx];
279 		if (test_buffer[idx] == '\n') {
280 			test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0;
281 			test_pr_idx = 0;
282 			test_pr_bufferidx++;
283 		} else {
284 			++test_pr_idx;
285 		}
286 	}
287 
288 	return cnt;
289 }
290 
291 /* Define the test cases. */
292 
293 static void vcap_api_addr_keyset_test(struct kunit *test)
294 {
295 	u32 keydata[12] = {
296 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
297 		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
298 		0x00000020, 0x00000008, 0x00000240, 0x00000000,
299 	};
300 	u32 mskdata[12] = {
301 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
302 		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
303 		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
304 	};
305 	u32 actdata[12] = {};
306 	struct vcap_admin admin = {
307 		.vtype = VCAP_TYPE_IS2,
308 		.cache = {
309 			.keystream = keydata,
310 			.maskstream = mskdata,
311 			.actionstream = actdata,
312 		},
313 	};
314 	enum vcap_keyfield_set keysets[10];
315 	struct vcap_keyset_list matches;
316 	int ret, idx, addr;
317 
318 	vcap_test_api_init(&admin);
319 
320 	/* Go from higher to lower addresses searching for a keyset */
321 	matches.keysets = keysets;
322 	matches.cnt = 0;
323 	matches.max = ARRAY_SIZE(keysets);
324 	for (idx = ARRAY_SIZE(keydata) - 1, addr = 799; idx > 0;
325 	     --idx, --addr) {
326 		admin.cache.keystream = &keydata[idx];
327 		admin.cache.maskstream = &mskdata[idx];
328 		ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
329 					addr, &matches);
330 		KUNIT_EXPECT_EQ(test, -EINVAL, ret);
331 	}
332 
333 	/* Finally we hit the start of the rule */
334 	admin.cache.keystream = &keydata[idx];
335 	admin.cache.maskstream = &mskdata[idx];
336 	matches.cnt = 0;
337 	ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
338 				addr, &matches);
339 	KUNIT_EXPECT_EQ(test, 0, ret);
340 	KUNIT_EXPECT_EQ(test, matches.cnt, 1);
341 	KUNIT_EXPECT_EQ(test, matches.keysets[0], VCAP_KFS_MAC_ETYPE);
342 }
343 
344 static void vcap_api_show_admin_raw_test(struct kunit *test)
345 {
346 	u32 keydata[4] = {
347 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
348 	};
349 	u32 mskdata[4] = {
350 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
351 	};
352 	u32 actdata[12] = {};
353 	struct vcap_admin admin = {
354 		.vtype = VCAP_TYPE_IS2,
355 		.cache = {
356 			.keystream = keydata,
357 			.maskstream = mskdata,
358 			.actionstream = actdata,
359 		},
360 		.first_valid_addr = 786,
361 		.last_valid_addr = 788,
362 	};
363 	struct vcap_rule_internal ri = {
364 		.ndev = &test_netdev,
365 	};
366 	struct vcap_output_print out = {
367 		.prf = (void *)test_prf,
368 	};
369 	const char *test_expected =
370 		"  addr: 786, X6 rule, keysets: VCAP_KFS_MAC_ETYPE\n";
371 	int ret;
372 
373 	vcap_test_api_init(&admin);
374 	list_add_tail(&ri.list, &admin.rules);
375 
376 	ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
377 	KUNIT_EXPECT_EQ(test, 0, ret);
378 	KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
379 }
380 
381 static const char * const test_admin_info_expect[] = {
382 	"name: is2\n",
383 	"rows: 256\n",
384 	"sw_count: 12\n",
385 	"sw_width: 52\n",
386 	"sticky_width: 1\n",
387 	"act_width: 110\n",
388 	"default_cnt: 73\n",
389 	"require_cnt_dis: 0\n",
390 	"version: 1\n",
391 	"vtype: 4\n",
392 	"vinst: 0\n",
393 	"ingress: 1\n",
394 	"first_cid: 10000\n",
395 	"last_cid: 19999\n",
396 	"lookups: 4\n",
397 	"first_valid_addr: 0\n",
398 	"last_valid_addr: 3071\n",
399 	"last_used_addr: 794\n",
400 };
401 
402 static void vcap_api_show_admin_test(struct kunit *test)
403 {
404 	struct vcap_admin admin = {
405 		.vtype = VCAP_TYPE_IS2,
406 		.first_cid = 10000,
407 		.last_cid = 19999,
408 		.lookups = 4,
409 		.last_valid_addr = 3071,
410 		.first_valid_addr = 0,
411 		.last_used_addr = 794,
412 		.ingress = true,
413 	};
414 	struct vcap_output_print out = {
415 		.prf = (void *)test_prf,
416 	};
417 	int idx;
418 
419 	vcap_test_api_init(&admin);
420 
421 	vcap_show_admin_info(&test_vctrl, &admin, &out);
422 	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
423 		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
424 		KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
425 				   test_pr_buffer[idx]);
426 	}
427 }
428 
429 static const char * const test_admin_expect[] = {
430 	"name: is2\n",
431 	"rows: 256\n",
432 	"sw_count: 12\n",
433 	"sw_width: 52\n",
434 	"sticky_width: 1\n",
435 	"act_width: 110\n",
436 	"default_cnt: 73\n",
437 	"require_cnt_dis: 0\n",
438 	"version: 1\n",
439 	"vtype: 4\n",
440 	"vinst: 0\n",
441 	"ingress: 1\n",
442 	"first_cid: 8000000\n",
443 	"last_cid: 8199999\n",
444 	"lookups: 4\n",
445 	"first_valid_addr: 0\n",
446 	"last_valid_addr: 3071\n",
447 	"last_used_addr: 794\n",
448 	"\n",
449 	"rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
450 	"  chain_id: 0\n",
451 	"  user: 0\n",
452 	"  priority: 0\n",
453 	"  state: permanent\n",
454 	"  keysets: VCAP_KFS_MAC_ETYPE\n",
455 	"  keyset_sw: 6\n",
456 	"  keyset_sw_regs: 2\n",
457 	"    ETYPE_LEN_IS: W1: 1/1\n",
458 	"    IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
459 	"    IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
460 	"    L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
461 	"    L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
462 	"    L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
463 	"    LOOKUP_FIRST_IS: W1: 1/1\n",
464 	"    TYPE: W4: 0/15\n",
465 	"  actionset: VCAP_AFS_BASE_TYPE\n",
466 	"  actionset_sw: 3\n",
467 	"  actionset_sw_regs: 4\n",
468 	"    CNT_ID: W12: 100\n",
469 	"    MATCH_ID: W16: 1\n",
470 	"    MATCH_ID_MASK: W16: 1\n",
471 	"    POLICE_ENA: W1: 1\n",
472 	"    PORT_MASK: W68: 0x0514670115f3324589\n",
473 };
474 
475 static void vcap_api_show_admin_rule_test(struct kunit *test)
476 {
477 	u32 keydata[] = {
478 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
479 		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
480 		0x00000020, 0x00000008, 0x00000240, 0x00000000,
481 	};
482 	u32 mskdata[] = {
483 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
484 		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
485 		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
486 	};
487 	u32 actdata[] = {
488 		0x00040002, 0xf3324589, 0x14670115, 0x00000005,
489 		0x00000000, 0x00100000, 0x06400010, 0x00000000,
490 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
491 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
492 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
493 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
494 	};
495 	struct vcap_admin admin = {
496 		.vtype = VCAP_TYPE_IS2,
497 		.first_cid = 8000000,
498 		.last_cid = 8199999,
499 		.lookups = 4,
500 		.last_valid_addr = 3071,
501 		.first_valid_addr = 0,
502 		.last_used_addr = 794,
503 		.ingress = true,
504 		.cache = {
505 			.keystream = keydata,
506 			.maskstream = mskdata,
507 			.actionstream = actdata,
508 		},
509 	};
510 	struct vcap_rule_internal ri = {
511 		.admin = &admin,
512 		.data = {
513 			.id = 100,
514 			.keyset = VCAP_KFS_MAC_ETYPE,
515 			.actionset = VCAP_AFS_BASE_TYPE,
516 		},
517 		.size = 6,
518 		.keyset_sw = 6,
519 		.keyset_sw_regs = 2,
520 		.actionset_sw = 3,
521 		.actionset_sw_regs = 4,
522 		.addr = 794,
523 		.vctrl = &test_vctrl,
524 	};
525 	struct vcap_output_print out = {
526 		.prf = (void *)test_prf,
527 	};
528 	int ret, idx;
529 
530 	vcap_test_api_init(&admin);
531 	list_add_tail(&ri.list, &admin.rules);
532 
533 	ret = vcap_show_admin(&test_vctrl, &admin, &out);
534 	KUNIT_EXPECT_EQ(test, 0, ret);
535 	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
536 		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
537 		KUNIT_EXPECT_STREQ(test, test_admin_expect[idx],
538 				   test_pr_buffer[idx]);
539 	}
540 }
541 
542 static struct kunit_case vcap_api_debugfs_test_cases[] = {
543 	KUNIT_CASE(vcap_api_addr_keyset_test),
544 	KUNIT_CASE(vcap_api_show_admin_raw_test),
545 	KUNIT_CASE(vcap_api_show_admin_test),
546 	KUNIT_CASE(vcap_api_show_admin_rule_test),
547 	{}
548 };
549 
550 static struct kunit_suite vcap_api_debugfs_test_suite = {
551 	.name = "VCAP_API_DebugFS_Testsuite",
552 	.test_cases = vcap_api_debugfs_test_cases,
553 };
554 
555 kunit_test_suite(vcap_api_debugfs_test_suite);
556