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 int vcap_test_enable(struct net_device *ndev,
225 			    struct vcap_admin *admin,
226 			    bool enable)
227 {
228 	return 0;
229 }
230 
231 static struct vcap_operations test_callbacks = {
232 	.validate_keyset = test_val_keyset,
233 	.add_default_fields = test_add_def_fields,
234 	.cache_erase = test_cache_erase,
235 	.cache_write = test_cache_write,
236 	.cache_read = test_cache_read,
237 	.init = test_cache_init,
238 	.update = test_cache_update,
239 	.move = test_cache_move,
240 	.port_info = vcap_test_port_info,
241 	.enable = vcap_test_enable,
242 };
243 
244 static struct vcap_control test_vctrl = {
245 	.vcaps = kunit_test_vcaps,
246 	.stats = &kunit_test_vcap_stats,
247 	.ops = &test_callbacks,
248 };
249 
250 static void vcap_test_api_init(struct vcap_admin *admin)
251 {
252 	/* Initialize the shared objects */
253 	INIT_LIST_HEAD(&test_vctrl.list);
254 	INIT_LIST_HEAD(&admin->list);
255 	INIT_LIST_HEAD(&admin->rules);
256 	list_add_tail(&admin->list, &test_vctrl.list);
257 	memset(test_updateaddr, 0, sizeof(test_updateaddr));
258 	test_updateaddridx = 0;
259 	test_pr_bufferidx = 0;
260 	test_pr_idx = 0;
261 }
262 
263 /* callback used by the show_admin function */
264 static __printf(2, 3)
265 int test_prf(void *out, const char *fmt, ...)
266 {
267 	static char test_buffer[TEST_BUF_SZ];
268 	va_list args;
269 	int idx, cnt;
270 
271 	if (test_pr_bufferidx >= TEST_BUF_CNT) {
272 		pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
273 		       test_pr_bufferidx);
274 		return 0;
275 	}
276 
277 	va_start(args, fmt);
278 	cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args);
279 	va_end(args);
280 
281 	for (idx = 0; idx < cnt; ++idx) {
282 		test_pr_buffer[test_pr_bufferidx][test_pr_idx] =
283 			test_buffer[idx];
284 		if (test_buffer[idx] == '\n') {
285 			test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0;
286 			test_pr_idx = 0;
287 			test_pr_bufferidx++;
288 		} else {
289 			++test_pr_idx;
290 		}
291 	}
292 
293 	return cnt;
294 }
295 
296 /* Define the test cases. */
297 
298 static void vcap_api_addr_keyset_test(struct kunit *test)
299 {
300 	u32 keydata[12] = {
301 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
302 		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
303 		0x00000020, 0x00000008, 0x00000240, 0x00000000,
304 	};
305 	u32 mskdata[12] = {
306 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
307 		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
308 		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
309 	};
310 	u32 actdata[12] = {};
311 	struct vcap_admin admin = {
312 		.vtype = VCAP_TYPE_IS2,
313 		.cache = {
314 			.keystream = keydata,
315 			.maskstream = mskdata,
316 			.actionstream = actdata,
317 		},
318 	};
319 	enum vcap_keyfield_set keysets[10];
320 	struct vcap_keyset_list matches;
321 	int ret, idx, addr;
322 
323 	vcap_test_api_init(&admin);
324 
325 	/* Go from higher to lower addresses searching for a keyset */
326 	matches.keysets = keysets;
327 	matches.cnt = 0;
328 	matches.max = ARRAY_SIZE(keysets);
329 	for (idx = ARRAY_SIZE(keydata) - 1, addr = 799; idx > 0;
330 	     --idx, --addr) {
331 		admin.cache.keystream = &keydata[idx];
332 		admin.cache.maskstream = &mskdata[idx];
333 		ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
334 					addr, &matches);
335 		KUNIT_EXPECT_EQ(test, -EINVAL, ret);
336 	}
337 
338 	/* Finally we hit the start of the rule */
339 	admin.cache.keystream = &keydata[idx];
340 	admin.cache.maskstream = &mskdata[idx];
341 	matches.cnt = 0;
342 	ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
343 				addr, &matches);
344 	KUNIT_EXPECT_EQ(test, 0, ret);
345 	KUNIT_EXPECT_EQ(test, matches.cnt, 1);
346 	KUNIT_EXPECT_EQ(test, matches.keysets[0], VCAP_KFS_MAC_ETYPE);
347 }
348 
349 static void vcap_api_show_admin_raw_test(struct kunit *test)
350 {
351 	u32 keydata[4] = {
352 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
353 	};
354 	u32 mskdata[4] = {
355 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
356 	};
357 	u32 actdata[12] = {};
358 	struct vcap_admin admin = {
359 		.vtype = VCAP_TYPE_IS2,
360 		.cache = {
361 			.keystream = keydata,
362 			.maskstream = mskdata,
363 			.actionstream = actdata,
364 		},
365 		.first_valid_addr = 786,
366 		.last_valid_addr = 788,
367 	};
368 	struct vcap_rule_internal ri = {
369 		.ndev = &test_netdev,
370 	};
371 	struct vcap_output_print out = {
372 		.prf = (void *)test_prf,
373 	};
374 	const char *test_expected =
375 		"  addr: 786, X6 rule, keysets: VCAP_KFS_MAC_ETYPE\n";
376 	int ret;
377 
378 	vcap_test_api_init(&admin);
379 	list_add_tail(&ri.list, &admin.rules);
380 
381 	ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
382 	KUNIT_EXPECT_EQ(test, 0, ret);
383 	KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
384 }
385 
386 static const char * const test_admin_info_expect[] = {
387 	"name: is2\n",
388 	"rows: 256\n",
389 	"sw_count: 12\n",
390 	"sw_width: 52\n",
391 	"sticky_width: 1\n",
392 	"act_width: 110\n",
393 	"default_cnt: 73\n",
394 	"require_cnt_dis: 0\n",
395 	"version: 1\n",
396 	"vtype: 2\n",
397 	"vinst: 0\n",
398 	"first_cid: 10000\n",
399 	"last_cid: 19999\n",
400 	"lookups: 4\n",
401 	"first_valid_addr: 0\n",
402 	"last_valid_addr: 3071\n",
403 	"last_used_addr: 794\n",
404 };
405 
406 static void vcap_api_show_admin_test(struct kunit *test)
407 {
408 	struct vcap_admin admin = {
409 		.vtype = VCAP_TYPE_IS2,
410 		.first_cid = 10000,
411 		.last_cid = 19999,
412 		.lookups = 4,
413 		.last_valid_addr = 3071,
414 		.first_valid_addr = 0,
415 		.last_used_addr = 794,
416 	};
417 	struct vcap_output_print out = {
418 		.prf = (void *)test_prf,
419 	};
420 	int idx;
421 
422 	vcap_test_api_init(&admin);
423 
424 	vcap_show_admin_info(&test_vctrl, &admin, &out);
425 	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
426 		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
427 		KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
428 				   test_pr_buffer[idx]);
429 	}
430 }
431 
432 static const char * const test_admin_expect[] = {
433 	"name: is2\n",
434 	"rows: 256\n",
435 	"sw_count: 12\n",
436 	"sw_width: 52\n",
437 	"sticky_width: 1\n",
438 	"act_width: 110\n",
439 	"default_cnt: 73\n",
440 	"require_cnt_dis: 0\n",
441 	"version: 1\n",
442 	"vtype: 2\n",
443 	"vinst: 0\n",
444 	"first_cid: 8000000\n",
445 	"last_cid: 8199999\n",
446 	"lookups: 4\n",
447 	"first_valid_addr: 0\n",
448 	"last_valid_addr: 3071\n",
449 	"last_used_addr: 794\n",
450 	"\n",
451 	"rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
452 	"  chain_id: 0\n",
453 	"  user: 0\n",
454 	"  priority: 0\n",
455 	"  keysets: VCAP_KFS_MAC_ETYPE\n",
456 	"  keyset_sw: 6\n",
457 	"  keyset_sw_regs: 2\n",
458 	"    ETYPE_LEN_IS: W1: 1/1\n",
459 	"    IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
460 	"    IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
461 	"    L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
462 	"    L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
463 	"    L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
464 	"    LOOKUP_FIRST_IS: W1: 1/1\n",
465 	"    TYPE: W4: 0/15\n",
466 	"  actionset: VCAP_AFS_BASE_TYPE\n",
467 	"  actionset_sw: 3\n",
468 	"  actionset_sw_regs: 4\n",
469 	"    CNT_ID: W12: 100\n",
470 	"    MATCH_ID: W16: 1\n",
471 	"    MATCH_ID_MASK: W16: 1\n",
472 	"    POLICE_ENA: W1: 1\n",
473 	"    PORT_MASK: W68: 0x0514670115f3324589\n",
474 };
475 
476 static void vcap_api_show_admin_rule_test(struct kunit *test)
477 {
478 	u32 keydata[] = {
479 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
480 		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
481 		0x00000020, 0x00000008, 0x00000240, 0x00000000,
482 	};
483 	u32 mskdata[] = {
484 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
485 		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
486 		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
487 	};
488 	u32 actdata[] = {
489 		0x00040002, 0xf3324589, 0x14670115, 0x00000005,
490 		0x00000000, 0x00100000, 0x06400010, 0x00000000,
491 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
492 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
493 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
494 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
495 	};
496 	struct vcap_admin admin = {
497 		.vtype = VCAP_TYPE_IS2,
498 		.first_cid = 8000000,
499 		.last_cid = 8199999,
500 		.lookups = 4,
501 		.last_valid_addr = 3071,
502 		.first_valid_addr = 0,
503 		.last_used_addr = 794,
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