xref: /linux/drivers/net/ethernet/microchip/vcap/vcap_api_debugfs_kunit.c (revision f72eed59eab42414f3844f4a8e3ce0c4e6280733)
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 	int ret, idx, addr;
320 
321 	vcap_test_api_init(&admin);
322 
323 	/* Go from higher to lower addresses searching for a keyset */
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_keyset(&test_vctrl, &test_netdev, &admin, addr);
329 		KUNIT_EXPECT_EQ(test, -EINVAL, ret);
330 	}
331 
332 	/* Finally we hit the start of the rule */
333 	admin.cache.keystream = &keydata[idx];
334 	admin.cache.maskstream = &mskdata[idx];
335 	ret = vcap_addr_keyset(&test_vctrl, &test_netdev, &admin,  addr);
336 	KUNIT_EXPECT_EQ(test, VCAP_KFS_MAC_ETYPE, ret);
337 }
338 
339 static void vcap_api_show_admin_raw_test(struct kunit *test)
340 {
341 	u32 keydata[4] = {
342 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
343 	};
344 	u32 mskdata[4] = {
345 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
346 	};
347 	u32 actdata[12] = {};
348 	struct vcap_admin admin = {
349 		.vtype = VCAP_TYPE_IS2,
350 		.cache = {
351 			.keystream = keydata,
352 			.maskstream = mskdata,
353 			.actionstream = actdata,
354 		},
355 		.first_valid_addr = 786,
356 		.last_valid_addr = 788,
357 	};
358 	struct vcap_rule_internal ri = {
359 		.ndev = &test_netdev,
360 	};
361 	struct vcap_output_print out = {
362 		.prf = (void *)test_prf,
363 	};
364 	const char *test_expected =
365 		"  addr: 786, X6 rule, keyset: VCAP_KFS_MAC_ETYPE\n";
366 	int ret;
367 
368 	vcap_test_api_init(&admin);
369 	list_add_tail(&ri.list, &admin.rules);
370 
371 	ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
372 	KUNIT_EXPECT_EQ(test, 0, ret);
373 	KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
374 }
375 
376 static const char * const test_admin_info_expect[] = {
377 	"name: is2\n",
378 	"rows: 256\n",
379 	"sw_count: 12\n",
380 	"sw_width: 52\n",
381 	"sticky_width: 1\n",
382 	"act_width: 110\n",
383 	"default_cnt: 73\n",
384 	"require_cnt_dis: 0\n",
385 	"version: 1\n",
386 	"vtype: 2\n",
387 	"vinst: 0\n",
388 	"first_cid: 10000\n",
389 	"last_cid: 19999\n",
390 	"lookups: 4\n",
391 	"first_valid_addr: 0\n",
392 	"last_valid_addr: 3071\n",
393 	"last_used_addr: 794\n",
394 };
395 
396 static void vcap_api_show_admin_test(struct kunit *test)
397 {
398 	struct vcap_admin admin = {
399 		.vtype = VCAP_TYPE_IS2,
400 		.first_cid = 10000,
401 		.last_cid = 19999,
402 		.lookups = 4,
403 		.last_valid_addr = 3071,
404 		.first_valid_addr = 0,
405 		.last_used_addr = 794,
406 	};
407 	struct vcap_output_print out = {
408 		.prf = (void *)test_prf,
409 	};
410 	int idx;
411 
412 	vcap_test_api_init(&admin);
413 
414 	vcap_show_admin_info(&test_vctrl, &admin, &out);
415 	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
416 		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
417 		KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
418 				   test_pr_buffer[idx]);
419 	}
420 }
421 
422 static const char * const test_admin_expect[] = {
423 	"name: is2\n",
424 	"rows: 256\n",
425 	"sw_count: 12\n",
426 	"sw_width: 52\n",
427 	"sticky_width: 1\n",
428 	"act_width: 110\n",
429 	"default_cnt: 73\n",
430 	"require_cnt_dis: 0\n",
431 	"version: 1\n",
432 	"vtype: 2\n",
433 	"vinst: 0\n",
434 	"first_cid: 8000000\n",
435 	"last_cid: 8199999\n",
436 	"lookups: 4\n",
437 	"first_valid_addr: 0\n",
438 	"last_valid_addr: 3071\n",
439 	"last_used_addr: 794\n",
440 	"\n",
441 	"rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
442 	"  chain_id: 0\n",
443 	"  user: 0\n",
444 	"  priority: 0\n",
445 	"  keyset: VCAP_KFS_MAC_ETYPE\n",
446 	"  keyset_sw: 6\n",
447 	"  keyset_sw_regs: 2\n",
448 	"    ETYPE_LEN_IS: W1: 1/1\n",
449 	"    IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
450 	"    IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
451 	"    L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
452 	"    L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
453 	"    L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
454 	"    LOOKUP_FIRST_IS: W1: 1/1\n",
455 	"    TYPE: W4: 0/15\n",
456 	"  actionset: VCAP_AFS_BASE_TYPE\n",
457 	"  actionset_sw: 3\n",
458 	"  actionset_sw_regs: 4\n",
459 	"    CNT_ID: W12: 100\n",
460 	"    MATCH_ID: W16: 1\n",
461 	"    MATCH_ID_MASK: W16: 1\n",
462 	"    POLICE_ENA: W1: 1\n",
463 	"    PORT_MASK: W68: 0x0514670115f3324589\n",
464 };
465 
466 static void vcap_api_show_admin_rule_test(struct kunit *test)
467 {
468 	u32 keydata[] = {
469 		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
470 		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
471 		0x00000020, 0x00000008, 0x00000240, 0x00000000,
472 	};
473 	u32 mskdata[] = {
474 		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
475 		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
476 		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
477 	};
478 	u32 actdata[] = {
479 		0x00040002, 0xf3324589, 0x14670115, 0x00000005,
480 		0x00000000, 0x00100000, 0x06400010, 0x00000000,
481 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
482 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
483 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
484 		0x00000000, 0x00000000, 0x00000000, 0x00000000,
485 	};
486 	struct vcap_admin admin = {
487 		.vtype = VCAP_TYPE_IS2,
488 		.first_cid = 8000000,
489 		.last_cid = 8199999,
490 		.lookups = 4,
491 		.last_valid_addr = 3071,
492 		.first_valid_addr = 0,
493 		.last_used_addr = 794,
494 		.cache = {
495 			.keystream = keydata,
496 			.maskstream = mskdata,
497 			.actionstream = actdata,
498 		},
499 	};
500 	struct vcap_rule_internal ri = {
501 		.admin = &admin,
502 		.data = {
503 			.id = 100,
504 			.keyset = VCAP_KFS_MAC_ETYPE,
505 			.actionset = VCAP_AFS_BASE_TYPE,
506 		},
507 		.size = 6,
508 		.keyset_sw = 6,
509 		.keyset_sw_regs = 2,
510 		.actionset_sw = 3,
511 		.actionset_sw_regs = 4,
512 		.addr = 794,
513 		.vctrl = &test_vctrl,
514 	};
515 	struct vcap_output_print out = {
516 		.prf = (void *)test_prf,
517 	};
518 	int ret, idx;
519 
520 	vcap_test_api_init(&admin);
521 	list_add_tail(&ri.list, &admin.rules);
522 
523 	ret = vcap_show_admin(&test_vctrl, &admin, &out);
524 	KUNIT_EXPECT_EQ(test, 0, ret);
525 	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
526 		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
527 		KUNIT_EXPECT_STREQ(test, test_admin_expect[idx],
528 				   test_pr_buffer[idx]);
529 	}
530 }
531 
532 static struct kunit_case vcap_api_debugfs_test_cases[] = {
533 	KUNIT_CASE(vcap_api_addr_keyset_test),
534 	KUNIT_CASE(vcap_api_show_admin_raw_test),
535 	KUNIT_CASE(vcap_api_show_admin_test),
536 	KUNIT_CASE(vcap_api_show_admin_rule_test),
537 	{}
538 };
539 
540 static struct kunit_suite vcap_api_debugfs_test_suite = {
541 	.name = "VCAP_API_DebugFS_Testsuite",
542 	.test_cases = vcap_api_debugfs_test_cases,
543 };
544 
545 kunit_test_suite(vcap_api_debugfs_test_suite);
546