38f7fe419bdb3bbfca8a91d88cf739acb942d08d
[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 < TF_KEY0_TABLE || table_type > TF_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                                          TF_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                                          TF_KEY1_TABLE,
338                                          dir);
339
340         if (key0_entry == -EEXIST) {
341                 *table = TF_KEY0_TABLE;
342                 *index = key0_hash;
343                 return -EEXIST;
344         } else if (key1_entry == -EEXIST) {
345                 *table = TF_KEY1_TABLE;
346                 *index = key1_hash;
347                 return -EEXIST;
348         } else if (key0_entry == 0) {
349                 *table = TF_KEY0_TABLE;
350                 *index = key0_hash;
351                 return 0;
352         } else if (key1_entry == 0) {
353                 *table = TF_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[TF_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 == TF_KEY0_TABLE) {
424                         TF_SET_GFID(gfid,
425                                     key0_index,
426                                     TF_KEY0_TABLE);
427                 } else {
428                         TF_SET_GFID(gfid,
429                                     key1_index,
430                                     TF_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                 TFP_DRV_LOG(ERR,
483                    "dir:%d, EM entry index allocation failed\n",
484                    parms->dir);
485                 return rc;
486         }
487
488         rptr_index = index * TF_SESSION_EM_ENTRY_SIZE;
489         rc = tf_msg_insert_em_internal_entry(tfp,
490                                              parms,
491                                              &rptr_index,
492                                              &rptr_entry,
493                                              &num_of_entries);
494         if (rc != 0)
495                 return -1;
496
497         TFP_DRV_LOG(INFO,
498                    "Internal entry @ Index:%d rptr_index:0x%x rptr_entry:0x%x num_of_entries:%d\n",
499                    index * TF_SESSION_EM_ENTRY_SIZE,
500                    rptr_index,
501                    rptr_entry,
502                    num_of_entries);
503
504         TF_SET_GFID(gfid,
505                     ((rptr_index << TF_EM_INTERNAL_INDEX_SHIFT) |
506                      rptr_entry),
507                     0); /* N/A for internal table */
508
509         TF_SET_FLOW_ID(parms->flow_id,
510                        gfid,
511                        TF_GFID_TABLE_INTERNAL,
512                        parms->dir);
513
514         TF_SET_FIELDS_IN_FLOW_HANDLE(parms->flow_handle,
515                                      num_of_entries,
516                                      0,
517                                      0,
518                                      rptr_index,
519                                      rptr_entry,
520                                      0);
521         return 0;
522 }
523
524 /** Delete EM internal entry API
525  *
526  * returns:
527  * 0
528  * -EINVAL
529  */
530 int tf_delete_em_internal_entry(struct tf *tfp,
531                                 struct tf_delete_em_entry_parms *parms)
532 {
533         int rc;
534         struct tf_session *session =
535                 (struct tf_session *)(tfp->session->core_data);
536         struct stack *pool = &session->em_pool[parms->dir];
537
538         rc = tf_msg_delete_em_entry(tfp, parms);
539
540         /* Return resource to pool */
541         if (rc == 0)
542                 stack_push(pool, parms->index / TF_SESSION_EM_ENTRY_SIZE);
543
544         return rc;
545 }
546
547
548 /** delete EEM hash entry API
549  *
550  * returns:
551  *   0
552  *   -EINVAL      - parameter error
553  *   TF_NO_SESSION    - bad session ID
554  *   TF_ERR_TBL_SCOPE - invalid table scope
555  *   TF_ERR_TBL_IF    - invalid table interface
556  *
557  * insert callback returns
558  *   0
559  *   TF_NO_EM_MATCH - entry not found
560  */
561 int tf_delete_eem_entry(struct tf *tfp,
562                         struct tf_delete_em_entry_parms *parms)
563 {
564         struct tf_session          *session;
565         struct tf_tbl_scope_cb     *tbl_scope_cb;
566         enum tf_em_table_type hash_type;
567         uint32_t index;
568
569         if (parms == NULL)
570                 return -EINVAL;
571
572         session = (struct tf_session *)tfp->session->core_data;
573         if (session == NULL)
574                 return -EINVAL;
575
576         tbl_scope_cb = tbl_scope_cb_find(session,
577                                          parms->tbl_scope_id);
578         if (tbl_scope_cb == NULL)
579                 return -EINVAL;
580
581         if (parms->flow_handle == 0)
582                 return -EINVAL;
583
584         TF_GET_HASH_TYPE_FROM_FLOW_HANDLE(parms->flow_handle, hash_type);
585         TF_GET_INDEX_FROM_FLOW_HANDLE(parms->flow_handle, index);
586
587         if (tf_em_entry_exists(tbl_scope_cb,
588                                NULL,
589                                index,
590                                hash_type,
591                                parms->dir) == -EEXIST) {
592                 tf_em_write_entry(tbl_scope_cb,
593                                   &zero_key_entry,
594                                   TF_EM_KEY_RECORD_SIZE,
595                                   index,
596                                   hash_type,
597                                   parms->dir);
598
599                 return 0;
600         }
601
602         return -EINVAL;
603 }