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
19static u32 test_updateaddr[STREAMWSIZE] = {};
20static int test_updateaddridx;
21static int test_cache_erase_count;
22static u32 test_init_start;
23static u32 test_init_count;
24static u32 test_hw_counter_id;
25static struct vcap_cache_data test_hw_cache;
26static struct net_device test_netdev = {};
27static int test_move_addr;
28static int test_move_offset;
29static int test_move_count;
30static char test_pr_buffer[TEST_BUF_CNT][TEST_BUF_SZ];
31static int test_pr_bufferidx;
32static int test_pr_idx;
33
34/* Callback used by the VCAP API */
35static 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 */
80static 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 */
93static 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 */
104static 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 */
112static 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 */
154static 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 */
196static 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
208static 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 */
217static 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
224static 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
236static struct vcap_control test_vctrl = {
237	.vcaps = kunit_test_vcaps,
238	.stats = &kunit_test_vcap_stats,
239	.ops = &test_callbacks,
240};
241
242static void vcap_test_api_init(struct vcap_admin *admin)
243{
244	/* Initialize the shared objects */
245	INIT_LIST_HEAD(&test_vctrl.list);
246	INIT_LIST_HEAD(&admin->list);
247	INIT_LIST_HEAD(&admin->rules);
248	INIT_LIST_HEAD(&admin->enabled);
249	mutex_init(&admin->lock);
250	list_add_tail(&admin->list, &test_vctrl.list);
251	memset(test_updateaddr, 0, sizeof(test_updateaddr));
252	test_updateaddridx = 0;
253	test_pr_bufferidx = 0;
254	test_pr_idx = 0;
255}
256
257/* callback used by the show_admin function */
258static __printf(2, 3)
259int test_prf(void *out, const char *fmt, ...)
260{
261	static char test_buffer[TEST_BUF_SZ];
262	va_list args;
263	int idx, cnt;
264
265	if (test_pr_bufferidx >= TEST_BUF_CNT) {
266		pr_err("%s:%d: overflow: %d\n", __func__, __LINE__,
267		       test_pr_bufferidx);
268		return 0;
269	}
270
271	va_start(args, fmt);
272	cnt = vscnprintf(test_buffer, TEST_BUF_SZ, fmt, args);
273	va_end(args);
274
275	for (idx = 0; idx < cnt; ++idx) {
276		test_pr_buffer[test_pr_bufferidx][test_pr_idx] =
277			test_buffer[idx];
278		if (test_buffer[idx] == '\n') {
279			test_pr_buffer[test_pr_bufferidx][++test_pr_idx] = 0;
280			test_pr_idx = 0;
281			test_pr_bufferidx++;
282		} else {
283			++test_pr_idx;
284		}
285	}
286
287	return cnt;
288}
289
290/* Define the test cases. */
291
292static void vcap_api_addr_keyset_test(struct kunit *test)
293{
294	u32 keydata[12] = {
295		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
296		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
297		0x00000020, 0x00000008, 0x00000240, 0x00000000,
298	};
299	u32 mskdata[12] = {
300		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
301		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
302		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
303	};
304	u32 actdata[12] = {};
305	struct vcap_admin admin = {
306		.vtype = VCAP_TYPE_IS2,
307		.cache = {
308			.keystream = keydata,
309			.maskstream = mskdata,
310			.actionstream = actdata,
311		},
312	};
313	enum vcap_keyfield_set keysets[10];
314	struct vcap_keyset_list matches;
315	int ret, idx, addr;
316
317	vcap_test_api_init(&admin);
318
319	/* Go from higher to lower addresses searching for a keyset */
320	matches.keysets = keysets;
321	matches.cnt = 0;
322	matches.max = ARRAY_SIZE(keysets);
323	for (idx = ARRAY_SIZE(keydata) - 1, addr = 799; idx > 0;
324	     --idx, --addr) {
325		admin.cache.keystream = &keydata[idx];
326		admin.cache.maskstream = &mskdata[idx];
327		ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
328					addr, &matches);
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	matches.cnt = 0;
336	ret = vcap_addr_keysets(&test_vctrl, &test_netdev, &admin,
337				addr, &matches);
338	KUNIT_EXPECT_EQ(test, 0, ret);
339	KUNIT_EXPECT_EQ(test, matches.cnt, 1);
340	KUNIT_EXPECT_EQ(test, matches.keysets[0], VCAP_KFS_MAC_ETYPE);
341}
342
343static void vcap_api_show_admin_raw_test(struct kunit *test)
344{
345	u32 keydata[4] = {
346		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
347	};
348	u32 mskdata[4] = {
349		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
350	};
351	u32 actdata[12] = {};
352	struct vcap_admin admin = {
353		.vtype = VCAP_TYPE_IS2,
354		.cache = {
355			.keystream = keydata,
356			.maskstream = mskdata,
357			.actionstream = actdata,
358		},
359		.first_valid_addr = 786,
360		.last_valid_addr = 788,
361	};
362	struct vcap_rule_internal ri = {
363		.ndev = &test_netdev,
364	};
365	struct vcap_output_print out = {
366		.prf = (void *)test_prf,
367	};
368	const char *test_expected =
369		"  addr: 786, X6 rule, keysets: VCAP_KFS_MAC_ETYPE\n";
370	int ret;
371
372	vcap_test_api_init(&admin);
373	list_add_tail(&ri.list, &admin.rules);
374
375	ret = vcap_show_admin_raw(&test_vctrl, &admin, &out);
376	KUNIT_EXPECT_EQ(test, 0, ret);
377	KUNIT_EXPECT_STREQ(test, test_expected, test_pr_buffer[0]);
378}
379
380static const char * const test_admin_info_expect[] = {
381	"name: is2\n",
382	"rows: 256\n",
383	"sw_count: 12\n",
384	"sw_width: 52\n",
385	"sticky_width: 1\n",
386	"act_width: 110\n",
387	"default_cnt: 73\n",
388	"require_cnt_dis: 0\n",
389	"version: 1\n",
390	"vtype: 4\n",
391	"vinst: 0\n",
392	"ingress: 1\n",
393	"first_cid: 10000\n",
394	"last_cid: 19999\n",
395	"lookups: 4\n",
396	"first_valid_addr: 0\n",
397	"last_valid_addr: 3071\n",
398	"last_used_addr: 794\n",
399};
400
401static void vcap_api_show_admin_test(struct kunit *test)
402{
403	struct vcap_admin admin = {
404		.vtype = VCAP_TYPE_IS2,
405		.first_cid = 10000,
406		.last_cid = 19999,
407		.lookups = 4,
408		.last_valid_addr = 3071,
409		.first_valid_addr = 0,
410		.last_used_addr = 794,
411		.ingress = true,
412	};
413	struct vcap_output_print out = {
414		.prf = (void *)test_prf,
415	};
416	int idx;
417
418	vcap_test_api_init(&admin);
419
420	vcap_show_admin_info(&test_vctrl, &admin, &out);
421	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
422		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
423		KUNIT_EXPECT_STREQ(test, test_admin_info_expect[idx],
424				   test_pr_buffer[idx]);
425	}
426}
427
428static const char * const test_admin_expect[] = {
429	"name: is2\n",
430	"rows: 256\n",
431	"sw_count: 12\n",
432	"sw_width: 52\n",
433	"sticky_width: 1\n",
434	"act_width: 110\n",
435	"default_cnt: 73\n",
436	"require_cnt_dis: 0\n",
437	"version: 1\n",
438	"vtype: 4\n",
439	"vinst: 0\n",
440	"ingress: 1\n",
441	"first_cid: 8000000\n",
442	"last_cid: 8199999\n",
443	"lookups: 4\n",
444	"first_valid_addr: 0\n",
445	"last_valid_addr: 3071\n",
446	"last_used_addr: 794\n",
447	"\n",
448	"rule: 100, addr: [794,799], X6, ctr[0]: 0, hit: 0\n",
449	"  chain_id: 0\n",
450	"  user: 0\n",
451	"  priority: 0\n",
452	"  state: permanent\n",
453	"  keysets: VCAP_KFS_MAC_ETYPE\n",
454	"  keyset_sw: 6\n",
455	"  keyset_sw_regs: 2\n",
456	"    ETYPE_LEN_IS: W1: 1/1\n",
457	"    IF_IGR_PORT_MASK: W32: 0xffabcd01/0xffffffff\n",
458	"    IF_IGR_PORT_MASK_RNG: W4: 5/15\n",
459	"    L2_DMAC: W48: 01:02:03:04:05:06/ff:ff:ff:ff:ff:ff\n",
460	"    L2_PAYLOAD_ETYPE: W64: 0x9000002000000081/0xff000000000000ff\n",
461	"    L2_SMAC: W48: b1:9e:34:32:75:88/ff:ff:ff:ff:ff:ff\n",
462	"    LOOKUP_FIRST_IS: W1: 1/1\n",
463	"    TYPE: W4: 0/15\n",
464	"  actionset: VCAP_AFS_BASE_TYPE\n",
465	"  actionset_sw: 3\n",
466	"  actionset_sw_regs: 4\n",
467	"    CNT_ID: W12: 100\n",
468	"    MATCH_ID: W16: 1\n",
469	"    MATCH_ID_MASK: W16: 1\n",
470	"    POLICE_ENA: W1: 1\n",
471	"    PORT_MASK: W68: 0x0514670115f3324589\n",
472};
473
474static void vcap_api_show_admin_rule_test(struct kunit *test)
475{
476	u32 keydata[] = {
477		0x40450042, 0x000feaf3, 0x00000003, 0x00050600,
478		0x10203040, 0x00075880, 0x633c6864, 0x00040003,
479		0x00000020, 0x00000008, 0x00000240, 0x00000000,
480	};
481	u32 mskdata[] = {
482		0x0030ff80, 0xfff00000, 0xfffffffc, 0xfff000ff,
483		0x00000000, 0xfff00000, 0x00000000, 0xfff3fffc,
484		0xffffffc0, 0xffffffff, 0xfffffc03, 0xffffffff,
485	};
486	u32 actdata[] = {
487		0x00040002, 0xf3324589, 0x14670115, 0x00000005,
488		0x00000000, 0x00100000, 0x06400010, 0x00000000,
489		0x00000000, 0x00000000, 0x00000000, 0x00000000,
490		0x00000000, 0x00000000, 0x00000000, 0x00000000,
491		0x00000000, 0x00000000, 0x00000000, 0x00000000,
492		0x00000000, 0x00000000, 0x00000000, 0x00000000,
493	};
494	struct vcap_admin admin = {
495		.vtype = VCAP_TYPE_IS2,
496		.first_cid = 8000000,
497		.last_cid = 8199999,
498		.lookups = 4,
499		.last_valid_addr = 3071,
500		.first_valid_addr = 0,
501		.last_used_addr = 794,
502		.ingress = true,
503		.cache = {
504			.keystream = keydata,
505			.maskstream = mskdata,
506			.actionstream = actdata,
507		},
508	};
509	struct vcap_rule_internal ri = {
510		.admin = &admin,
511		.data = {
512			.id = 100,
513			.keyset = VCAP_KFS_MAC_ETYPE,
514			.actionset = VCAP_AFS_BASE_TYPE,
515		},
516		.size = 6,
517		.keyset_sw = 6,
518		.keyset_sw_regs = 2,
519		.actionset_sw = 3,
520		.actionset_sw_regs = 4,
521		.addr = 794,
522		.vctrl = &test_vctrl,
523	};
524	struct vcap_output_print out = {
525		.prf = (void *)test_prf,
526	};
527	int ret, idx;
528
529	vcap_test_api_init(&admin);
530	list_add_tail(&ri.list, &admin.rules);
531
532	ret = vcap_show_admin(&test_vctrl, &admin, &out);
533	KUNIT_EXPECT_EQ(test, 0, ret);
534	for (idx = 0; idx < test_pr_bufferidx; ++idx) {
535		/* pr_info("log[%02d]: %s", idx, test_pr_buffer[idx]); */
536		KUNIT_EXPECT_STREQ(test, test_admin_expect[idx],
537				   test_pr_buffer[idx]);
538	}
539}
540
541static struct kunit_case vcap_api_debugfs_test_cases[] = {
542	KUNIT_CASE(vcap_api_addr_keyset_test),
543	KUNIT_CASE(vcap_api_show_admin_raw_test),
544	KUNIT_CASE(vcap_api_show_admin_test),
545	KUNIT_CASE(vcap_api_show_admin_rule_test),
546	{}
547};
548
549static struct kunit_suite vcap_api_debugfs_test_suite = {
550	.name = "VCAP_API_DebugFS_Testsuite",
551	.test_cases = vcap_api_debugfs_test_cases,
552};
553
554kunit_test_suite(vcap_api_debugfs_test_suite);
555