1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
9 #include "tf_shadow_tcam.h"
12 * The implementation includes 3 tables per tcam table type.
14 * - sized so that a minimum of 4 slots per shadow entry are available to
15 * minimize the likelihood of collisions.
17 * - sized to the number of entries requested and is directly indexed
18 * - the index is zero based and is the tcam index - the base address
19 * - the key and mask are stored in the key table.
20 * - The stored key is the AND of the key/mask in order to eliminate the need
21 * to compare both the key and mask.
22 * - shadow result table
23 * - the result table is stored separately since it only needs to be accessed
24 * when the key matches.
25 * - the result has a back pointer to the hash table via the hb handle. The
26 * hb handle is a 32 bit represention of the hash with a valid bit, bucket
27 * element index, and the hash index. It is necessary to store the hb handle
28 * with the result since subsequent removes only provide the tcam index.
30 * - Max entries is limited in the current implementation since bit 15 is the
31 * valid bit in the hash table.
32 * - A 16bit hash is calculated and masked based on the number of entries
33 * - 64b wide bucket is used and broken into 4x16bit elements.
34 * This decision is based on quicker bucket scanning to determine if any
35 * elements are in use.
36 * - bit 15 of each bucket element is the valid, this is done to prevent having
37 * to read the larger key/result data for determining VALID. It also aids
38 * in the more efficient scanning of the bucket for slot usage.
42 * The maximum number of shadow entries supported. The value also doubles as
43 * the maximum number of hash buckets. There are only 15 bits of data per
44 * bucket to point to the shadow tables.
46 #define TF_SHADOW_TCAM_ENTRIES_MAX (1 << 15)
48 /* The number of elements(BE) per hash bucket (HB) */
49 #define TF_SHADOW_TCAM_HB_NUM_ELEM (4)
50 #define TF_SHADOW_TCAM_BE_VALID (1 << 15)
51 #define TF_SHADOW_TCAM_BE_IS_VALID(be) (((be) & TF_SHADOW_TCAM_BE_VALID) != 0)
54 * The hash bucket handle is 32b
55 * - bit 31, the Valid bit
56 * - bit 29-30, the element
57 * - bits 0-15, the hash idx (is masked based on the allocated size)
59 #define TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(hndl) (((hndl) & (1 << 31)) != 0)
60 #define TF_SHADOW_TCAM_HB_HANDLE_CREATE(idx, be) ((1 << 31) | \
63 #define TF_SHADOW_TCAM_HB_HANDLE_BE_GET(hdl) (((hdl) >> 29) & \
64 (TF_SHADOW_TCAM_HB_NUM_ELEM - 1))
66 #define TF_SHADOW_TCAM_HB_HANDLE_HASH_GET(ctxt, hdl)((hdl) & \
67 (ctxt)->hash_ctxt.hid_mask)
70 * The idx provided by the caller is within a region, so currently the base is
71 * either added or subtracted from the idx to ensure it can be used as a
75 /* Convert the tcam index to a shadow index */
76 #define TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, idx) ((idx) - \
77 (ctxt)->shadow_ctxt.base_addr)
79 /* Convert the shadow index to a tcam index */
80 #define TF_SHADOW_TCAM_SHIDX_TO_IDX(ctxt, idx) ((idx) + \
81 (ctxt)->shadow_ctxt.base_addr)
83 /* Simple helper masks for clearing en element from the bucket */
84 #define TF_SHADOW_TCAM_BE0_MASK_CLEAR(hb) ((hb) & 0xffffffffffff0000ull)
85 #define TF_SHADOW_TCAM_BE1_MASK_CLEAR(hb) ((hb) & 0xffffffff0000ffffull)
86 #define TF_SHADOW_TCAM_BE2_MASK_CLEAR(hb) ((hb) & 0xffff0000ffffffffull)
87 #define TF_SHADOW_TCAM_BE3_MASK_CLEAR(hb) ((hb) & 0x0000ffffffffffffull)
90 * This should be coming from external, but for now it is assumed that no key
91 * is greater than 1K bits and no result is bigger than 128 bits. This makes
92 * allocation of the hash table easier without having to allocate on the fly.
94 #define TF_SHADOW_TCAM_MAX_KEY_SZ 128
95 #define TF_SHADOW_TCAM_MAX_RESULT_SZ 16
98 * Local only defines for the internal data.
102 * tf_shadow_tcam_shadow_key_entry is the key/mask entry of the key table.
103 * The key stored in the table is the masked version of the key. This is done
104 * to eliminate the need of comparing both the key and mask.
106 struct tf_shadow_tcam_shadow_key_entry {
107 uint8_t key[TF_SHADOW_TCAM_MAX_KEY_SZ];
108 uint8_t mask[TF_SHADOW_TCAM_MAX_KEY_SZ];
112 * tf_shadow_tcam_shadow_result_entry is the result table entry.
113 * The result table writes are broken into two phases:
114 * - The search phase, which stores the hb_handle and key size and
115 * - The set phase, which writes the result, refcnt, and result size
117 struct tf_shadow_tcam_shadow_result_entry {
118 uint8_t result[TF_SHADOW_TCAM_MAX_RESULT_SZ];
119 uint16_t result_size;
126 * tf_shadow_tcam_shadow_ctxt holds all information for accessing the key and
129 struct tf_shadow_tcam_shadow_ctxt {
130 struct tf_shadow_tcam_shadow_key_entry *sh_key_tbl;
131 struct tf_shadow_tcam_shadow_result_entry *sh_res_tbl;
133 uint16_t num_entries;
138 * tf_shadow_tcam_hash_ctxt holds all information related to accessing the hash
141 struct tf_shadow_tcam_hash_ctxt {
144 uint16_t hash_entries;
148 * tf_shadow_tcam_ctxt holds the hash and shadow tables for the current shadow
149 * tcam db. This structure is per tcam table type as each tcam table has it's
150 * own shadow and hash table.
152 struct tf_shadow_tcam_ctxt {
153 struct tf_shadow_tcam_shadow_ctxt shadow_ctxt;
154 struct tf_shadow_tcam_hash_ctxt hash_ctxt;
158 * tf_shadow_tcam_db is the allocated db structure returned as an opaque
159 * void * pointer to the caller during create db. It holds the pointers for
160 * each tcam associated with the db.
162 struct tf_shadow_tcam_db {
163 /* Each context holds the shadow and hash table information */
164 struct tf_shadow_tcam_ctxt *ctxt[TF_TCAM_TBL_TYPE_MAX];
167 /* CRC polynomial 0xedb88320 */
168 static const uint32_t tf_shadow_tcam_crc32tbl[] = {
169 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
170 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
171 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
172 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
173 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
174 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
175 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
176 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
177 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
178 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
179 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
180 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
181 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
182 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
183 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
184 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
185 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
186 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
187 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
188 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
189 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
190 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
191 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
192 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
193 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
194 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
195 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
196 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
197 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
198 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
199 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
200 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
201 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
202 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
203 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
204 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
205 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
206 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
207 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
208 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
209 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
210 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
211 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
212 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
213 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
214 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
215 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
216 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
217 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
218 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
219 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
220 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
221 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
222 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
223 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
224 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
225 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
226 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
227 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
228 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
229 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
230 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
231 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
232 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
236 * Returns the number of entries in the contexts shadow table.
238 static inline uint16_t
239 tf_shadow_tcam_sh_num_entries_get(struct tf_shadow_tcam_ctxt *ctxt)
241 return ctxt->shadow_ctxt.num_entries;
245 * Compare the give key with the key in the shadow table.
247 * Returns 0 if the keys match
250 tf_shadow_tcam_key_cmp(struct tf_shadow_tcam_ctxt *ctxt,
256 if (size != ctxt->shadow_ctxt.sh_res_tbl[sh_idx].key_size ||
257 sh_idx >= tf_shadow_tcam_sh_num_entries_get(ctxt) || !key || !mask)
260 return memcmp(key, ctxt->shadow_ctxt.sh_key_tbl[sh_idx].key, size);
264 * Copies the shadow result to the result.
266 * Returns 0 on failure
269 tf_shadow_tcam_res_cpy(struct tf_shadow_tcam_ctxt *ctxt,
274 if (sh_idx >= tf_shadow_tcam_sh_num_entries_get(ctxt) || !result)
277 if (ctxt->shadow_ctxt.sh_res_tbl[sh_idx].result_size != size)
280 return memcpy(result,
281 ctxt->shadow_ctxt.sh_res_tbl[sh_idx].result,
286 * Using a software based CRC function for now, but will look into using hw
287 * assisted in the future.
290 tf_shadow_tcam_crc32_calc(uint8_t *key, uint32_t len)
295 crc = tf_shadow_tcam_crc32tbl[(crc ^ key[len]) & 0xff] ^
302 * Free the memory associated with the context.
305 tf_shadow_tcam_ctxt_delete(struct tf_shadow_tcam_ctxt *ctxt)
310 tfp_free(ctxt->hash_ctxt.hashtbl);
311 tfp_free(ctxt->shadow_ctxt.sh_key_tbl);
312 tfp_free(ctxt->shadow_ctxt.sh_res_tbl);
316 * The TF Shadow TCAM context is per TCAM and holds all information relating to
317 * managing the shadow and search capability. This routine allocated data that
318 * needs to be deallocated by the tf_shadow_tcam_ctxt_delete prior when deleting
322 tf_shadow_tcam_ctxt_create(struct tf_shadow_tcam_ctxt *ctxt,
323 uint16_t num_entries,
326 struct tfp_calloc_parms cparms;
327 uint16_t hash_size = 1;
331 /* Hash table is a power of two that holds the number of entries */
332 if (num_entries > TF_SHADOW_TCAM_ENTRIES_MAX) {
333 TFP_DRV_LOG(ERR, "Too many entries for shadow %d > %d\n",
335 TF_SHADOW_TCAM_ENTRIES_MAX);
339 while (hash_size < num_entries)
340 hash_size = hash_size << 1;
342 hash_mask = hash_size - 1;
344 /* Allocate the hash table */
345 cparms.nitems = hash_size;
346 cparms.size = sizeof(uint64_t);
347 cparms.alignment = 0;
348 rc = tfp_calloc(&cparms);
351 ctxt->hash_ctxt.hashtbl = cparms.mem_va;
352 ctxt->hash_ctxt.hid_mask = hash_mask;
353 ctxt->hash_ctxt.hash_entries = hash_size;
355 /* allocate the shadow tables */
356 /* allocate the shadow key table */
357 cparms.nitems = num_entries;
358 cparms.size = sizeof(struct tf_shadow_tcam_shadow_key_entry);
359 cparms.alignment = 0;
360 rc = tfp_calloc(&cparms);
363 ctxt->shadow_ctxt.sh_key_tbl = cparms.mem_va;
365 /* allocate the shadow result table */
366 cparms.nitems = num_entries;
367 cparms.size = sizeof(struct tf_shadow_tcam_shadow_result_entry);
368 cparms.alignment = 0;
369 rc = tfp_calloc(&cparms);
372 ctxt->shadow_ctxt.sh_res_tbl = cparms.mem_va;
374 ctxt->shadow_ctxt.num_entries = num_entries;
375 ctxt->shadow_ctxt.base_addr = base_addr;
379 tf_shadow_tcam_ctxt_delete(ctxt);
385 * Get a shadow TCAM context given the db and the TCAM type
387 static struct tf_shadow_tcam_ctxt *
388 tf_shadow_tcam_ctxt_get(struct tf_shadow_tcam_db *shadow_db,
389 enum tf_tcam_tbl_type type)
391 if (type >= TF_TCAM_TBL_TYPE_MAX ||
393 !shadow_db->ctxt[type])
396 return shadow_db->ctxt[type];
400 * Sets the hash entry into the table given the TCAM context, hash bucket
401 * handle, and shadow index.
404 tf_shadow_tcam_set_hash_entry(struct tf_shadow_tcam_ctxt *ctxt,
408 uint16_t hid = TF_SHADOW_TCAM_HB_HANDLE_HASH_GET(ctxt, hb_handle);
409 uint16_t be = TF_SHADOW_TCAM_HB_HANDLE_BE_GET(hb_handle);
410 uint64_t entry = sh_idx | TF_SHADOW_TCAM_BE_VALID;
412 if (hid >= ctxt->hash_ctxt.hash_entries)
415 ctxt->hash_ctxt.hashtbl[hid] |= entry << (be * 16);
420 * Clears the hash entry given the TCAM context and hash bucket handle.
423 tf_shadow_tcam_clear_hash_entry(struct tf_shadow_tcam_ctxt *ctxt,
429 if (!TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(hb_handle))
432 hid = TF_SHADOW_TCAM_HB_HANDLE_HASH_GET(ctxt, hb_handle);
433 be = TF_SHADOW_TCAM_HB_HANDLE_BE_GET(hb_handle);
434 bucket = &ctxt->hash_ctxt.hashtbl[hid];
438 *bucket = TF_SHADOW_TCAM_BE0_MASK_CLEAR(*bucket);
441 *bucket = TF_SHADOW_TCAM_BE1_MASK_CLEAR(*bucket);
444 *bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);
447 *bucket = TF_SHADOW_TCAM_BE2_MASK_CLEAR(*bucket);
453 * Clears the shadow key and result entries given the TCAM context and
457 tf_shadow_tcam_clear_sh_entry(struct tf_shadow_tcam_ctxt *ctxt,
460 struct tf_shadow_tcam_shadow_key_entry *sk_entry;
461 struct tf_shadow_tcam_shadow_result_entry *sr_entry;
463 if (sh_idx >= tf_shadow_tcam_sh_num_entries_get(ctxt))
466 sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[sh_idx];
467 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[sh_idx];
470 * memset key/result to zero for now, possibly leave the data alone
471 * in the future and rely on the valid bit in the hash table.
473 memset(sk_entry, 0, sizeof(struct tf_shadow_tcam_shadow_key_entry));
474 memset(sr_entry, 0, sizeof(struct tf_shadow_tcam_shadow_result_entry));
478 * Binds the allocated tcam index with the hash and shadow tables.
479 * The entry will be incomplete until the set has happened with the result
483 tf_shadow_tcam_bind_index(struct tf_shadow_tcam_bind_index_parms *parms)
488 struct tf_shadow_tcam_ctxt *ctxt;
489 struct tf_shadow_tcam_db *shadow_db;
490 struct tf_shadow_tcam_shadow_key_entry *sk_entry;
491 struct tf_shadow_tcam_shadow_result_entry *sr_entry;
492 uint8_t tkey[TF_SHADOW_TCAM_MAX_KEY_SZ];
494 if (!parms || !TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(parms->hb_handle) ||
495 !parms->key || !parms->mask) {
496 TFP_DRV_LOG(ERR, "Invalid parms\n");
500 shadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;
501 ctxt = tf_shadow_tcam_ctxt_get(shadow_db, parms->type);
503 TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
504 tf_tcam_tbl_2_str(parms->type));
508 memset(tkey, 0, sizeof(tkey));
509 idx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, parms->idx);
510 klen = parms->key_size;
511 if (idx >= tf_shadow_tcam_sh_num_entries_get(ctxt) ||
512 klen > TF_SHADOW_TCAM_MAX_KEY_SZ) {
513 TFP_DRV_LOG(ERR, "%s:%s Invalid len (%d) > %d || oob idx %d\n",
514 tf_dir_2_str(parms->dir),
515 tf_tcam_tbl_2_str(parms->type),
517 TF_SHADOW_TCAM_MAX_KEY_SZ, idx);
522 rc = tf_shadow_tcam_set_hash_entry(ctxt, parms->hb_handle, idx);
526 sk_entry = &ctxt->shadow_ctxt.sh_key_tbl[idx];
527 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
530 * Write the masked key to the table for more efficient comparisons
533 for (i = 0; i < klen; i++)
534 tkey[i] = parms->key[i] & parms->mask[i];
536 memcpy(sk_entry->key, tkey, klen);
537 memcpy(sk_entry->mask, parms->mask, klen);
539 /* Write the result table */
540 sr_entry->key_size = parms->key_size;
541 sr_entry->hb_handle = parms->hb_handle;
542 sr_entry->refcnt = 1;
548 * Deletes hash/shadow information if no more references.
550 * Returns 0 - The caller should delete the tcam entry in hardware.
551 * Returns non-zero - The number of references to the entry
554 tf_shadow_tcam_remove(struct tf_shadow_tcam_remove_parms *parms)
558 struct tf_shadow_tcam_ctxt *ctxt;
559 struct tf_shadow_tcam_db *shadow_db;
560 struct tf_tcam_free_parms *fparms;
561 struct tf_shadow_tcam_shadow_result_entry *sr_entry;
563 if (!parms || !parms->fparms) {
564 TFP_DRV_LOG(ERR, "Invalid parms\n");
568 fparms = parms->fparms;
571 * Initialize the reference count to zero. It will only be changed if
576 shadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;
577 ctxt = tf_shadow_tcam_ctxt_get(shadow_db, fparms->type);
579 TFP_DRV_LOG(DEBUG, "%s no ctxt for table\n",
580 tf_tcam_tbl_2_str(fparms->type));
584 idx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, fparms->idx);
585 if (idx >= tf_shadow_tcam_sh_num_entries_get(ctxt)) {
586 TFP_DRV_LOG(DEBUG, "%s %d >= %d\n",
587 tf_tcam_tbl_2_str(fparms->type),
589 tf_shadow_tcam_sh_num_entries_get(ctxt));
593 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
594 if (sr_entry->refcnt <= 1) {
595 hb_handle = sr_entry->hb_handle;
596 tf_shadow_tcam_clear_hash_entry(ctxt, hb_handle);
597 tf_shadow_tcam_clear_sh_entry(ctxt, idx);
600 fparms->ref_cnt = sr_entry->refcnt;
607 tf_shadow_tcam_search(struct tf_shadow_tcam_search_parms *parms)
613 struct tf_shadow_tcam_ctxt *ctxt;
614 struct tf_shadow_tcam_db *shadow_db;
615 uint16_t hid16, hb_idx, hid_mask, shtbl_idx, shtbl_key, be_valid;
616 struct tf_tcam_alloc_search_parms *sparms;
617 uint8_t tkey[TF_SHADOW_TCAM_MAX_KEY_SZ];
618 uint32_t be_avail = TF_SHADOW_TCAM_HB_NUM_ELEM;
620 if (!parms || !parms->sparms) {
621 TFP_DRV_LOG(ERR, "tcam search with invalid parms\n");
625 memset(tkey, 0, sizeof(tkey));
626 sparms = parms->sparms;
628 /* Initialize return values to invalid */
630 sparms->search_status = REJECT;
631 parms->hb_handle = 0;
633 /* see if caller wanted the result */
634 rcopy = sparms->result && sparms->result_size;
636 shadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;
637 ctxt = tf_shadow_tcam_ctxt_get(shadow_db, sparms->type);
639 TFP_DRV_LOG(ERR, "%s Unable to get tcam mgr context\n",
640 tf_tcam_tbl_2_str(sparms->type));
644 hid_mask = ctxt->hash_ctxt.hid_mask;
646 len = sparms->key_size;
648 if (len > TF_SHADOW_TCAM_MAX_KEY_SZ ||
649 !sparms->key || !sparms->mask || !len) {
650 TFP_DRV_LOG(ERR, "%s:%s Invalid parms %d : %p : %p\n",
651 tf_dir_2_str(sparms->dir),
652 tf_tcam_tbl_2_str(sparms->type),
659 /* Combine the key and mask */
660 for (i = 0; i < len; i++)
661 tkey[i] = sparms->key[i] & sparms->mask[i];
664 * Calculate the crc32
665 * Fold it to create a 16b value
666 * Reduce it to fit the table
668 hid32 = tf_shadow_tcam_crc32_calc(tkey, len);
669 hid16 = (uint16_t)(((hid32 >> 16) & 0xffff) ^ (hid32 & 0xffff));
670 hb_idx = hid16 & hid_mask;
672 bucket = ctxt->hash_ctxt.hashtbl[hb_idx];
675 /* empty bucket means a miss and available entry */
676 sparms->search_status = MISS;
677 parms->hb_handle = TF_SHADOW_TCAM_HB_HANDLE_CREATE(hb_idx, 0);
682 /* Set the avail to max so we can detect when there is an avail entry */
683 be_avail = TF_SHADOW_TCAM_HB_NUM_ELEM;
684 for (i = 0; i < TF_SHADOW_TCAM_HB_NUM_ELEM; i++) {
685 shtbl_idx = (uint16_t)((bucket >> (i * 16)) & 0xffff);
686 be_valid = TF_SHADOW_TCAM_BE_IS_VALID(shtbl_idx);
688 /* The element is avail, keep going */
692 /* There is a valid entry, compare it */
693 shtbl_key = shtbl_idx & ~TF_SHADOW_TCAM_BE_VALID;
694 if (!tf_shadow_tcam_key_cmp(ctxt,
700 * It matches, increment the ref count if the caller
701 * requested allocation and return the info
704 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt =
705 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt + 1;
708 sparms->search_status = HIT;
710 TF_SHADOW_TCAM_HB_HANDLE_CREATE(hb_idx, i);
711 sparms->idx = TF_SHADOW_TCAM_SHIDX_TO_IDX(ctxt,
714 ctxt->shadow_ctxt.sh_res_tbl[shtbl_key].refcnt;
716 /* copy the result, if caller wanted it. */
718 !tf_shadow_tcam_res_cpy(ctxt,
721 sparms->result_size)) {
723 * Should never get here, possible memory
724 * corruption or something unexpected.
726 TFP_DRV_LOG(ERR, "Error copying result\n");
734 /* No hits, return avail entry if exists */
735 if (be_avail < TF_SHADOW_TCAM_HB_NUM_ELEM) {
737 TF_SHADOW_TCAM_HB_HANDLE_CREATE(hb_idx, be_avail);
738 sparms->search_status = MISS;
742 sparms->search_status = REJECT;
749 tf_shadow_tcam_insert(struct tf_shadow_tcam_insert_parms *parms)
752 struct tf_shadow_tcam_ctxt *ctxt;
753 struct tf_tcam_set_parms *sparms;
754 struct tf_shadow_tcam_db *shadow_db;
755 struct tf_shadow_tcam_shadow_result_entry *sr_entry;
757 if (!parms || !parms->sparms) {
758 TFP_DRV_LOG(ERR, "Null parms\n");
762 sparms = parms->sparms;
763 if (!sparms->result || !sparms->result_size) {
764 TFP_DRV_LOG(ERR, "%s:%s No result to set.\n",
765 tf_dir_2_str(sparms->dir),
766 tf_tcam_tbl_2_str(sparms->type));
770 shadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;
771 ctxt = tf_shadow_tcam_ctxt_get(shadow_db, sparms->type);
773 /* We aren't tracking this table, so return success */
774 TFP_DRV_LOG(DEBUG, "%s Unable to get tcam mgr context\n",
775 tf_tcam_tbl_2_str(sparms->type));
779 idx = TF_SHADOW_TCAM_IDX_TO_SHIDX(ctxt, sparms->idx);
780 if (idx >= tf_shadow_tcam_sh_num_entries_get(ctxt)) {
781 TFP_DRV_LOG(ERR, "%s:%s Invalid idx(0x%x)\n",
782 tf_dir_2_str(sparms->dir),
783 tf_tcam_tbl_2_str(sparms->type),
788 /* Write the result table, the key/hash has been written already */
789 sr_entry = &ctxt->shadow_ctxt.sh_res_tbl[idx];
792 * If the handle is not valid, the bind was never called. We aren't
793 * tracking this entry.
795 if (!TF_SHADOW_TCAM_HB_HANDLE_IS_VALID(sr_entry->hb_handle))
798 if (sparms->result_size > TF_SHADOW_TCAM_MAX_RESULT_SZ) {
799 TFP_DRV_LOG(ERR, "%s:%s Result length %d > %d\n",
800 tf_dir_2_str(sparms->dir),
801 tf_tcam_tbl_2_str(sparms->type),
803 TF_SHADOW_TCAM_MAX_RESULT_SZ);
807 memcpy(sr_entry->result, sparms->result, sparms->result_size);
808 sr_entry->result_size = sparms->result_size;
814 tf_shadow_tcam_free_db(struct tf_shadow_tcam_free_db_parms *parms)
816 struct tf_shadow_tcam_db *shadow_db;
819 TF_CHECK_PARMS1(parms);
821 shadow_db = (struct tf_shadow_tcam_db *)parms->shadow_db;
823 TFP_DRV_LOG(DEBUG, "Shadow db is NULL cannot be freed\n");
827 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
828 if (shadow_db->ctxt[i]) {
829 tf_shadow_tcam_ctxt_delete(shadow_db->ctxt[i]);
830 tfp_free(shadow_db->ctxt[i]);
840 * Allocate the TCAM resources for search and allocate
843 int tf_shadow_tcam_create_db(struct tf_shadow_tcam_create_db_parms *parms)
848 struct tfp_calloc_parms cparms;
849 struct tf_shadow_tcam_db *shadow_db = NULL;
851 TF_CHECK_PARMS1(parms);
853 /* Build the shadow DB per the request */
855 cparms.size = sizeof(struct tf_shadow_tcam_db);
856 cparms.alignment = 0;
857 rc = tfp_calloc(&cparms);
860 shadow_db = (void *)cparms.mem_va;
862 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
863 /* If the element didn't request an allocation no need
864 * to create a pool nor verify if we got a reservation.
866 if (!parms->cfg->alloc_cnt[i]) {
867 shadow_db->ctxt[i] = NULL;
872 cparms.size = sizeof(struct tf_shadow_tcam_ctxt);
873 cparms.alignment = 0;
874 rc = tfp_calloc(&cparms);
878 shadow_db->ctxt[i] = cparms.mem_va;
879 base = parms->cfg->base_addr[i];
880 rc = tf_shadow_tcam_ctxt_create(shadow_db->ctxt[i],
881 parms->cfg->alloc_cnt[i],
887 *parms->shadow_db = (void *)shadow_db;
890 "TF SHADOW TCAM - initialized\n");
894 for (i = 0; i < TF_TCAM_TBL_TYPE_MAX; i++) {
895 if (shadow_db->ctxt[i]) {
896 tf_shadow_tcam_ctxt_delete(shadow_db->ctxt[i]);
897 tfp_free(shadow_db->ctxt[i]);