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