1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
3 * All rights reserved.
4 */
5
6 #include "tf_common.h"
7 #include "tf_util.h"
8 #include "tfp.h"
9 #include "tf_core.h"
10 #include "tf_shadow_tbl.h"
11 #include "tf_hash.h"
12
13 /**
14 * The implementation includes 3 tables per table table type.
15 * - hash table
16 * - sized so that a minimum of 4 slots per shadow entry are available to
17 * minimize the likelihood of collisions.
18 * - shadow key table
19 * - sized to the number of entries requested and is directly indexed
20 * - the index is zero based and is the table index - the base address
21 * - the data associated with the entry is stored in the key table.
22 * - The stored key is actually the data associated with the entry.
23 * - shadow result table
24 * - the result table is stored separately since it only needs to be accessed
25 * when the key matches.
26 * - the result has a back pointer to the hash table via the hb handle. The
27 * hb handle is a 32 bit represention of the hash with a valid bit, bucket
28 * element index, and the hash index. It is necessary to store the hb handle
29 * with the result since subsequent removes only provide the table index.
30 *
31 * - Max entries is limited in the current implementation since bit 15 is the
32 * valid bit in the hash table.
33 * - A 16bit hash is calculated and masked based on the number of entries
34 * - 64b wide bucket is used and broken into 4x16bit elements.
35 * This decision is based on quicker bucket scanning to determine if any
36 * elements are in use.
37 * - bit 15 of each bucket element is the valid, this is done to prevent having
38 * to read the larger key/result data for determining VALID. It also aids
39 * in the more efficient scanning of the bucket for slot usage.
40 */
41
42 /*
43 * The maximum number of shadow entries supported. The value also doubles as
44 * the maximum number of hash buckets. There are only 15 bits of data per
45 * bucket to point to the shadow tables.
46 */
47 #define TF_SHADOW_ENTRIES_MAX (1 << 15)
48
49 /* The number of elements(BE) per hash bucket (HB) */
50 #define TF_SHADOW_HB_NUM_ELEM (4)
51 #define TF_SHADOW_BE_VALID (1 << 15)
52 #define TF_SHADOW_BE_IS_VALID(be) (((be) & TF_SHADOW_BE_VALID) != 0)
53
54 /**
55 * The hash bucket handle is 32b
56 * - bit 31, the Valid bit
57 * - bit 29-30, the element
58 * - bits 0-15, the hash idx (is masked based on the allocated size)
59 */
60 #define TF_SHADOW_HB_HANDLE_IS_VALID(hndl) (((hndl) & (1 << 31)) != 0)
61 #define TF_SHADOW_HB_HANDLE_CREATE(idx, be) ((1 << 31) | \
62 ((be) << 29) | (idx))
63
64 #define TF_SHADOW_HB_HANDLE_BE_GET(hdl) (((hdl) >> 29) & \
65 (TF_SHADOW_HB_NUM_ELEM - 1))
66
67 #define TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hdl)((hdl) & \
68 (ctxt)->hash_ctxt.hid_mask)
69
70 /**
71 * The idx provided by the caller is within a region, so currently the base is
72 * either added or subtracted from the idx to ensure it can be used as a
73 * compressed index
74 */
75
76 /* Convert the table index to a shadow index */
77 #define TF_SHADOW_IDX_TO_SHIDX(ctxt, idx) ((idx) - \
78 (ctxt)->shadow_ctxt.base_addr)
79
80 /* Convert the shadow index to a tbl index */
81 #define TF_SHADOW_SHIDX_TO_IDX(ctxt, idx) ((idx) + \
82 (ctxt)->shadow_ctxt.base_addr)
83
84 /* Simple helper masks for clearing en element from the bucket */
85 #define TF_SHADOW_BE0_MASK_CLEAR(hb) ((hb) & 0xffffffffffff0000ull)
86 #define TF_SHADOW_BE1_MASK_CLEAR(hb) ((hb) & 0xffffffff0000ffffull)
87 #define TF_SHADOW_BE2_MASK_CLEAR(hb) ((hb) & 0xffff0000ffffffffull)
88 #define TF_SHADOW_BE3_MASK_CLEAR(hb) ((hb) & 0x0000ffffffffffffull)
89
90 /**
91 * This should be coming from external, but for now it is assumed that no key
92 * is greater than 512 bits (64B). This makes allocation of the key table
93 * easier without having to allocate on the fly.
94 */
95 #define TF_SHADOW_MAX_KEY_SZ 64
96
97 /*
98 * Local only defines for the internal data.
99 */
100
101 /**
102 * tf_shadow_tbl_shadow_key_entry is the key entry of the key table.
103 * The key stored in the table is the result data of the index table.
104 */
105 struct tf_shadow_tbl_shadow_key_entry {
106 uint8_t key[TF_SHADOW_MAX_KEY_SZ];
107 };
108
109 /**
110 * tf_shadow_tbl_shadow_result_entry is the result table entry.
111 * The result table writes are broken into two phases:
112 * - The search phase, which stores the hb_handle and key size and
113 * - The set phase, which writes the refcnt
114 */
115 struct tf_shadow_tbl_shadow_result_entry {
116 uint16_t key_size;
117 uint32_t refcnt;
118 uint32_t hb_handle;
119 };
120
121 /**
122 * tf_shadow_tbl_shadow_ctxt holds all information for accessing the key and
123 * result tables.
124 */
125 struct tf_shadow_tbl_shadow_ctxt {
126 struct tf_shadow_tbl_shadow_key_entry *sh_key_tbl;
127 struct tf_shadow_tbl_shadow_result_entry *sh_res_tbl;
128 uint32_t base_addr;
129 uint16_t num_entries;
130 uint16_t alloc_idx;
131 };
132
133 /**
134 * tf_shadow_tbl_hash_ctxt holds all information related to accessing the hash
135 * table.
136 */
137 struct tf_shadow_tbl_hash_ctxt {
138 uint64_t *hashtbl;
139 uint16_t hid_mask;
140 uint16_t hash_entries;
141 };
142
143 /**
144 * tf_shadow_tbl_ctxt holds the hash and shadow tables for the current shadow
145 * table db. This structure is per table table type as each table table has
146 * it's own shadow and hash table.
147 */
148 struct tf_shadow_tbl_ctxt {
149 struct tf_shadow_tbl_shadow_ctxt shadow_ctxt;
150 struct tf_shadow_tbl_hash_ctxt hash_ctxt;
151 };
152
153 /**
154 * tf_shadow_tbl_db is the allocated db structure returned as an opaque
155 * void * pointer to the caller during create db. It holds the pointers for
156 * each table associated with the db.
157 */
158 struct tf_shadow_tbl_db {
159 /* Each context holds the shadow and hash table information */
160 struct tf_shadow_tbl_ctxt *ctxt[TF_TBL_TYPE_MAX];
161 };
162
163 /**
164 * Simple routine that decides what table types can be searchable.
165 *
166 */
tf_shadow_tbl_is_searchable(enum tf_tbl_type type)167 static int tf_shadow_tbl_is_searchable(enum tf_tbl_type type)
168 {
169 int rc = 0;
170
171 switch (type) {
172 case TF_TBL_TYPE_ACT_ENCAP_8B:
173 case TF_TBL_TYPE_ACT_ENCAP_16B:
174 case TF_TBL_TYPE_ACT_ENCAP_32B:
175 case TF_TBL_TYPE_ACT_ENCAP_64B:
176 case TF_TBL_TYPE_ACT_SP_SMAC:
177 case TF_TBL_TYPE_ACT_SP_SMAC_IPV4:
178 case TF_TBL_TYPE_ACT_SP_SMAC_IPV6:
179 case TF_TBL_TYPE_ACT_MODIFY_IPV4:
180 case TF_TBL_TYPE_ACT_MODIFY_SPORT:
181 case TF_TBL_TYPE_ACT_MODIFY_DPORT:
182 rc = 1;
183 break;
184 default:
185 rc = 0;
186 break;
187 };
188
189 return rc;
190 }
191
192 /**
193 * Returns the number of entries in the contexts shadow table.
194 */
195 static inline uint16_t
tf_shadow_tbl_sh_num_entries_get(struct tf_shadow_tbl_ctxt * ctxt)196 tf_shadow_tbl_sh_num_entries_get(struct tf_shadow_tbl_ctxt *ctxt)
197 {
198 return ctxt->shadow_ctxt.num_entries;
199 }
200
201 /**
202 * Compare the give key with the key in the shadow table.
203 *
204 * Returns 0 if the keys match
205 */
206 static int
tf_shadow_tbl_key_cmp(struct tf_shadow_tbl_ctxt * ctxt,uint8_t * key,uint16_t sh_idx,uint16_t size)207 tf_shadow_tbl_key_cmp(struct tf_shadow_tbl_ctxt *ctxt,
208 uint8_t *key,
209 uint16_t sh_idx,
210 uint16_t size)
211 {
212 if (size != ctxt->shadow_ctxt.sh_res_tbl[sh_idx].key_size ||
213 sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) || !key)
214 return -1;
215
216 return memcmp(key, ctxt->shadow_ctxt.sh_key_tbl[sh_idx].key, size);
217 }
218
219 /**
220 * Free the memory associated with the context.
221 */
222 static void
tf_shadow_tbl_ctxt_delete(struct tf_shadow_tbl_ctxt * ctxt)223 tf_shadow_tbl_ctxt_delete(struct tf_shadow_tbl_ctxt *ctxt)
224 {
225 if (!ctxt)
226 return;
227
228 tfp_free(ctxt->hash_ctxt.hashtbl);
229 tfp_free(ctxt->shadow_ctxt.sh_key_tbl);
230 tfp_free(ctxt->shadow_ctxt.sh_res_tbl);
231 }
232
233 /**
234 * The TF Shadow TBL context is per TBL and holds all information relating to
235 * managing the shadow and search capability. This routine allocated data that
236 * needs to be deallocated by the tf_shadow_tbl_ctxt_delete prior when deleting
237 * the shadow db.
238 */
239 static int
tf_shadow_tbl_ctxt_create(struct tf_shadow_tbl_ctxt * ctxt,uint16_t num_entries,uint16_t base_addr)240 tf_shadow_tbl_ctxt_create(struct tf_shadow_tbl_ctxt *ctxt,
241 uint16_t num_entries,
242 uint16_t base_addr)
243 {
244 struct tfp_calloc_parms cparms;
245 uint16_t hash_size = 1;
246 uint16_t hash_mask;
247 int rc;
248
249 /* Hash table is a power of two that holds the number of entries */
250 if (num_entries > TF_SHADOW_ENTRIES_MAX) {
251 TFP_DRV_LOG(ERR, "Too many entries for shadow %d > %d\n",
252 num_entries,
253 TF_SHADOW_ENTRIES_MAX);
254 return -ENOMEM;
255 }
256
257 while (hash_size < num_entries)
258 hash_size = hash_size << 1;
259
260 hash_mask = hash_size - 1;
261
262 /* Allocate the hash table */
263 cparms.nitems = hash_size;
264 cparms.size = sizeof(uint64_t);
265 cparms.alignment = 0;
266 rc = tfp_calloc(&cparms);
267 if (rc)
268 goto error;
269 ctxt->hash_ctxt.hashtbl = cparms.mem_va;
270 ctxt->hash_ctxt.hid_mask = hash_mask;
271 ctxt->hash_ctxt.hash_entries = hash_size;
272
273 /* allocate the shadow tables */
274 /* allocate the shadow key table */
275 cparms.nitems = num_entries;
276 cparms.size = sizeof(struct tf_shadow_tbl_shadow_key_entry);
277 cparms.alignment = 0;
278 rc = tfp_calloc(&cparms);
279 if (rc)
280 goto error;
281 ctxt->shadow_ctxt.sh_key_tbl = cparms.mem_va;
282
283 /* allocate the shadow result table */
284 cparms.nitems = num_entries;
285 cparms.size = sizeof(struct tf_shadow_tbl_shadow_result_entry);
286 cparms.alignment = 0;
287 rc = tfp_calloc(&cparms);
288 if (rc)
289 goto error;
290 ctxt->shadow_ctxt.sh_res_tbl = cparms.mem_va;
291
292 ctxt->shadow_ctxt.num_entries = num_entries;
293 ctxt->shadow_ctxt.base_addr = base_addr;
294
295 return 0;
296 error:
297 tf_shadow_tbl_ctxt_delete(ctxt);
298
299 return -ENOMEM;
300 }
301
302 /**
303 * Get a shadow table context given the db and the table type
304 */
305 static struct tf_shadow_tbl_ctxt *
tf_shadow_tbl_ctxt_get(struct tf_shadow_tbl_db * shadow_db,enum tf_tbl_type type)306 tf_shadow_tbl_ctxt_get(struct tf_shadow_tbl_db *shadow_db,
307 enum tf_tbl_type type)
308 {
309 if (type >= TF_TBL_TYPE_MAX ||
310 !shadow_db ||
311 !shadow_db->ctxt[type])
312 return NULL;
313
314 return shadow_db->ctxt[type];
315 }
316
317 /**
318 * Sets the hash entry into the table given the table context, hash bucket
319 * handle, and shadow index.
320 */
321 static inline int
tf_shadow_tbl_set_hash_entry(struct tf_shadow_tbl_ctxt * ctxt,uint32_t hb_handle,uint16_t sh_idx)322 tf_shadow_tbl_set_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,
323 uint32_t hb_handle,
324 uint16_t sh_idx)
325 {
326 uint16_t hid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);
327 uint16_t be = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);
328 uint64_t entry = sh_idx | TF_SHADOW_BE_VALID;
329
330 if (hid >= ctxt->hash_ctxt.hash_entries)
331 return -EINVAL;
332
333 ctxt->hash_ctxt.hashtbl[hid] |= entry << (be * 16);
334 return 0;
335 }
336
337 /**
338 * Clears the hash entry given the TBL context and hash bucket handle.
339 */
340 static inline void
tf_shadow_tbl_clear_hash_entry(struct tf_shadow_tbl_ctxt * ctxt,uint32_t hb_handle)341 tf_shadow_tbl_clear_hash_entry(struct tf_shadow_tbl_ctxt *ctxt,
342 uint32_t hb_handle)
343 {
344 uint16_t hid, be;
345 uint64_t *bucket;
346
347 if (!TF_SHADOW_HB_HANDLE_IS_VALID(hb_handle))
348 return;
349
350 hid = TF_SHADOW_HB_HANDLE_HASH_GET(ctxt, hb_handle);
351 be = TF_SHADOW_HB_HANDLE_BE_GET(hb_handle);
352 bucket = &ctxt->hash_ctxt.hashtbl[hid];
353
354 switch (be) {
355 case 0:
356 *bucket = TF_SHADOW_BE0_MASK_CLEAR(*bucket);
357 break;
358 case 1:
359 *bucket = TF_SHADOW_BE1_MASK_CLEAR(*bucket);
360 break;
361 case 2:
362 *bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);
363 break;
364 case 3:
365 *bucket = TF_SHADOW_BE2_MASK_CLEAR(*bucket);
366 break;
367 default:
368 /*
369 * Since the BE_GET masks non-inclusive bits, this will not
370 * happen.
371 */
372 break;
373 }
374 }
375
376 /**
377 * Clears the shadow key and result entries given the table context and
378 * shadow index.
379 */
380 static void
tf_shadow_tbl_clear_sh_entry(struct tf_shadow_tbl_ctxt * ctxt,uint16_t sh_idx)381 tf_shadow_tbl_clear_sh_entry(struct tf_shadow_tbl_ctxt *ctxt,
382 uint16_t sh_idx)
383 {
384 struct tf_shadow_tbl_shadow_key_entry *sk_entry;
385 struct tf_shadow_tbl_shadow_result_entry *sr_entry;
386
387 if (sh_idx >= tf_shadow_tbl_sh_num_entries_get(ctxt))
388 return;
389
390 sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[sh_idx];
391 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[sh_idx];
392
393 /*
394 * memset key/result to zero for now, possibly leave the data alone
395 * in the future and rely on the valid bit in the hash table.
396 */
397 memset(sk_entry, 0, sizeof(struct tf_shadow_tbl_shadow_key_entry));
398 memset(sr_entry, 0, sizeof(struct tf_shadow_tbl_shadow_result_entry));
399 }
400
401 /**
402 * Binds the allocated tbl index with the hash and shadow tables.
403 * The entry will be incomplete until the set has happened with the result
404 * data.
405 */
406 int
tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms * parms)407 tf_shadow_tbl_bind_index(struct tf_shadow_tbl_bind_index_parms *parms)
408 {
409 int rc;
410 uint16_t idx, len;
411 struct tf_shadow_tbl_ctxt *ctxt;
412 struct tf_shadow_tbl_db *shadow_db;
413 struct tf_shadow_tbl_shadow_key_entry *sk_entry;
414 struct tf_shadow_tbl_shadow_result_entry *sr_entry;
415
416 if (!parms || !TF_SHADOW_HB_HANDLE_IS_VALID(parms->hb_handle) ||
417 !parms->data) {
418 TFP_DRV_LOG(ERR, "Invalid parms\n");
419 return -EINVAL;
420 }
421
422 shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
423 ctxt = tf_shadow_tbl_ctxt_get(shadow_db, parms->type);
424 if (!ctxt) {
425 TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
426 tf_tbl_type_2_str(parms->type));
427 return -EINVAL;
428 }
429
430 idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, parms->idx);
431 len = parms->data_sz_in_bytes;
432 if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt) ||
433 len > TF_SHADOW_MAX_KEY_SZ) {
434 TFP_DRV_LOG(ERR, "%s:%s Invalid len (%d) > %d || oob idx %d\n",
435 tf_dir_2_str(parms->dir),
436 tf_tbl_type_2_str(parms->type),
437 len,
438 TF_SHADOW_MAX_KEY_SZ, idx);
439
440 return -EINVAL;
441 }
442
443 rc = tf_shadow_tbl_set_hash_entry(ctxt, parms->hb_handle, idx);
444 if (rc)
445 return -EINVAL;
446
447 sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[idx];
448 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
449
450 /* For tables, the data is the key */
451 memcpy(sk_entry->key, parms->data, len);
452
453 /* Write the result table */
454 sr_entry->key_size = len;
455 sr_entry->hb_handle = parms->hb_handle;
456 sr_entry->refcnt = 1;
457
458 return 0;
459 }
460
461 /**
462 * Deletes hash/shadow information if no more references.
463 *
464 * Returns 0 - The caller should delete the table entry in hardware.
465 * Returns non-zero - The number of references to the entry
466 */
467 int
tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms * parms)468 tf_shadow_tbl_remove(struct tf_shadow_tbl_remove_parms *parms)
469 {
470 uint16_t idx;
471 uint32_t hb_handle;
472 struct tf_shadow_tbl_ctxt *ctxt;
473 struct tf_shadow_tbl_db *shadow_db;
474 struct tf_tbl_free_parms *fparms;
475 struct tf_shadow_tbl_shadow_result_entry *sr_entry;
476
477 if (!parms || !parms->fparms) {
478 TFP_DRV_LOG(ERR, "Invalid parms\n");
479 return -EINVAL;
480 }
481
482 fparms = parms->fparms;
483 if (!tf_shadow_tbl_is_searchable(fparms->type))
484 return 0;
485 /*
486 * Initialize the ref count to zero. The default would be to remove
487 * the entry.
488 */
489 fparms->ref_cnt = 0;
490
491 shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
492 ctxt = tf_shadow_tbl_ctxt_get(shadow_db, fparms->type);
493 if (!ctxt) {
494 TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
495 tf_tbl_type_2_str(fparms->type));
496 return 0;
497 }
498
499 idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, fparms->idx);
500 if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {
501 TFP_DRV_LOG(DEBUG, "%s %d >= %d\n",
502 tf_tbl_type_2_str(fparms->type),
503 fparms->idx,
504 tf_shadow_tbl_sh_num_entries_get(ctxt));
505 return 0;
506 }
507
508 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
509 if (sr_entry->refcnt <= 1) {
510 hb_handle = sr_entry->hb_handle;
511 tf_shadow_tbl_clear_hash_entry(ctxt, hb_handle);
512 tf_shadow_tbl_clear_sh_entry(ctxt, idx);
513 } else {
514 sr_entry->refcnt--;
515 fparms->ref_cnt = sr_entry->refcnt;
516 }
517
518 return 0;
519 }
520
521 int
tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms * parms)522 tf_shadow_tbl_search(struct tf_shadow_tbl_search_parms *parms)
523 {
524 uint16_t len;
525 uint64_t bucket;
526 uint32_t i, hid32;
527 struct tf_shadow_tbl_ctxt *ctxt;
528 struct tf_shadow_tbl_db *shadow_db;
529 uint16_t hid16, hb_idx, hid_mask, shtbl_idx, shtbl_key, be_valid;
530 struct tf_tbl_alloc_search_parms *sparms;
531 uint32_t be_avail = TF_SHADOW_HB_NUM_ELEM;
532
533 if (!parms || !parms->sparms) {
534 TFP_DRV_LOG(ERR, "tbl search with invalid parms\n");
535 return -EINVAL;
536 }
537
538 sparms = parms->sparms;
539 /* Check that caller was supposed to call search */
540 if (!tf_shadow_tbl_is_searchable(sparms->type))
541 return -EINVAL;
542
543 /* Initialize return values to invalid */
544 sparms->hit = 0;
545 sparms->search_status = REJECT;
546 parms->hb_handle = 0;
547 sparms->ref_cnt = 0;
548
549 shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
550 ctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);
551 if (!ctxt) {
552 TFP_DRV_LOG(ERR, "%s Unable to get tbl mgr context\n",
553 tf_tbl_type_2_str(sparms->type));
554 return -EINVAL;
555 }
556
557 len = sparms->result_sz_in_bytes;
558 if (len > TF_SHADOW_MAX_KEY_SZ || !sparms->result || !len) {
559 TFP_DRV_LOG(ERR, "%s:%s Invalid parms %d : %p\n",
560 tf_dir_2_str(sparms->dir),
561 tf_tbl_type_2_str(sparms->type),
562 len,
563 sparms->result);
564 return -EINVAL;
565 }
566
567 /*
568 * Calculate the crc32
569 * Fold it to create a 16b value
570 * Reduce it to fit the table
571 */
572 hid32 = tf_hash_calc_crc32(sparms->result, len);
573 hid16 = (uint16_t)(((hid32 >> 16) & 0xffff) ^ (hid32 & 0xffff));
574 hid_mask = ctxt->hash_ctxt.hid_mask;
575 hb_idx = hid16 & hid_mask;
576
577 bucket = ctxt->hash_ctxt.hashtbl[hb_idx];
578 if (!bucket) {
579 /* empty bucket means a miss and available entry */
580 sparms->search_status = MISS;
581 parms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, 0);
582 sparms->idx = 0;
583 return 0;
584 }
585
586 /* Set the avail to max so we can detect when there is an avail entry */
587 be_avail = TF_SHADOW_HB_NUM_ELEM;
588 for (i = 0; i < TF_SHADOW_HB_NUM_ELEM; i++) {
589 shtbl_idx = (uint16_t)((bucket >> (i * 16)) & 0xffff);
590 be_valid = TF_SHADOW_BE_IS_VALID(shtbl_idx);
591 if (!be_valid) {
592 /* The element is avail, keep going */
593 be_avail = i;
594 continue;
595 }
596 /* There is a valid entry, compare it */
597 shtbl_key = shtbl_idx & ~TF_SHADOW_BE_VALID;
598 if (!tf_shadow_tbl_key_cmp(ctxt,
599 sparms->result,
600 shtbl_key,
601 len)) {
602 /*
603 * It matches, increment the ref count if the caller
604 * requested allocation and return the info
605 */
606 if (sparms->alloc)
607 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt =
608 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt + 1;
609
610 sparms->hit = 1;
611 sparms->search_status = HIT;
612 parms->hb_handle =
613 TF_SHADOW_HB_HANDLE_CREATE(hb_idx, i);
614 sparms->idx = TF_SHADOW_SHIDX_TO_IDX(ctxt, shtbl_key);
615 sparms->ref_cnt =
616 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt;
617
618 return 0;
619 }
620 }
621
622 /* No hits, return avail entry if exists */
623 if (be_avail < TF_SHADOW_HB_NUM_ELEM) {
624 /*
625 * There is an available hash entry, so return MISS and the
626 * hash handle for the subsequent bind.
627 */
628 parms->hb_handle = TF_SHADOW_HB_HANDLE_CREATE(hb_idx, be_avail);
629 sparms->search_status = MISS;
630 sparms->hit = 0;
631 sparms->idx = 0;
632 } else {
633 /* No room for the entry in the hash table, must REJECT */
634 sparms->search_status = REJECT;
635 }
636
637 return 0;
638 }
639
640 int
tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms * parms)641 tf_shadow_tbl_insert(struct tf_shadow_tbl_insert_parms *parms)
642 {
643 uint16_t idx;
644 struct tf_shadow_tbl_ctxt *ctxt;
645 struct tf_tbl_set_parms *sparms;
646 struct tf_shadow_tbl_db *shadow_db;
647 struct tf_shadow_tbl_shadow_result_entry *sr_entry;
648
649 if (!parms || !parms->sparms) {
650 TFP_DRV_LOG(ERR, "Null parms\n");
651 return -EINVAL;
652 }
653
654 sparms = parms->sparms;
655 if (!sparms->data || !sparms->data_sz_in_bytes) {
656 TFP_DRV_LOG(ERR, "%s:%s No result to set.\n",
657 tf_dir_2_str(sparms->dir),
658 tf_tbl_type_2_str(sparms->type));
659 return -EINVAL;
660 }
661
662 shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
663 ctxt = tf_shadow_tbl_ctxt_get(shadow_db, sparms->type);
664 if (!ctxt) {
665 /* We aren't tracking this table, so return success */
666 TFP_DRV_LOG(DEBUG, "%s Unable to get tbl mgr context\n",
667 tf_tbl_type_2_str(sparms->type));
668 return 0;
669 }
670
671 idx = TF_SHADOW_IDX_TO_SHIDX(ctxt, sparms->idx);
672 if (idx >= tf_shadow_tbl_sh_num_entries_get(ctxt)) {
673 TFP_DRV_LOG(ERR, "%s:%s Invalid idx(0x%x)\n",
674 tf_dir_2_str(sparms->dir),
675 tf_tbl_type_2_str(sparms->type),
676 sparms->idx);
677 return -EINVAL;
678 }
679
680 /* Write the result table, the key/hash has been written already */
681 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
682
683 /*
684 * If the handle is not valid, the bind was never called. We aren't
685 * tracking this entry.
686 */
687 if (!TF_SHADOW_HB_HANDLE_IS_VALID(sr_entry->hb_handle))
688 return 0;
689
690 return 0;
691 }
692
693 int
tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms * parms)694 tf_shadow_tbl_free_db(struct tf_shadow_tbl_free_db_parms *parms)
695 {
696 struct tf_shadow_tbl_db *shadow_db;
697 int i;
698
699 TF_CHECK_PARMS1(parms);
700
701 shadow_db = (struct tf_shadow_tbl_db *)parms->shadow_db;
702 if (!shadow_db) {
703 TFP_DRV_LOG(DEBUG, "Shadow db is NULL cannot be freed\n");
704 return -EINVAL;
705 }
706
707 for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
708 if (shadow_db->ctxt[i]) {
709 tf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);
710 tfp_free(shadow_db->ctxt[i]);
711 }
712 }
713
714 tfp_free(shadow_db);
715
716 return 0;
717 }
718
719 /**
720 * Allocate the table resources for search and allocate
721 *
722 */
tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms * parms)723 int tf_shadow_tbl_create_db(struct tf_shadow_tbl_create_db_parms *parms)
724 {
725 int rc;
726 int i;
727 uint16_t base;
728 struct tfp_calloc_parms cparms;
729 struct tf_shadow_tbl_db *shadow_db = NULL;
730
731 TF_CHECK_PARMS1(parms);
732
733 /* Build the shadow DB per the request */
734 cparms.nitems = 1;
735 cparms.size = sizeof(struct tf_shadow_tbl_db);
736 cparms.alignment = 0;
737 rc = tfp_calloc(&cparms);
738 if (rc)
739 return rc;
740 shadow_db = (void *)cparms.mem_va;
741
742 for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
743 /* If the element didn't request an allocation no need
744 * to create a pool nor verify if we got a reservation.
745 */
746 if (!parms->cfg->alloc_cnt[i] ||
747 !tf_shadow_tbl_is_searchable(i)) {
748 shadow_db->ctxt[i] = NULL;
749 continue;
750 }
751
752 cparms.nitems = 1;
753 cparms.size = sizeof(struct tf_shadow_tbl_ctxt);
754 cparms.alignment = 0;
755 rc = tfp_calloc(&cparms);
756 if (rc)
757 goto error;
758
759 shadow_db->ctxt[i] = cparms.mem_va;
760 base = parms->cfg->base_addr[i];
761 rc = tf_shadow_tbl_ctxt_create(shadow_db->ctxt[i],
762 parms->cfg->alloc_cnt[i],
763 base);
764 if (rc)
765 goto error;
766 }
767
768 *parms->shadow_db = (void *)shadow_db;
769
770 TFP_DRV_LOG(INFO,
771 "TF SHADOW TABLE - initialized\n");
772
773 return 0;
774 error:
775 for (i = 0; i < TF_TBL_TYPE_MAX; i++) {
776 if (shadow_db->ctxt[i]) {
777 tf_shadow_tbl_ctxt_delete(shadow_db->ctxt[i]);
778 tfp_free(shadow_db->ctxt[i]);
779 }
780 }
781
782 tfp_free(shadow_db);
783
784 return -ENOMEM;
785 }
786