xref: /dpdk/drivers/net/bnxt/tf_core/v3/tfc_em.c (revision 0513f0af034df5dc543bb6eb6b17661839491a89)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019-2021 Broadcom
3  * All rights reserved.
4  */
5 
6 #include <memory.h>
7 
8 #include "bnxt.h"
9 #include "bnxt_mpc.h"
10 
11 #include "tfc.h"
12 #include "tfo.h"
13 #include "tfc_em.h"
14 #include "tfc_cpm.h"
15 #include "tfc_msg.h"
16 #include "tfc_priv.h"
17 #include "cfa_types.h"
18 #include "cfa_mm.h"
19 #include "cfa_bld_mpc_field_ids.h"
20 #include "tfc_flow_handle.h"
21 #include "sys_util.h"
22 #include "tfc_util.h"
23 
24 #include "tfc_debug.h"
25 
26 #define TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE 1
27 
28 /* Enable cache configuration */
29 #define TFC_EM_CACHE_OPT_EN	 0
30 /* Enable dynamic bucket support */
31 
32 #ifdef EM_DEBUG
33 char const *tfc_mpc_error_string[] = {
34 	"OK",
35 	"Unsupported Opcode",
36 	"Format",
37 	"Scope",
38 	"Address",
39 	"Cache",
40 	"EM Miss",
41 	"Duplicate",
42 	"No Events",
43 	"EM Abort"
44 };
45 #endif
46 
47 static int tfc_em_insert_response(struct cfa_bld_mpcinfo *mpc_info,
48 				  struct bnxt_mpc_mbuf *mpc_msg_out,
49 				  uint8_t *rx_msg,
50 				  uint32_t *hash)
51 {
52 	int i;
53 	int rc;
54 	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_MAX_FLD];
55 
56 		/* Process response */
57 	for (i = 0; i < CFA_BLD_MPC_EM_INSERT_CMP_MAX_FLD; i++)
58 		fields_cmp[i].field_id = INVALID_U16;
59 
60 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].field_id =
61 		CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD;
62 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_BKT_NUM_FLD].field_id =
63 		CFA_BLD_MPC_EM_INSERT_CMP_BKT_NUM_FLD;
64 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_NUM_ENTRIES_FLD].field_id =
65 		CFA_BLD_MPC_EM_INSERT_CMP_NUM_ENTRIES_FLD;
66 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD].field_id =
67 		CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD;
68 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD].field_id =
69 		CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD;
70 	fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_HASH_MSB_FLD].field_id =
71 		CFA_BLD_MPC_EM_INSERT_CMP_HASH_MSB_FLD;
72 
73 	rc = mpc_info->mpcops->cfa_bld_mpc_parse_em_insert(rx_msg,
74 							   mpc_msg_out->msg_size,
75 							   fields_cmp);
76 	if (rc) {
77 		PMD_DRV_LOG_LINE(ERR, "EM insert parse failed: %d", rc);
78 		return -EINVAL;
79 	}
80 	if (fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
81 #ifdef EM_DEBUG
82 		PMD_DRV_LOG_LINE(ERR, "MPC failed with error:%s",
83 				 tfc_mpc_error_string[(uint32_t)
84 				 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val]);
85 #else
86 		PMD_DRV_LOG_LINE(ERR, "MPC failed with status code:%d",
87 				 (uint32_t)
88 				 fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val);
89 #endif
90 		rc = ((int)fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_STATUS_FLD].val) * -1;
91 		return rc;
92 	}
93 
94 #if TFC_EM_DYNAMIC_BUCKET_EN
95 	/* If the dynamic bucket is unused then free it */
96 	if (bucket_offset && fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_CHAIN_UPD_FLD].val == 0) {
97 		/* Free allocated resources */
98 		fparms.record_offset = bucket_offset;
99 		fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE;
100 
101 		rc = cfa_mm_free(cmm, &fparms);
102 		bucket_offset = 0;
103 	}
104 #endif
105 
106 	*hash = fields_cmp[CFA_BLD_MPC_EM_INSERT_CMP_TABLE_INDEX3_FLD].val;
107 
108 	return rc;
109 }
110 
111 int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
112 		  struct tfc_em_insert_parms *parms)
113 {
114 	int rc;
115 	int cleanup_rc;
116 	struct tfc_cpm *cpm_lkup = NULL;
117 	struct tfc_cpm *cpm_act = NULL;
118 	uint16_t pool_id;
119 	struct tfc_cmm *cmm = NULL;
120 	bool is_bs_owner;
121 	struct tfc_ts_mem_cfg mem_cfg;
122 	uint32_t entry_offset;
123 	uint32_t num_contig_records;
124 	struct bnxt_mpc_mbuf mpc_msg_in;
125 	struct bnxt_mpc_mbuf mpc_msg_out;
126 	struct tfc_ts_pool_info pi;
127 	struct cfa_mm_free_parms fparms;
128 	struct cfa_mm_alloc_parms aparms;
129 	uint32_t buff_len;
130 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
131 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
132 	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
133 	uint32_t i;
134 	uint32_t hash = 0;
135 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD];
136 	bool is_shared;
137 	struct cfa_bld_mpcinfo *mpc_info;
138 	bool valid;
139 	uint16_t max_pools;
140 #if TFC_EM_DYNAMIC_BUCKET_EN
141 	struct cfa_mm_alloc_parms bucket_aparms;
142 	bool shared = false;
143 	uint32_t bucket_offset;
144 #endif
145 
146 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
147 
148 	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, &max_pools);
149 	if (unlikely(rc)) {
150 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
151 		return -EINVAL;
152 	}
153 	if (unlikely(!valid)) {
154 		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
155 		return -EINVAL;
156 	}
157 	if (unlikely(!max_pools)) {
158 		PMD_DRV_LOG_LINE(ERR, "tsid(%d) Max pools must be greater than 0 %d",
159 				 tsid, max_pools);
160 		return -EINVAL;
161 	}
162 
163 	/* Check that MPC APIs are bound */
164 	if (unlikely(mpc_info->mpcops == NULL)) {
165 		PMD_DRV_LOG_LINE(ERR, "MPC not initialized");
166 		return -EINVAL;
167 	}
168 
169 	rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid,
170 				parms->dir,
171 				CFA_REGION_TYPE_LKUP,
172 				&is_bs_owner,
173 				&mem_cfg);   /* Gets rec_cnt */
174 	if (unlikely(rc)) {
175 		PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s",
176 				 strerror(-rc));
177 		return -EINVAL;
178 	}
179 
180 
181 	/* Get CPM instances */
182 	rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, parms->dir, &cpm_lkup, &cpm_act);
183 	if (unlikely(rc)) {
184 		PMD_DRV_LOG_LINE(ERR, "failed to get CPM instances: %s",
185 				 strerror(-rc));
186 		return -EINVAL;
187 	}
188 
189 	num_contig_records = 1 << next_pow2(parms->lkup_key_sz_words);
190 
191 	tfo_ts_get_pool_info(tfcp->tfo, tsid, parms->dir, &pi);
192 
193 	rc = tfc_cpm_get_avail_pool(cpm_lkup, &pool_id);
194 
195 	/* if no pool available locally or all pools full */
196 	if (rc) {
197 		/* Allocate a pool */
198 		struct cfa_mm_query_parms qparms;
199 		struct cfa_mm_open_parms oparms;
200 		uint16_t fid;
201 
202 		/* There is only 1 pool for a non-shared table scope and
203 		 * it is full.
204 		 */
205 		if (!is_shared) {
206 			PMD_DRV_LOG_LINE(ERR, "no records remain");
207 			return -ENOMEM;
208 		}
209 
210 		rc = tfc_get_fid(tfcp, &fid);
211 		if (unlikely(rc))
212 			return rc;
213 
214 		rc = tfc_tbl_scope_pool_alloc(tfcp,
215 					      fid,
216 					      tsid,
217 					      CFA_REGION_TYPE_LKUP,
218 					      parms->dir,
219 					      NULL,
220 					      &pool_id);
221 
222 		if (unlikely(rc)) {
223 			PMD_DRV_LOG_LINE(ERR, "table scope pool alloc failed: %s",
224 					 strerror(-rc));
225 			return -EINVAL;
226 		}
227 
228 		/*
229 		 * Create pool CMM instance.
230 		 * rec_cnt is the total number of records which includes static buckets,
231 		 */
232 		qparms.max_records = (mem_cfg.rec_cnt - mem_cfg.lkup_rec_start_offset) / max_pools;
233 		qparms.max_contig_records = pi.lkup_max_contig_rec;
234 		rc = cfa_mm_query(&qparms);
235 		if (unlikely(rc)) {
236 			PMD_DRV_LOG_LINE(ERR, "cfa_mm_query() failed: %s", strerror(-rc));
237 			rte_free(cmm);
238 			return -EINVAL;
239 		}
240 
241 		cmm = rte_zmalloc("tf", qparms.db_size, 0);
242 		oparms.db_mem_size = qparms.db_size;
243 		oparms.max_contig_records = qparms.max_contig_records;
244 		oparms.max_records = qparms.max_records;
245 		rc = cfa_mm_open(cmm, &oparms);
246 		if (unlikely(rc)) {
247 			PMD_DRV_LOG_LINE(ERR, "cfa_mm_open() failed: %s", strerror(-rc));
248 			rte_free(cmm);
249 			return -EINVAL;
250 		}
251 
252 		/* Store CMM instance in the CPM */
253 		rc = tfc_cpm_set_cmm_inst(cpm_lkup, pool_id, cmm);
254 		if (unlikely(rc)) {
255 			PMD_DRV_LOG_LINE(ERR, "tfc_cpm_set_cmm_inst() failed: %s",
256 					 strerror(-rc));
257 			return -EINVAL;
258 		}
259 
260 		/* Store the updated pool information */
261 		tfo_ts_set_pool_info(tfcp->tfo, tsid, parms->dir, &pi);
262 
263 	} else {
264 		/* Get the pool instance and allocate an lkup rec index from the pool */
265 		rc = tfc_cpm_get_cmm_inst(cpm_lkup, pool_id, &cmm);
266 		if (unlikely(rc)) {
267 			PMD_DRV_LOG_LINE(ERR, "tfc_cpm_get_cmm_inst() failed: %s",
268 					 strerror(-rc));
269 			return -EINVAL;
270 		}
271 	}
272 
273 	aparms.num_contig_records = num_contig_records;
274 	rc = cfa_mm_alloc(cmm, &aparms);
275 	if (unlikely(rc)) {
276 		PMD_DRV_LOG_LINE(ERR, "cfa_mm_alloc() failed: %s", strerror(-rc));
277 		return -EINVAL;
278 	}
279 
280 #if TFC_EM_DYNAMIC_BUCKET_EN
281 	if (!shared) {
282 		/* Allocate dynamic bucket */
283 		bucket_aparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE;
284 		rc = cfa_mm_alloc(cmm, &bucket_aparms);
285 		if (unlikely(rc)) {
286 			PMD_DRV_LOG_LINE(ERR,
287 					 "cfa_mm_alloc() for dynamic bucket failed: %s\n",
288 					 strerror(-rc));
289 			return -EINVAL;
290 		}
291 
292 		bucket_offset  = bucket_aparms.record_offset;
293 	}
294 #endif
295 
296 	CREATE_OFFSET(&entry_offset, pi.lkup_pool_sz_exp, pool_id, aparms.record_offset);
297 
298 	/* Create MPC EM insert command using builder */
299 	for (i = 0; i < CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD; i++)
300 		fields_cmd[i].field_id = INVALID_U16;
301 
302 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD].field_id =
303 		CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD;
304 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_OPAQUE_FLD].val = 0xAA;
305 
306 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD].field_id =
307 		CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD;
308 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_SCOPE_FLD].val = tsid;
309 
310 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD].field_id =
311 		CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD;
312 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_DATA_SIZE_FLD].val = parms->lkup_key_sz_words;
313 
314 		/* LREC address */
315 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD].field_id =
316 		CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD;
317 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX_FLD].val = entry_offset +
318 		mem_cfg.lkup_rec_start_offset;
319 
320 #if TFC_EM_DYNAMIC_BUCKET_EN
321 		/* Dynamic bucket address */
322 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD].field_id =
323 		CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD;
324 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_TABLE_INDEX2_FLD].val = bucket_offset;
325 #endif
326 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD].field_id =
327 		CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD;
328 	fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_REPLACE_FLD].val = 0x0;
329 
330 	buff_len = TFC_MPC_MAX_TX_BYTES;
331 
332 	rc = mpc_info->mpcops->cfa_bld_mpc_build_em_insert(tx_msg,
333 							   &buff_len,
334 							   parms->lkup_key_data,
335 							   fields_cmd);
336 
337 	if (unlikely(rc)) {
338 		PMD_DRV_LOG_LINE(ERR, "EM insert build failed: %s",
339 				 strerror(-rc));
340 		goto cleanup;
341 	}
342 
343 	/* Send MPC */
344 	mpc_msg_in.chnl_id = (parms->dir == CFA_DIR_TX ?
345 			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
346 			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
347 	mpc_msg_in.msg_data = &tx_msg[TFC_MPC_HEADER_SIZE_BYTES];
348 	mpc_msg_in.msg_size = (parms->lkup_key_sz_words * 32) +
349 		TFC_MPC_HEADER_SIZE_BYTES;
350 	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_LONG;
351 	mpc_msg_out.msg_data = &rx_msg[TFC_MPC_HEADER_SIZE_BYTES];
352 	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
353 
354 	rc = tfc_mpc_send(tfcp->bp,
355 			  &mpc_msg_in,
356 			  &mpc_msg_out,
357 			  &msg_count,
358 			  TFC_MPC_EM_INSERT,
359 			  parms->batch_info);
360 
361 	if (unlikely(rc)) {
362 		PMD_DRV_LOG_LINE(ERR, "EM insert send failed: %s", strerror(-rc));
363 		goto cleanup;
364 	}
365 
366 	if (parms->batch_info && !parms->batch_info->enabled) {
367 		rc = tfc_em_insert_response(mpc_info,
368 					    &mpc_msg_out,
369 					    rx_msg,
370 					    &hash);
371 		if (rc) {
372 			PMD_DRV_LOG_LINE(ERR,
373 					 "EM insert tfc_em_insert_response() failed: %d",
374 					 rc);
375 			goto cleanup;
376 		}
377 	}
378 
379 	*parms->flow_handle = tfc_create_flow_handle(tsid,
380 						     num_contig_records, /* Based on key size */
381 						     entry_offset,
382 						     hash);
383 
384 	/* Update CPM info so it will determine best pool to use next alloc */
385 	rc = tfc_cpm_set_usage(cpm_lkup, pool_id, aparms.used_count, aparms.all_used);
386 	if (unlikely(rc)) {
387 		PMD_DRV_LOG_LINE(ERR,
388 				 "EM insert tfc_cpm_set_usage() failed: %d",
389 				 rc);
390 		goto cleanup;
391 	}
392 
393 	if (!rc)
394 		return 0;
395 
396  cleanup:
397 	/*
398 	 * Preserve the rc from the actual error rather than
399 	 * an error during cleanup.
400 	 */
401 #if TFC_EM_DYNAMIC_BUCKET_EN
402 	/* If the dynamic bucket set then free it */
403 	if (bucket_offset) {
404 		/* Free allocated resources */
405 		fparms.record_offset = bucket_offset;
406 		fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE;
407 
408 		cleanup_rc = cfa_mm_free(cmm, &fparms);
409 	}
410 #endif
411 
412 	/* Free allocated resources */
413 	fparms.record_offset = aparms.record_offset;
414 	fparms.num_contig_records = num_contig_records;
415 	cleanup_rc = cfa_mm_free(cmm, &fparms);
416 	if (cleanup_rc != 0)
417 		PMD_DRV_LOG_LINE(ERR, "failed to free entry: %s", strerror(-rc));
418 
419 	cleanup_rc = tfc_cpm_set_usage(cpm_lkup, pool_id, fparms.used_count, false);
420 	if (cleanup_rc != 0)
421 		PMD_DRV_LOG_LINE(ERR, "failed to set usage: %s", strerror(-rc));
422 
423 	return rc;
424 }
425 
426 static int tfc_em_delete_response(struct cfa_bld_mpcinfo *mpc_info,
427 				  struct bnxt_mpc_mbuf *mpc_msg_out,
428 				  uint8_t *rx_msg
429 #if TFC_EM_DYNAMIC_BUCKET_EN
430 				  , bool *db_unused,
431 				  uint32_t *db_offset
432 #endif
433 			      )
434 {
435 	int i;
436 	int rc;
437 	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_MAX_FLD];
438 
439 	/* Process response */
440 	for (i = 0; i < CFA_BLD_MPC_EM_DELETE_CMP_MAX_FLD; i++)
441 		fields_cmp[i].field_id = INVALID_U16;
442 
443 	fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].field_id =
444 		CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD;
445 #ifdef EM_DEBUF
446 	fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_BKT_NUM_FLD].field_id =
447 		CFA_BLD_MPC_EM_DELETE_CMP_BKT_NUM_FLD;
448 	fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_NUM_ENTRIES_FLD].field_id =
449 		CFA_BLD_MPC_EM_DELETE_CMP_NUM_ENTRIES_FLD;
450 	fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD].field_id =
451 		CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD;
452 	fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD].field_id =
453 		CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD;
454 #endif
455 	rc = mpc_info->mpcops->cfa_bld_mpc_parse_em_delete(rx_msg,
456 							   mpc_msg_out->msg_size,
457 							   fields_cmp);
458 	if (rc) {
459 		PMD_DRV_LOG_LINE(ERR, "delete parse failed: %s", strerror(-rc));
460 		return -EINVAL;
461 	}
462 
463 	if (fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
464 #ifdef EM_DEBUG
465 		PMD_DRV_LOG_LINE(ERR, "MPC failed with error:%s",
466 				 tfc_mpc_error_string[(uint32_t)
467 				 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val]);
468 #else
469 		PMD_DRV_LOG_LINE(ERR, "MPC failed with status code:%d",
470 				 (uint32_t)
471 				 fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val);
472 #endif
473 		rc = ((int)fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_STATUS_FLD].val) * -1;
474 		return rc;
475 	}
476 
477 #if TFC_EM_DYNAMIC_BUCKET_EN
478 	*db_unused = fields_cmp[CFA_BLD_MPC_EM_DELETE_CMP_CHAIN_UPD_FLD].val == 1 ?
479 		true : false;
480 	*db_offset = fields[CFA_BLD_MPC_EM_DELETE_CMP_TABLE_INDEX3_FLD].val;
481 #endif
482 	return 0;
483 }
484 
485 int tfc_em_delete_raw(struct tfc *tfcp,
486 		      uint8_t tsid,
487 		      enum cfa_dir dir,
488 		      uint32_t offset,
489 		      uint32_t static_bucket,
490 		      struct tfc_mpc_batch_info_t *batch_info
491 #if TFC_EM_DYNAMIC_BUCKET_EN
492 		      , bool *db_unused,
493 		      uint32_t *db_offset
494 #endif
495 		      )
496 {
497 	int rc = 0;
498 	uint32_t buff_len;
499 	struct bnxt_mpc_mbuf mpc_msg_in;
500 	struct bnxt_mpc_mbuf mpc_msg_out;
501 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
502 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
503 	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
504 	int i;
505 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_MAX_FLD];
506 	struct cfa_bld_mpcinfo *mpc_info;
507 
508 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
509 	if (mpc_info->mpcops == NULL) {
510 		PMD_DRV_LOG_LINE(ERR, "MPC not initialized");
511 		return -EINVAL;
512 	}
513 
514 	/* Create MPC EM delete command using builder */
515 	for (i = 0; i < CFA_BLD_MPC_EM_DELETE_CMD_MAX_FLD; i++)
516 		fields_cmd[i].field_id = INVALID_U16;
517 
518 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD].field_id =
519 		CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD;
520 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_OPAQUE_FLD].val = 0xAA;
521 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD].field_id =
522 		CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD;
523 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_SCOPE_FLD].val = tsid;
524 
525 	/* LREC address to delete */
526 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD].field_id =
527 		CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD;
528 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX_FLD].val = offset;
529 
530 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].field_id =
531 		CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD;
532 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].val = static_bucket;
533 
534 #if TFC_EM_DYNAMIC_BUCKET_EN
535 	/* Static bucket address */
536 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].field_id =
537 		CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD;
538 	fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_TABLE_INDEX2_FLD].val = 0x01222222;
539 #endif
540 
541 	/* Create MPC EM delete command using builder */
542 	buff_len = TFC_MPC_MAX_TX_BYTES;
543 
544 	rc = mpc_info->mpcops->cfa_bld_mpc_build_em_delete(tx_msg,
545 							   &buff_len,
546 							   fields_cmd);
547 
548 	if (rc) {
549 		PMD_DRV_LOG_LINE(ERR, "delete mpc build failed: %s",
550 				 strerror(-rc));
551 		return -EINVAL;
552 	}
553 
554 	/* Send MPC */
555 	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
556 			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
557 			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
558 	mpc_msg_in.msg_data = &tx_msg[TFC_MPC_HEADER_SIZE_BYTES];
559 	mpc_msg_in.msg_size = 16;
560 	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_LONG;
561 	mpc_msg_out.msg_data = &rx_msg[TFC_MPC_HEADER_SIZE_BYTES];
562 	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
563 
564 	rc = tfc_mpc_send(tfcp->bp,
565 			  &mpc_msg_in,
566 			  &mpc_msg_out,
567 			  &msg_count,
568 			  TFC_MPC_EM_DELETE,
569 			  batch_info);
570 	if (rc) {
571 		PMD_DRV_LOG_LINE(ERR, "delete MPC send failed: %s",
572 				 strerror(-rc));
573 		return -EINVAL;
574 	}
575 
576 	if (!batch_info->enabled)
577 		rc = tfc_em_delete_response(mpc_info,
578 					    &mpc_msg_out,
579 					    rx_msg
580 #if TFC_EM_DYNAMIC_BUCKET_EN
581 					    , db_unused,
582 					    db_offset
583 #endif
584 					    );
585 	return rc;
586 }
587 
588 int tfc_em_delete(struct tfc *tfcp, struct tfc_em_delete_parms *parms)
589 {
590 	int rc = 0;
591 	uint32_t static_bucket;
592 	uint32_t pool_id;
593 	struct tfc_cpm *cpm_lkup = NULL;
594 	struct tfc_cpm *cpm_act = NULL;
595 	struct tfc_cmm *cmm;
596 	uint32_t record_offset;
597 	uint32_t record_size;
598 	struct cfa_mm_free_parms fparms;
599 	uint8_t tsid;
600 	bool is_shared;
601 	struct tfc_ts_pool_info pi;
602 	bool is_bs_owner;
603 	struct tfc_ts_mem_cfg mem_cfg;
604 	bool valid;
605 
606 #if TFC_EM_DYNAMIC_BUCKET_EN
607 	bool db_unused;
608 	uint32_t db_offset;
609 #endif
610 	/* Get fields from MPC Flow handle */
611 	tfc_get_fields_from_flow_handle(&parms->flow_handle,
612 					&tsid,
613 					&record_size,
614 					&record_offset,
615 					&static_bucket);
616 
617 	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
618 	if (rc != 0) {
619 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s",
620 				 strerror(-rc));
621 		return -EINVAL;
622 	}
623 	if (!valid) {
624 		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
625 		return -EINVAL;
626 	}
627 
628 	tfo_ts_get_pool_info(tfcp->tfo, tsid, parms->dir, &pi);
629 
630 	pool_id = TFC_FLOW_GET_POOL_ID(record_offset, pi.lkup_pool_sz_exp);
631 
632 	rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid,
633 				parms->dir,
634 				CFA_REGION_TYPE_LKUP,
635 				&is_bs_owner,
636 				&mem_cfg);   /* Gets rec_cnt */
637 	if (rc != 0) {
638 		PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s",
639 				 strerror(-rc));
640 		return -EINVAL;
641 	}
642 
643 	/* Get CPM instance for this table scope */
644 	rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, parms->dir, &cpm_lkup, &cpm_act);
645 	if (rc != 0) {
646 		PMD_DRV_LOG_LINE(ERR, "failed to get CMM instance: %s",
647 				 strerror(-rc));
648 		return -EINVAL;
649 	}
650 
651 	rc = tfc_em_delete_raw(tfcp,
652 			       tsid,
653 			       parms->dir,
654 			       record_offset +
655 			       mem_cfg.lkup_rec_start_offset,
656 			       static_bucket,
657 			       parms->batch_info
658 #if TFC_EM_DYNAMIC_BUCKET_EN
659 			       , &db_unused,
660 			       &db_offset
661 #endif
662 			       );
663 
664 #if TFC_EM_DYNAMIC_BUCKET_EN
665 	/* If the dynamic bucket is unused then free it */
666 	if (db_unused) {
667 		/* Free allocated resources */
668 		fparms.record_offset = db_offset;
669 		fparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE;
670 
671 		rc = cfa_mm_free(cmm, &fparms);
672 	}
673 #endif
674 
675 	rc = tfc_cpm_get_cmm_inst(cpm_lkup, pool_id, &cmm);
676 	if (rc != 0) {
677 		PMD_DRV_LOG_LINE(ERR, "failed to get CMM instance: %s",
678 				 strerror(-rc));
679 		return -EINVAL;
680 	}
681 
682 	fparms.record_offset = record_offset;
683 	fparms.num_contig_records = 1 << next_pow2(record_size);
684 
685 	rc = cfa_mm_free(cmm, &fparms);
686 	if (rc != 0) {
687 		PMD_DRV_LOG_LINE(ERR, "failed to free CMM instance: %s",
688 				 strerror(-rc));
689 		return -EINVAL;
690 	}
691 
692 	rc = tfc_cpm_set_usage(cpm_lkup, pool_id, fparms.used_count, false);
693 	if (rc != 0)
694 		PMD_DRV_LOG_LINE(ERR, "failed to set usage: %s",
695 				 strerror(-rc));
696 
697 	return rc;
698 }
699 
700 static void bucket_decode(uint32_t *bucket_ptr,
701 			  struct bucket_info_t *bucket_info)
702 {
703 	int i;
704 	int offset = 0;
705 
706 	bucket_info->valid = false;
707 	bucket_info->chain = tfc_getbits(bucket_ptr, 254, 1);
708 	bucket_info->chain_ptr = tfc_getbits(bucket_ptr, 228, 26);
709 
710 	if  (bucket_info->chain ||
711 	     bucket_info->chain_ptr)
712 		bucket_info->valid = true;
713 
714 	for (i = 0; i < TFC_BUCKET_ENTRIES; i++) {
715 		bucket_info->entries[i].entry_ptr = tfc_getbits(bucket_ptr, offset, 26);
716 		offset +=  26;
717 		bucket_info->entries[i].hash_msb = tfc_getbits(bucket_ptr, offset, 12);
718 		offset += 12;
719 		if  (bucket_info->entries[i].hash_msb ||
720 		     bucket_info->entries[i].entry_ptr) {
721 			bucket_info->valid = true;
722 		}
723 	}
724 }
725 
726 int tfc_em_delete_entries_by_pool_id(struct tfc *tfcp,
727 				     uint8_t tsid,
728 				     enum cfa_dir dir,
729 				     uint16_t pool_id,
730 				     uint8_t debug,
731 				     uint8_t *data)
732 {
733 	uint32_t offset;
734 	int rc;
735 	int i;
736 	int j;
737 	struct bucket_info_t bucket;
738 	struct tfc_ts_pool_info pi;
739 	struct tfc_ts_mem_cfg mem_cfg;
740 	bool is_bs_owner;
741 #if TFC_EM_DYNAMIC_BUCKET_EN
742 	bool db_unused;
743 	uint32_t db_offset;
744 #endif
745 	struct tfc_mpc_batch_info_t batch_info;
746 
747 	memset(&batch_info, 0, sizeof(batch_info));
748 
749 	/* Get memory info */
750 	rc = tfo_ts_get_pool_info(tfcp->tfo, tsid, dir, &pi);
751 	if (rc) {
752 		PMD_DRV_LOG_LINE(ERR,
753 				 "Failed to get pool info for tsid:%d",
754 				 tsid);
755 		return -EINVAL;
756 	}
757 
758 	rc = tfo_ts_get_mem_cfg(tfcp->tfo,
759 				tsid,
760 				dir,
761 				CFA_REGION_TYPE_LKUP,
762 				&is_bs_owner,
763 				&mem_cfg);
764 	if (rc != 0) {
765 		PMD_DRV_LOG_LINE(ERR, "tfo_ts_get_mem_cfg() failed: %s",
766 				 strerror(-rc));
767 		return -EINVAL;
768 	}
769 
770 	/* Read static bucket entries */
771 	for (offset = 0; offset < mem_cfg.lkup_rec_start_offset; ) {
772 		/*
773 		 * Read static bucket region of lookup table.
774 		 * A static bucket is 32B in size and must be 32B aligned.
775 		 * A table read can read up to 4 * 32B so in the interest
776 		 * of efficiency the max read size will be used.
777 		 */
778 		rc = tfc_mpc_table_read(tfcp,
779 					tsid,
780 					dir,
781 					CFA_REGION_TYPE_LKUP,
782 					offset,
783 					TFC_MPC_MAX_TABLE_READ_WORDS,
784 					data,
785 					debug);
786 
787 		if (rc != 0) {
788 			PMD_DRV_LOG_LINE(ERR,
789 					 "tfc_mpc_table_read() failed for offset:%d: %s",
790 					 offset, strerror(-rc));
791 			return -EINVAL;
792 		}
793 
794 		for (i = 0; (i < TFC_MPC_MAX_TABLE_READ_WORDS) &&
795 			     (offset < mem_cfg.lkup_rec_start_offset); i++) {
796 			/* Walk static bucket entry pointers */
797 			bucket_decode((uint32_t *)&data[i * TFC_MPC_BYTES_PER_WORD],
798 				      &bucket);
799 
800 			for (j = 0; j < TFC_BUCKET_ENTRIES; j++) {
801 				if (bucket.entries[j].entry_ptr != 0 &&
802 		    pool_id == (bucket.entries[j].entry_ptr >> pi.lkup_pool_sz_exp)) {
803 					/* Delete EM entry */
804 					rc = tfc_em_delete_raw(tfcp,
805 							       tsid,
806 							       dir,
807 							       bucket.entries[j].entry_ptr,
808 							       offset,
809 							       &batch_info
810 #if TFC_EM_DYNAMIC_BUCKET_EN
811 							       , &db_unused,
812 							       &db_offset
813 #endif
814 							       );
815 					if (rc) {
816 						PMD_DRV_LOG_LINE(ERR,
817 								 "EM delete failed for offset:0x%08x %d",
818 								 offset, rc);
819 						return -1;
820 					}
821 				}
822 			}
823 
824 			offset++;
825 		}
826 	}
827 
828 	return rc;
829 }
830 
831 int tfc_mpc_send(struct bnxt *bp,
832 		 struct bnxt_mpc_mbuf *in_msg,
833 		 struct bnxt_mpc_mbuf *out_msg,
834 		 uint32_t *opaque,
835 		 int type,
836 		 struct tfc_mpc_batch_info_t *batch_info)
837 {
838 	int rc;
839 	bool enabled = false;
840 
841 	if (batch_info)
842 		enabled = batch_info->enabled;
843 
844 	rc = bnxt_mpc_send(bp, in_msg, out_msg, opaque, enabled);
845 
846 	if (rc)
847 		return rc;
848 
849 	if (batch_info && batch_info->enabled) {
850 		memcpy(&batch_info->comp_info[batch_info->count].out_msg,
851 		       out_msg,
852 		       sizeof(*out_msg));
853 		batch_info->comp_info[batch_info->count].mpc_queue =
854 			bp->mpc->mpc_txq[in_msg->chnl_id];
855 		batch_info->comp_info[batch_info->count].type = type;
856 		batch_info->count++;
857 	}
858 
859 	return 0;
860 }
861 
862 static int tfc_mpc_process_completions(uint8_t *rx_msg,
863 				       struct tfc_mpc_comp_info_t *comp_info)
864 {
865 	int rc;
866 	int retry = BNXT_MPC_RX_RETRY;
867 
868 	comp_info->out_msg.msg_data = rx_msg;
869 
870 	do {
871 		rc =  bnxt_mpc_cmd_cmpl(comp_info->mpc_queue,
872 					&comp_info->out_msg);
873 
874 		if (likely(rc == 1)) {
875 #ifdef MPC_DEBUG
876 			if (unlikely(retry != BNXT_MPC_RX_RETRY))
877 				PMD_DRV_LOG_LINE(ERR, "Retrys:%d",
878 						 BNXT_MPC_RX_RETRY - retry);
879 #endif
880 			return 0;
881 		}
882 #ifdef MPC_DEBUG
883 		PMD_DRV_LOG_LINE(ERR,
884 				 "Received zero or more than one completion:%d",
885 				 rc);
886 #endif
887 		retry--;
888 	} while (retry);
889 
890 	PMD_DRV_LOG_LINE(ERR, "Retry timeout rc:%d", rc);
891 	return -1;
892 }
893 
894 int tfc_mpc_batch_start(struct tfc_mpc_batch_info_t *batch_info)
895 {
896 	if (unlikely(batch_info->enabled))
897 		return -EBUSY;
898 
899 	batch_info->enabled = true;
900 	batch_info->count = 0;
901 	batch_info->error = false;
902 	return 0;
903 }
904 
905 bool tfc_mpc_batch_started(struct tfc_mpc_batch_info_t *batch_info)
906 {
907 	if (unlikely(!batch_info))
908 		return false;
909 
910 	return (batch_info->enabled && batch_info->count > 0);
911 }
912 
913 int tfc_mpc_batch_end(struct tfc *tfcp,
914 		      struct tfc_mpc_batch_info_t *batch_info)
915 {
916 	uint32_t i;
917 	int rc;
918 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
919 	struct cfa_bld_mpcinfo *mpc_info;
920 	uint32_t hash = 0;
921 #if TFC_EM_DYNAMIC_BUCKET_EN
922 	bool *db_unused;
923 	uint32_t *db_offset;
924 #endif
925 
926 	if (unlikely(!batch_info->enabled))
927 		return -EBUSY;
928 
929 	if (unlikely(!batch_info->count)) {
930 		batch_info->enabled = false;
931 		return 0;
932 	}
933 
934 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
935 
936 	if (unlikely(mpc_info->mpcops == NULL)) {
937 		PMD_DRV_LOG_LINE(ERR, "MPC not initialized");
938 		return -EINVAL;
939 	}
940 
941 	if (batch_info->count < (BNXT_MPC_COMP_MAX_COUNT / 4))
942 		rte_delay_us_block(BNXT_MPC_RX_US_DELAY * 4);
943 
944 	for (i = 0; i < batch_info->count; i++) {
945 		rc = tfc_mpc_process_completions(&rx_msg[TFC_MPC_HEADER_SIZE_BYTES],
946 						 &batch_info->comp_info[i]);
947 		if (unlikely(rc))
948 			return -1;
949 
950 
951 		switch (batch_info->comp_info[i].type) {
952 		case TFC_MPC_EM_INSERT:
953 			rc = tfc_em_insert_response(mpc_info,
954 						    &batch_info->comp_info[i].out_msg,
955 						    rx_msg,
956 						    &hash);
957 			/*
958 			 * If the handle is non NULL it should reference a
959 			 * flow DB entry that requires the flow_handle
960 			 * contained within to be updated.
961 			 */
962 			batch_info->em_hdl[i] =
963 				tfc_create_flow_handle2(batch_info->em_hdl[i],
964 							hash);
965 			batch_info->em_error = rc;
966 			break;
967 		case TFC_MPC_EM_DELETE:
968 			rc = tfc_em_delete_response(mpc_info,
969 						    &batch_info->comp_info[i].out_msg,
970 						    rx_msg
971 #if TFC_EM_DYNAMIC_BUCKET_EN
972 						    , bool *db_unused,
973 						    uint32_t *db_offset
974 #endif
975 						    );
976 			break;
977 		case TFC_MPC_TABLE_WRITE:
978 			rc = tfc_act_set_response(mpc_info,
979 						  &batch_info->comp_info[i].out_msg,
980 						  rx_msg);
981 			break;
982 		case TFC_MPC_TABLE_READ:
983 			rc = tfc_act_get_only_response(mpc_info,
984 						       &batch_info->comp_info[i].out_msg,
985 						       rx_msg,
986 						       &batch_info->comp_info[i].read_words);
987 			break;
988 
989 		case TFC_MPC_TABLE_READ_CLEAR:
990 			rc = tfc_act_get_clear_response(mpc_info,
991 							&batch_info->comp_info[i].out_msg,
992 							rx_msg,
993 							&batch_info->comp_info[i].read_words);
994 			break;
995 
996 		default:
997 			PMD_DRV_LOG_LINE(ERR, "MPC Batch not supported for type: %d",
998 					 batch_info->comp_info[i].type);
999 			return -1;
1000 		}
1001 
1002 		batch_info->result[i] = rc;
1003 		if (rc)
1004 			batch_info->error = true;
1005 	}
1006 
1007 	batch_info->enabled = false;
1008 	batch_info->count = 0;
1009 
1010 	return 0;
1011 }
1012