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