net/bnxt: support exact match
[dpdk.git] / drivers / net / bnxt / tf_core / tf_em.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2020 Broadcom
3  * All rights reserved.
4  */
5
6 #include <string.h>
7 #include <rte_common.h>
8 #include <rte_errno.h>
9 #include <rte_log.h>
10
11 #include "tf_core.h"
12 #include "tf_em.h"
13 #include "tf_msg.h"
14 #include "tfp.h"
15 #include "lookup3.h"
16 #include "tf_ext_flow_handle.h"
17
18 #include "bnxt.h"
19
20 /* Enable EEM table dump
21  */
22 #define TF_EEM_DUMP
23
24 static struct tf_eem_64b_entry zero_key_entry;
25
26 static uint32_t tf_em_get_key_mask(int num_entries)
27 {
28         uint32_t mask = num_entries - 1;
29
30         if (num_entries & 0x7FFF)
31                 return 0;
32
33         if (num_entries > (128 * 1024 * 1024))
34                 return 0;
35
36         return mask;
37 }
38
39 /* CRC32i support for Key0 hash */
40 #define ucrc32(ch, crc) (crc32tbl[((crc) ^ (ch)) & 0xff] ^ ((crc) >> 8))
41 #define crc32(x, y) crc32i(~0, x, y)
42
43 static const uint32_t crc32tbl[] = {    /* CRC polynomial 0xedb88320 */
44 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
45 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
46 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
47 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
48 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
49 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
50 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
51 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
52 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
53 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
54 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
55 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
56 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
57 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
58 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
59 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
60 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
61 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
62 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
63 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
64 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
65 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
66 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
67 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
68 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
69 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
70 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
71 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
72 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
73 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
74 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
75 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
76 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
77 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
78 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
79 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
80 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
81 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
82 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
83 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
84 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
85 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
86 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
87 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
88 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
89 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
90 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
91 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
92 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
93 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
94 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
95 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
96 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
97 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
98 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
99 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
100 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
101 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
102 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
103 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
104 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
105 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
106 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
107 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
108 };
109
110 static uint32_t crc32i(uint32_t crc, const uint8_t *buf, size_t len)
111 {
112         int l;
113
114         for (l = (len - 1); l >= 0; l--)
115                 crc = ucrc32(buf[l], crc);
116
117         return ~crc;
118 }
119
120 static uint32_t tf_em_lkup_get_crc32_hash(struct tf_session *session,
121                                           uint8_t *key,
122                                           enum tf_dir dir)
123 {
124         int i;
125         uint32_t index;
126         uint32_t val1, val2;
127         uint8_t temp[4];
128         uint8_t *kptr = key;
129
130         /* Do byte-wise XOR of the 52-byte HASH key first. */
131         index = *key;
132         kptr--;
133
134         for (i = TF_HW_EM_KEY_MAX_SIZE - 2; i >= 0; i--) {
135                 index = index ^ *kptr;
136                 kptr--;
137         }
138
139         /* Get seeds */
140         val1 = session->lkup_em_seed_mem[dir][index * 2];
141         val2 = session->lkup_em_seed_mem[dir][index * 2 + 1];
142
143         temp[3] = (uint8_t)(val1 >> 24);
144         temp[2] = (uint8_t)(val1 >> 16);
145         temp[1] = (uint8_t)(val1 >> 8);
146         temp[0] = (uint8_t)(val1 & 0xff);
147         val1 = 0;
148
149         /* Start with seed */
150         if (!(val2 & 0x1))
151                 val1 = crc32i(~val1, temp, 4);
152
153         val1 = crc32i(~val1,
154                       (key - (TF_HW_EM_KEY_MAX_SIZE - 1)),
155                       TF_HW_EM_KEY_MAX_SIZE);
156
157         /* End with seed */
158         if (val2 & 0x1)
159                 val1 = crc32i(~val1, temp, 4);
160
161         return val1;
162 }
163
164 static uint32_t tf_em_lkup_get_lookup3_hash(uint32_t lookup3_init_value,
165                                             uint8_t *in_key)
166 {
167         uint32_t val1;
168
169         val1 = hashword(((uint32_t *)in_key) + 1,
170                          TF_HW_EM_KEY_MAX_SIZE / (sizeof(uint32_t)),
171                          lookup3_init_value);
172
173         return val1;
174 }
175
176 void *tf_em_get_table_page(struct tf_tbl_scope_cb *tbl_scope_cb,
177                            enum tf_dir dir,
178                            uint32_t offset,
179                            enum tf_em_table_type table_type)
180 {
181         int level = 0;
182         int page = offset / TF_EM_PAGE_SIZE;
183         void *addr = NULL;
184         struct tf_em_ctx_mem_info *ctx = &tbl_scope_cb->em_ctx_info[dir];
185
186         if (ctx == NULL)
187                 return NULL;
188
189         if (dir != TF_DIR_RX && dir != TF_DIR_TX)
190                 return NULL;
191
192         if (table_type < KEY0_TABLE || table_type > EFC_TABLE)
193                 return NULL;
194
195         /*
196          * Use the level according to the num_level of page table
197          */
198         level = ctx->em_tables[table_type].num_lvl - 1;
199
200         addr = (void *)ctx->em_tables[table_type].pg_tbl[level].pg_va_tbl[page];
201
202         return addr;
203 }
204
205 /** Read Key table entry
206  *
207  * Entry is read in to entry
208  */
209 static int tf_em_read_entry(struct tf_tbl_scope_cb *tbl_scope_cb,
210                                  struct tf_eem_64b_entry *entry,
211                                  uint32_t entry_size,
212                                  uint32_t index,
213                                  enum tf_em_table_type table_type,
214                                  enum tf_dir dir)
215 {
216         void *page;
217         uint32_t entry_offset = (index * entry_size) % TF_EM_PAGE_SIZE;
218
219         page = tf_em_get_table_page(tbl_scope_cb,
220                                     dir,
221                                     (index * entry_size),
222                                     table_type);
223
224         if (page == NULL)
225                 return -EINVAL;
226
227         memcpy((uint8_t *)entry, (uint8_t *)page + entry_offset, entry_size);
228         return 0;
229 }
230
231 static int tf_em_write_entry(struct tf_tbl_scope_cb *tbl_scope_cb,
232                                  struct tf_eem_64b_entry *entry,
233                                  uint32_t entry_size,
234                                  uint32_t index,
235                                  enum tf_em_table_type table_type,
236                                  enum tf_dir dir)
237 {
238         void *page;
239         uint32_t entry_offset = (index * entry_size) % TF_EM_PAGE_SIZE;
240
241         page = tf_em_get_table_page(tbl_scope_cb,
242                                     dir,
243                                     (index * entry_size),
244                                     table_type);
245
246         if (page == NULL)
247                 return -EINVAL;
248
249         memcpy((uint8_t *)page + entry_offset, entry, entry_size);
250
251         return 0;
252 }
253
254 static int tf_em_entry_exists(struct tf_tbl_scope_cb *tbl_scope_cb,
255                                struct tf_eem_64b_entry *entry,
256                                uint32_t index,
257                                enum tf_em_table_type table_type,
258                                enum tf_dir dir)
259 {
260         int rc;
261         struct tf_eem_64b_entry table_entry;
262
263         rc = tf_em_read_entry(tbl_scope_cb,
264                               &table_entry,
265                               TF_EM_KEY_RECORD_SIZE,
266                               index,
267                               table_type,
268                               dir);
269
270         if (rc != 0)
271                 return -EINVAL;
272
273         if (table_entry.hdr.word1 & (1 << TF_LKUP_RECORD_VALID_SHIFT)) {
274                 if (entry != NULL) {
275                         if (memcmp(&table_entry,
276                                    entry,
277                                    TF_EM_KEY_RECORD_SIZE) == 0)
278                                 return -EEXIST;
279                 } else {
280                         return -EEXIST;
281                 }
282
283                 return -EBUSY;
284         }
285
286         return 0;
287 }
288
289 static void tf_em_create_key_entry(struct tf_eem_entry_hdr *result,
290                                     uint8_t *in_key,
291                                     struct tf_eem_64b_entry *key_entry)
292 {
293         key_entry->hdr.word1 = result->word1;
294
295         if (result->word1 & TF_LKUP_RECORD_ACT_REC_INT_MASK)
296                 key_entry->hdr.pointer = result->pointer;
297         else
298                 key_entry->hdr.pointer = result->pointer;
299
300         memcpy(key_entry->key, in_key, TF_HW_EM_KEY_MAX_SIZE + 4);
301 }
302
303 /* tf_em_select_inject_table
304  *
305  * Returns:
306  * 0 - Key does not exist in either table and can be inserted
307  *              at "index" in table "table".
308  * EEXIST  - Key does exist in table at "index" in table "table".
309  * TF_ERR     - Something went horribly wrong.
310  */
311 static int tf_em_select_inject_table(struct tf_tbl_scope_cb *tbl_scope_cb,
312                                           enum tf_dir dir,
313                                           struct tf_eem_64b_entry *entry,
314                                           uint32_t key0_hash,
315                                           uint32_t key1_hash,
316                                           uint32_t *index,
317                                           enum tf_em_table_type *table)
318 {
319         int key0_entry;
320         int key1_entry;
321
322         /*
323          * Check KEY0 table.
324          */
325         key0_entry = tf_em_entry_exists(tbl_scope_cb,
326                                          entry,
327                                          key0_hash,
328                                          KEY0_TABLE,
329                                          dir);
330
331         /*
332          * Check KEY1 table.
333          */
334         key1_entry = tf_em_entry_exists(tbl_scope_cb,
335                                          entry,
336                                          key1_hash,
337                                          KEY1_TABLE,
338                                          dir);
339
340         if (key0_entry == -EEXIST) {
341                 *table = KEY0_TABLE;
342                 *index = key0_hash;
343                 return -EEXIST;
344         } else if (key1_entry == -EEXIST) {
345                 *table = KEY1_TABLE;
346                 *index = key1_hash;
347                 return -EEXIST;
348         } else if (key0_entry == 0) {
349                 *table = KEY0_TABLE;
350                 *index = key0_hash;
351                 return 0;
352         } else if (key1_entry == 0) {
353                 *table = KEY1_TABLE;
354                 *index = key1_hash;
355                 return 0;
356         }
357
358         return -EINVAL;
359 }
360
361 /** insert EEM entry API
362  *
363  * returns:
364  *  0
365  *  TF_ERR          - unable to get lock
366  *
367  * insert callback returns:
368  *   0
369  *   TF_ERR_EM_DUP  - key is already in table
370  */
371 int tf_insert_eem_entry(struct tf_session *session,
372                         struct tf_tbl_scope_cb *tbl_scope_cb,
373                         struct tf_insert_em_entry_parms *parms)
374 {
375         uint32_t           mask;
376         uint32_t           key0_hash;
377         uint32_t           key1_hash;
378         uint32_t           key0_index;
379         uint32_t           key1_index;
380         struct tf_eem_64b_entry key_entry;
381         uint32_t           index;
382         enum tf_em_table_type table_type;
383         uint32_t           gfid;
384         int                num_of_entry;
385
386         /* Get mask to use on hash */
387         mask = tf_em_get_key_mask(tbl_scope_cb->em_ctx_info[parms->dir].em_tables[KEY0_TABLE].num_entries);
388
389         if (!mask)
390                 return -EINVAL;
391
392         num_of_entry = TF_HW_EM_KEY_MAX_SIZE + 4;
393
394         key0_hash = tf_em_lkup_get_crc32_hash(session,
395                                       &parms->key[num_of_entry] - 1,
396                                       parms->dir);
397         key0_index = key0_hash & mask;
398
399         key1_hash =
400            tf_em_lkup_get_lookup3_hash(session->lkup_lkup3_init_cfg[parms->dir],
401                                         parms->key);
402         key1_index = key1_hash & mask;
403
404         /*
405          * Use the "result" arg to populate all of the key entry then
406          * store the byte swapped "raw" entry in a local copy ready
407          * for insertion in to the table.
408          */
409         tf_em_create_key_entry((struct tf_eem_entry_hdr *)parms->em_record,
410                                 ((uint8_t *)parms->key),
411                                 &key_entry);
412
413         /*
414          * Find which table to use
415          */
416         if (tf_em_select_inject_table(tbl_scope_cb,
417                                       parms->dir,
418                                       &key_entry,
419                                       key0_index,
420                                       key1_index,
421                                       &index,
422                                       &table_type) == 0) {
423                 if (table_type == KEY0_TABLE) {
424                         TF_SET_GFID(gfid,
425                                     key0_index,
426                                     KEY0_TABLE);
427                 } else {
428                         TF_SET_GFID(gfid,
429                                     key1_index,
430                                     KEY1_TABLE);
431                 }
432
433                 /*
434                  * Inject
435                  */
436                 if (tf_em_write_entry(tbl_scope_cb,
437                                       &key_entry,
438                                       TF_EM_KEY_RECORD_SIZE,
439                                       index,
440                                       table_type,
441                                       parms->dir) == 0) {
442                         TF_SET_FLOW_ID(parms->flow_id,
443                                        gfid,
444                                        TF_GFID_TABLE_EXTERNAL,
445                                        parms->dir);
446                         TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
447                                                      0,
448                                                      0,
449                                                      0,
450                                                      index,
451                                                      0,
452                                                      table_type);
453                         return 0;
454                 }
455         }
456
457         return -EINVAL;
458 }
459
460 /**
461  * Insert EM internal entry API
462  *
463  *  returns:
464  *     0 - Success
465  */
466 int tf_insert_em_internal_entry(struct tf *tfp,
467                                 struct tf_insert_em_entry_parms *parms)
468 {
469         int       rc;
470         uint32_t  gfid;
471         uint16_t  rptr_index = 0;
472         uint8_t   rptr_entry = 0;
473         uint8_t   num_of_entries = 0;
474         struct tf_session *session =
475                 (struct tf_session *)(tfp->session->core_data);
476         struct stack *pool = &session->em_pool[parms->dir];
477         uint32_t index;
478
479         rc = stack_pop(pool, &index);
480
481         if (rc != 0) {
482                 PMD_DRV_LOG
483                    (ERR,
484                    "dir:%d, EM entry index allocation failed\n",
485                    parms->dir);
486                 return rc;
487         }
488
489         rptr_index = index * TF_SESSION_EM_ENTRY_SIZE;
490         rc = tf_msg_insert_em_internal_entry(tfp,
491                                              parms,
492                                              &rptr_index,
493                                              &rptr_entry,
494                                              &num_of_entries);
495         if (rc != 0)
496                 return -1;
497
498         PMD_DRV_LOG
499                    (ERR,
500                    "Internal entry @ Index:%d rptr_index:0x%x rptr_entry:0x%x num_of_entries:%d\n",
501                    index * TF_SESSION_EM_ENTRY_SIZE,
502                    rptr_index,
503                    rptr_entry,
504                    num_of_entries);
505
506         TF_SET_GFID(gfid,
507                     ((rptr_index << TF_EM_INTERNAL_INDEX_SHIFT) |
508                      rptr_entry),
509                     0); /* N/A for internal table */
510
511         TF_SET_FLOW_ID(parms->flow_id,
512                        gfid,
513                        TF_GFID_TABLE_INTERNAL,
514                        parms->dir);
515
516         TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
517                                      num_of_entries,
518                                      0,
519                                      0,
520                                      rptr_index,
521                                      rptr_entry,
522                                      0);
523         return 0;
524 }
525
526 /** Delete EM internal entry API
527  *
528  * returns:
529  * 0
530  * -EINVAL
531  */
532 int tf_delete_em_internal_entry(struct tf *tfp,
533                                 struct tf_delete_em_entry_parms *parms)
534 {
535         int rc;
536         struct tf_session *session =
537                 (struct tf_session *)(tfp->session->core_data);
538         struct stack *pool = &session->em_pool[parms->dir];
539
540         rc = tf_msg_delete_em_entry(tfp, parms);
541
542         /* Return resource to pool */
543         if (rc == 0)
544                 stack_push(pool, parms->index / TF_SESSION_EM_ENTRY_SIZE);
545
546         return rc;
547 }
548
549
550 /** delete EEM hash entry API
551  *
552  * returns:
553  *   0
554  *   -EINVAL      - parameter error
555  *   TF_NO_SESSION    - bad session ID
556  *   TF_ERR_TBL_SCOPE - invalid table scope
557  *   TF_ERR_TBL_IF    - invalid table interface
558  *
559  * insert callback returns
560  *   0
561  *   TF_NO_EM_MATCH - entry not found
562  */
563 int tf_delete_eem_entry(struct tf *tfp,
564                         struct tf_delete_em_entry_parms *parms)
565 {
566         struct tf_session          *session;
567         struct tf_tbl_scope_cb     *tbl_scope_cb;
568         enum tf_em_table_type hash_type;
569         uint32_t index;
570
571         if (parms == NULL)
572                 return -EINVAL;
573
574         session = (struct tf_session *)tfp->session->core_data;
575         if (session == NULL)
576                 return -EINVAL;
577
578         tbl_scope_cb = tbl_scope_cb_find(session,
579                                          parms->tbl_scope_id);
580         if (tbl_scope_cb == NULL)
581                 return -EINVAL;
582
583         if (parms->flow_handle == 0)
584                 return -EINVAL;
585
586         TF_GET_HASH_TYPE_FROM_FLOW_HANDLE(parms->flow_handle, hash_type);
587         TF_GET_INDEX_FROM_FLOW_HANDLE(parms->flow_handle, index);
588
589         if (tf_em_entry_exists(tbl_scope_cb,
590                                NULL,
591                                index,
592                                hash_type,
593                                parms->dir) == -EEXIST) {
594                 tf_em_write_entry(tbl_scope_cb,
595                                   &zero_key_entry,
596                                   TF_EM_KEY_RECORD_SIZE,
597                                   index,
598                                   hash_type,
599                                   parms->dir);
600
601                 return 0;
602         }
603
604         return -EINVAL;
605 }