GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / microchip / vcap / vcap_api_debugfs_kunit.c
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 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         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 */
258 static __printf(2, 3)
259 int 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
292 static 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
343 static 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
380 static 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
401 static 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
428 static 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
474 static 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
541 static 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
549 static struct kunit_suite vcap_api_debugfs_test_suite = {
550         .name = "VCAP_API_DebugFS_Testsuite",
551         .test_cases = vcap_api_debugfs_test_cases,
552 };
553
554 kunit_test_suite(vcap_api_debugfs_test_suite);