DPDK patches and discussions
 help / color / mirror / Atom feed
* [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk
@ 2025-10-21 18:56 Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 33/57] net/bnxt/tf_core: truflow global table scope Manish Kurup
                   ` (19 more replies)
  0 siblings, 20 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Peter Spreadborough, Jay Ding, Farah Smith

From: Peter Spreadborough <peter.spreadborough@broadcom.com>

This change updates the existing backing store debug by
adding more decode to EM entries and adding wildcard entry debug.
A new cli command has also been added to exercise the function that
loops through all ports and table scopes so that a single call
can dump and decode all backing stores.

Signed-off-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Jay Ding <jay.ding@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
---
 drivers/net/bnxt/tf_core/v3/meson.build      |    3 +-
 drivers/net/bnxt/tf_core/v3/tfc_debug.h      |   12 +-
 drivers/net/bnxt/tf_core/v3/tfc_em.h         |   98 +-
 drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c  | 1411 +++++++++++++
 drivers/net/bnxt/tf_core/v3/tfc_mpc_table.c  |  565 ------
 drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c | 1875 ++++++++++++++++++
 drivers/net/bnxt/tf_core/v3/tfo.c            |   32 +
 drivers/net/bnxt/tf_core/v3/tfo.h            |   14 +
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h       |    5 +
 drivers/net/bnxt/tf_ulp/ulp_fc_mgr_tfc.c     |    1 -
 drivers/net/bnxt/tf_ulp/ulp_flow_db.c        |    4 +-
 drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c         |    1 -
 drivers/net/bnxt/tf_ulp/ulp_sc_mgr_tfc.c     |    1 -
 13 files changed, 3437 insertions(+), 585 deletions(-)
 create mode 100644 drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
 delete mode 100644 drivers/net/bnxt/tf_core/v3/tfc_mpc_table.c
 create mode 100644 drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c

diff --git a/drivers/net/bnxt/tf_core/v3/meson.build b/drivers/net/bnxt/tf_core/v3/meson.build
index 159e7a2b17..8d62e14274 100644
--- a/drivers/net/bnxt/tf_core/v3/meson.build
+++ b/drivers/net/bnxt/tf_core/v3/meson.build
@@ -21,7 +21,8 @@ sources += files(
         'tfc_idx_tbl.c',
         'tfc_if_tbl.c',
         'tfc_init.c',
-        'tfc_mpc_table.c',
+        'tfc_mpc_debug.c',
+        'tfc_tcam_debug.c',
         'tfc_msg.c',
         'tfc_priv.c',
         'tfc_resources.c',
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_debug.h b/drivers/net/bnxt/tf_core/v3/tfc_debug.h
index 0a4a0b4846..86492f3a69 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_debug.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_debug.h
@@ -7,6 +7,7 @@
 #define _TFC_DEBUG_H_
 
 /* #define EM_DEBUG */
+/* #define WC_DEBUG */
 /* #define ACT_DEBUG */
 
 int tfc_mpc_table_write_zero(struct tfc *tfcp,
@@ -16,13 +17,18 @@ int tfc_mpc_table_write_zero(struct tfc *tfcp,
 			     uint32_t offset,
 			     uint8_t words,
 			     uint8_t *data);
-
-int tfc_act_show(struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir);
-int tfc_em_show(struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir);
+const char *get_lrec_opcode_str(uint8_t opcode);
+void act_show(FILE *fd, struct act_info_t *act_info, uint32_t offset);
+int tfc_em_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir);
+int tfc_wc_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir);
 int tfc_mpc_table_invalidate(struct tfc *tfcp,
 			     uint8_t tsid,
 			     enum cfa_dir dir,
 			     uint32_t type,
 			     uint32_t offset,
 			     uint32_t words);
+void act_process(uint32_t act_rec_ptr,
+		 struct act_info_t *act_info,
+		 struct tfc_ts_mem_cfg *act_mem_cfg);
+void tfc_backing_store_dump(FILE *fd);
 #endif
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_em.h b/drivers/net/bnxt/tf_core/v3/tfc_em.h
index 9ad3ef9fd2..52589ea9c3 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_em.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_em.h
@@ -61,6 +61,86 @@ enum tfc_mpc_cmd_type {
 
 #define TFC_BUCKET_ENTRIES 6
 
+/* MPC opaque currently unused */
+#define TFC_MPC_OPAQUE_VAL 0
+
+#define TFC_MOD_STRING_LENGTH  512
+#define TFC_STAT_STRING_LENGTH 128
+#define TFC_ENC_STRING_LENGTH  256
+
+struct act_compact_info_t {
+	bool drop;
+	uint8_t vlan_del_rep;
+	uint8_t dest_op;
+	uint16_t vnic_vport;
+	uint8_t decap_func;
+	uint8_t mirror;
+	uint16_t meter_ptr;
+	uint8_t stat0_ctr_type;
+	bool stat0_ing_egr;
+	uint8_t stat0_offs;
+	uint8_t mod_offs;
+	uint8_t enc_offs;
+	uint8_t src_offs;
+	char mod_str[512];
+	char stat0_str[128];
+	char enc_str[256];
+};
+
+struct act_full_info_t {
+	bool drop;
+	uint8_t vlan_del_rep;
+	uint8_t dest_op;
+	uint16_t vnic_vport;
+	uint8_t decap_func;
+	uint16_t mirror;
+	uint16_t meter_ptr;
+	uint8_t stat0_ctr_type;
+	bool stat0_ing_egr;
+	uint32_t stat0_ptr;
+	uint8_t stat1_ctr_type;
+	bool stat1_ing_egr;
+	uint32_t stat1_ptr;
+	uint32_t mod_ptr;
+	uint32_t enc_ptr;
+	uint32_t src_ptr;
+	char mod_str[512];
+	char stat0_str[128];
+	char stat1_str[128];
+	char enc_str[256];
+};
+
+struct act_mcg_info_t {
+	uint8_t src_ko_en;
+	uint32_t nxt_ptr;
+	uint8_t act_hint0;
+	uint32_t act_rec_ptr0;
+	uint8_t act_hint1;
+	uint32_t act_rec_ptr1;
+	uint8_t act_hint2;
+	uint32_t act_rec_ptr2;
+	uint8_t act_hint3;
+	uint32_t act_rec_ptr3;
+	uint8_t act_hint4;
+	uint32_t act_rec_ptr4;
+	uint8_t act_hint5;
+	uint32_t act_rec_ptr5;
+	uint8_t act_hint6;
+	uint32_t act_rec_ptr6;
+	uint8_t act_hint7;
+	uint32_t act_rec_ptr7;
+};
+
+struct act_info_t {
+	bool valid;
+	uint8_t vector;
+	union {
+		struct act_compact_info_t compact;
+		struct act_full_info_t full;
+		struct act_mcg_info_t mcg;
+	};
+};
+
 struct em_info_t {
 	bool valid;
 	uint8_t rec_size;
@@ -69,12 +149,9 @@ struct em_info_t {
 	uint8_t opcode;
 	uint8_t strength;
 	uint8_t act_hint;
-
-	uint32_t act_rec_ptr; /* Not FAST */
-
-	uint32_t destination; /* Just FAST */
-
-	uint8_t tcp_direction; /* Just CT */
+	uint32_t act_rec_ptr;	/* Not FAST */
+	uint32_t destination;	/* Just FAST */
+	uint8_t tcp_direction;	/* Just CT */
 	uint8_t tcp_update_en;
 	uint8_t tcp_win;
 	uint32_t tcp_msb_loc;
@@ -82,23 +159,20 @@ struct em_info_t {
 	uint8_t tcp_msb_opp_init;
 	uint8_t state;
 	uint8_t timer_value;
-
-	uint16_t ring_table_idx; /* Not CT and not RECYCLE */
+	uint16_t ring_table_idx;	/* Not CT and not RECYCLE */
 	uint8_t act_rec_size;
 	uint8_t paths_m1;
 	uint8_t fc_op;
 	uint8_t fc_type;
 	uint32_t fc_ptr;
-
-	uint8_t recycle_dest; /* Just Recycle */
+	uint8_t recycle_dest;	/* Just Recycle */
 	uint8_t prof_func;
 	uint8_t meta_prof;
 	uint32_t metadata;
-
 	uint8_t range_profile;
 	uint16_t range_index;
-
 	uint8_t *key;
+	struct act_info_t act_info;
 };
 
 struct sb_entry_t {
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c b/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
new file mode 100644
index 0000000000..5690f072e2
--- /dev/null
+++ b/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
@@ -0,0 +1,1411 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2019-2021 Broadcom
+ * All rights reserved.
+ */
+#include <stdio.h>
+#include <inttypes.h>
+#include <math.h>
+#include <string.h>
+
+#include "bnxt.h"
+#include "bnxt_mpc.h"
+
+#include "tfc.h"
+#include "cfa_bld_mpc_field_ids.h"
+#include "cfa_bld_mpcops.h"
+#include "tfo.h"
+#include "tfc_em.h"
+#include "tfc_cpm.h"
+#include "tfc_msg.h"
+#include "tfc_debug.h"
+#include "cfa_types.h"
+#include "cfa_mm.h"
+#include "sys_util.h"
+#include "cfa_bld.h"
+#include "tfc_util.h"
+
+int tfc_mpc_table_read(struct tfc *tfcp,
+		       uint8_t tsid,
+		       enum cfa_dir dir,
+		       uint32_t type,
+		       uint32_t offset,
+		       uint8_t words,
+		       uint8_t *data,
+		       uint8_t debug)
+{
+	int rc = 0;
+	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
+	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
+	uint16_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	int i;
+	uint32_t buff_len;
+	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_READ_CMD_MAX_FLD];
+	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_READ_CMP_MAX_FLD];
+	struct bnxt_mpc_mbuf mpc_msg_in;
+	struct bnxt_mpc_mbuf mpc_msg_out;
+	bool is_shared;
+	struct cfa_bld_mpcinfo *mpc_info;
+	uint64_t host_address;
+	uint8_t discard_data[128];
+	uint32_t set;
+	uint32_t way;
+	bool valid;
+
+	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
+
+	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	if (rc != 0) {
+		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
+		return -EINVAL;
+	}
+	if (!valid) {
+		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
+		return -EINVAL;
+	}
+
+	/* Check that data pointer is word aligned */
+	if (((uint64_t)data)  & 0x1fULL) {
+		PMD_DRV_LOG_LINE(ERR, "Table read data pointer not word aligned");
+		return -EINVAL;
+	}
+
+	host_address = (uint64_t)rte_mem_virt2iova(data);
+
+	/* Check that MPC APIs are bound */
+	if (mpc_info->mpcops == NULL) {
+		PMD_DRV_LOG_LINE(ERR, "MPC not initialized");
+		return -EINVAL;
+	}
+
+	set =  offset & 0x7ff;
+	way = (offset >> 12)  & 0xf;
+
+	if (debug)
+		PMD_DRV_LOG_LINE(ERR,
+				 "Debug read table type:%s %d words32B at way:%d set:%d debug:%d words32B",
+				 (type  == 0 ? "Lookup" : "Action"),
+				 words, way, set, debug);
+	else
+		PMD_DRV_LOG_LINE(ERR,
+				 "Reading table type:%s %d words32B at offset %d words32B",
+				 (type  == 0 ? "Lookup" : "Action"),
+				 words, offset);
+
+	/* Create MPC EM insert command using builder */
+	for (i = 0; i < CFA_BLD_MPC_READ_CMD_MAX_FLD; i++)
+		fields_cmd[i].field_id = INVALID_U16;
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_OPAQUE_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_OPAQUE_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_OPAQUE_FLD].val = 0xAA;
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
+	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD].val =
+		(debug ? way : tsid);
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD].val = words;
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD].val =
+		(debug ? set : offset);
+
+	fields_cmd[CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD;
+	fields_cmd[CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD].val = host_address;
+
+	if (debug) {
+		fields_cmd[CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD].field_id =
+		CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD;
+		fields_cmd[CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD].val = debug; /* Debug read */
+	}
+
+	buff_len = TFC_MPC_MAX_TX_BYTES;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_read(tx_msg,
+							    &buff_len,
+							    fields_cmd);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "Action read build failed: %d", rc);
+		goto cleanup;
+	}
+
+	/* Send MPC */
+	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
+	mpc_msg_in.msg_data = &tx_msg[16];
+	mpc_msg_in.msg_size = 16;
+	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
+	mpc_msg_out.msg_data = &rx_msg[16];
+	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
+
+	rc = tfc_mpc_send(tfcp->bp,
+			  &mpc_msg_in,
+			  &mpc_msg_out,
+			  &msg_count,
+			  TFC_MPC_TABLE_READ,
+			  NULL);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "Table read MPC send failed: %d", rc);
+		goto cleanup;
+	}
+
+		/* Process response */
+	for (i = 0; i < CFA_BLD_MPC_READ_CMP_MAX_FLD; i++)
+		fields_cmp[i].field_id = INVALID_U16;
+
+	fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].field_id =
+		CFA_BLD_MPC_READ_CMP_STATUS_FLD;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_read(rx_msg,
+							    mpc_msg_out.msg_size,
+							    discard_data,
+							    words * TFC_MPC_BYTES_PER_WORD,
+							    fields_cmp);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "Table read parse failed: %d", rc);
+		goto cleanup;
+	}
+
+	if (fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
+		PMD_DRV_LOG_LINE(ERR, "Table read failed with status code:%d",
+				 (uint32_t)fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].val);
+		rc = -1;
+		goto cleanup;
+	}
+
+	return 0;
+
+ cleanup:
+
+	return rc;
+}
+
+int tfc_mpc_table_write_zero(struct tfc *tfcp,
+			     uint8_t tsid,
+			     enum cfa_dir dir,
+			     uint32_t type,
+			     uint32_t offset,
+			     uint8_t words,
+			     uint8_t *data)
+{
+	int rc = 0;
+	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
+	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
+	uint16_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	int i;
+	uint32_t buff_len;
+	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_WRITE_CMD_MAX_FLD];
+	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_WRITE_CMP_MAX_FLD];
+	struct bnxt_mpc_mbuf mpc_msg_in;
+	struct bnxt_mpc_mbuf mpc_msg_out;
+	struct cfa_bld_mpcinfo *mpc_info;
+	bool is_shared;
+	bool valid;
+
+	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
+
+	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	if (rc != 0) {
+		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
+		return -EINVAL;
+	}
+	if (!valid) {
+		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
+		return -EINVAL;
+	}
+	/* Check that MPC APIs are bound */
+	if (mpc_info->mpcops == NULL) {
+		PMD_DRV_LOG_LINE(ERR, " MPC not initialized");
+		return -EINVAL;
+	}
+
+	/* Create MPC EM insert command using builder */
+	for (i = 0; i < CFA_BLD_MPC_WRITE_CMD_MAX_FLD; i++)
+		fields_cmd[i].field_id = INVALID_U16;
+
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD;
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD].val = 0xAA;
+
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD;
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
+	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
+
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD;
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD].val = tsid;
+
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD;
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD].val = words;
+
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD;
+	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD].val = offset;
+
+	buff_len = TFC_MPC_MAX_TX_BYTES;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_write(tx_msg,
+							     &buff_len,
+							     data,
+							     fields_cmd);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "write build failed: %d", rc);
+		goto cleanup;
+	}
+
+	/* Send MPC */
+	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
+	mpc_msg_in.msg_data = &tx_msg[16];
+	mpc_msg_in.msg_size = (words * TFC_MPC_BYTES_PER_WORD) + 16;
+	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
+	mpc_msg_out.msg_data = &rx_msg[16];
+	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
+
+	rc = tfc_mpc_send(tfcp->bp,
+			  &mpc_msg_in,
+			  &mpc_msg_out,
+			  &msg_count,
+			  TFC_MPC_TABLE_WRITE,
+			  NULL);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "write MPC send failed: %d", rc);
+		goto cleanup;
+	}
+
+	/* Process response */
+	for (i = 0; i < CFA_BLD_MPC_WRITE_CMP_MAX_FLD; i++)
+		fields_cmp[i].field_id = INVALID_U16;
+
+	fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].field_id =
+		CFA_BLD_MPC_WRITE_CMP_STATUS_FLD;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_write(rx_msg,
+							     mpc_msg_out.msg_size,
+							     fields_cmp);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "write parse failed: %d", rc);
+		goto cleanup;
+	}
+
+	if (fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
+		PMD_DRV_LOG_LINE(ERR, "Action write failed with status code:%d",
+				 (uint32_t)fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].val);
+		PMD_DRV_LOG_LINE(ERR, "Hash MSB:0x%0x",
+		       (uint32_t)fields_cmp[CFA_BLD_MPC_WRITE_CMP_HASH_MSB_FLD].val);
+		goto cleanup;
+	}
+
+	return 0;
+
+ cleanup:
+
+	return rc;
+}
+
+int tfc_mpc_table_invalidate(struct tfc *tfcp,
+			     uint8_t tsid,
+			     enum cfa_dir dir,
+			     uint32_t type,
+			     uint32_t offset,
+			     uint32_t words)
+{
+	int rc = 0;
+	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
+	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
+	uint16_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	int i;
+	uint32_t buff_len;
+	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_MAX_FLD];
+	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_MAX_FLD];
+	struct bnxt_mpc_mbuf mpc_msg_in;
+	struct bnxt_mpc_mbuf mpc_msg_out;
+	struct cfa_bld_mpcinfo *mpc_info;
+	bool is_shared;
+	bool valid;
+
+	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
+
+	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	if (rc != 0) {
+		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
+		return -EINVAL;
+	}
+	if (!valid) {
+		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
+		return -EINVAL;
+	}
+	/* Check that MPC APIs are bound */
+	if (mpc_info->mpcops == NULL) {
+		PMD_DRV_LOG_LINE(ERR, " MPC not initialized");
+		return -EINVAL;
+	}
+
+	/* Create MPC EM insert command using builder */
+	for (i = 0; i < CFA_BLD_MPC_INVALIDATE_CMD_MAX_FLD; i++)
+		fields_cmd[i].field_id = INVALID_U16;
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD].val = 0xAA;
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
+	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD].val = tsid;
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD].val = words;
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD].val = offset;
+
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD;
+	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD].val =
+		CFA_BLD_MPC_EV_EVICT_SCOPE_ADDRESS;
+
+	buff_len = TFC_MPC_MAX_TX_BYTES;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_evict(tx_msg,
+							     &buff_len,
+							     fields_cmd);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "evict build failed: %d", rc);
+		goto cleanup;
+	}
+
+	/* Send MPC */
+	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
+			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
+	mpc_msg_in.msg_data = &tx_msg[16];
+	mpc_msg_in.msg_size = 16;
+	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
+	mpc_msg_out.msg_data = &rx_msg[16];
+	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
+
+	rc = tfc_mpc_send(tfcp->bp,
+			  &mpc_msg_in,
+			  &mpc_msg_out,
+			  &msg_count,
+			  TFC_MPC_INVALIDATE,
+			  NULL);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "write MPC send failed: %d", rc);
+		goto cleanup;
+	}
+
+	/* Process response */
+	for (i = 0; i < CFA_BLD_MPC_INVALIDATE_CMP_MAX_FLD; i++)
+		fields_cmp[i].field_id = INVALID_U16;
+
+	fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].field_id =
+		CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD;
+
+	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_evict(rx_msg,
+							     mpc_msg_out.msg_size,
+							     fields_cmp);
+
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR, "evict parse failed: %d", rc);
+		goto cleanup;
+	}
+
+	if (fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
+		PMD_DRV_LOG_LINE(ERR, "evict failed with status code:%d",
+				 (uint32_t)fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].val);
+		PMD_DRV_LOG_LINE(ERR, "Hash MSB:0x%0x",
+		       (uint32_t)fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_HASH_MSB_FLD].val);
+		goto cleanup;
+	}
+
+	return 0;
+
+ cleanup:
+
+	return rc;
+}
+
+#define TFC_ACTION_SIZE_BYTES  32
+#define TFC_BUCKET_SIZE_BYTES  32
+
+#define TFC_STRING_LENGTH_32  32
+#define TFC_STRING_LENGTH_64  64
+#define TFC_STRING_LENGTH_96  96
+#define TFC_STRING_LENGTH_256 256
+
+static const char * const opcode_string[] = {
+	"NORMAL",
+	"NORMAL_RFS",
+	"FAST",
+	"FAST_RFS",
+	"CT_MISS_DEF",
+	"INVALID",
+	"CT_HIT_DEF",
+	"INVALID",
+	"RECYCLE"
+};
+
+static void act_decode(uint32_t *act_ptr,
+		       uintptr_t base,
+		       struct act_info_t *act_info);
+static void stat_decode(char *str,
+			uint8_t stat_num,
+			uint8_t stat1_ctr_type,
+			uint32_t *stat_ptr);
+
+const char *get_lrec_opcode_str(uint8_t opcode)
+{
+	return opcode_string[opcode];
+}
+
+static uintptr_t get_address(struct tfc_ts_mem_cfg *mem, uint32_t offset)
+{
+	uint32_t page =  offset / mem->pg_tbl[0].pg_size;
+	uint32_t adj_offset = offset % mem->pg_tbl[0].pg_size;
+	int level = 0;
+	uint64_t addr;
+
+	/*
+	 * Use the level according to the num_level of page table
+	 */
+	level = mem->num_lvl - 1;
+
+	addr = (uint64_t)mem->pg_tbl[level].pg_va_tbl[page] + adj_offset;
+
+	return addr;
+}
+
+void act_process(uint32_t act_rec_ptr,
+		 struct act_info_t *act_info,
+		 struct tfc_ts_mem_cfg *act_mem_cfg)
+{
+	uint8_t *act_ptr;
+	uintptr_t base;
+	uint32_t act_offset = act_rec_ptr << 5;
+
+	base = get_address(act_mem_cfg, 0);
+	act_ptr = (uint8_t *)get_address(act_mem_cfg, act_offset);
+	act_decode((uint32_t *)act_ptr, base, act_info);
+}
+
+static void em_decode(uint32_t *em_ptr,
+		      struct em_info_t *em_info,
+		      struct tfc_ts_mem_cfg *act_mem_cfg)
+{
+	em_info->key = (uint8_t *)em_ptr;
+
+	em_ptr += (128 / 8) / 4; /* For EM records the LREC follows 128 bits of key */
+	em_info->valid = tfc_getbits(em_ptr, 127, 1);
+	em_info->rec_size = tfc_getbits(em_ptr, 125, 2);
+	em_info->epoch0 = tfc_getbits(em_ptr, 113, 12);
+	em_info->epoch1 = tfc_getbits(em_ptr, 107, 6);
+	em_info->opcode = tfc_getbits(em_ptr, 103, 4);
+	em_info->strength = tfc_getbits(em_ptr, 101, 2);
+	em_info->act_hint = tfc_getbits(em_ptr, 99, 2);
+
+	if (em_info->opcode != 2 && em_info->opcode != 3) {
+		/* All but FAST */
+		em_info->act_rec_ptr = tfc_getbits(em_ptr, 73, 26);
+		act_process(em_info->act_rec_ptr, &em_info->act_info, act_mem_cfg);
+	} else {
+		/* Just FAST */
+		em_info->destination = tfc_getbits(em_ptr, 73, 17);
+	}
+
+	if (em_info->opcode == 4 || em_info->opcode == 6) {
+		/* CT only */
+		em_info->tcp_direction = tfc_getbits(em_ptr, 72, 1);
+		em_info->tcp_update_en = tfc_getbits(em_ptr, 71, 1);
+		em_info->tcp_win = tfc_getbits(em_ptr, 66, 5);
+		em_info->tcp_msb_loc = tfc_getbits(em_ptr, 48, 18);
+		em_info->tcp_msb_opp = tfc_getbits(em_ptr, 30, 18);
+		em_info->tcp_msb_opp_init = tfc_getbits(em_ptr, 29, 1);
+		em_info->state = tfc_getbits(em_ptr, 24, 5);
+		em_info->timer_value  = tfc_getbits(em_ptr, 20, 4);
+	} else if (em_info->opcode != 8) {
+		/* Not CT and nor RECYCLE */
+		em_info->ring_table_idx = tfc_getbits(em_ptr, 64, 9);
+		em_info->act_rec_size = tfc_getbits(em_ptr, 59, 5);
+		em_info->paths_m1 = tfc_getbits(em_ptr, 55, 4);
+		em_info->fc_op  = tfc_getbits(em_ptr, 54, 1);
+		em_info->fc_type = tfc_getbits(em_ptr, 52, 2);
+		em_info->fc_ptr = tfc_getbits(em_ptr, 24, 28);
+	} else {
+		em_info->recycle_dest = tfc_getbits(em_ptr, 72, 1); /* Just Recycle */
+		em_info->prof_func = tfc_getbits(em_ptr, 64, 8);
+		em_info->meta_prof = tfc_getbits(em_ptr, 61, 3);
+		em_info->metadata = tfc_getbits(em_ptr, 29, 32);
+	}
+
+	em_info->range_profile = tfc_getbits(em_ptr, 16, 4);
+	em_info->range_index = tfc_getbits(em_ptr, 0, 16);
+}
+
+static void em_show(FILE *fd, struct em_info_t *em_info)
+{
+	int i;
+	char *line1 = NULL;
+	char *line2 = NULL;
+	char *line3 = NULL;
+	char *line4 = NULL;
+	char tmp1[TFC_STRING_LENGTH_64];
+	char tmp2[TFC_STRING_LENGTH_64];
+	char tmp3[TFC_STRING_LENGTH_64];
+	char tmp4[TFC_STRING_LENGTH_64];
+
+	line1 = rte_zmalloc("data", TFC_STRING_LENGTH_256, 8);
+	line2 = rte_zmalloc("data", TFC_STRING_LENGTH_256, 8);
+	line3 = rte_zmalloc("data", TFC_STRING_LENGTH_256, 8);
+	line4 = rte_zmalloc("data", TFC_STRING_LENGTH_256, 8);
+	if (!line1 || !line2 || !line3 || !line4) {
+		rte_free(line1);
+		rte_free(line2);
+		rte_free(line3);
+		rte_free(line4);
+		fprintf(fd, "%s: Failed to allocate temp buffer\n",
+			   __func__);
+		return;
+	}
+
+	fprintf(fd, ":LREC: opcode:%s\n", get_lrec_opcode_str(em_info->opcode));
+
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+-Epoch-+--+--+--+");
+	snprintf(line2, TFC_STRING_LENGTH_256, " V|rs|  0  1 |Op|St|ah|");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+----+--+--+--+--+");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %1d %2d %4d %2d %2d %2d %2d ",
+		 em_info->valid,
+		 em_info->rec_size,
+		 em_info->epoch0,
+		 em_info->epoch1,
+		 em_info->opcode,
+		 em_info->strength,
+		 em_info->act_hint);
+
+	if (em_info->opcode != 2 && em_info->opcode != 3) {
+		/* All but FAST */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "-Act Rec--+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, " Ptr      |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "----------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "0x%08x ",
+			 em_info->act_rec_ptr);
+	} else {
+		/* Just FAST */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "-------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, " Dest  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "-------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "0x05%x ",
+			 em_info->destination);
+	}
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	if (em_info->opcode == 4 || em_info->opcode == 6) {
+		/* CT only */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+-------------TCP-------+--+---+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "Dr|ue| Win|   lc  |   op  |oi|st|tmr|");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+----+-------+-------+--+--+---+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d %2d %4d %0x5x %0x5x %2d %2d %3d ",
+			 em_info->tcp_direction,
+			 em_info->tcp_update_en,
+			 em_info->tcp_win,
+			 em_info->tcp_msb_loc,
+			 em_info->tcp_msb_opp,
+			 em_info->tcp_msb_opp_init,
+			 em_info->state,
+			 em_info->timer_value);
+	} else if (em_info->opcode != 8) {
+		/* Not CT and nor RECYCLE */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+--+-------FC-------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "RI|as|pm|op|tp|     Ptr  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+--+--+--+----------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d %2d %2d %2d %2d 0x%08x ",
+			 em_info->ring_table_idx,
+			 em_info->act_rec_size,
+			 em_info->paths_m1,
+			 em_info->fc_op,
+			 em_info->fc_type,
+			 em_info->fc_ptr);
+	} else {
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+--+---------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "RD|pf|mp| cMData  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+--+---------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d 0x%2x %2d %08x ",
+			 em_info->recycle_dest,
+			 em_info->prof_func,
+			 em_info->meta_prof,
+			 em_info->metadata);
+	}
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-----Range-+\n");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "Prof|  Idx |\n");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "----+------+\n");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "0x%02x 0x%04x\n",
+		 em_info->range_profile,
+		 em_info->range_index);
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	fprintf(fd, "%s%s%s%s",
+		   line1,
+		   line2,
+		   line3,
+		   line4);
+
+	fputs("Key:", fd);
+	for (i = 0; i < ((em_info->rec_size + 1) * 32); i++) {
+		if (i % 32 == 0)
+			fprintf(fd, "\n%04d:  ", i);
+		fprintf(fd, "%02x", em_info->key[i]);
+	}
+	i = ((em_info->rec_size + 1) * 32);
+	fprintf(fd, "\nKey Reversed:\n%04d:  ", i - 32);
+	do {
+		i--;
+		fprintf(fd, "%02x", em_info->key[i]);
+		if (i != 0 && i % 32 == 0)
+			fprintf(fd, "\n%04d:  ", i - 32);
+	} while (i > 0);
+	fputs("\n", fd);
+
+	if (em_info->opcode != 2 && em_info->opcode != 3)
+		act_show(fd, &em_info->act_info, em_info->act_rec_ptr << 5);
+
+	rte_free(line1);
+	rte_free(line2);
+	rte_free(line3);
+	rte_free(line4);
+}
+
+struct mod_field_s {
+	uint8_t num_bits;
+	const char *name;
+};
+
+struct mod_data_s {
+	uint8_t num_fields;
+	const char *name;
+	struct mod_field_s field[4];
+};
+
+struct mod_data_s mod_data[] = {
+	{1, "Replace", {{16,  "DPort"}}},
+	{1, "Replace", {{16,  "SPort"}}},
+	{1, "Replace", {{32,  "IPv4 DIP"}}},
+	{1, "Replace", {{32,  "IPv4 SIP"}}},
+	{1, "Replace", {{128, "IPv6 DIP"}}},
+	{1, "Replace", {{128, "IPv6 SIP"}}},
+	{1, "Replace", {{48,  "SMAC"}}},
+	{1, "Replace", {{48,  "DMAC"}}},
+	{2, "Update Field",  {{16, "uf_vec"}, {32, "uf_data"}}},
+	{3, "Tunnel Modify", {{16, "tun_mv"}, {16, "tun_ex_prot"}, {16, "tun_new_prot"}}},
+	{4, "TTL Update",    {{5,  "alt_pfid"}, {12, "alt_vid"}, {10, "rsvd"}, {5, "ttl_op"}}},
+	{4, "Replace/Add Outer VLAN", {{16, "tpid"}, {3, "pri"}, {1, "de"}, {12, "vid"}}},
+	{4, "Replace/Add Inner",      {{16, "tpid"}, {3, "pri"}, {1, "de"}, {12, "vid"}}},
+	{0, "Remove outer VLAN", {{0, NULL}}},
+	{0, "Remove inner VLAN", {{0, NULL}}},
+	{4, "Metadata Update",   {{2, "md_op"}, {4, "md_prof"}, {10, "rsvd"}, {32, "md_data"}}},
+};
+
+static void mod_decode(uint32_t *data, char *mod_str)
+{
+	int i;
+	int j;
+	int k;
+	uint16_t mod_vector;
+	int32_t row_offset = 64;
+	int32_t read_offset;
+	int32_t row = 0;
+	uint32_t val[8];
+	char str[256];
+	int16_t vect;
+	uint16_t bit = 0x8000;
+
+	row_offset -= 16;
+	read_offset = row_offset;
+	mod_vector = tfc_getbits(data, read_offset, 16);
+	snprintf(mod_str,
+		 TFC_MOD_STRING_LENGTH,
+		 "\nModify Record: Vector:0x%08x\n", mod_vector);
+
+	for (vect = 15; vect >= 0; vect--) {
+		if (mod_vector & bit) {
+			snprintf(str, TFC_STRING_LENGTH_256, "%s: ", mod_data[vect].name);
+			strcat(mod_str, str);
+
+			for (i = 0; i < mod_data[vect].num_fields; i++) {
+				row_offset -= mod_data[vect].field[i].num_bits;
+				if (row_offset < 0) {
+					row++;
+					row_offset = 64 + row_offset;
+				}
+				read_offset = row_offset + (row * 64);
+
+				for (j = 0; j < mod_data[vect].field[i].num_bits / 32; j++) {
+					val[j] = tfc_getbits(data, read_offset, 32);
+					read_offset -= 32;
+				}
+
+				if (mod_data[vect].field[i].num_bits % 32) {
+					val[j] = tfc_getbits(data,
+							     read_offset,
+						     (mod_data[vect].field[i].num_bits % 32));
+					j++;
+				}
+
+				snprintf(str,
+					 TFC_STRING_LENGTH_256,
+					 "%s:0x",
+					 mod_data[vect].field[i].name);
+				strcat(mod_str, str);
+
+				switch (mod_data[vect].field[i].num_bits) {
+				case 128:
+					for (k = 0; k < 8; k++) {
+						snprintf(str,
+							 TFC_STRING_LENGTH_256,
+							 "%08x",
+							 val[k]);
+						strcat(mod_str, str);
+					}
+					break;
+				case 48:
+					snprintf(str, TFC_STRING_LENGTH_256, "%08x", val[0]);
+					strcat(mod_str, str);
+					snprintf(str,
+						 TFC_STRING_LENGTH_256,
+						 "%04x",
+						 (val[1] & 0xffff));
+					strcat(mod_str, str);
+					break;
+				case 32:
+					snprintf(str, TFC_STRING_LENGTH_256, "%08x ", val[0]);
+					strcat(mod_str, str);
+					break;
+				case 16:
+					snprintf(str, TFC_STRING_LENGTH_256, "%04x ", val[0]);
+					strcat(mod_str, str);
+					break;
+				default:
+					snprintf(str, TFC_STRING_LENGTH_256, "%04x ",
+						 (val[0] &
+						  ((1 << mod_data[vect].field[i].num_bits) - 1)));
+					strcat(mod_str, str);
+					break;
+				}
+			}
+
+			snprintf(str, TFC_STRING_LENGTH_256, "\n");
+			strcat(mod_str, str);
+		}
+
+		bit = bit >> 1;
+	}
+
+	snprintf(str, TFC_STRING_LENGTH_256, "\n");
+	strcat(mod_str, str);
+}
+
+static void enc_decode(uint32_t *data, char *enc_str)
+{
+	uint16_t vector;
+	char str[64];
+	uint32_t val[16];
+	uint32_t offset = 0;
+	uint8_t vtag;
+	uint8_t l2;
+	uint8_t l3;
+	uint8_t l4;
+	uint8_t tunnel;
+
+	vector = tfc_getbits(data, offset, 16);
+	offset += 16;
+
+	vtag = ((vector >> 2) & 0xf);
+	l2 = ((vector >> 6) & 0x1);
+	l3 = ((vector >> 7) & 0x7);
+	l4 = ((vector >> 10) & 0x7);
+	tunnel = ((vector >> 13) & 0x7);
+
+	snprintf(enc_str,
+		 TFC_ENC_STRING_LENGTH,
+		 "Encap Record: vector:0x%04x\n", vector);
+
+	snprintf(str, TFC_STRING_LENGTH_64,
+		 "Valid:%d EC:%d VTAG:0x%01x L2:%d L3:0x%01x L4:0x%01x Tunnel:0x%01x\n",
+		 (vector & 0x1),
+		 ((vector >> 1) & 0x1),
+		 vtag,
+		 l2,
+		 l3,
+		 l4,
+		 tunnel);
+
+	strcat(enc_str, str);
+
+	if (l2) { /* L2 */
+		snprintf(str, TFC_STRING_LENGTH_64, "L2:\n");
+		strcat(enc_str, str);
+
+		val[0] = tfc_getbits(data, offset, 32);
+		offset += 32;
+		val[1] = tfc_getbits(data, offset, 16);
+		offset += 16;
+
+		snprintf(str, TFC_STRING_LENGTH_64, "DMAC:0x%08x%04x\n", val[0], val[1]);
+		strcat(enc_str, str);
+	}
+
+	if (l3) { /* L3 */
+		snprintf(str, TFC_STRING_LENGTH_64, "L3:\n");
+		strcat(enc_str, str);
+	}
+
+	if (l4) { /* L4 */
+		snprintf(str, TFC_STRING_LENGTH_64, "L4:\n");
+		strcat(enc_str, str);
+	}
+
+	if (tunnel) { /* Tunnel */
+		snprintf(str, TFC_STRING_LENGTH_64, "Tunnel:\n");
+		strcat(enc_str, str);
+	}
+}
+
+static void act_decode(uint32_t *act_ptr,
+		       uintptr_t base,
+		       struct act_info_t *act_info)
+{
+	if (!act_ptr || !act_info) {
+		PMD_DRV_LOG_LINE(ERR, "act_ptr %p, act_info %p", act_ptr, act_info);
+		return;
+	}
+
+	act_info->valid = false;
+	act_info->vector = tfc_getbits(act_ptr, 0, 3);
+
+	if (act_info->vector == 0 ||
+	    act_info->vector == 1 ||
+	    act_info->vector == 4)
+		act_info->valid = true;
+
+	switch (act_info->vector) {
+	case 0:
+		act_info->compact.drop = tfc_getbits(act_ptr, 3, 1);
+		act_info->compact.vlan_del_rep = tfc_getbits(act_ptr, 4, 2);
+		act_info->compact.vnic_vport = tfc_getbits(act_ptr, 6, 11);
+		act_info->compact.dest_op = tfc_getbits(act_ptr, 17, 2);
+		act_info->compact.decap_func = tfc_getbits(act_ptr, 19, 5);
+		act_info->compact.mirror = tfc_getbits(act_ptr, 24, 5);
+		act_info->compact.meter_ptr = tfc_getbits(act_ptr, 29, 10);
+		act_info->compact.stat0_offs = tfc_getbits(act_ptr, 39, 3);
+		act_info->compact.stat0_ing_egr = tfc_getbits(act_ptr, 42, 1);
+		act_info->compact.stat0_ctr_type = tfc_getbits(act_ptr, 43, 2);
+		act_info->compact.mod_offs = tfc_getbits(act_ptr, 45, 5);
+		act_info->compact.enc_offs = tfc_getbits(act_ptr, 50, 6);
+		act_info->compact.src_offs = tfc_getbits(act_ptr, 56, 4);
+
+		if (act_info->compact.mod_offs) {
+			mod_decode((uint32_t *)(act_ptr + (act_info->compact.mod_offs <<  3)),
+				   act_info->compact.mod_str);
+		}
+		if (act_info->compact.stat0_offs)
+			stat_decode(act_info->compact.stat0_str,
+				    0,
+				    act_info->compact.stat0_ctr_type,
+				    (uint32_t *)(act_ptr + (act_info->compact.stat0_offs <<  3)));
+		if (act_info->compact.enc_offs)
+			enc_decode((uint32_t *)(act_ptr + (act_info->compact.enc_offs <<  3)),
+				   act_info->compact.enc_str);
+	break;
+	case 1:
+		act_info->full.drop = tfc_getbits(act_ptr, 3, 1);
+		act_info->full.vlan_del_rep = tfc_getbits(act_ptr, 4, 2);
+		act_info->full.vnic_vport = tfc_getbits(act_ptr, 6, 11);
+		act_info->full.dest_op = tfc_getbits(act_ptr, 17, 2);
+		act_info->full.decap_func = tfc_getbits(act_ptr, 19, 5);
+		act_info->full.mirror = tfc_getbits(act_ptr, 24, 5);
+		act_info->full.meter_ptr = tfc_getbits(act_ptr, 29, 10);
+		act_info->full.stat0_ptr = tfc_getbits(act_ptr, 39, 28);
+		act_info->full.stat0_ing_egr = tfc_getbits(act_ptr, 67, 1);
+		act_info->full.stat0_ctr_type = tfc_getbits(act_ptr, 68, 2);
+		act_info->full.stat1_ptr = tfc_getbits(act_ptr, 70, 28);
+		act_info->full.stat1_ing_egr = tfc_getbits(act_ptr, 98, 1);
+		act_info->full.stat1_ctr_type = tfc_getbits(act_ptr, 99, 2);
+		act_info->full.mod_ptr = tfc_getbits(act_ptr, 101, 28);
+		act_info->full.enc_ptr = tfc_getbits(act_ptr, 129, 28);
+		act_info->full.src_ptr = tfc_getbits(act_ptr, 157, 28);
+
+		if (act_info->full.mod_ptr)
+			mod_decode((uint32_t *)(base + (act_info->full.mod_ptr <<  3)),
+				   act_info->full.mod_str);
+		if (act_info->full.stat0_ptr)
+			stat_decode(act_info->full.stat0_str,
+				    0,
+				    act_info->full.stat0_ctr_type,
+				    (uint32_t *)(base + (act_info->full.stat0_ptr <<  3)));
+		if (act_info->full.stat1_ptr)
+			stat_decode(act_info->full.stat1_str,
+				    1,
+				    act_info->full.stat1_ctr_type,
+				    (uint32_t *)(base + (act_info->full.stat1_ptr <<  3)));
+		if (act_info->full.enc_ptr)
+			enc_decode((uint32_t *)(base + (act_info->full.enc_ptr <<  3)),
+				   act_info->full.enc_str);
+	break;
+	case 4:
+		act_info->mcg.nxt_ptr = tfc_getbits(act_ptr, 6, 26);
+		act_info->mcg.act_hint0    = tfc_getbits(act_ptr, 32, 2);
+		act_info->mcg.act_rec_ptr0 = tfc_getbits(act_ptr, 34, 26);
+		act_info->mcg.act_hint1    = tfc_getbits(act_ptr, 60, 2);
+		act_info->mcg.act_rec_ptr1 = tfc_getbits(act_ptr, 62, 26);
+		act_info->mcg.act_hint2    = tfc_getbits(act_ptr, 88, 2);
+		act_info->mcg.act_rec_ptr2 = tfc_getbits(act_ptr, 90, 26);
+		act_info->mcg.act_hint3    = tfc_getbits(act_ptr, 116, 2);
+		act_info->mcg.act_rec_ptr3 = tfc_getbits(act_ptr, 118, 26);
+		act_info->mcg.act_hint4    = tfc_getbits(act_ptr, 144, 2);
+		act_info->mcg.act_rec_ptr4 = tfc_getbits(act_ptr, 146, 26);
+		act_info->mcg.act_hint5    = tfc_getbits(act_ptr, 172, 2);
+		act_info->mcg.act_rec_ptr5 = tfc_getbits(act_ptr, 174, 26);
+		act_info->mcg.act_hint6    = tfc_getbits(act_ptr, 200, 2);
+		act_info->mcg.act_rec_ptr6 = tfc_getbits(act_ptr, 202, 26);
+		act_info->mcg.act_hint7    = tfc_getbits(act_ptr, 228, 2);
+		act_info->mcg.act_rec_ptr7 = tfc_getbits(act_ptr, 230, 26);
+		break;
+	}
+}
+
+void act_show(FILE *fd, struct act_info_t *act_info, uint32_t offset)
+{
+	if (act_info->valid) {
+		switch (act_info->vector) {
+		case 0:
+			fputs("Compact Action Record\n", fd);
+			fputs("+----------+--+-+--+--+-----+--+-+------+---Stat0"
+			      "---+------+------+------+\n", fd);
+			fputs("|   Index  |V |d|dr|do|vn/p |df|m| mtp  |ct|ie| offs|"
+			      " moffs| eoffs| soffs|\n", fd);
+			fputs("+----------+--+-+--+--+-----+--+-+------+--+--+-----+"
+			      "------+------+------+\n", fd);
+
+			fprintf(fd,
+	" 0x%08x %2d %d %2d %2d 0x%03x %2d %d 0x%04x %2d %2d  0x%02x   0x%02x   0x%02x   0x%02x\n",
+				offset,
+				act_info->vector,
+				act_info->compact.drop,
+				act_info->compact.vlan_del_rep,
+				act_info->compact.dest_op,
+				act_info->compact.vnic_vport,
+				act_info->compact.decap_func,
+				act_info->compact.mirror,
+				act_info->compact.meter_ptr,
+				act_info->compact.stat0_ctr_type,
+				act_info->compact.stat0_ing_egr,
+				act_info->compact.stat0_offs,
+				act_info->compact.mod_offs,
+				act_info->compact.enc_offs,
+				act_info->compact.src_offs);
+
+		if (act_info->compact.mod_offs)
+			fprintf(fd, "%s", act_info->compact.mod_str);
+		if (act_info->compact.stat0_offs)
+			fprintf(fd, "%s", act_info->compact.stat0_str);
+		if (act_info->compact.enc_offs)
+			fprintf(fd, "%s", act_info->compact.enc_str);
+		break;
+		case 1:
+		fputs("Full Action Record\n", fd);
+		fputs("+----------+--+-+--+--+-----+--+-+------+----Stat0-------+------Stat1-----+----------+----------+----------+\n",
+		      fd);
+		fputs("|   Index  |V |d|dr|do|vn/p |df|m| mtp  |ct|ie|    ptr   |ct|ie|    ptr   |   mptr   |   eptr   |   sptr   |\n",
+		      fd);
+		fputs("+----------+--+-+--+--+-----+--+-+------+--+--+----------+--+--+----------+----------+----------+----------+\n",
+		      fd);
+
+		fprintf(fd, " 0x%08x %2d %d %2d %2d 0x%03x %2d %d 0x%04x %2d %2d 0x%08x %2d %2d 0x%08x 0x%08x 0x%08x 0x%08x\n",
+			offset,
+			act_info->vector,
+			act_info->full.drop,
+			act_info->full.vlan_del_rep,
+			act_info->full.dest_op,
+			act_info->full.vnic_vport,
+			act_info->full.decap_func,
+			act_info->full.mirror,
+			act_info->full.meter_ptr,
+			act_info->full.stat0_ctr_type,
+			act_info->full.stat0_ing_egr,
+			act_info->full.stat0_ptr,
+			act_info->full.stat1_ctr_type,
+			act_info->full.stat1_ing_egr,
+			act_info->full.stat1_ptr,
+			act_info->full.mod_ptr,
+			act_info->full.enc_ptr,
+			act_info->full.src_ptr);
+		if (act_info->full.mod_ptr)
+			fprintf(fd, "%s", act_info->full.mod_str);
+		if (act_info->full.stat0_ptr)
+			fprintf(fd, "%s", act_info->full.stat0_str);
+		if (act_info->full.stat1_ptr)
+			fprintf(fd, "%s", act_info->full.stat1_str);
+		if (act_info->full.enc_ptr)
+			fprintf(fd, "%s", act_info->full.enc_str);
+
+		break;
+		case 4:
+			fputs("Multicast Group Record\n", fd);
+			fputs("+----------+--+----------+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+\n",
+			      fd);
+			fputs("|   Index  |V |  NxtPtr  | ActRPtr0 |ah| ActRPtr1 |ah| ActRPtr2 |ah| ActRPtr3 |ah| ActRPtr4 |ah| ActRPtr5 |ah| ActRPtr6 |ah| ActRPtr7 |ah|\n",
+			      fd);
+			fputs("+----------+--+----------+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+----------+--+\n",
+			      fd);
+
+		fprintf(fd, " 0x%08x %2d 0x%08x 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d 0x%08x %2d\n",
+			offset,
+			act_info->vector,
+			act_info->mcg.nxt_ptr,
+			act_info->mcg.act_rec_ptr0,
+			act_info->mcg.act_hint0,
+			act_info->mcg.act_rec_ptr1,
+			act_info->mcg.act_hint1,
+			act_info->mcg.act_rec_ptr2,
+			act_info->mcg.act_hint2,
+			act_info->mcg.act_rec_ptr3,
+			act_info->mcg.act_hint3,
+			act_info->mcg.act_rec_ptr4,
+			act_info->mcg.act_hint4,
+			act_info->mcg.act_rec_ptr5,
+			act_info->mcg.act_hint5,
+			act_info->mcg.act_rec_ptr6,
+			act_info->mcg.act_hint6,
+			act_info->mcg.act_rec_ptr7,
+			act_info->mcg.act_hint7);
+			break;
+		}
+	}
+}
+
+struct stat_fields_s {
+	uint64_t pkt_cnt;
+	uint64_t byte_cnt;
+	union {
+		struct {
+			uint32_t timestamp;
+			uint16_t tcp_flags;
+		} c_24b;
+		struct {
+			uint64_t meter_pkt_cnt;
+			uint64_t meter_byte_cnt;
+		} c_32b;
+		struct {
+			uint64_t timestamp : 32;
+			uint64_t tcp_flags : 16;
+			uint64_t meter_pkt_cnt : 38;
+			uint64_t meter_byte_cnt : 42;
+		} c_32b_all;
+	} t;
+};
+
+#define STATS_COMMON_FMT    \
+	"Stats:%d Pkt count:%016" PRIu64 " Byte count:%016" PRIu64 "\n"
+#define STATS_METER_FMT     \
+	"\tMeter pkt count:%016" PRIu64 " Meter byte count:%016" PRIu64 "\n"
+#define STATS_TCP_FLAGS_FMT \
+	"\tTCP flags:0x%04x timestamp:0x%08x\n"
+
+static void stat_decode(char *str,
+			uint8_t stat_num,
+			uint8_t stat_ctr_type,
+			uint32_t *stat_ptr)
+{
+	struct stat_fields_s *stats = (struct stat_fields_s *)stat_ptr;
+	uint64_t meter_pkt_cnt;
+	uint64_t meter_byte_cnt;
+	uint32_t timestamp;
+	char tmp0[96];
+
+	/* Common fields */
+	snprintf(str,
+		 TFC_STAT_STRING_LENGTH,
+		 STATS_COMMON_FMT,
+		 stat_num, stats->pkt_cnt, stats->byte_cnt);
+
+	switch (stat_ctr_type) {
+	case CFA_BLD_STAT_COUNTER_SIZE_16B:
+		/* Nothing further to do */
+		break;
+	case CFA_BLD_STAT_COUNTER_SIZE_24B:
+		timestamp = stats->t.c_24b.timestamp;
+		snprintf(tmp0,
+			 TFC_STRING_LENGTH_96,
+			 STATS_TCP_FLAGS_FMT,
+			 stats->t.c_24b.tcp_flags,
+			 timestamp);
+		strcat(str, tmp0);
+		break;
+	case CFA_BLD_STAT_COUNTER_SIZE_32B:
+		snprintf(tmp0,
+			 TFC_STRING_LENGTH_96,
+			 STATS_METER_FMT,
+			 stats->t.c_32b.meter_pkt_cnt,
+			 stats->t.c_32b.meter_byte_cnt);
+		strcat(str, tmp0);
+		break;
+	case CFA_BLD_STAT_COUNTER_SIZE_32B_ALL:
+		meter_pkt_cnt = stats->t.c_32b_all.meter_pkt_cnt;
+		meter_byte_cnt = stats->t.c_32b_all.meter_byte_cnt;
+		timestamp = stats->t.c_32b_all.timestamp;
+		snprintf(tmp0,
+			 TFC_STRING_LENGTH_96,
+			 STATS_METER_FMT STATS_TCP_FLAGS_FMT,
+			 meter_pkt_cnt,
+			 meter_byte_cnt,
+			 stats->t.c_32b_all.tcp_flags,
+			 timestamp);
+		strcat(str, tmp0);
+		break;
+	default:
+		       /* Should never happen since type is 2 bits in size */
+		snprintf(tmp0,
+			 TFC_STRING_LENGTH_96,
+			 "Unknown counter type %d\n", stat_ctr_type);
+		strcat(str, tmp0);
+		break;
+	}
+}
+
+static void bucket_decode(uint32_t *bucket_ptr,
+			  struct bucket_info_t *bucket_info,
+			  struct tfc_ts_mem_cfg *lkup_mem_cfg,
+			  struct tfc_ts_mem_cfg *act_mem_cfg)
+{
+	int i;
+	int offset = 0;
+	uint8_t *em_ptr;
+
+	bucket_info->valid = false;
+	bucket_info->chain = tfc_getbits(bucket_ptr, 254, 1);
+	bucket_info->chain_ptr = tfc_getbits(bucket_ptr, 228, 26);
+
+	if  (bucket_info->chain ||
+	     bucket_info->chain_ptr)
+		bucket_info->valid = true;
+
+	for (i = 0; i < TFC_BUCKET_ENTRIES; i++) {
+		bucket_info->entries[i].entry_ptr = tfc_getbits(bucket_ptr, offset, 26);
+		offset +=  26;
+		bucket_info->entries[i].hash_msb = tfc_getbits(bucket_ptr, offset, 12);
+		offset += 12;
+
+		if  (bucket_info->entries[i].hash_msb ||
+		     bucket_info->entries[i].entry_ptr) {
+			bucket_info->valid = true;
+
+			em_ptr = (uint8_t *)get_address(lkup_mem_cfg,
+							bucket_info->entries[i].entry_ptr * 32);
+			em_decode((uint32_t *)em_ptr, &bucket_info->em_info[i], act_mem_cfg);
+		}
+	}
+}
+
+static void bucket_show(FILE *fd, struct bucket_info_t *bucket_info, uint32_t offset)
+{
+	int i;
+
+	if (bucket_info->valid) {
+		fprintf(fd, "Static Bucket:0x%08x\n", offset);
+		fputs("+-+ +---------+ +----------------------------------- Entries --------------------------------------------------------------+\n",
+		      fd);
+		fputs(" C     CPtr     0                 1                 2                 3                 4                 5\n",
+		      fd);
+		fputs("+-+ +---------+ +-----+---------+ +-----+---------+ +-----+---------+ +-----+---------+ +-----+---------+ +------+---------+\n",
+		      fd);
+		fprintf(fd, " %d   0x%07x",
+			   bucket_info->chain,
+			   bucket_info->chain_ptr);
+		for (i = 0; i < TFC_BUCKET_ENTRIES; i++) {
+			fprintf(fd, "   0x%03x 0x%07x",
+				   bucket_info->entries[i].hash_msb,
+				   bucket_info->entries[i].entry_ptr);
+		}
+		fputs("\n", fd);
+
+		/*
+		 * Now display each valid EM entry from the bucket
+		 */
+		for (i = 0; i < TFC_BUCKET_ENTRIES; i++) {
+			if (bucket_info->entries[i].entry_ptr != 0) {
+				if (bucket_info->em_info[i].valid)
+					em_show(fd, &bucket_info->em_info[i]);
+				else
+					fputs("<<< Invalid LREC  >>>\n", fd);
+			}
+		}
+
+		fputs("\n", fd);
+	}
+}
+
+int tfc_em_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir)
+{
+	int rc = 0;
+	bool is_shared;
+	bool is_bs_owner;
+	struct tfc_ts_mem_cfg *lkup_mem_cfg;
+	struct tfc_ts_mem_cfg *act_mem_cfg;
+	uint32_t bucket_row;
+	uint32_t bucket_count;
+	uint8_t *bucket_ptr;
+	struct bucket_info_t *bucket_info;
+	uint32_t bucket_offset = 0;
+	bool valid;
+
+	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	if (rc != 0) {
+		fprintf(fd, "%s: failed to get tsid: %d\n",
+			   __func__, rc);
+		return -EINVAL;
+	}
+	if (!valid) {
+		fprintf(fd, "%s: tsid not allocated %d\n",
+			   __func__, tsid);
+		return -EINVAL;
+	}
+
+	lkup_mem_cfg = rte_zmalloc("data", sizeof(*lkup_mem_cfg), 8);
+	if (!lkup_mem_cfg)
+		return -ENOMEM;
+
+	rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid,
+				dir,
+				CFA_REGION_TYPE_LKUP,
+				&is_bs_owner,
+				lkup_mem_cfg);   /* Gets rec_cnt */
+	if (rc != 0) {
+		fprintf(fd, "%s: tfo_ts_get_mem_cfg() failed for LKUP: %d\n",
+			   __func__, rc);
+		rte_free(lkup_mem_cfg);
+		return -EINVAL;
+	}
+
+	act_mem_cfg = rte_zmalloc("data", sizeof(*act_mem_cfg), 8);
+	if (!act_mem_cfg) {
+		rte_free(lkup_mem_cfg);
+		return -ENOMEM;
+	}
+
+	rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid,
+				dir,
+				CFA_REGION_TYPE_ACT,
+				&is_bs_owner,
+				act_mem_cfg);   /* Gets rec_cnt */
+	if (rc != 0) {
+		fprintf(fd, "%s: tfo_ts_get_mem_cfg() failed for ACT: %d\n",
+			   __func__, rc);
+		rte_free(lkup_mem_cfg);
+		rte_free(act_mem_cfg);
+		return -EINVAL;
+	}
+
+	bucket_count = lkup_mem_cfg->lkup_rec_start_offset;
+
+	fputs(" Lookup Table\n", fd);
+	fprintf(fd, " Static bucket count:%d\n", bucket_count);
+
+	bucket_info = rte_zmalloc("data", sizeof(*bucket_info), 8);
+	if (!bucket_info) {
+		fprintf(fd, "%s: Failed to allocate bucket info struct\n",
+			   __func__);
+		rte_free(lkup_mem_cfg);
+		rte_free(act_mem_cfg);
+		return -ENOMEM;
+	}
+
+	/*
+	 * Go through the static buckets looking for valid entries.
+	 * If a valid entry is found then  display it and also display
+	 * the EM entries it points to.
+	 */
+	for (bucket_row = 0; bucket_row < bucket_count; ) {
+		bucket_ptr = (uint8_t *)get_address(lkup_mem_cfg, bucket_offset);
+		bucket_decode((uint32_t *)bucket_ptr, bucket_info, lkup_mem_cfg, act_mem_cfg);
+
+		if (bucket_info->valid)
+			bucket_show(fd, bucket_info, bucket_offset);
+
+		bucket_offset += TFC_BUCKET_SIZE_BYTES;
+		bucket_row++;
+	}
+
+	rte_free(bucket_info);
+	rte_free(lkup_mem_cfg);
+	rte_free(act_mem_cfg);
+
+	return rc;
+}
+
+void tfc_backing_store_dump(FILE *fd)
+{
+	uint16_t port;
+	struct bnxt *bp;
+	uint8_t tsid;
+	int dir;
+
+	RTE_ETH_FOREACH_DEV(port) {
+		bp = bnxt_pmd_get_bp(port);
+		if (bp && !tfo_tsid_get(bp->tfcp.tfo, &tsid)) {
+			for (dir = 0; dir <= 1; dir++) {
+				fputs("+------------------- EM ------------------+\n", fd);
+				fprintf(fd, "+--------- Port:%d TSID:%d DIR:%s ----------+\n",
+					port, tsid, (dir == CFA_DIR_RX ? "rx" : "tx"));
+				fputs("+-----------------------------------------+\n", fd);
+				tfc_em_show(fd, &bp->tfcp, tsid, dir);
+
+				fputs("+------------------- WC ------------------+\n", fd);
+				fprintf(fd, "+--------- Port:%d TSID:%d DIR:%s ----------+\n",
+					port, tsid, (dir == CFA_DIR_RX ? "rx" : "tx"));
+				fputs("+-----------------------------------------+\n", fd);
+				tfc_wc_show(fd, &bp->tfcp, tsid, dir);
+			}
+		}
+	}
+}
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_mpc_table.c b/drivers/net/bnxt/tf_core/v3/tfc_mpc_table.c
deleted file mode 100644
index be16d00deb..0000000000
--- a/drivers/net/bnxt/tf_core/v3/tfc_mpc_table.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2019-2021 Broadcom
- * All rights reserved.
- */
-#include <stdio.h>
-#include <inttypes.h>
-#include <math.h>
-
-#include "bnxt.h"
-#include "bnxt_mpc.h"
-
-#include "tfc.h"
-#include "cfa_bld_mpc_field_ids.h"
-#include "cfa_bld_mpcops.h"
-#include "tfo.h"
-#include "tfc_em.h"
-#include "tfc_cpm.h"
-#include "tfc_msg.h"
-#include "tfc_debug.h"
-#include "cfa_types.h"
-#include "cfa_mm.h"
-#include "sys_util.h"
-#include "cfa_bld.h"
-#include "tfc_util.h"
-
-int tfc_mpc_table_read(struct tfc *tfcp,
-		       uint8_t tsid,
-		       enum cfa_dir dir,
-		       uint32_t type,
-		       uint32_t offset,
-		       uint8_t words,
-		       uint8_t *data,
-		       uint8_t debug)
-{
-	int rc = 0;
-	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
-	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
-	int i;
-	uint32_t buff_len;
-	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_READ_CMD_MAX_FLD];
-	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_READ_CMP_MAX_FLD];
-	struct bnxt_mpc_mbuf mpc_msg_in;
-	struct bnxt_mpc_mbuf mpc_msg_out;
-	bool is_shared;
-	struct cfa_bld_mpcinfo *mpc_info;
-	uint64_t host_address;
-	uint8_t discard_data[128];
-	uint32_t set;
-	uint32_t way;
-	bool valid;
-
-	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
-
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
-	if (rc != 0) {
-		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
-		return -EINVAL;
-	}
-	if (!valid) {
-		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
-		return -EINVAL;
-	}
-
-	/* Check that data pointer is word aligned */
-	if (((uint64_t)data)  & 0x1fULL) {
-		PMD_DRV_LOG_LINE(ERR, "Table read data pointer not word aligned");
-		return -EINVAL;
-	}
-
-	host_address = (uint64_t)rte_mem_virt2iova(data);
-
-	/* Check that MPC APIs are bound */
-	if (mpc_info->mpcops == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "MPC not initialized");
-		return -EINVAL;
-	}
-
-	set =  offset & 0x7ff;
-	way = (offset >> 12)  & 0xf;
-
-	if (debug)
-		PMD_DRV_LOG_LINE(ERR,
-				 "Debug read table type:%s %d words32B at way:%d set:%d debug:%d words32B",
-				 (type  == 0 ? "Lookup" : "Action"),
-				 words, way, set, debug);
-	else
-		PMD_DRV_LOG_LINE(ERR,
-				 "Reading table type:%s %d words32B at offset %d words32B",
-				 (type  == 0 ? "Lookup" : "Action"),
-				 words, offset);
-
-	/* Create MPC EM insert command using builder */
-	for (i = 0; i < CFA_BLD_MPC_READ_CMD_MAX_FLD; i++)
-		fields_cmd[i].field_id = INVALID_U16;
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_OPAQUE_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_OPAQUE_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_OPAQUE_FLD].val = 0xAA;
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
-	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_SCOPE_FLD].val =
-		(debug ? way : tsid);
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_DATA_SIZE_FLD].val = words;
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_TABLE_INDEX_FLD].val =
-		(debug ? set : offset);
-
-	fields_cmd[CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD;
-	fields_cmd[CFA_BLD_MPC_READ_CMD_HOST_ADDRESS_FLD].val = host_address;
-
-	if (debug) {
-		fields_cmd[CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD].field_id =
-		CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD;
-		fields_cmd[CFA_BLD_MPC_READ_CMD_CACHE_OPTION_FLD].val = debug; /* Debug read */
-	}
-
-	buff_len = TFC_MPC_MAX_TX_BYTES;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_read(tx_msg,
-							    &buff_len,
-							    fields_cmd);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "Action read build failed: %d", rc);
-		goto cleanup;
-	}
-
-	/* Send MPC */
-	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
-	mpc_msg_in.msg_data = &tx_msg[16];
-	mpc_msg_in.msg_size = 16;
-	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
-	mpc_msg_out.msg_data = &rx_msg[16];
-	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
-
-	rc = tfc_mpc_send(tfcp->bp,
-			  &mpc_msg_in,
-			  &mpc_msg_out,
-			  &msg_count,
-			  TFC_MPC_TABLE_READ,
-			  NULL);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "Table read MPC send failed: %d", rc);
-		goto cleanup;
-	}
-
-		/* Process response */
-	for (i = 0; i < CFA_BLD_MPC_READ_CMP_MAX_FLD; i++)
-		fields_cmp[i].field_id = INVALID_U16;
-
-	fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].field_id =
-		CFA_BLD_MPC_READ_CMP_STATUS_FLD;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_read(rx_msg,
-							    mpc_msg_out.msg_size,
-							    discard_data,
-							    words * TFC_MPC_BYTES_PER_WORD,
-							    fields_cmp);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "Table read parse failed: %d", rc);
-		goto cleanup;
-	}
-
-	if (fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
-		PMD_DRV_LOG_LINE(ERR, "Table read failed with status code:%d",
-				 (uint32_t)fields_cmp[CFA_BLD_MPC_READ_CMP_STATUS_FLD].val);
-		rc = -1;
-		goto cleanup;
-	}
-
-	return 0;
-
- cleanup:
-
-	return rc;
-}
-
-int tfc_mpc_table_write_zero(struct tfc *tfcp,
-			     uint8_t tsid,
-			     enum cfa_dir dir,
-			     uint32_t type,
-			     uint32_t offset,
-			     uint8_t words,
-			     uint8_t *data)
-{
-	int rc = 0;
-	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
-	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
-	int i;
-	uint32_t buff_len;
-	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_WRITE_CMD_MAX_FLD];
-	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_WRITE_CMP_MAX_FLD];
-	struct bnxt_mpc_mbuf mpc_msg_in;
-	struct bnxt_mpc_mbuf mpc_msg_out;
-	struct cfa_bld_mpcinfo *mpc_info;
-	bool is_shared;
-	bool valid;
-
-	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
-
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
-	if (rc != 0) {
-		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
-		return -EINVAL;
-	}
-	if (!valid) {
-		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
-		return -EINVAL;
-	}
-	/* Check that MPC APIs are bound */
-	if (mpc_info->mpcops == NULL) {
-		PMD_DRV_LOG_LINE(ERR, " MPC not initialized");
-		return -EINVAL;
-	}
-
-	/* Create MPC EM insert command using builder */
-	for (i = 0; i < CFA_BLD_MPC_WRITE_CMD_MAX_FLD; i++)
-		fields_cmd[i].field_id = INVALID_U16;
-
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD;
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_OPAQUE_FLD].val = 0xAA;
-
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD;
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
-	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
-
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD;
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_SCOPE_FLD].val = tsid;
-
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD;
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_DATA_SIZE_FLD].val = words;
-
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD;
-	fields_cmd[CFA_BLD_MPC_WRITE_CMD_TABLE_INDEX_FLD].val = offset;
-
-	buff_len = TFC_MPC_MAX_TX_BYTES;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_write(tx_msg,
-							     &buff_len,
-							     data,
-							     fields_cmd);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "write build failed: %d", rc);
-		goto cleanup;
-	}
-
-	/* Send MPC */
-	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
-	mpc_msg_in.msg_data = &tx_msg[16];
-	mpc_msg_in.msg_size = (words * TFC_MPC_BYTES_PER_WORD) + 16;
-	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
-	mpc_msg_out.msg_data = &rx_msg[16];
-	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
-
-	rc = tfc_mpc_send(tfcp->bp,
-			  &mpc_msg_in,
-			  &mpc_msg_out,
-			  &msg_count,
-			  TFC_MPC_TABLE_WRITE,
-			  NULL);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "write MPC send failed: %d", rc);
-		goto cleanup;
-	}
-
-	/* Process response */
-	for (i = 0; i < CFA_BLD_MPC_WRITE_CMP_MAX_FLD; i++)
-		fields_cmp[i].field_id = INVALID_U16;
-
-	fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].field_id =
-		CFA_BLD_MPC_WRITE_CMP_STATUS_FLD;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_write(rx_msg,
-							     mpc_msg_out.msg_size,
-							     fields_cmp);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "write parse failed: %d", rc);
-		goto cleanup;
-	}
-
-	if (fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
-		PMD_DRV_LOG_LINE(ERR, "Action write failed with status code:%d",
-				 (uint32_t)fields_cmp[CFA_BLD_MPC_WRITE_CMP_STATUS_FLD].val);
-		PMD_DRV_LOG_LINE(ERR, "Hash MSB:0x%0x",
-		       (uint32_t)fields_cmp[CFA_BLD_MPC_WRITE_CMP_HASH_MSB_FLD].val);
-		goto cleanup;
-	}
-
-	return 0;
-
- cleanup:
-
-	return rc;
-}
-
-int tfc_mpc_table_invalidate(struct tfc *tfcp,
-			     uint8_t tsid,
-			     enum cfa_dir dir,
-			     uint32_t type,
-			     uint32_t offset,
-			     uint32_t words)
-{
-	int rc = 0;
-	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
-	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
-	int i;
-	uint32_t buff_len;
-	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_MAX_FLD];
-	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_MAX_FLD];
-	struct bnxt_mpc_mbuf mpc_msg_in;
-	struct bnxt_mpc_mbuf mpc_msg_out;
-	struct cfa_bld_mpcinfo *mpc_info;
-	bool is_shared;
-	bool valid;
-
-	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
-
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
-	if (rc != 0) {
-		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
-		return -EINVAL;
-	}
-	if (!valid) {
-		PMD_DRV_LOG_LINE(ERR, "tsid not allocated %d", tsid);
-		return -EINVAL;
-	}
-	/* Check that MPC APIs are bound */
-	if (mpc_info->mpcops == NULL) {
-		PMD_DRV_LOG_LINE(ERR, " MPC not initialized");
-		return -EINVAL;
-	}
-
-	/* Create MPC EM insert command using builder */
-	for (i = 0; i < CFA_BLD_MPC_INVALIDATE_CMD_MAX_FLD; i++)
-		fields_cmd[i].field_id = INVALID_U16;
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_OPAQUE_FLD].val = 0xAA;
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_TYPE_FLD].val = (type == 0 ?
-	       CFA_BLD_MPC_HW_TABLE_TYPE_LOOKUP : CFA_BLD_MPC_HW_TABLE_TYPE_ACTION);
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_SCOPE_FLD].val = tsid;
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_DATA_SIZE_FLD].val = words;
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_TABLE_INDEX_FLD].val = offset;
-
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD;
-	fields_cmd[CFA_BLD_MPC_INVALIDATE_CMD_CACHE_OPTION_FLD].val =
-		CFA_BLD_MPC_EV_EVICT_SCOPE_ADDRESS;
-
-	buff_len = TFC_MPC_MAX_TX_BYTES;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_build_cache_evict(tx_msg,
-							     &buff_len,
-							     fields_cmd);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "evict build failed: %d", rc);
-		goto cleanup;
-	}
-
-	/* Send MPC */
-	mpc_msg_in.chnl_id = (dir == CFA_DIR_TX ?
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_TE_CFA :
-			      HWRM_RING_ALLOC_INPUT_MPC_CHNLS_TYPE_RE_CFA);
-	mpc_msg_in.msg_data = &tx_msg[16];
-	mpc_msg_in.msg_size = 16;
-	mpc_msg_out.cmp_type = CMPL_BASE_TYPE_MID_PATH_SHORT;
-	mpc_msg_out.msg_data = &rx_msg[16];
-	mpc_msg_out.msg_size = TFC_MPC_MAX_RX_BYTES;
-
-	rc = tfc_mpc_send(tfcp->bp,
-			  &mpc_msg_in,
-			  &mpc_msg_out,
-			  &msg_count,
-			  TFC_MPC_INVALIDATE,
-			  NULL);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "write MPC send failed: %d", rc);
-		goto cleanup;
-	}
-
-	/* Process response */
-	for (i = 0; i < CFA_BLD_MPC_INVALIDATE_CMP_MAX_FLD; i++)
-		fields_cmp[i].field_id = INVALID_U16;
-
-	fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].field_id =
-		CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD;
-
-	rc = mpc_info->mpcops->cfa_bld_mpc_parse_cache_evict(rx_msg,
-							     mpc_msg_out.msg_size,
-							     fields_cmp);
-
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "evict parse failed: %d", rc);
-		goto cleanup;
-	}
-
-	if (fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].val != CFA_BLD_MPC_OK) {
-		PMD_DRV_LOG_LINE(ERR, "evict failed with status code:%d",
-				 (uint32_t)fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_STATUS_FLD].val);
-		PMD_DRV_LOG_LINE(ERR, "Hash MSB:0x%0x",
-		       (uint32_t)fields_cmp[CFA_BLD_MPC_INVALIDATE_CMP_HASH_MSB_FLD].val);
-		goto cleanup;
-	}
-
-	return 0;
-
- cleanup:
-
-	return rc;
-}
-
-#define TFC_ACTION_SIZE_BYTES  32
-#define TFC_BUCKET_SIZE_BYTES  32
-
-struct act_full_info_t {
-	bool drop;
-	uint8_t vlan_del_rep;
-	uint8_t dest_op;
-	uint16_t vnic_vport;
-	uint8_t decap_func;
-	uint16_t mirror;
-	uint16_t meter_ptr;
-	uint8_t stat0_ctr_type;
-	bool stat0_ing_egr;
-	uint32_t stat0_ptr;
-	uint8_t stat1_ctr_type;
-	bool stat1_ing_egr;
-	uint32_t stat1_ptr;
-	uint32_t mod_ptr;
-	uint32_t enc_ptr;
-	uint32_t src_ptr;
-	char mod_str[512];
-};
-
-struct act_mcg_info_t {
-	uint8_t src_ko_en;
-	uint32_t nxt_ptr;
-	uint8_t act_hint0;
-	uint32_t act_rec_ptr0;
-	uint8_t act_hint1;
-	uint32_t act_rec_ptr1;
-	uint8_t act_hint2;
-	uint32_t act_rec_ptr2;
-	uint8_t act_hint3;
-	uint32_t act_rec_ptr3;
-	uint8_t act_hint4;
-	uint32_t act_rec_ptr4;
-	uint8_t act_hint5;
-	uint32_t act_rec_ptr5;
-	uint8_t act_hint6;
-	uint32_t act_rec_ptr6;
-	uint8_t act_hint7;
-	uint32_t act_rec_ptr7;
-};
-
-struct act_info_t {
-	bool valid;
-	uint8_t vector;
-	union {
-		struct act_full_info_t full;
-		struct act_mcg_info_t mcg;
-	};
-};
-
-struct mod_field_s {
-	uint8_t num_bits;
-	const char *name;
-};
-
-struct mod_data_s {
-	uint8_t num_fields;
-	const char *name;
-	struct mod_field_s field[4];
-};
-
-struct mod_data_s mod_data[] = {
-	{1, "Replace:", {{16,  "DPort"} } },
-	{1, "Replace:", {{16,  "SPort"} } },
-	{1, "Replace:", {{32,  "IPv4 DIP"} } },
-	{1, "Replace:", {{32,  "IPv4 SIP"} } },
-	{1, "Replace:", {{128, "IPv6 DIP"} } },
-	{1, "Replace:", {{128, "IPv6 SIP"} } },
-	{1, "Replace:", {{48,  "SMAC"} } },
-	{1, "Replace:", {{48,  "DMAC"} } },
-	{2, "Update Field:",  {{16, "uf_vec"}, {32, "uf_data"} } },
-	{3, "Tunnel Modify:", {{16, "tun_mv"}, {16, "tun_ex_prot"}, {16, "tun_new_prot"} } },
-	{3, "TTL Update:",    {{5,  "alt_pfid"}, {12, "alt_vid"}, {5, "ttl_op"} } },
-	{4, "Replace/Add Outer VLAN:", {{16, "tpid"}, {3, "pri"}, {1, "de"}, {12, "vid"} } },
-	{4, "Replace/Add Inner:",      {{16, "tpid"}, {3, "pri"}, {1, "de"}, {12, "vid"} } },
-	{0, "Remove outer VLAN:", {{0, NULL} } },
-	{0, "Remove inner VLAN:", {{0, NULL} } },
-	{4, "Metadata Update:",   {{2, "md_op"}, {4, "md_prof"}, {10, "rsvd"}, {32, "md_data"} } },
-};
-
-struct stat_fields_s {
-	uint64_t pkt_cnt;
-	uint64_t byte_cnt;
-	union {
-		struct __rte_packed_begin {
-			uint32_t timestamp;
-			uint16_t tcp_flags;
-		} c_24b __rte_packed_end;
-		struct {
-			uint64_t meter_pkt_cnt;
-			uint64_t meter_byte_cnt;
-		} c_32b;
-		struct __rte_packed_begin {
-			uint64_t timestamp:32;
-			uint64_t tcp_flags:16;
-			uint64_t meter_pkt_cnt:38;
-			uint64_t meter_byte_cnt:42;
-		} c_32b_all __rte_packed_end;
-	} t;
-};
-
-#define STATS_COMMON_FMT    \
-	"\tPkt count    : 0x%016" PRIu64 ", Byte count    : 0x%016" PRIu64 "\n"
-#define STATS_METER_FMT     \
-	"\tMeter pkt cnt: 0x%016" PRIx64 ", Meter byte cnt: 0x%016" PRIx64 "\n"
-#define STATS_TCP_FLAGS_FMT \
-	"\tTCP flags    : 0x%04x, timestamp     : 0x%08x\n"
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c b/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c
new file mode 100644
index 0000000000..0527e34525
--- /dev/null
+++ b/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c
@@ -0,0 +1,1875 @@
+// SPDX-License-Identifier: BSD-3-Clause
+/* Copyright(c) 2024 Broadcom
+ * All rights reserved.
+ */
+#include <stdio.h>
+#include <inttypes.h>
+#include <string.h>
+
+#include "bnxt.h"
+
+#include "tfc.h"
+#include "tfo.h"
+#include "tfc_em.h"
+#include "tfc_debug.h"
+#include "cfa_types.h"
+
+#include "sys_util.h"
+#include "tfc_util.h"
+/* only debug files can include ULP headers */
+#include "ulp_flow_db.h"
+#include "bnxt_ulp_tfc.h"
+#include "bnxt_ulp_utils.h"
+#include "tfc_debug.h"
+
+#define TFC_STRING_LENGTH_32  32
+#define TFC_STRING_LENGTH_64  64
+#define TFC_STRING_LENGTH_96  96
+#define TFC_STRING_LENGTH_256 256
+
+/* Enable this flag if you want to dump all TCAM records,
+ * including the default L2 context records and profile TCAM
+ * entries. This method is sub-optimal, but can used for lack of
+ * a better way to walk and dump flow DB resources for particular
+ * flow types.
+ * Disabling this flag will dump WC TCAM entries and their
+ * associated action-records by default.
+ */
+#define TFC_DEBUG_DUMP_ALL_FLOWS 1
+
+/*
+ * Function pointer type for custom processing resources
+ */
+typedef int (*FDB_RESOURCE_PROCFUNC)(struct ulp_flow_db_res_params *rp,
+				     void *frp_ctxt);
+static
+void hex_buf_dump(FILE *fd, const char *hdr, uint8_t *msg,
+		  int msglen, int prtwidth, int linewidth);
+
+struct wc_frp_context {
+	FILE *fd;
+	struct bnxt_ulp_context *ulp_ctxt;
+	struct tfc_ts_mem_cfg *act_mem_cfg;
+};
+
+struct wc_lrec_t {
+	bool valid;
+	uint8_t rec_size;
+	uint16_t epoch0;
+	uint16_t epoch1;
+	uint8_t opcode;
+	uint8_t strength;
+	uint8_t act_hint;
+	uint32_t act_rec_ptr;	/* Not FAST */
+	uint32_t destination;	/* Just FAST */
+	uint8_t tcp_direction;	/* Just CT */
+	uint8_t tcp_update_en;
+	uint8_t tcp_win;
+	uint32_t tcp_msb_loc;
+	uint32_t tcp_msb_opp;
+	uint8_t tcp_msb_opp_init;
+	uint8_t state;
+	uint8_t timer_value;
+	uint16_t ring_table_idx;	/* Not CT and not RECYCLE */
+	uint8_t act_rec_size;
+	uint8_t paths_m1;
+	uint8_t fc_op;
+	uint8_t fc_type;
+	uint32_t fc_ptr;
+	uint8_t recycle_dest;	/* Just Recycle */
+	uint8_t prof_func;
+	uint8_t meta_prof;
+	uint32_t metadata;
+	uint8_t range_profile;
+	uint16_t range_index;
+	struct act_info_t act_info;
+};
+
+/* L2 context TCAM key formats
+ *
+ * IPv4
+ * ----
+ * valid                       255       1   TCAM entry is valid
+ * spare                       254:253   2   Spare bits.
+ * mpass_cnt                   252:251   2   Multi-pass cycle count ? {0,1,2,3}
+ * rcyc[3:0]                   250:247   4   Recycle count from prof_in
+ * loopback                    246       1   loopback input from prof_in
+ * spif                        245:244   2   Source network port from prof_in
+ * parif                       243:239   5   Partition provided by input block
+ * svif                        238:228   11  Source of the packet: Ethernet network port or
+ *                                           vnic; provided on prof_in
+ * metadata                    227:196   32  Metadata provided by Input block
+ * l2ip_func                   195:188   8   Used to create logical (feature specific) context
+ *                                           TCAM tables. Provided from ILT or Recycle.
+ * roce                        187       1   ROCE Packet detected by the Parser
+ * pure_llc                    186       1   Pure LLC Packet detected by the Parser. If set
+ *                                           the etype field will contain the DSAP/SSAP from
+ *                                           LLC header.
+ * ot_hdr_type                 185:181   5   5b encoded Outer Tunnel Type (see Table 4-12)
+ * t_hdr_type                  180:176   5   5b encoded Tunnel Type (see Table 4-12)
+ * tunnel_id/context/L4        175:144   32  Tunnel ID/Tunnel Context/L4 ports selected.
+ * ADDR0                       143:96    48  ADDR0: DMAC/SMAC/IPv4 selected.
+ * ADDR1                       95:48     48  ADDR1: DMAC/SMAC/IPv4 selected.
+ * otl2/tl2/l2_vtag_present    47        1   1+ VLAN tags present (L2 selected)
+ * otl2/tl2/l2_two_vtags       46        1   2 VLAN tags present (comp. flds_num_vtags)
+ * otl2/tl2/l2_ovlan_vid       45:34     12  VID from outer VLAN tag if present (L2 selected)
+ * otl2/tl2/l2_ovlan_tpid_sel  33:31     3   3b encoding for TPID (L2 selected)
+ * otl2/tl2/l2_ivlan_vid       30:19     12  VID from inner VLAN tag if present (L2 selected)
+ * otl2/tl2/l2_ivlan_tpid_sel  18:16     3   3b encoding for TPID (L2 selected)
+ * otl2/tl2/l2_etype           15:0      16  L2 Header Ethertype (L2 selected)
+ *
+ * IPv6
+ * ----
+ * valid                 255      1    TCAM entry is valid
+ * spare                 254:253  2    Spare bits.
+ * mpass_cnt             252:251  2    Multi-pass cycle count ? {0,1,2,3}
+ * rcyc[3:0]             250:247  4    Recycle count from prof_in
+ * loopback              246      1    loopback input from prof_in
+ * spif                  245:244  2    Source network port from prof_in
+ * parif                 243:239  5    Partition provided by input block
+ * svif                  238:228  11   Source of the packet: Ethernet network port or
+ *                                     vnic; provided on prof_in
+ * metadata              227:196  32   Metadata provided by Input block
+ * l2ip_func             195:188  8    Used to create logical (feature specific) context
+ *                                     TCAM tables. Provided from ILT or Recycle.
+ * roce                  187      1    ROCE Packet detected by the Parser
+ * pure_llc              186      1    Pure LLC Packet detected by the Parser. If set
+ *                                     the etype field will contain the DSAP/SSAP from
+ *                                     LLC header.
+ * ot_hdr_type           185:181  5    5b encoded Outer Tunnel Type (see Table 4-12)
+ * t_hdr_type            180:176  5    5b encoded Tunnel Type (see Table 4-12)
+ * tunnel_id/context/L4  175:144  32   Tunnel ID/Tunnel Context/L4 ports selected.
+ * ADDR0                 143:16   128  ADDR0: IPv6 selected.
+ * otl2/tl2/l2_etype     15:0     16   L2 Header Ethertype (L2 selected)
+ */
+struct l2ctx_tcam_key_t {
+	uint8_t valid;
+	uint8_t spare;
+	uint8_t mpass_cnt;
+	uint8_t rcyc;
+	uint8_t loopback;
+	uint8_t spif;
+	uint8_t parif;
+	uint16_t svif;
+	uint32_t metadata;
+	uint8_t l2ip_func;
+	uint8_t roce;
+	uint8_t pure_llc;
+	uint8_t ot_hdr_type;
+	uint8_t t_hdr_type;
+	uint32_t tunnel_id_context_L4;
+	union {
+		struct ipv4_key_t {
+			uint64_t ADDR0;
+			uint64_t ADDR1;
+			uint8_t otl2_tl2_l2_vtag_present;
+			uint8_t otl2_tl2_l2_two_vtags;
+			uint16_t otl2_tl2_l2_ovlan_vid;
+			uint8_t otl2_tl2_l2_ovlan_tpid_sel;
+			uint16_t otl2_tl2_l2_ivlan_vid;
+			uint8_t otl2_tl2_l2_ivlan_tpid_sel;
+			uint16_t otl2_tl2_l2_etype;
+		} ipv4;
+		struct ipv6_key_t {
+			uint64_t ADDR0[2];
+			uint16_t otl2_tl2_l2_etype;
+		} ipv6;
+	};
+};
+
+/* L2 context TCAM remap
+ *
+ * prsv_parif      126      1   Preserve incoming partition, i.e. don?t remap.
+ * parif           125:121  5   Partition. Replaces parif from Input block
+ * prsv_l2ip_ctxt  120      1   Preserve incoming l2ip_ctxt, i.e. don?t remap.
+ * l2ip_ctxt       119:109  11  May be used in EM and WC Lookups to support logical
+ *                              partitions of these tables
+ * prsv_prof_func  108      1   Preserve incoming PROF_FUNC, i.e. don?t remap.
+ * prof_func       107:100  8   Allow Profile TCAM Lookup Table to be logically partitioned.
+ * ctxt_opcode     99:98    2   0: BYPASS_CFA
+ *                              1: BYPASS_LKUP
+ *                              2: NORMAL_FLOW
+ *                              3: DROP
+ * l2ip_meta_enb   97       1   Enables remap of meta_data from Input block.
+ * l2ip_meta       96:62    35  l2ip_meta_prof[2:0] = l2ip_meta[34:32]
+ *                              l2ip_meta_data[31:0] = l2ip_meta[31:0]
+ * l2ip_act_enb    61       1   Enables remap of Action Record pointer from Input block.
+ * l2ip_act_data   60:28    33  l2ip_act_hint[1:0] = l2ip_act_data[32:31]
+ *                              l2ip_act_scope[4:0] = l2ip_act_data[30:26]
+ *                              l2ip_act_rec_ptr[25:0] = l2ip_act_data[25:0]
+ * l2ip_rfs_enb    27       1   Enables remap of ring_table_idx and sets rfs_valid.
+ * l2ip_rfs_data   26:18    9   ring_table_idx[8:0] = l2ip_rfs_data[8:0] (RX only)
+ * l2ip_dest_enb   17       1   Enables remap of destination from Input block.
+ * l2ip_dest_data  16:0     17  destination[16:0] = l2ip_dest_data[16:0]
+ */
+struct l2ctx_tcam_remap_t {
+	uint8_t prsv_parif;
+	uint8_t parif;
+	uint8_t prsv_l2ip_ctxt;
+	uint16_t l2ip_ctxt;
+	uint8_t prsv_prof_func;
+	uint8_t prof_func;
+	uint8_t ctxt_opcode;
+	uint8_t l2ip_meta_enb;
+	uint8_t l2ip_meta_prof;
+	uint32_t l2ip_meta_data;
+	uint8_t l2ip_act_enb;
+	uint8_t l2ip_act_hint;
+	uint8_t l2ip_act_scope;
+	uint32_t l2ip_act_ptr;
+	uint8_t l2ip_rfs_enb;
+	uint16_t l2ip_rfs_data;
+	uint8_t l2ip_dest_enb;
+	uint32_t l2ip_dest_data;
+	struct act_info_t act_info;
+};
+
+/* Profile TCAM key
+ *
+ * valid                 183      1  Valid(1)/Invalid(0) TCAM entry.
+ * spare                 182:181  2  Spare bits.
+ * loopback              180      1  END.loopback
+ * pkt_type              179:176  4  Packet type directly from END bus.
+ * rcyc[3:0]             175:172  4  Recycle count from prof_in
+ * metadata              171:140  32 From previous stage.
+ * agg_error             139      1  Aggregate error flag from Input stage.
+ * l2ip_func             138:131  8  L2-IP Context function from Input Lookup stage.
+ * prof_func             130:123  8  Profile function from L2-IP Context Lookup stage.
+ * hrec_next             122:121  2  From FLDS Input, General Status
+ *                                   1=tunnel/0=no tunnel
+ * int_hdr_type          120:119  2  INT header type directly from FLDS.
+ * int_hdr_group         118:117  2  INT header group directly from FLDS.
+ * int_ifa_tail          116      1  INT metadata is tail stamp.
+ * otl2_hdr_valid        115      1  !(flds_otl2_hdr_valid==stop_w_error |
+ *                                     flds_otl2_hdr_valid==not_reached)
+ * otl2_hdr_type         114:113  2  Outer Tunnel L2 header type directly from FLDS.
+ * otl2_uc_mc_bc         112:111  2  flds_otl2_dst_type remapped: UC(0)/MC(2)/BC(3)
+ * otl2_vtag_present     110      1  1+ VLAN tags present (comp. lds_otl2_num_vtags)
+ * otl2_two_vtags        109      1  2 VLAN tags present (comp. flds_otl2_num_vtags)
+ * otl3_hdr_valid        108      1  !(flds_otl3_hdr_valid== stop_w_error |
+ *                                     flds_otl3_hdr_valid== not_reached )
+ * otl3_hdr_error        107      1  flds_tl3_hdr_valid == stop_w_error
+ * otl3_hdr_type         106:103  4  Outer Tunnel L3 header type directly from FLDS.
+ * otl3_hdr_isip         102      1  Outer Tunnel L3 header is IPV4 or IPV6.
+ * otl4_hdr_valid        101      1  !(flds_otl4_hdr_valid== stop_w_error |
+ *                                     flds_otl4_hdr_valid== not_reached )
+ * otl4_hdr_error        100      1  flds_otl4_hdr_valid == stop_w_error
+ * otl4_hdr_type         99:96    4  Outer Tunnel L4 header type directly from FLDS.
+ * otl4_hdr_is_udp_tcp   95       1  OTL4 header is UDP-TCP. (comp. flds_otl4_hdr_type)
+ * ot_hdr_valid          94       1  !(flds_ot_hdr_valid== stop_w_error |
+ *                                     flds_ot_hdr_valid== not_reached )
+ * ot_hdr_error          93       1  flds_ot_hdr_valid == stop_w_error
+ * ot_hdr_type           92:88    5  Outer Tunnel header type directly from FLDS.
+ * ot_hdr_flags          87:80    8  Outer Tunnel header flags directly from FLDS.
+ * tl2_hdr_valid         79       1  !(flds_tl2_hdr_valid==stop_w_error |
+ *                                     flds_tl2_hdr_valid==not_reached)
+ * tl2_hdr_type          78:77    2  Tunnel L2 header type directly from FLDS.
+ * tl2_uc_mc_bc          76:75    2  flds_tl2_dst_type remapped: UC(0)/MC(2)/BC(3)
+ * tl2_vtag_present      74       1  1+ VLAN tags present (comp. lds_tl2_num_vtags)
+ * tl2_two_vtags         73       1  2 VLAN tags present (comp. flds_tl2_num_vtags)
+ * tl3_hdr_valid         72       1  !(flds_tl3_hdr_valid== stop_w_error |
+ *                                     flds_tl3_hdr_valid== not_reached )
+ * tl3_hdr_error         71       1  flds_tl3_hdr_valid == stop_w_error
+ * tl3_hdr_type          70:67    4  Tunnel L3 header type directly from FLDS.
+ * tl3_hdr_isip          66       1  Tunnel L3 header is IPV4 or IPV6.
+ * tl4_hdr_valid         65       1  !(flds_tl4_hdr_valid== stop_w_error |
+ *                                     flds_tl4_hdr_valid== not_reached )
+ * tl4_hdr_error         64       1  flds_tl4_hdr_valid == stop_w_error
+ * tl4_hdr_type          63:60    4  Tunnel L4 header type directly from FLDS.
+ * tl4_hdr_is_udp_tcp    59       1  TL4 header is UDP or TCP. (comp. flds_tl4_hdr_type)
+ * t_hdr_valid           58       1  !(flds_tun_hdr_valid== stop_w_error |
+ *                                     flds_tun_hdr_valid== not_reached )
+ * t_hdr_error           57       1  flds_tun_hdr_valid == stop_w_error
+ * t_hdr_type            56:52    5  Tunnel header type directly from FLDS.
+ * t_hdr_flags           51:44    8  Tunnel header flags directly from FLDS.
+ * l2_hdr_valid          43       1  !(flds_l2_hdr_valid== stop_w_error |
+ *                                     flds_l2_hdr_valid== not_reached )
+ * l2_hdr_error          42       1  flds_l2_hdr_valid == stop_w_error
+ * l2_hdr_type           41:40    2  L2 header type directly from FLDS.
+ * l2_uc_mc_bc           39:38    2  flds_l2_dst_type remapped: UC(0)/MC(2)/BC(3)
+ * l2_vtag_present       37       1  1+ VLAN tags present (comp. flds_l2_num_vtags)
+ * l2_two_vtags          36       1  2 VLAN tags present (comp. flds_l2_num_vtags)
+ * l3_hdr_valid          35       1  !(flds_l3_hdr_valid== stop_w_error |
+ *                                     flds_l3_hdr_valid== not_reached )
+ * l3_hdr_error          34       1  flds_l3_hdr_valid == stop_w_error
+ * l3_hdr_type           33:30    4  L3 header type directly from FLDS.
+ * l3_hdr_isip           29       1  L3 header is IPV4 or IPV6.
+ * l3_protocol           28:21    8  L3 header next protocol directly from FLDS.
+ * l4_hdr_valid          20       1  !(flds_l4_hdr_valid== stop_w_error |
+ *                                     flds_l4_hdr_valid== not_reached )
+ * l4_hdr_error          19       1  flds_l4_hdr_valid == stop_w_error
+ * l4_hdr_type           18:15    4  L4 header type directly from FLDS.
+ * l4_hdr_is_udp_tcp     14       1  L4 header is UDP or TCP (comp. flds_l4_hdr_type)
+ * l4_hdr_subtype        13:11    3  L4 header sub-type directly from FLDS.
+ * l4_flags              10:2     9  L4 header flags directly from FLDS.
+ * l4_dcn_present        1:0      2  DCN present bits directly from L4 header FLDS.
+ */
+
+struct prof_tcam_key_t {
+	uint8_t valid;
+	uint8_t spare;
+	uint8_t loopback;
+	uint8_t pkt_type;
+	uint8_t rcyc;
+	uint32_t metadata;
+	uint8_t agg_error;
+	uint8_t l2ip_func;
+	uint8_t prof_func;
+	uint8_t hrec_next;
+	uint8_t int_hdr_type;
+	uint8_t int_hdr_group;
+	uint8_t int_ifa_tail;
+	uint8_t otl2_hdr_valid;
+	uint8_t otl2_hdr_type;
+	uint8_t otl2_uc_mc_bc;
+	uint8_t otl2_vtag_present;
+	uint8_t otl2_two_vtags;
+	uint8_t otl3_hdr_valid;
+	uint8_t otl3_hdr_error;
+	uint8_t otl3_hdr_type;
+	uint8_t otl3_hdr_isip;
+	uint8_t otl4_hdr_valid;
+	uint8_t otl4_hdr_error;
+	uint8_t otl4_hdr_type;
+	uint8_t otl4_hdr_is_udp_tcp;
+	uint8_t ot_hdr_valid;
+	uint8_t ot_hdr_error;
+	uint8_t ot_hdr_type;
+	uint8_t ot_hdr_flags;
+	uint8_t tl2_hdr_valid;
+	uint8_t tl2_hdr_type;
+	uint8_t tl2_uc_mc_bc;
+	uint8_t tl2_vtag_present;
+	uint8_t tl2_two_vtags;
+	uint8_t tl3_hdr_valid;
+	uint8_t tl3_hdr_error;
+	uint8_t tl3_hdr_type;
+	uint8_t tl3_hdr_isip;
+	uint8_t tl4_hdr_valid;
+	uint8_t tl4_hdr_error;
+	uint8_t tl4_hdr_type;
+	uint8_t tl4_hdr_is_udp_tcp;
+	uint8_t t_hdr_valid;
+	uint8_t t_hdr_error;
+	uint8_t t_hdr_type;
+	uint8_t t_hdr_flags;
+	uint8_t l2_hdr_valid;
+	uint8_t l2_hdr_error;
+	uint8_t l2_hdr_type;
+	uint8_t l2_uc_mc_bc;
+	uint8_t l2_vtag_present;
+	uint8_t l2_two_vtags;
+	uint8_t l3_hdr_valid;
+	uint8_t l3_hdr_error;
+	uint8_t l3_hdr_type;
+	uint8_t l3_hdr_isip;
+	uint8_t l3_protocol;
+	uint8_t l4_hdr_valid;
+	uint8_t l4_hdr_error;
+	uint8_t l4_hdr_type;
+	uint8_t l4_hdr_is_udp_tcp;
+	uint8_t l4_hdr_subtype;
+	uint16_t l4_flags;
+	uint8_t l4_dcn_present;
+};
+
+/*
+ * Profile TCAM remap record:
+ *
+ * pl_byp_lkup_en   1  42     When set to ?0? remaining bits are defined below.
+ * em_search_en     1  41     Enable search in EM database
+ * em_profile_id    8  40:33  Selected key structure for EM search. This is used as part of
+ *                            the EM keys to differentiate common key types.
+ * em_key_id        7  32:26  Exact match key template select
+ * em_scope         5  25:21  Exact Match Lookup scope. Action scope on EM hit.
+ * tcam_search_en   1  20     Enable search in TCAM database
+ * tcam_profile_id  8  19:12  Selected key structure for TCAM search. This is used as part of
+ *                            the TCAM keys to differentiate common key types.
+ * tcam_key_id      7  11:5   TCAM key template select
+ * tcam_scope       5  4:0    Wild Card Lookup Action table scope (used if WC hits).
+ */
+struct prof_tcam_remap_t {
+	bool pl_byp_lkup_en;
+	bool em_search_en;
+	uint8_t em_profile_id;
+	uint8_t em_key_id;
+	uint8_t em_scope;
+	bool tcam_search_en;
+	uint8_t tcam_profile_id;
+	uint8_t tcam_key_id;
+	uint8_t tcam_scope;
+};
+
+/* Internal function to read the tcam entry */
+static int
+tfc_tcam_entry_read(struct bnxt_ulp_context *ulp_ctxt,
+		    uint8_t dir,
+		    uint8_t res_type,
+		    uint16_t res_idx,
+		    uint8_t *key,
+		    uint8_t *mask,
+		    uint8_t *remap,
+		    uint16_t *key_size,
+		    uint16_t *remap_size)
+{
+	struct tfc_tcam_info tfc_info = {0};
+	struct tfc_tcam_data tfc_data = {0};
+	struct tfc *tfcp = NULL;
+	uint16_t fw_fid;
+	int rc;
+
+	tfcp = bnxt_ulp_cntxt_tfcp_get(ulp_ctxt);
+	if (!tfcp) {
+		PMD_DRV_LOG_LINE(ERR, "Failed to get tfcp pointer");
+		return -EINVAL;
+	}
+
+	rc = bnxt_ulp_cntxt_fid_get(ulp_ctxt, &fw_fid);
+	if (rc)
+		return rc;
+
+	tfc_info.dir = dir;
+	tfc_info.rsubtype = res_type;
+	tfc_info.id = res_idx;
+
+	tfc_data.key = key;
+	tfc_data.mask = mask;
+	tfc_data.remap = remap;
+	tfc_data.key_sz_in_bytes = *key_size;
+	tfc_data.remap_sz_in_bytes = *remap_size;
+
+	if (tfc_tcam_get(tfcp, fw_fid, &tfc_info, &tfc_data)) {
+		PMD_DRV_LOG_LINE(ERR, "tcam[%s][%s][%x] read failed.",
+				 tfc_tcam_2_str(tfc_info.rsubtype),
+				 tfc_dir_2_str(tfc_info.dir), tfc_info.id);
+		return -EIO;
+	}
+
+	*key_size = (uint16_t)tfc_data.key_sz_in_bytes;
+	*remap_size = (uint16_t)tfc_data.remap_sz_in_bytes;
+
+	return rc;
+}
+
+/*
+ * bnxt_tfc_buf_dump: Pretty-prints a buffer using the following options
+ *
+ * Parameters:
+ * hdr       - A header that is printed as-is
+ * msg       - This is a pointer to the uint8_t buffer to be dumped
+ * prtwidth  - The width of the words to be printed, allowed options 1, 2, 4
+ *             Defaults to 1 if either:
+ *             1) any other value
+ *             2) if buffer length is not a multiple of width
+ * linewidth - The length of the lines printed (in items/words)
+ */
+static
+void hex_buf_dump(FILE *fd, const char *hdr, uint8_t *msg,
+		  int msglen, int prtwidth, int linewidth)
+{
+	char msg_line[128];
+	int msg_i = 0, i;
+	uint16_t *sw_msg = (uint16_t *)msg;
+	uint32_t *lw_msg = (uint32_t *)msg;
+
+	if (hdr)
+		fprintf(fd, "%s\n", hdr);
+
+	if (msglen % prtwidth) {
+		fprintf(fd, "msglen[%u] not aligned on width[%u]\n",
+			   msglen, prtwidth);
+		prtwidth = 1;
+	}
+
+	for (i = 0; i < msglen / prtwidth; i++) {
+		if ((i % linewidth == 0) && i)
+			fprintf(fd, "%s\n", msg_line);
+		if (i % linewidth == 0) {
+			msg_i = 0;
+			msg_i += snprintf(&msg_line[msg_i],
+					  (sizeof(msg_line) - msg_i),
+					  "0x%04x: ", (i * prtwidth));
+		}
+		switch (prtwidth) {
+		case 2:
+			msg_i += snprintf(&msg_line[msg_i],
+					  (sizeof(msg_line) - msg_i),
+					  "0x%04x ", sw_msg[i]);
+			break;
+
+		case 4:
+			msg_i += snprintf(&msg_line[msg_i],
+					  (sizeof(msg_line) - msg_i),
+					  "0x%08x ", lw_msg[i]);
+			break;
+
+		case 1:
+		default:
+			msg_i += snprintf(&msg_line[msg_i],
+					  (sizeof(msg_line) - msg_i),
+					  "0x%02x ", msg[i]);
+			break;
+		}
+	}
+	fprintf(fd, "%s\n", msg_line);
+}
+
+#define L2CTX_KEY_INFO_VALID(kptr)				tfc_getbits(kptr, 255, 1)
+#define L2CTX_KEY_INFO_SPARE(kptr)				tfc_getbits(kptr, 253, 2)
+#define L2CTX_KEY_INFO_MPASS_CNT(kptr)				tfc_getbits(kptr, 251, 2)
+#define L2CTX_KEY_INFO_RCYC(kptr)				tfc_getbits(kptr, 247, 4)
+#define L2CTX_KEY_INFO_LOOPBACK(kptr)				tfc_getbits(kptr, 246, 1)
+#define L2CTX_KEY_INFO_SPIF(kptr)				tfc_getbits(kptr, 244, 2)
+#define L2CTX_KEY_INFO_PARIF(kptr)				tfc_getbits(kptr, 239, 5)
+#define L2CTX_KEY_INFO_SVIF(kptr)				tfc_getbits(kptr, 228, 11)
+#define L2CTX_KEY_INFO_METADATA(kptr)				tfc_getbits(kptr, 196, 32)
+#define L2CTX_KEY_INFO_L2IP_FUNC(kptr)				tfc_getbits(kptr, 188, 8)
+#define L2CTX_KEY_INFO_ROCE(kptr)				tfc_getbits(kptr, 187, 1)
+#define L2CTX_KEY_INFO_PURE_LLC(kptr)				tfc_getbits(kptr, 186, 1)
+#define L2CTX_KEY_INFO_OT_HDR_TYPE(kptr)			tfc_getbits(kptr, 181, 5)
+#define L2CTX_KEY_INFO_T_HDR_TYPE(kptr)				tfc_getbits(kptr, 176, 5)
+#define L2CTX_KEY_INFO_TUNNEL_ID_CONTEXT_L4(kptr)		tfc_getbits(kptr, 144, 32)
+
+#define L2CTX_KEY_INFO_IPV6_ADDR0_1(kptr)			tfc_getbits(kptr, 80, 64)
+#define L2CTX_KEY_INFO_IPV6_ADDR0_0(kptr)			tfc_getbits(kptr, 16, 64)
+#define L2CTX_KEY_INFO_IPV6_OTL2_TL2_L2_ETYPE(kptr)		tfc_getbits(kptr, 0, 16)
+
+#define L2CTX_KEY_INFO_IPV4_ADDR0(kptr)				tfc_getbits(kptr, 96, 48)
+#define L2CTX_KEY_INFO_IPV4_ADDR1(kptr)				tfc_getbits(kptr, 48, 48)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_VTAG_PRESENT(kptr)	tfc_getbits(kptr, 47, 1)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_TWO_VTAGS(kptr)		tfc_getbits(kptr, 46, 1)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_OVLAN_VID(kptr)		tfc_getbits(kptr, 34, 12)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_OVLAN_TPID_SEL(kptr)	tfc_getbits(kptr, 31, 3)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_IVLAN_VID(kptr)		tfc_getbits(kptr, 19, 12)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_IVLAN_TPID_SEL(kptr)	tfc_getbits(kptr, 16, 3)
+#define L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_ETYPE(kptr)		tfc_getbits(kptr, 0, 16)
+
+static void l2ctx_tcam_key_decode(uint32_t *l2ctx_key_ptr,
+				  struct l2ctx_tcam_key_t *l2ctx_key_info)
+{
+	l2ctx_key_info->valid                = L2CTX_KEY_INFO_VALID(l2ctx_key_ptr);
+	l2ctx_key_info->spare                = L2CTX_KEY_INFO_SPARE(l2ctx_key_ptr);
+	l2ctx_key_info->mpass_cnt            = L2CTX_KEY_INFO_MPASS_CNT(l2ctx_key_ptr);
+	l2ctx_key_info->rcyc                 = L2CTX_KEY_INFO_RCYC(l2ctx_key_ptr);
+	l2ctx_key_info->loopback             = L2CTX_KEY_INFO_LOOPBACK(l2ctx_key_ptr);
+	l2ctx_key_info->spif                 = L2CTX_KEY_INFO_SPIF(l2ctx_key_ptr);
+	l2ctx_key_info->parif                = L2CTX_KEY_INFO_PARIF(l2ctx_key_ptr);
+	l2ctx_key_info->svif                 = L2CTX_KEY_INFO_SVIF(l2ctx_key_ptr);
+	l2ctx_key_info->metadata             = L2CTX_KEY_INFO_METADATA(l2ctx_key_ptr);
+	l2ctx_key_info->l2ip_func            = L2CTX_KEY_INFO_L2IP_FUNC(l2ctx_key_ptr);
+	l2ctx_key_info->roce                 = L2CTX_KEY_INFO_ROCE(l2ctx_key_ptr);
+	l2ctx_key_info->pure_llc             = L2CTX_KEY_INFO_PURE_LLC(l2ctx_key_ptr);
+	l2ctx_key_info->ot_hdr_type          = L2CTX_KEY_INFO_OT_HDR_TYPE(l2ctx_key_ptr);
+	l2ctx_key_info->t_hdr_type           = L2CTX_KEY_INFO_T_HDR_TYPE(l2ctx_key_ptr);
+	l2ctx_key_info->tunnel_id_context_L4 = L2CTX_KEY_INFO_TUNNEL_ID_CONTEXT_L4(l2ctx_key_ptr);
+
+	if (l2ctx_key_info->t_hdr_type == 0x5 ||
+	    l2ctx_key_info->ot_hdr_type == 0x5) {
+		l2ctx_key_info->ipv6.ADDR0[1] = L2CTX_KEY_INFO_IPV6_ADDR0_1(l2ctx_key_ptr);
+		l2ctx_key_info->ipv6.ADDR0[0] = L2CTX_KEY_INFO_IPV6_ADDR0_0(l2ctx_key_ptr);
+		l2ctx_key_info->ipv6.otl2_tl2_l2_etype =
+					L2CTX_KEY_INFO_IPV6_OTL2_TL2_L2_ETYPE(l2ctx_key_ptr);
+	} else {
+		l2ctx_key_info->ipv4.ADDR0 = L2CTX_KEY_INFO_IPV4_ADDR0(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.ADDR1 = L2CTX_KEY_INFO_IPV4_ADDR1(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_vtag_present =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_VTAG_PRESENT(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_two_vtags =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_TWO_VTAGS(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_ovlan_vid =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_OVLAN_VID(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_ovlan_tpid_sel =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_OVLAN_TPID_SEL(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_ivlan_vid =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_IVLAN_VID(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_ivlan_tpid_sel =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_IVLAN_TPID_SEL(l2ctx_key_ptr);
+		l2ctx_key_info->ipv4.otl2_tl2_l2_etype =
+				L2CTX_KEY_INFO_IPV4_OTL2_TL2_L2_ETYPE(l2ctx_key_ptr);
+	}
+}
+
+#define L2CTX_RMP_INFO_PRSV_PARIF(kptr)      tfc_getbits(l2ctx_rmp_ptr, 126, 1)
+#define L2CTX_RMP_INFO_PARIF(kptr)           tfc_getbits(l2ctx_rmp_ptr, 121, 5)
+#define L2CTX_RMP_INFO_PRSV_L2IP_CTXT(kptr)  tfc_getbits(l2ctx_rmp_ptr, 120, 1)
+#define L2CTX_RMP_INFO_L2IP_CTXT(kptr)       tfc_getbits(l2ctx_rmp_ptr, 109, 11)
+#define L2CTX_RMP_INFO_PRSV_PROF_FUNC(kptr)  tfc_getbits(l2ctx_rmp_ptr, 108, 1)
+#define L2CTX_RMP_INFO_PROF_FUNC(kptr)       tfc_getbits(l2ctx_rmp_ptr, 100, 8)
+#define L2CTX_RMP_INFO_CTXT_OPCODE(kptr)     tfc_getbits(l2ctx_rmp_ptr, 98, 2)
+#define L2CTX_RMP_INFO_L2IP_META_ENB(kptr)   tfc_getbits(l2ctx_rmp_ptr, 97, 1)
+#define L2CTX_RMP_INFO_L2IP_META_PROF(kptr)  tfc_getbits(l2ctx_rmp_ptr, 94, 3)
+#define L2CTX_RMP_INFO_L2IP_META_DATA(kptr)  tfc_getbits(l2ctx_rmp_ptr, 62, 32)
+#define L2CTX_RMP_INFO_L2IP_ACT_ENB(kptr)    tfc_getbits(l2ctx_rmp_ptr, 61, 1)
+#define L2CTX_RMP_INFO_L2IP_ACT_HINT(kptr)   tfc_getbits(l2ctx_rmp_ptr, 59, 2)
+#define L2CTX_RMP_INFO_L2IP_ACT_SCOPE(kptr)  tfc_getbits(l2ctx_rmp_ptr, 54, 5)
+#define L2CTX_RMP_INFO_L2IP_ACT_PTR(kptr)    tfc_getbits(l2ctx_rmp_ptr, 28, 26)
+#define L2CTX_RMP_INFO_L2IP_RFS_ENB(kptr)    tfc_getbits(l2ctx_rmp_ptr, 27, 1)
+#define L2CTX_RMP_INFO_L2IP_RFS_DATA(kptr)   tfc_getbits(l2ctx_rmp_ptr, 18, 9)
+#define L2CTX_RMP_INFO_L2IP_DEST_ENB(kptr)   tfc_getbits(l2ctx_rmp_ptr, 17, 1)
+#define L2CTX_RMP_INFO_L2IP_DEST_DATA(kptr)  tfc_getbits(l2ctx_rmp_ptr, 0, 17)
+
+static void l2ctx_tcam_remap_decode(uint32_t *l2ctx_rmp_ptr,
+				    struct l2ctx_tcam_remap_t *l2ctx_rmp_info,
+				    struct tfc_ts_mem_cfg *act_mem_cfg)
+{
+	l2ctx_rmp_info->prsv_parif      = L2CTX_RMP_INFO_PRSV_PARIF(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->parif           = L2CTX_RMP_INFO_PARIF(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->prsv_l2ip_ctxt  = L2CTX_RMP_INFO_PRSV_L2IP_CTXT(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_ctxt       = L2CTX_RMP_INFO_L2IP_CTXT(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->prsv_prof_func  = L2CTX_RMP_INFO_PRSV_PROF_FUNC(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->prof_func       = L2CTX_RMP_INFO_PROF_FUNC(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->ctxt_opcode     = L2CTX_RMP_INFO_CTXT_OPCODE(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_meta_enb   = L2CTX_RMP_INFO_L2IP_META_ENB(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_meta_prof  = L2CTX_RMP_INFO_L2IP_META_PROF(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_meta_data  = L2CTX_RMP_INFO_L2IP_META_DATA(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_act_enb    = L2CTX_RMP_INFO_L2IP_ACT_ENB(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_act_hint   = L2CTX_RMP_INFO_L2IP_ACT_HINT(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_act_scope  = L2CTX_RMP_INFO_L2IP_ACT_SCOPE(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_act_ptr    = L2CTX_RMP_INFO_L2IP_ACT_PTR(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_rfs_enb    = L2CTX_RMP_INFO_L2IP_RFS_ENB(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_rfs_data   = L2CTX_RMP_INFO_L2IP_RFS_DATA(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_dest_enb   = L2CTX_RMP_INFO_L2IP_DEST_ENB(l2ctx_rmp_ptr);
+	l2ctx_rmp_info->l2ip_dest_data  = L2CTX_RMP_INFO_L2IP_DEST_DATA(l2ctx_rmp_ptr);
+	act_process(l2ctx_rmp_info->l2ip_act_ptr, &l2ctx_rmp_info->act_info, act_mem_cfg);
+}
+
+static void l2ctx_tcam_show(FILE *fd,
+			    struct l2ctx_tcam_key_t *l2ctx_key_info,
+			    struct l2ctx_tcam_key_t *l2ctx_mask_info,
+			    struct l2ctx_tcam_remap_t *l2ctx_rmp_info)
+{
+	char *line1 = NULL;
+	char *line2 = NULL;
+	char *line3 = NULL;
+	char *line4 = NULL;
+	char *line5 = NULL;
+
+	line1 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line2 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line3 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line4 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line5 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	if (!line1 || !line2 || !line3 || !line4 || !line5) {
+		rte_free(line1);
+		rte_free(line2);
+		rte_free(line3);
+		rte_free(line4);
+		rte_free(line5);
+		fprintf(fd, "%s: Failed to allocate temp buffer\n",
+			__func__);
+		return;
+	}
+
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+---+----+---+----+-----+----+---------"
+		 "+------+----+----+---+---+----------+\n");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|V|Sp|mpc|rcyc|lbk|spif|parif|svif| metadata"
+		 "|l2func|roce|pllc|OTH| TH|TID/ctx/L4|\n");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+---+----+---+----+-----+----+---------"
+		 "+------+----+----+---+---+----------+\n");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %01x  %01x  %01x   x%01x   %01x    %01x   x%02x"
+		 "  x%03x x%08x   x%02x    %01x    %01x  x%02x x%02x  x%08x  key\n",
+		 l2ctx_key_info->valid,
+		 l2ctx_key_info->spare,
+		 l2ctx_key_info->mpass_cnt,
+		 l2ctx_key_info->rcyc,
+		 l2ctx_key_info->loopback,
+		 l2ctx_key_info->spif,
+		 l2ctx_key_info->parif,
+		 l2ctx_key_info->svif,
+		 l2ctx_key_info->metadata,
+		 l2ctx_key_info->l2ip_func,
+		 l2ctx_key_info->roce,
+		 l2ctx_key_info->pure_llc,
+		 l2ctx_key_info->ot_hdr_type,
+		 l2ctx_key_info->t_hdr_type,
+		 l2ctx_key_info->tunnel_id_context_L4);
+	snprintf(line5, TFC_STRING_LENGTH_256, " %01x  %01x  %01x   x%01x   %01x    %01x   x%02x"
+		 "  x%03x x%08x   x%02x    %01x    %01x  x%02x x%02x  x%08x  mask\n",
+		 l2ctx_mask_info->valid,
+		 l2ctx_mask_info->spare,
+		 l2ctx_mask_info->mpass_cnt,
+		 l2ctx_mask_info->rcyc,
+		 l2ctx_mask_info->loopback,
+		 l2ctx_mask_info->spif,
+		 l2ctx_mask_info->parif,
+		 l2ctx_mask_info->svif,
+		 l2ctx_mask_info->metadata,
+		 l2ctx_mask_info->l2ip_func,
+		 l2ctx_mask_info->roce,
+		 l2ctx_mask_info->pure_llc,
+		 l2ctx_mask_info->ot_hdr_type,
+		 l2ctx_mask_info->t_hdr_type,
+		 l2ctx_mask_info->tunnel_id_context_L4);
+	fprintf(fd, "%s%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line5,
+		line4);
+
+	if (l2ctx_key_info->t_hdr_type == 0x5 ||
+	    l2ctx_key_info->ot_hdr_type == 0x5) {
+		snprintf(line1, TFC_STRING_LENGTH_256, "+------IPv6-------+------IPv6-------"
+			 "+-----+\n");
+		snprintf(line2, TFC_STRING_LENGTH_256, "|      ADDR0      |      ADDR1      "
+			 "|etype|\n");
+		snprintf(line3, TFC_STRING_LENGTH_256, "+-----------------+-----------------"
+			 "+-----+\n");
+		snprintf(line4, TFC_STRING_LENGTH_256, " x%016" PRIx64 " x%016" PRIx64 " x%04x  key\n",
+			 l2ctx_key_info->ipv6.ADDR0[1],
+			 l2ctx_key_info->ipv6.ADDR0[0],
+			 l2ctx_key_info->ipv6.otl2_tl2_l2_etype);
+		snprintf(line5, TFC_STRING_LENGTH_256, " x%016" PRIx64 " x%016" PRIx64 " x%04x  mask\n",
+			 l2ctx_mask_info->ipv6.ADDR0[1],
+			 l2ctx_mask_info->ipv6.ADDR0[0],
+			 l2ctx_mask_info->ipv6.otl2_tl2_l2_etype);
+	} else {
+		snprintf(line1, TFC_STRING_LENGTH_256, "+----IPv4-----+----IPv4-----+--+---"
+			 "+----+-----+----+-----+-----+\n");
+		snprintf(line2, TFC_STRING_LENGTH_256, "|    ADDR0    |    ADDR1    |VT|2VT"
+			 "|ovid|otpid|ivid|itpid|etype|\n");
+		snprintf(line3, TFC_STRING_LENGTH_256, "+-------------+-------------+--+---"
+			 "+----+-----+----+-----+-----+\n");
+		snprintf(line4, TFC_STRING_LENGTH_256, " x%012" PRIx64 " x%012" PRIx64 "  %01x  %01x  x%03x"
+			 "    %01x  x%03x   %01x   x%04x  key\n",
+			 l2ctx_key_info->ipv4.ADDR0,
+			 l2ctx_key_info->ipv4.ADDR1,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_vtag_present,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_two_vtags,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_ovlan_vid,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_ovlan_tpid_sel,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_ivlan_vid,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_ivlan_tpid_sel,
+			 l2ctx_key_info->ipv4.otl2_tl2_l2_etype);
+		snprintf(line5, TFC_STRING_LENGTH_256, " x%012" PRIx64 " x%012" PRIx64 "  %01x  %01x  x%03x"
+			 "    %01x  x%03x   %01x   x%04x  mask\n",
+			 l2ctx_mask_info->ipv4.ADDR0,
+			 l2ctx_mask_info->ipv4.ADDR1,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_vtag_present,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_two_vtags,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_ovlan_vid,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_ovlan_tpid_sel,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_ivlan_vid,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_ivlan_tpid_sel,
+			 l2ctx_mask_info->ipv4.otl2_tl2_l2_etype);
+	}
+	fprintf(fd, "%s%s%s%s%s",
+		   line1,
+		   line2,
+		   line3,
+		   line5,
+		   line4);
+
+	fputs(":L2CTX TCAM: remap\n", fd);
+	snprintf(line1, TFC_STRING_LENGTH_256, "+---+----+----+----+---+---+-----+---"
+		 "+-----+---------+\n");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|PIP|prif|PL2C| L2C|PPF|PRF|ctxop|mde"
+		 "|mprof| metadata|\n");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+---+----+----+----+---+---+-----+---"
+		 "+-----+---------+\n");
+	snprintf(line4, TFC_STRING_LENGTH_256, "  %01x   x%02x   %01x  x%03x  %01x  x%02x"
+		 "    %01x    %01x    %01x  x%08x\n",
+		 l2ctx_rmp_info->prsv_parif,
+		 l2ctx_rmp_info->parif,
+		 l2ctx_rmp_info->prsv_l2ip_ctxt,
+		 l2ctx_rmp_info->l2ip_ctxt,
+		 l2ctx_rmp_info->prsv_prof_func,
+		 l2ctx_rmp_info->prof_func,
+		 l2ctx_rmp_info->ctxt_opcode,
+		 l2ctx_rmp_info->l2ip_meta_enb,
+		 l2ctx_rmp_info->l2ip_meta_prof,
+		 l2ctx_rmp_info->l2ip_meta_data);
+	fprintf(fd, "%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line4);
+
+	snprintf(line1, TFC_STRING_LENGTH_256, "+----+----+----+---------+----+-------"
+		 "+----+--------+\n");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|acte|ahnt|ascp|   act   |rfse|rfsdata"
+		 "|dste|dst_data|\n");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+----+----+----+---------+----+-------"
+		 "+----+--------+\n");
+	snprintf(line4, TFC_STRING_LENGTH_256, "   %01x    %01x   x%02x x%08x   %01x"
+		 "    x%03x    %01x   x%05x\n",
+		 l2ctx_rmp_info->l2ip_act_enb,
+		 l2ctx_rmp_info->l2ip_act_hint,
+		 l2ctx_rmp_info->l2ip_act_scope,
+		 l2ctx_rmp_info->l2ip_act_ptr,
+		 l2ctx_rmp_info->l2ip_rfs_enb,
+		 l2ctx_rmp_info->l2ip_rfs_data,
+		 l2ctx_rmp_info->l2ip_dest_enb,
+		 l2ctx_rmp_info->l2ip_dest_data);
+	fprintf(fd, "%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line4);
+
+	act_show(fd, &l2ctx_rmp_info->act_info, l2ctx_rmp_info->l2ip_act_ptr << 5);
+
+	rte_free(line1);
+	rte_free(line2);
+	rte_free(line3);
+	rte_free(line4);
+	rte_free(line5);
+}
+
+#define PTKEY_INFO_VALID(kptr)                tfc_getbits(kptr, 183, 1)
+#define PTKEY_INFO_SPARE(kptr)                tfc_getbits(kptr, 181, 2)
+#define PTKEY_INFO_LOOPBACK(kptr)             tfc_getbits(kptr, 180, 1)
+#define PTKEY_INFO_PKT_TYPE(kptr)             tfc_getbits(kptr, 176, 4)
+#define PTKEY_INFO_RCYC(kptr)                 tfc_getbits(kptr, 172, 4)
+#define PTKEY_INFO_METADATA(kptr)             tfc_getbits(kptr, 140, 32)
+#define PTKEY_INFO_AGG_ERROR(kptr)            tfc_getbits(kptr, 139, 1)
+#define PTKEY_INFO_L2IP_FUNC(kptr)            tfc_getbits(kptr, 131, 8)
+#define PTKEY_INFO_PROF_FUNC(kptr)            tfc_getbits(kptr, 123, 8)
+#define PTKEY_INFO_HREC_NEXT(kptr)            tfc_getbits(kptr, 121, 2)
+#define PTKEY_INFO_INT_HDR_TYPE(kptr)         tfc_getbits(kptr, 119, 2)
+#define PTKEY_INFO_INT_HDR_GROUP(kptr)        tfc_getbits(kptr, 117, 2)
+#define PTKEY_INFO_INT_IFA_TAIL(kptr)         tfc_getbits(kptr, 116, 1)
+
+#define PTKEY_INFO_OTL2_HDR_VALID(kptr)       tfc_getbits(kptr, 115, 1)
+#define PTKEY_INFO_OTL2_HDR_TYPE(kptr)        tfc_getbits(kptr, 113, 2)
+#define PTKEY_INFO_OTL2_UC_MC_BC(kptr)        tfc_getbits(kptr, 111, 2)
+#define PTKEY_INFO_OTL2_VTAG_PRESENT(kptr)    tfc_getbits(kptr, 110, 1)
+#define PTKEY_INFO_OTL2_TWO_VTAGS(kptr)       tfc_getbits(kptr, 109, 1)
+
+#define PTKEY_INFO_OTL3_HDR_VALID(kptr)       tfc_getbits(kptr, 108, 1)
+#define PTKEY_INFO_OTL3_HDR_ERROR(kptr)       tfc_getbits(kptr, 107, 1)
+#define PTKEY_INFO_OTL3_HDR_TYPE(kptr)        tfc_getbits(kptr, 103, 4)
+#define PTKEY_INFO_OTL3_HDR_ISIP(kptr)        tfc_getbits(kptr, 102, 1)
+
+#define PTKEY_INFO_OTL4_HDR_VALID(kptr)       tfc_getbits(kptr, 101, 1)
+#define PTKEY_INFO_OTL4_HDR_ERROR(kptr)       tfc_getbits(kptr, 100, 1)
+#define PTKEY_INFO_OTL4_HDR_TYPE(kptr)        tfc_getbits(kptr, 96, 4)
+#define PTKEY_INFO_OTL4_HDR_IS_UDP_TCP(kptr)  tfc_getbits(kptr, 95, 1)
+
+#define PTKEY_INFO_OT_HDR_VALID(kptr)         tfc_getbits(kptr, 94, 1)
+#define PTKEY_INFO_OT_HDR_ERROR(kptr)         tfc_getbits(kptr, 93, 1)
+#define PTKEY_INFO_OT_HDR_TYPE(kptr)          tfc_getbits(kptr, 88, 5)
+#define PTKEY_INFO_OT_HDR_FLAGS(kptr)         tfc_getbits(kptr, 80, 8)
+
+#define PTKEY_INFO_TL2_HDR_VALID(kptr)        tfc_getbits(kptr, 79, 1)
+#define PTKEY_INFO_TL2_HDR_TYPE(kptr)         tfc_getbits(kptr, 77, 2)
+#define PTKEY_INFO_TL2_UC_MC_BC(kptr)         tfc_getbits(kptr, 75, 2)
+#define PTKEY_INFO_TL2_VTAG_PRESENT(kptr)     tfc_getbits(kptr, 74, 1)
+#define PTKEY_INFO_TL2_TWO_VTAGS(kptr)        tfc_getbits(kptr, 73, 1)
+
+#define PTKEY_INFO_TL3_HDR_VALID(kptr)        tfc_getbits(kptr, 72, 1)
+#define PTKEY_INFO_TL3_HDR_ERROR(kptr)        tfc_getbits(kptr, 71, 1)
+#define PTKEY_INFO_TL3_HDR_TYPE(kptr)         tfc_getbits(kptr, 67, 4)
+#define PTKEY_INFO_TL3_HDR_ISIP(kptr)         tfc_getbits(kptr, 66, 1)
+
+#define PTKEY_INFO_TL4_HDR_VALID(kptr)        tfc_getbits(kptr, 65, 1)
+#define PTKEY_INFO_TL4_HDR_ERROR(kptr)        tfc_getbits(kptr, 64, 1)
+#define PTKEY_INFO_TL4_HDR_TYPE(kptr)         tfc_getbits(kptr, 60, 4)
+#define PTKEY_INFO_TL4_HDR_IS_UDP_TCP(kptr)   tfc_getbits(kptr, 59, 1)
+
+#define PTKEY_INFO_T_HDR_VALID(kptr)          tfc_getbits(kptr, 58, 1)
+#define PTKEY_INFO_T_HDR_ERROR(kptr)          tfc_getbits(kptr, 57, 1)
+#define PTKEY_INFO_T_HDR_TYPE(kptr)           tfc_getbits(kptr, 52, 5)
+#define PTKEY_INFO_T_HDR_FLAGS(kptr)          tfc_getbits(kptr, 44, 8)
+
+#define PTKEY_INFO_L2_HDR_VALID(kptr)         tfc_getbits(kptr, 43, 1)
+#define PTKEY_INFO_L2_HDR_ERROR(kptr)         tfc_getbits(kptr, 42, 1)
+#define PTKEY_INFO_L2_HDR_TYPE(kptr)          tfc_getbits(kptr, 40, 2)
+#define PTKEY_INFO_L2_UC_MC_BC(kptr)          tfc_getbits(kptr, 38, 2)
+#define PTKEY_INFO_L2_VTAG_PRESENT(kptr)      tfc_getbits(kptr, 37, 1)
+#define PTKEY_INFO_L2_TWO_VTAGS(kptr)         tfc_getbits(kptr, 36, 1)
+
+#define PTKEY_INFO_L3_HDR_VALID(kptr)         tfc_getbits(kptr, 35, 1)
+#define PTKEY_INFO_L3_HDR_ERROR(kptr)         tfc_getbits(kptr, 34, 1)
+#define PTKEY_INFO_L3_HDR_TYPE(kptr)          tfc_getbits(kptr, 30, 4)
+#define PTKEY_INFO_L3_HDR_ISIP(kptr)          tfc_getbits(kptr, 29, 1)
+#define PTKEY_INFO_L3_PROTOCOL(kptr)          tfc_getbits(kptr, 21, 8)
+
+#define PTKEY_INFO_L4_HDR_VALID(kptr)         tfc_getbits(kptr, 20, 1)
+#define PTKEY_INFO_L4_HDR_ERROR(kptr)         tfc_getbits(kptr, 19, 1)
+#define PTKEY_INFO_L4_HDR_TYPE(kptr)          tfc_getbits(kptr, 15, 4)
+#define PTKEY_INFO_L4_HDR_IS_UDP_TCP(kptr)    tfc_getbits(kptr, 14, 1)
+#define PTKEY_INFO_L4_HDR_SUBTYPE(kptr)       tfc_getbits(kptr, 11, 3)
+#define PTKEY_INFO_L4_FLAGS(kptr)             tfc_getbits(kptr, 2, 9)
+#define PTKEY_INFO_L4_DCN_PRESENT(kptr)       tfc_getbits(kptr, 0, 2)
+
+static void prof_tcam_key_decode(uint32_t *ptc_key_ptr,
+				 struct prof_tcam_key_t *ptkey_info)
+{
+	ptkey_info->valid               = PTKEY_INFO_VALID(ptc_key_ptr);
+	ptkey_info->spare               = PTKEY_INFO_SPARE(ptc_key_ptr);
+	ptkey_info->loopback            = PTKEY_INFO_LOOPBACK(ptc_key_ptr);
+	ptkey_info->pkt_type            = PTKEY_INFO_PKT_TYPE(ptc_key_ptr);
+	ptkey_info->rcyc                = PTKEY_INFO_RCYC(ptc_key_ptr);
+	ptkey_info->metadata            = PTKEY_INFO_METADATA(ptc_key_ptr);
+	ptkey_info->agg_error           = PTKEY_INFO_AGG_ERROR(ptc_key_ptr);
+	ptkey_info->l2ip_func           = PTKEY_INFO_L2IP_FUNC(ptc_key_ptr);
+	ptkey_info->prof_func           = PTKEY_INFO_PROF_FUNC(ptc_key_ptr);
+	ptkey_info->hrec_next           = PTKEY_INFO_HREC_NEXT(ptc_key_ptr);
+	ptkey_info->int_hdr_type        = PTKEY_INFO_INT_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->int_hdr_group       = PTKEY_INFO_INT_HDR_GROUP(ptc_key_ptr);
+	ptkey_info->int_ifa_tail        = PTKEY_INFO_INT_IFA_TAIL(ptc_key_ptr);
+
+	ptkey_info->otl2_hdr_valid      = PTKEY_INFO_OTL2_HDR_VALID(ptc_key_ptr);
+	ptkey_info->otl2_hdr_type       = PTKEY_INFO_OTL2_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->otl2_uc_mc_bc       = PTKEY_INFO_OTL2_UC_MC_BC(ptc_key_ptr);
+	ptkey_info->otl2_vtag_present   = PTKEY_INFO_OTL2_VTAG_PRESENT(ptc_key_ptr);
+	ptkey_info->otl2_two_vtags      = PTKEY_INFO_OTL2_TWO_VTAGS(ptc_key_ptr);
+
+	ptkey_info->otl3_hdr_valid      = PTKEY_INFO_OTL3_HDR_VALID(ptc_key_ptr);
+	ptkey_info->otl3_hdr_error      = PTKEY_INFO_OTL3_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->otl3_hdr_type       = PTKEY_INFO_OTL3_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->otl3_hdr_isip       = PTKEY_INFO_OTL3_HDR_ISIP(ptc_key_ptr);
+
+	ptkey_info->otl4_hdr_valid      = PTKEY_INFO_OTL4_HDR_VALID(ptc_key_ptr);
+	ptkey_info->otl4_hdr_error      = PTKEY_INFO_OTL4_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->otl4_hdr_type       = PTKEY_INFO_OTL4_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->otl4_hdr_is_udp_tcp = PTKEY_INFO_OTL4_HDR_IS_UDP_TCP(ptc_key_ptr);
+
+	ptkey_info->ot_hdr_valid        = PTKEY_INFO_OT_HDR_VALID(ptc_key_ptr);
+	ptkey_info->ot_hdr_error        = PTKEY_INFO_OT_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->ot_hdr_type         = PTKEY_INFO_OT_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->ot_hdr_flags        = PTKEY_INFO_OT_HDR_FLAGS(ptc_key_ptr);
+
+	ptkey_info->tl2_hdr_valid       = PTKEY_INFO_TL2_HDR_VALID(ptc_key_ptr);
+	ptkey_info->tl2_hdr_type        = PTKEY_INFO_TL2_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->tl2_uc_mc_bc        = PTKEY_INFO_TL2_UC_MC_BC(ptc_key_ptr);
+	ptkey_info->tl2_vtag_present    = PTKEY_INFO_TL2_VTAG_PRESENT(ptc_key_ptr);
+	ptkey_info->tl2_two_vtags       = PTKEY_INFO_TL2_TWO_VTAGS(ptc_key_ptr);
+
+	ptkey_info->tl3_hdr_valid       = PTKEY_INFO_TL3_HDR_VALID(ptc_key_ptr);
+	ptkey_info->tl3_hdr_error       = PTKEY_INFO_TL3_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->tl3_hdr_type        = PTKEY_INFO_TL3_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->tl3_hdr_isip        = PTKEY_INFO_TL3_HDR_ISIP(ptc_key_ptr);
+
+	ptkey_info->tl4_hdr_valid       = PTKEY_INFO_TL4_HDR_VALID(ptc_key_ptr);
+	ptkey_info->tl4_hdr_error       = PTKEY_INFO_TL4_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->tl4_hdr_type        = PTKEY_INFO_TL4_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->tl4_hdr_is_udp_tcp  = PTKEY_INFO_TL4_HDR_IS_UDP_TCP(ptc_key_ptr);
+
+	ptkey_info->t_hdr_valid         = PTKEY_INFO_T_HDR_VALID(ptc_key_ptr);
+	ptkey_info->t_hdr_error         = PTKEY_INFO_T_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->t_hdr_type          = PTKEY_INFO_T_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->t_hdr_flags         = PTKEY_INFO_T_HDR_FLAGS(ptc_key_ptr);
+
+	ptkey_info->l2_hdr_valid        = PTKEY_INFO_L2_HDR_VALID(ptc_key_ptr);
+	ptkey_info->l2_hdr_error        = PTKEY_INFO_L2_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->l2_hdr_type         = PTKEY_INFO_L2_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->l2_uc_mc_bc         = PTKEY_INFO_L2_UC_MC_BC(ptc_key_ptr);
+	ptkey_info->l2_vtag_present     = PTKEY_INFO_L2_VTAG_PRESENT(ptc_key_ptr);
+	ptkey_info->l2_two_vtags        = PTKEY_INFO_L2_TWO_VTAGS(ptc_key_ptr);
+
+	ptkey_info->l3_hdr_valid        = PTKEY_INFO_L3_HDR_VALID(ptc_key_ptr);
+	ptkey_info->l3_hdr_error        = PTKEY_INFO_L3_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->l3_hdr_type         = PTKEY_INFO_L3_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->l3_hdr_isip         = PTKEY_INFO_L3_HDR_ISIP(ptc_key_ptr);
+	ptkey_info->l3_protocol         = PTKEY_INFO_L3_PROTOCOL(ptc_key_ptr);
+
+	ptkey_info->l4_hdr_valid        = PTKEY_INFO_L4_HDR_VALID(ptc_key_ptr);
+	ptkey_info->l4_hdr_error        = PTKEY_INFO_L4_HDR_ERROR(ptc_key_ptr);
+	ptkey_info->l4_hdr_type         = PTKEY_INFO_L4_HDR_TYPE(ptc_key_ptr);
+	ptkey_info->l4_hdr_is_udp_tcp   = PTKEY_INFO_L4_HDR_IS_UDP_TCP(ptc_key_ptr);
+	ptkey_info->l4_hdr_subtype      = PTKEY_INFO_L4_HDR_SUBTYPE(ptc_key_ptr);
+	ptkey_info->l4_flags            = PTKEY_INFO_L4_FLAGS(ptc_key_ptr);
+	ptkey_info->l4_dcn_present      = PTKEY_INFO_L4_DCN_PRESENT(ptc_key_ptr);
+}
+
+#define PTRMP_INFO_PL_BYP_LKUP_EN(kptr)   tfc_getbits(ptc_rmp_ptr, 42, 1)
+#define PTRMP_INFO_EM_SEARCH_EN(kptr)     tfc_getbits(ptc_rmp_ptr, 41, 1)
+#define PTRMP_INFO_EM_PROFILE_ID(kptr)    tfc_getbits(ptc_rmp_ptr, 33, 8)
+#define PTRMP_INFO_EM_KEY_ID(kptr)        tfc_getbits(ptc_rmp_ptr, 26, 7)
+#define PTRMP_INFO_EM_SCOPE(kptr)         tfc_getbits(ptc_rmp_ptr, 21, 5)
+#define PTRMP_INFO_TCAM_SEARCH_EN(kptr)   tfc_getbits(ptc_rmp_ptr, 20, 1)
+#define PTRMP_INFO_TCAM_PROFILE_ID(kptr)  tfc_getbits(ptc_rmp_ptr, 12, 8)
+#define PTRMP_INFO_TCAM_KEY_ID(kptr)      tfc_getbits(ptc_rmp_ptr, 5, 7)
+#define PTRMP_INFO_TCAM_SCOPE(kptr)       tfc_getbits(ptc_rmp_ptr, 0, 5)
+
+static void prof_tcam_remap_decode(uint32_t *ptc_rmp_ptr,
+				   struct prof_tcam_remap_t *ptrmp_info)
+{
+	ptrmp_info->pl_byp_lkup_en  = PTRMP_INFO_PL_BYP_LKUP_EN(ptc_rmp_ptr) ? true : false;
+	ptrmp_info->em_search_en    = PTRMP_INFO_EM_SEARCH_EN(ptc_rmp_ptr) ? true : false;
+	ptrmp_info->em_profile_id   = PTRMP_INFO_EM_PROFILE_ID(ptc_rmp_ptr);
+	ptrmp_info->em_key_id       = PTRMP_INFO_EM_KEY_ID(ptc_rmp_ptr);
+	ptrmp_info->em_scope        = PTRMP_INFO_EM_SCOPE(ptc_rmp_ptr);
+	ptrmp_info->tcam_search_en  = PTRMP_INFO_TCAM_SEARCH_EN(ptc_rmp_ptr) ? true : false;
+	ptrmp_info->tcam_profile_id = PTRMP_INFO_TCAM_PROFILE_ID(ptc_rmp_ptr);
+	ptrmp_info->tcam_key_id     = PTRMP_INFO_TCAM_KEY_ID(ptc_rmp_ptr);
+	ptrmp_info->tcam_scope      = PTRMP_INFO_TCAM_SCOPE(ptc_rmp_ptr);
+}
+
+static void prof_tcam_show(FILE *fd,
+			   struct prof_tcam_key_t *ptkey_info,
+			   struct prof_tcam_key_t *ptmask_info,
+			   struct prof_tcam_remap_t *ptrmp_info)
+{
+	char tmph[TFC_STRING_LENGTH_64];
+	char tmp1[TFC_STRING_LENGTH_64];
+	char tmp2[TFC_STRING_LENGTH_64];
+	char tmp3[TFC_STRING_LENGTH_64];
+	char tmp4[TFC_STRING_LENGTH_64];
+	char tmp5[TFC_STRING_LENGTH_64];
+	char *lineh = NULL;
+	char *line1 = NULL;
+	char *line2 = NULL;
+	char *line3 = NULL;
+	char *line4 = NULL;
+	char *line5 = NULL;
+
+	lineh = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line1 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line2 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line3 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line4 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line5 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	if (!lineh || !line1 || !line2 || !line3 || !line4 || !line5) {
+		rte_free(lineh);
+		rte_free(line1);
+		rte_free(line2);
+		rte_free(line3);
+		rte_free(line4);
+		rte_free(line5);
+		fprintf(fd, "%s: Failed to allocate temp buffer\n",
+			__func__);
+		return;
+	}
+
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+----+----+----+---------+------"
+		 "+--------+-------+-----+---+---+---+\n");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|V|Sp|lpbk|ptyp|rcyc|    MD   |aggerr"
+		 "|l2ipfunc|profunc|hrnxt|IHT|IHG|IIT|\n");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+----+----+----+---------+------"
+		 "+--------+-------+-----+---+---+---+\n");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %01x x%01x   %01x   x%01x  x%01x  x%08x"
+		 "    %01x     x%02x      x%02x     x%01x   x%01x  x%01x   %01x  key\n",
+		 ptkey_info->valid,
+		 ptkey_info->spare,
+		 ptkey_info->loopback,
+		 ptkey_info->pkt_type,
+		 ptkey_info->rcyc,
+		 ptkey_info->metadata,
+		 ptkey_info->agg_error,
+		 ptkey_info->l2ip_func,
+		 ptkey_info->prof_func,
+		 ptkey_info->hrec_next,
+		 ptkey_info->int_hdr_type,
+		 ptkey_info->int_hdr_group,
+		 ptkey_info->int_ifa_tail);
+	snprintf(line5, TFC_STRING_LENGTH_256, " %01x x%01x   %01x   x%01x  x%01x  x%08x"
+		 "    %01x     x%02x      x%02x     x%01x   x%01x  x%01x   %01x  mask\n",
+		 ptmask_info->valid,
+		 ptmask_info->spare,
+		 ptmask_info->loopback,
+		 ptmask_info->pkt_type,
+		 ptmask_info->rcyc,
+		 ptmask_info->metadata,
+		 ptmask_info->agg_error,
+		 ptmask_info->l2ip_func,
+		 ptmask_info->prof_func,
+		 ptmask_info->hrec_next,
+		 ptmask_info->int_hdr_type,
+		 ptmask_info->int_hdr_group,
+		 ptmask_info->int_ifa_tail);
+	fprintf(fd, "%s%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line5,
+		line4);
+
+	snprintf(lineh, TFC_STRING_LENGTH_256, "|OTL2 hdr       |");
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|V|HT|UMB|VT|2VT|");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptkey_info->otl2_hdr_valid,
+		 ptkey_info->otl2_hdr_type,
+		 ptkey_info->otl2_uc_mc_bc,
+		 ptkey_info->otl2_vtag_present,
+		 ptkey_info->otl2_two_vtags);
+	snprintf(line5, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptmask_info->otl2_hdr_valid,
+		 ptmask_info->otl2_hdr_type,
+		 ptmask_info->otl2_uc_mc_bc,
+		 ptmask_info->otl2_vtag_present,
+		 ptmask_info->otl2_two_vtags);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "OTL3 hdr  |");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x ",
+		 ptkey_info->otl3_hdr_valid,
+		 ptkey_info->otl3_hdr_error,
+		 ptkey_info->otl3_hdr_type,
+		 ptkey_info->otl3_hdr_isip);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x ",
+		 ptmask_info->otl3_hdr_valid,
+		 ptmask_info->otl3_hdr_error,
+		 ptmask_info->otl3_hdr_type,
+		 ptmask_info->otl3_hdr_isip);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "OTL4 hdr  |");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x ",
+		 ptkey_info->otl4_hdr_valid,
+		 ptkey_info->otl4_hdr_error,
+		 ptkey_info->otl4_hdr_type,
+		 ptkey_info->otl4_hdr_is_udp_tcp);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x ",
+		 ptmask_info->otl4_hdr_valid,
+		 ptmask_info->otl4_hdr_error,
+		 ptmask_info->otl4_hdr_type,
+		 ptmask_info->otl4_hdr_is_udp_tcp);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "OT hdr      |\n");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+---+---+\n");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE| HT|flg|\n");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+---+---+\n");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "%01x  %01x x%02x x%02x  key\n",
+		 ptkey_info->ot_hdr_valid,
+		 ptkey_info->ot_hdr_error,
+		 ptkey_info->ot_hdr_type,
+		 ptkey_info->ot_hdr_flags);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, "%01x  %01x x%02x x%02x  mask\n",
+		 ptmask_info->ot_hdr_valid,
+		 ptmask_info->ot_hdr_error,
+		 ptmask_info->ot_hdr_type,
+		 ptmask_info->ot_hdr_flags);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	fprintf(fd, "%s%s%s%s%s%s",
+		lineh,
+		line1,
+		line2,
+		line3,
+		line5,
+		line4);
+
+	snprintf(lineh, TFC_STRING_LENGTH_256, "|TL2 hdr        |");
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|V|HT|UMB|VT|2VT|");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptkey_info->tl2_hdr_valid,
+		 ptkey_info->tl2_hdr_type,
+		 ptkey_info->tl2_uc_mc_bc,
+		 ptkey_info->tl2_vtag_present,
+		 ptkey_info->tl2_two_vtags);
+	snprintf(line5, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptmask_info->tl2_hdr_valid,
+		 ptmask_info->tl2_hdr_type,
+		 ptmask_info->tl2_uc_mc_bc,
+		 ptmask_info->tl2_vtag_present,
+		 ptmask_info->tl2_two_vtags);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "TL3 hdr   |");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x ",
+		 ptkey_info->tl3_hdr_valid,
+		 ptkey_info->tl3_hdr_error,
+		 ptkey_info->tl3_hdr_type,
+		 ptkey_info->tl3_hdr_isip);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x ",
+		 ptmask_info->tl3_hdr_valid,
+		 ptmask_info->tl3_hdr_error,
+		 ptmask_info->tl3_hdr_type,
+		 ptmask_info->tl3_hdr_isip);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "TL4 hdr   |");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x ",
+		 ptkey_info->tl4_hdr_valid,
+		 ptkey_info->tl4_hdr_error,
+		 ptkey_info->tl4_hdr_type,
+		 ptkey_info->tl4_hdr_is_udp_tcp);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x ",
+		 ptmask_info->tl4_hdr_valid,
+		 ptmask_info->tl4_hdr_error,
+		 ptmask_info->tl4_hdr_type,
+		 ptmask_info->tl4_hdr_is_udp_tcp);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "T hdr       |\n");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+---+---+\n");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE| HT|flg|\n");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+---+---+\n");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "%01x  %01x x%02x x%02x  key\n",
+		 ptkey_info->t_hdr_valid,
+		 ptkey_info->t_hdr_error,
+		 ptkey_info->t_hdr_type,
+		 ptkey_info->t_hdr_flags);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, "%01x  %01x x%02x x%02x  mask\n",
+		 ptmask_info->t_hdr_valid,
+		 ptmask_info->t_hdr_error,
+		 ptmask_info->t_hdr_type,
+		 ptmask_info->t_hdr_flags);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	fprintf(fd, "%s%s%s%s%s%s",
+		lineh,
+		line1,
+		line2,
+		line3,
+		line5,
+		line4);
+
+	snprintf(lineh, TFC_STRING_LENGTH_256, "|L2 hdr         |");
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|V|HT|UMB|VT|2VT|");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+---+--+---+");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptkey_info->l2_hdr_valid,
+		 ptkey_info->l2_hdr_type,
+		 ptkey_info->l2_uc_mc_bc,
+		 ptkey_info->l2_vtag_present,
+		 ptkey_info->l2_two_vtags);
+	snprintf(line5, TFC_STRING_LENGTH_256, " %01x x%01x  x%01x  %01x  %01x ",
+		 ptmask_info->l2_hdr_valid,
+		 ptmask_info->l2_hdr_type,
+		 ptmask_info->l2_uc_mc_bc,
+		 ptmask_info->l2_vtag_present,
+		 ptmask_info->l2_two_vtags);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "L3 hdr         |");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+----+");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|prot|");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+----+");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x  x%02x ",
+		 ptkey_info->l3_hdr_valid,
+		 ptkey_info->l3_hdr_error,
+		 ptkey_info->l3_hdr_type,
+		 ptkey_info->l3_hdr_isip,
+		 ptkey_info->l3_protocol);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, " %01x  %01x x%01x  %01x  x%02x ",
+		 ptmask_info->l3_hdr_valid,
+		 ptmask_info->l3_hdr_error,
+		 ptmask_info->l3_hdr_type,
+		 ptmask_info->l3_hdr_isip,
+		 ptmask_info->l3_protocol);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	snprintf(tmph, TFC_STRING_LENGTH_64, "L4 hdr                 |\n");
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-+--+--+--+---+----+---+\n");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "V|HE|HT|IP|HST|flgs|DCN|\n");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "-+--+--+--+---+----+---+\n");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x  x%01x x%03x  x%01x  key\n",
+		 ptkey_info->l4_hdr_valid,
+		 ptkey_info->l4_hdr_error,
+		 ptkey_info->l4_hdr_type,
+		 ptkey_info->l4_hdr_is_udp_tcp,
+		 ptkey_info->l4_hdr_subtype,
+		 ptkey_info->l4_flags,
+		 ptkey_info->l4_dcn_present);
+	snprintf(tmp5, TFC_STRING_LENGTH_64, "%01x  %01x x%01x  %01x  x%01x x%03x  x%01x  mask\n",
+		 ptmask_info->l4_hdr_valid,
+		 ptmask_info->l4_hdr_error,
+		 ptmask_info->l4_hdr_type,
+		 ptmask_info->l4_hdr_is_udp_tcp,
+		 ptmask_info->l4_hdr_subtype,
+		 ptmask_info->l4_flags,
+		 ptmask_info->l4_dcn_present);
+
+	strcat(lineh, tmph);
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+	strcat(line5, tmp5);
+
+	fprintf(fd, "%s%s%s%s%s%s",
+		lineh,
+		line1,
+		line2,
+		line3,
+		line5,
+		line4);
+
+	fputs("\n:Profile TCAM: remap\n", fd);
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+---+---+---+--+---+---+---+\n");
+	snprintf(line2, TFC_STRING_LENGTH_256, "|B|EM|PID|KId|Scp|WC|PID|KId|Scp|\n");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+---+---+---+--+---+---+---+\n");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %c  %c x%02x x%02x x%02x  %c x%02x x%02x x%02x\n",
+		 ptrmp_info->pl_byp_lkup_en ? 'Y' : 'N',
+		 ptrmp_info->em_search_en ? 'Y' : 'N',
+		 ptrmp_info->em_profile_id,
+		 ptrmp_info->em_key_id,
+		 ptrmp_info->em_scope,
+		 ptrmp_info->tcam_search_en ? 'Y' : 'N',
+		 ptrmp_info->tcam_profile_id,
+		 ptrmp_info->tcam_key_id,
+		 ptrmp_info->tcam_scope);
+
+	fprintf(fd, "%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line4);
+
+	rte_free(lineh);
+	rte_free(line1);
+	rte_free(line2);
+	rte_free(line3);
+	rte_free(line4);
+	rte_free(line5);
+}
+
+/* Offset all WC LREC fields by -24  as per CFA EAS */
+#define WC_INFO_VALID(kptr)		tfc_getbits(kptr, (127 - 24), 1)
+#define WC_INFO_REC_SIZE(kptr)		tfc_getbits(kptr, (125 - 24), 2)
+#define WC_INFO_EPOCH0(kptr)		tfc_getbits(kptr, (113 - 24), 12)
+#define WC_INFO_EPOCH1(kptr)		tfc_getbits(kptr, (107 - 24), 6)
+#define WC_INFO_OPCODE(kptr)		tfc_getbits(kptr, (103 - 24), 4)
+#define WC_INFO_STRENGTH(kptr)		tfc_getbits(kptr, (101 - 24), 2)
+#define WC_INFO_ACT_HINT(kptr)		tfc_getbits(kptr, (99 - 24), 2)
+
+#define WC_INFO_ACT_REC_PTR(kptr)	tfc_getbits(kptr, (73 - 24), 26)
+
+#define WC_INFO_DESTINATION(kptr)	tfc_getbits(kptr, (73 - 24), 17)
+
+#define WC_INFO_TCP_DIRECTION(kptr)	tfc_getbits(kptr, (72 - 24), 1)
+#define WC_INFO_TCP_UPDATE_EN(kptr)	tfc_getbits(kptr, (71 - 24), 1)
+#define WC_INFO_TCP_WIN(kptr)		tfc_getbits(kptr, (66 - 24), 5)
+#define WC_INFO_TCP_MSB_LOC(kptr)	tfc_getbits(kptr, (48 - 24), 18)
+#define WC_INFO_TCP_MSB_OPP(kptr)	tfc_getbits(kptr, (30 - 24), 18)
+#define WC_INFO_TCP_MSB_OPP_INIT(kptr)	tfc_getbits(kptr, (29 - 24), 1)
+#define WC_INFO_STATE(kptr)		tfc_getbits(kptr, (24 - 24), 5)
+
+#define WC_INFO_RING_TABLE_IDX(kptr)	tfc_getbits(kptr, (64 - 24), 9)
+#define WC_INFO_ACT_REC_SIZE(kptr)	tfc_getbits(kptr, (59 - 24), 5)
+#define WC_INFO_PATHS_M1(kptr)		tfc_getbits(kptr, (55 - 24), 4)
+#define WC_INFO_FC_OP(kptr)		tfc_getbits(kptr, (54 - 24), 1)
+#define WC_INFO_FC_TYPE(kptr)		tfc_getbits(kptr, (52 - 24), 2)
+#define WC_INFO_FC_PTR(kptr)		tfc_getbits(kptr, (24 - 24), 28)
+
+#define WC_INFO_RECYCLE_DEST(kptr)	tfc_getbits(kptr, (72 - 24), 1)
+#define WC_INFO_PROF_FUNC(kptr)		tfc_getbits(kptr, (64 - 24), 8)
+#define WC_INFO_META_PROF(kptr)		tfc_getbits(kptr, (61 - 24), 3)
+#define WC_INFO_METADATA(kptr)		tfc_getbits(kptr, (29 - 24), 32)
+
+static void wc_tcam_decode(uint32_t *wc_res_ptr,
+			   struct wc_lrec_t *wc_info,
+			   struct tfc_ts_mem_cfg *act_mem_cfg)
+{
+	wc_info->valid    = WC_INFO_VALID(wc_res_ptr);
+	wc_info->rec_size = WC_INFO_REC_SIZE(wc_res_ptr);
+	wc_info->epoch0   = WC_INFO_EPOCH0(wc_res_ptr);
+	wc_info->epoch1   = WC_INFO_EPOCH1(wc_res_ptr);
+	wc_info->opcode   = WC_INFO_OPCODE(wc_res_ptr);
+	wc_info->strength = WC_INFO_STRENGTH(wc_res_ptr);
+	wc_info->act_hint = WC_INFO_ACT_HINT(wc_res_ptr);
+
+	if (wc_info->opcode != 2 && wc_info->opcode != 3) {
+		/* All but FAST */
+		wc_info->act_rec_ptr = WC_INFO_ACT_REC_PTR(wc_res_ptr);
+		act_process(wc_info->act_rec_ptr, &wc_info->act_info, act_mem_cfg);
+	} else {
+		/* Just FAST */
+		wc_info->destination = WC_INFO_DESTINATION(wc_res_ptr);
+	}
+
+	if (wc_info->opcode == 4 || wc_info->opcode == 6) {
+		/* CT only */
+		wc_info->tcp_direction    = WC_INFO_TCP_DIRECTION(wc_res_ptr);
+		wc_info->tcp_update_en    = WC_INFO_TCP_UPDATE_EN(wc_res_ptr);
+		wc_info->tcp_win          = WC_INFO_TCP_WIN(wc_res_ptr);
+		wc_info->tcp_msb_loc      = WC_INFO_TCP_MSB_LOC(wc_res_ptr);
+		wc_info->tcp_msb_opp      = WC_INFO_TCP_MSB_OPP(wc_res_ptr);
+		wc_info->tcp_msb_opp_init = WC_INFO_TCP_MSB_OPP_INIT(wc_res_ptr);
+		wc_info->state            = WC_INFO_STATE(wc_res_ptr);
+	} else if (wc_info->opcode != 8) {
+		/* Not CT and nor RECYCLE */
+		wc_info->ring_table_idx = WC_INFO_RING_TABLE_IDX(wc_res_ptr);
+		wc_info->act_rec_size   = WC_INFO_ACT_REC_SIZE(wc_res_ptr);
+		wc_info->paths_m1       = WC_INFO_PATHS_M1(wc_res_ptr);
+		wc_info->fc_op          = WC_INFO_FC_OP(wc_res_ptr);
+		wc_info->fc_type        = WC_INFO_FC_TYPE(wc_res_ptr);
+		wc_info->fc_ptr         = WC_INFO_FC_PTR(wc_res_ptr);
+	} else {
+		/* Recycle */
+		wc_info->recycle_dest = WC_INFO_RECYCLE_DEST(wc_res_ptr);
+		wc_info->prof_func    = WC_INFO_PROF_FUNC(wc_res_ptr);
+		wc_info->meta_prof    = WC_INFO_META_PROF(wc_res_ptr);
+		wc_info->metadata     = WC_INFO_METADATA(wc_res_ptr);
+	}
+}
+
+static void wc_tcam_show(FILE *fd, struct wc_lrec_t *wc_info)
+{
+	char *line1 = NULL;
+	char *line2 = NULL;
+	char *line3 = NULL;
+	char *line4 = NULL;
+	char tmp1[TFC_STRING_LENGTH_64];
+	char tmp2[TFC_STRING_LENGTH_64];
+	char tmp3[TFC_STRING_LENGTH_64];
+	char tmp4[TFC_STRING_LENGTH_64];
+
+	line1 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line2 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line3 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	line4 = rte_malloc("data", TFC_STRING_LENGTH_256, 8);
+	if (!line1 || !line2 || !line3 || !line4) {
+		rte_free(line1);
+		rte_free(line2);
+		rte_free(line3);
+		rte_free(line4);
+		fprintf(fd, "%s: Failed to allocate temp buffer\n",
+			__func__);
+		return;
+	}
+
+	fprintf(fd, ":LREC: opcode:%s\n", get_lrec_opcode_str(wc_info->opcode));
+
+	snprintf(line1, TFC_STRING_LENGTH_256, "+-+--+-Epoch-+--+--+--+");
+	snprintf(line2, TFC_STRING_LENGTH_256, " V|rs|  0  1 |Op|St|ah|");
+	snprintf(line3, TFC_STRING_LENGTH_256, "+-+--+----+--+--+--+--+");
+	snprintf(line4, TFC_STRING_LENGTH_256, " %1d %2d %4d %2d %2d %2d %2d ",
+		 wc_info->valid,
+		 wc_info->rec_size,
+		 wc_info->epoch0,
+		 wc_info->epoch1,
+		 wc_info->opcode,
+		 wc_info->strength,
+		 wc_info->act_hint);
+
+	if (wc_info->opcode != 2 && wc_info->opcode != 3) {
+		/* All but FAST */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "-Act Rec--+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, " Ptr      |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "----------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "0x%08x ",
+			 wc_info->act_rec_ptr);
+	} else {
+		/* Just FAST */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "-------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, " Dest  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "-------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "0x05%x ",
+			 wc_info->destination);
+	}
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	if (wc_info->opcode == 4 || wc_info->opcode == 6) {
+		/* CT only */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+-------------TCP-------+--+---+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "Dr|ue| Win|   lc  |   op  |oi|st|tmr|");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+----+-------+-------+--+--+---+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d %2d %4d %0x5x %0x5x %2d %2d %3d ",
+			 wc_info->tcp_direction,
+			 wc_info->tcp_update_en,
+			 wc_info->tcp_win,
+			 wc_info->tcp_msb_loc,
+			 wc_info->tcp_msb_opp,
+			 wc_info->tcp_msb_opp_init,
+			 wc_info->state,
+			 wc_info->timer_value);
+	} else if (wc_info->opcode != 8) {
+		/* Not CT and nor RECYCLE */
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+--+-------FC-------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "RI|as|pm|op|tp|     Ptr  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+--+--+--+----------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d %2d %2d %2d %2d 0x%08x ",
+			 wc_info->ring_table_idx,
+			 wc_info->act_rec_size,
+			 wc_info->paths_m1,
+			 wc_info->fc_op,
+			 wc_info->fc_type,
+			 wc_info->fc_ptr);
+	} else {
+		snprintf(tmp1, TFC_STRING_LENGTH_64, "--+--+--+---------+");
+		snprintf(tmp2, TFC_STRING_LENGTH_64, "RD|pf|mp| cMData  |");
+		snprintf(tmp3, TFC_STRING_LENGTH_64, "--+--+--+---------+");
+		snprintf(tmp4, TFC_STRING_LENGTH_64, "%2d 0x%2x %2d %08x ",
+			 wc_info->recycle_dest,
+			 wc_info->prof_func,
+			 wc_info->meta_prof,
+			 wc_info->metadata);
+	}
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	snprintf(tmp1, TFC_STRING_LENGTH_64, "-----Range-+\n");
+	snprintf(tmp2, TFC_STRING_LENGTH_64, "Prof|  Idx |\n");
+	snprintf(tmp3, TFC_STRING_LENGTH_64, "----+------+\n");
+	snprintf(tmp4, TFC_STRING_LENGTH_64, "0x%02x 0x%04x\n",
+		 wc_info->range_profile,
+		 wc_info->range_index);
+
+	strcat(line1, tmp1);
+	strcat(line2, tmp2);
+	strcat(line3, tmp3);
+	strcat(line4, tmp4);
+
+	fprintf(fd, "%s%s%s%s",
+		line1,
+		line2,
+		line3,
+		line4);
+
+	if (wc_info->opcode != 2 && wc_info->opcode != 3)
+		act_show(fd, &wc_info->act_info, wc_info->act_rec_ptr << 5);
+
+	rte_free(line1);
+	rte_free(line2);
+	rte_free(line3);
+	rte_free(line4);
+}
+
+static int tfc_tcam_process(struct ulp_flow_db_res_params *rp,
+			    void *frp_ctxt)
+{
+	struct wc_frp_context *wc_frp = (struct wc_frp_context *)frp_ctxt;
+	struct l2ctx_tcam_key_t *l2ctx_key_info, *l2ctx_mask_info;
+	struct prof_tcam_key_t *ptkey_info, *ptmask_info;
+	struct l2ctx_tcam_remap_t *l2ctx_rmp_info;
+	struct prof_tcam_remap_t *ptrmp_info;
+	FILE *fd = wc_frp->fd;
+	struct wc_lrec_t *wc_lrec;
+	uint8_t *key, *mask, *remap;
+	uint16_t key_sz = 128, remap_sz = 128;
+	int rc = -ENOMEM;
+
+	/* Allocate all temp storage */
+	wc_lrec = rte_zmalloc("data", sizeof(*wc_lrec), 8);
+	l2ctx_key_info = rte_zmalloc("data", sizeof(*l2ctx_key_info), 8);
+	l2ctx_mask_info = rte_zmalloc("data", sizeof(*l2ctx_mask_info), 8);
+	l2ctx_rmp_info = rte_zmalloc("data", sizeof(*l2ctx_rmp_info), 8);
+	ptkey_info = rte_zmalloc("data", sizeof(*ptkey_info), 8);
+	ptmask_info = rte_zmalloc("data", sizeof(*ptmask_info), 8);
+	ptrmp_info = rte_zmalloc("data", sizeof(*ptrmp_info), 8);
+	key = rte_zmalloc("data", key_sz, 8);
+	mask = rte_zmalloc("data", key_sz, 8);
+	remap = rte_zmalloc("data", remap_sz, 8);
+
+	if (!wc_lrec || !l2ctx_key_info || !l2ctx_mask_info ||
+	    !l2ctx_rmp_info || !ptkey_info || !ptmask_info ||
+	    !ptrmp_info || !key || !mask || !remap) {
+		fputs("Out of memory:\n", fd);
+		fprintf(fd, "%p:%p:%p\n", wc_lrec, l2ctx_key_info, l2ctx_mask_info);
+		fprintf(fd, "%p:%p:%p\n", l2ctx_rmp_info, ptkey_info, ptmask_info);
+		fprintf(fd, "%p:%p:%p:%p\n", ptrmp_info, key, mask, remap);
+		goto tcam_process_error;
+	}
+
+	rc = tfc_tcam_entry_read(wc_frp->ulp_ctxt,
+				 rp->direction,
+				 rp->resource_type,
+				 rp->resource_hndl,
+				 key,
+				 mask,
+				 remap,
+				 &key_sz,
+				 &remap_sz);
+	if (rc) {
+		fprintf(fd, "TCAM read error rc[%d]\n", rc);
+		rc = -EINVAL;
+		goto tcam_process_error;
+	}
+
+	/*
+	 * Decode result, and extract act_ptr, only for L2 ctx or WC TCAM
+	 * entries
+	 */
+	switch (rp->resource_type) {
+	case CFA_RSUBTYPE_TCAM_L2CTX:
+		fprintf(fd, "\n:L2CTX TCAM [%u]:\n", (uint16_t)rp->resource_hndl);
+		hex_buf_dump(fd, "Key:", key, (int)key_sz, 1, 16);
+		hex_buf_dump(fd, "Mask:", mask, (int)key_sz, 1, 16);
+		l2ctx_tcam_key_decode((uint32_t *)key, l2ctx_key_info);
+		l2ctx_tcam_key_decode((uint32_t *)mask, l2ctx_mask_info);
+		l2ctx_tcam_remap_decode((uint32_t *)remap,
+					l2ctx_rmp_info, wc_frp->act_mem_cfg);
+		l2ctx_tcam_show(fd, l2ctx_key_info, l2ctx_mask_info, l2ctx_rmp_info);
+		break;
+
+	case CFA_RSUBTYPE_TCAM_WC:
+		fprintf(fd, "\n:WC TCAM [%u]:\n", (uint16_t)rp->resource_hndl);
+		hex_buf_dump(fd, "Key:", key, (int)key_sz, 1, 16);
+		hex_buf_dump(fd, "Mask:", mask, (int)key_sz, 1, 16);
+		wc_tcam_decode((uint32_t *)remap, wc_lrec, wc_frp->act_mem_cfg);
+		wc_tcam_show(fd, wc_lrec);
+		break;
+
+	case CFA_RSUBTYPE_TCAM_PROF_TCAM:
+		fprintf(fd, "\n:Profile TCAM [%u]:\n", (uint16_t)rp->resource_hndl);
+		hex_buf_dump(fd, "Key:", key, (int)key_sz, 1, 16);
+		hex_buf_dump(fd, "Mask:", mask, (int)key_sz, 1, 16);
+		prof_tcam_key_decode((uint32_t *)key, ptkey_info);
+		prof_tcam_key_decode((uint32_t *)mask, ptmask_info);
+		prof_tcam_remap_decode((uint32_t *)remap, ptrmp_info);
+		prof_tcam_show(fd, ptkey_info, ptmask_info, ptrmp_info);
+		break;
+
+	case CFA_RSUBTYPE_TCAM_CT_RULE:
+	case CFA_RSUBTYPE_TCAM_VEB:
+	case CFA_RSUBTYPE_TCAM_FEATURE_CHAIN:
+		fprintf(fd, "Unsupported decode: %s\n", tfc_tcam_2_str(rp->resource_type));
+	default:
+		break;
+	}
+
+tcam_process_error:
+	rte_free(l2ctx_key_info);
+	rte_free(l2ctx_mask_info);
+	rte_free(l2ctx_rmp_info);
+	rte_free(wc_lrec);
+	rte_free(ptkey_info);
+	rte_free(ptmask_info);
+	rte_free(ptrmp_info);
+	rte_free(key);
+	rte_free(mask);
+	rte_free(remap);
+	return rc;
+}
+
+/*
+ * Check for the following conditions:
+ * 1. res_dir == p_res_dir
+ * 2. res_func == p_res_func
+ * 3. res_type == p_res_type
+ * 4. if res_dir == CFA_DIR_MAX, skip #1
+ * 5. if res_func == BNXT_ULP_RESOURCE_FUNC_INVALID, skip #2
+ * 6. if res_type == CFA_RSUBTYPE_TCAM_MAX, skip #3
+ *
+ * Bascally implements a wildcarded match for either-or-and all conditions.
+ */
+#define TFC_INVALID_RES 0xFFFFFFFF
+static bool tfc_flow_db_resource_filter(uint32_t p_res_dir, uint32_t p_res_func,
+					uint32_t p_res_type, uint32_t res_dir,
+					uint32_t res_func, uint32_t res_type)
+{
+	if (res_dir != CFA_DIR_MAX && p_res_dir != res_dir)
+		return false;
+
+	/* res_dir == CFA_DIR_MAX */
+	if (res_func == TFC_INVALID_RES &&
+	    res_type == TFC_INVALID_RES)
+		return true;
+	else if (res_func == TFC_INVALID_RES &&
+		 res_type == p_res_type)
+		return true;
+	else if (res_func == p_res_func &&
+		 res_type == TFC_INVALID_RES)
+		return true;
+
+	return false;
+}
+
+/**
+ * Walk through a resource matching a spec (resource_func+resource_type) for a
+ * particular flow (or all flows), and call a processing callback to handle
+ * data per resource/type.
+ *
+ * @ulp_ctxt:      Ptr to ulp_context
+ * @flow_type:     FDB flow type (default/regular)
+ * @resource_func: if zero then all resource_funcs are dumped.
+ * @resource_type: if zero then all resource_types are dumped.
+ * @frp:           FDB resource processor function
+ * @frp_ctxt:      FDB resource processor context
+ *
+ * returns 0 if success, error code if not
+ */
+static
+int tfc_flow_db_resource_walk(struct bnxt_ulp_context *ulp_ctxt, uint8_t flow_type,
+			      uint32_t resource_dir, uint32_t resource_func, uint32_t resource_type,
+			      FDB_RESOURCE_PROCFUNC frp,
+			      void *frp_ctxt)
+{
+	struct wc_frp_context *wc_frp = (struct wc_frp_context *)frp_ctxt;
+	FILE *fd = wc_frp->fd;
+	struct ulp_flow_db_res_params params;
+#if (TFC_DEBUG_DUMP_ALL_FLOWS)
+	struct bnxt_ulp_flow_tbl *flow_tbl;
+#endif
+	struct bnxt_ulp_flow_db *flow_db;
+	uint32_t ridx, fid = 1;
+	int rc;
+
+	if (!ulp_ctxt || !ulp_ctxt->cfg_data)
+		return -EINVAL;
+
+	if (!frp) {
+		fputs("No FDB proc_func\n", fd);
+		return -EINVAL;
+	}
+
+	flow_db = bnxt_ulp_cntxt_ptr2_flow_db_get(ulp_ctxt);
+	if (!flow_db) {
+		fputs("Invalid Arguments\n", fd);
+		return -EINVAL;
+	}
+
+#if (TFC_DEBUG_DUMP_ALL_FLOWS)
+	flow_tbl = &flow_db->flow_tbl;
+
+	for (fid = 1; fid < flow_tbl->num_flows; fid++) {
+#else
+	while (!ulp_flow_db_next_entry_get(flow_db, flow_type, &fid)) {
+#endif
+		ridx = 0;
+
+		rc = ulp_flow_db_resource_get(ulp_ctxt, flow_type, fid,
+					      &ridx, &params);
+		if (!rc) {
+			if (tfc_flow_db_resource_filter(params.direction,
+							params.resource_func,
+							params.resource_type,
+							resource_dir,
+							resource_func,
+							resource_type)) {
+				(*frp)(&params, (void *)frp_ctxt);
+			}
+
+			do {
+				rc = ulp_flow_db_resource_get(ulp_ctxt, flow_type, fid,
+							      &ridx, &params);
+				if (!rc) {
+					if (tfc_flow_db_resource_filter(params.direction,
+									params.resource_func,
+									params.resource_type,
+									resource_dir,
+									resource_func,
+									resource_type))
+						(*frp)(&params, (void *)frp_ctxt);
+				}
+			} while (ridx);
+		}
+	}
+	return 0;
+}
+
+int tfc_wc_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir)
+{
+	struct tfc_ts_mem_cfg *act_mem_cfg;
+	struct bnxt_ulp_context *ulp_ctx;
+	struct wc_frp_context wc_frp;
+	bool is_bs_owner;
+	struct bnxt *bp;
+	bool is_shared;
+	bool valid;
+	int rc = 0;
+
+	if (!tfcp)
+		return -EINVAL;
+
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
+	if (rc != 0) {
+		fprintf(fd, "%s: failed to get tsid: %d\n",
+			   __func__, rc);
+		return -EINVAL;
+	}
+	if (!valid) {
+		fprintf(fd, "%s: tsid not allocated %d\n",
+			   __func__, tsid);
+		return -EINVAL;
+	}
+
+	act_mem_cfg = rte_zmalloc("data", sizeof(*act_mem_cfg), 8);
+	if (!act_mem_cfg)
+		return -ENOMEM;
+
+	rc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid,
+				dir,
+				CFA_REGION_TYPE_ACT,
+				&is_bs_owner,
+				act_mem_cfg);   /* Gets rec_cnt */
+	if (rc != 0) {
+		fprintf(fd, "%s: tfo_ts_get_mem_cfg() failed for ACT: %d\n",
+			   __func__, rc);
+		rte_free(act_mem_cfg);
+		return -EINVAL;
+	}
+
+	if (tfcp &&
+	    tfcp->bp) {
+		bp = (struct bnxt *)(tfcp->bp);
+		ulp_ctx = bp->ulp_ctx;
+
+		if (ulp_ctx) {
+			wc_frp.ulp_ctxt = ulp_ctx;
+			wc_frp.fd = fd;
+			wc_frp.act_mem_cfg = act_mem_cfg;
+
+			/* Dump-decode all TCAM resources for default flows */
+			fputs("\nDefault flows TCAM:\n", fd);
+			fputs("===================\n", fd);
+			tfc_flow_db_resource_walk(ulp_ctx, BNXT_ULP_FDB_TYPE_DEFAULT, dir,
+						  BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE,
+						  -1, &tfc_tcam_process, (void *)&wc_frp);
+			/* Dump-decode all TCAM resources for resource-id flows */
+			fputs("\nRID flows TCAM:\n", fd);
+			fputs("===============\n", fd);
+			tfc_flow_db_resource_walk(ulp_ctx, BNXT_ULP_FDB_TYPE_RID, dir,
+						  BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE,
+						  -1, &tfc_tcam_process, (void *)&wc_frp);
+			/* Dump-decode all TCAM resources for regular flows */
+			fputs("\nRegular flows TCAM:\n", fd);
+			fputs("===================\n", fd);
+			tfc_flow_db_resource_walk(ulp_ctx, BNXT_ULP_FDB_TYPE_REGULAR, dir,
+						  BNXT_ULP_RESOURCE_FUNC_TCAM_TABLE,
+						  -1, &tfc_tcam_process, (void *)&wc_frp);
+		}
+	}
+
+	rte_free(act_mem_cfg);
+	return rc;
+}
diff --git a/drivers/net/bnxt/tf_core/v3/tfo.c b/drivers/net/bnxt/tf_core/v3/tfo.c
index 5ec2f7afa2..21146d1daa 100644
--- a/drivers/net/bnxt/tf_core/v3/tfo.c
+++ b/drivers/net/bnxt/tf_core/v3/tfo.c
@@ -571,3 +571,35 @@ int tfo_tim_get(void *tfo, void **tim)
 
 	return 0;
 }
+
+
+int tfo_tsid_get(void *tfo, uint8_t *tsid)
+{
+	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_tsid_db *tsid_db;
+	uint8_t i;
+
+	if (tfo == NULL) {
+		PMD_DRV_LOG(ERR, "%s: Invalid tfo pointer", __func__);
+		return -EINVAL;
+	}
+	if (tfco->signature != TFC_OBJ_SIGNATURE) {
+		PMD_DRV_LOG(ERR, "%s: Invalid tfo object", __func__);
+		return -EINVAL;
+	}
+	if (tsid == NULL) {
+		PMD_DRV_LOG(ERR, "%s: Invalid tsid pointer", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 1; i < TFC_TBL_SCOPE_MAX; i++) {
+		tsid_db = &tfco->tsid_db[i];
+
+		if (tsid_db->ts_valid) {
+			*tsid = i;
+			return 0;
+		}
+	}
+
+	return -1;
+}
diff --git a/drivers/net/bnxt/tf_core/v3/tfo.h b/drivers/net/bnxt/tf_core/v3/tfo.h
index f97d4cdd2d..e572db5991 100644
--- a/drivers/net/bnxt/tf_core/v3/tfo.h
+++ b/drivers/net/bnxt/tf_core/v3/tfo.h
@@ -426,4 +426,18 @@ int tfo_tim_set(void *tfo, void *tim);
  */
 int tfo_tim_get(void *tfo, void **tim);
 
+/**
+ * Get the table scope
+ *
+ * @param[in] tfo
+ *   Pointer to TFC object
+ *
+ * @param[out] tsid
+ *   Pointer to the returned table scope
+ *
+ * @return
+ *   0 for SUCCESS, negative error value for FAILURE (errno.h)
+ */
+int tfo_tsid_get(void *tfo, uint8_t *tsid);
+
 #endif /* _TFO_H_ */
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
index f2426ce3c1..ab6608ac74 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.h
@@ -76,4 +76,9 @@ bnxt_ulp_cntxt_page_sz_get(struct bnxt_ulp_context *ulp_ctxt);
 int32_t
 bnxt_ulp_cntxt_page_sz_set(struct bnxt_ulp_context *ulp_ctxt,
 			   uint32_t page_sz);
+
+int32_t
+ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
+			   enum bnxt_ulp_fdb_type flow_type,
+			   uint32_t *fid);
 #endif
diff --git a/drivers/net/bnxt/tf_ulp/ulp_fc_mgr_tfc.c b/drivers/net/bnxt/tf_ulp/ulp_fc_mgr_tfc.c
index d1b374e603..8e61c71f97 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_fc_mgr_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_fc_mgr_tfc.c
@@ -18,7 +18,6 @@
 #include "ulp_template_db_enum.h"
 #include "ulp_template_struct.h"
 #include "tfc.h"
-#include "tfc_debug.h"
 #include "tfc_action_handle.h"
 
 /* Need to create device parms for these values and handle
diff --git a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c
index 943c9b799c..46f5a96baf 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_flow_db.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_flow_db.c
@@ -9,6 +9,8 @@
 #include "bnxt.h"
 #include "bnxt_tf_common.h"
 #include "bnxt_ulp_utils.h"
+#include "bnxt_ulp_tfc.h"
+#include "ulp_utils.h"
 #include "ulp_template_struct.h"
 #include "ulp_mapper.h"
 #include "ulp_flow_db.h"
@@ -883,7 +885,7 @@ ulp_flow_db_resource_get(struct bnxt_ulp_context *ulp_ctxt,
  *
  * returns 0 on success and negative on failure.
  */
-static int32_t
+int32_t
 ulp_flow_db_next_entry_get(struct bnxt_ulp_flow_db *flow_db,
 			   enum bnxt_ulp_fdb_type flow_type,
 			   uint32_t *fid)
diff --git a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
index 24012e30b1..191157ebe1 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr.c
@@ -19,7 +19,6 @@
 #include "ulp_template_db_enum.h"
 #include "ulp_template_struct.h"
 #include "tfc.h"
-#include "tfc_debug.h"
 #include "tfc_action_handle.h"
 
 #define ULP_TFC_CNTR_READ_BYTES 32
diff --git a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr_tfc.c b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr_tfc.c
index 23edf9f755..3b863115f0 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_sc_mgr_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_sc_mgr_tfc.c
@@ -18,7 +18,6 @@
 #include "ulp_template_db_enum.h"
 #include "ulp_template_struct.h"
 #include "tfc.h"
-#include "tfc_debug.h"
 #include "tfc_action_handle.h"
 
 static int32_t
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 33/57] net/bnxt/tf_core: truflow global table scope
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 34/57] net/bnxt/tf_ulp: ulp parser support to handle gre key Manish Kurup
                   ` (18 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev
  Cc: ajit.khaparde, Farah Smith, Jay Ding, Kishore Padmanabha,
	Peter Spreadborough

From: Farah Smith <farah.smith@broadcom.com>

1. Add support for a global table scope used for socket direct
   applications.  Create database, select database based upon table
   scope supplied.  Table scopes can now be one of 3 types: global,
   shared application and non-shared.
2. Fix issue when shutting down DPDK.  Firmware deconfigures the
   table scope when the fid is removed so no need to issue deconfig,
   just free the memory.

Signed-off-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Jay Ding <jay.ding@broadcom.com>
Reviewed-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
Reviewed-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
---
 drivers/net/bnxt/bnxt_ethdev.c                |  53 ++---
 .../net/bnxt/hcapi/cfa_v3/include/cfa_types.h |  10 +
 drivers/net/bnxt/hsi_struct_def_dpdk.h        | 221 +++++++++++++++---
 drivers/net/bnxt/tf_core/v3/tfc.h             |  81 ++++---
 drivers/net/bnxt/tf_core/v3/tfc_act.c         |  32 +--
 drivers/net/bnxt/tf_core/v3/tfc_cpm.c         |  13 ++
 drivers/net/bnxt/tf_core/v3/tfc_em.c          |  16 +-
 drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c   |  16 +-
 drivers/net/bnxt/tf_core/v3/tfc_msg.c         |  63 +++--
 drivers/net/bnxt/tf_core/v3/tfc_msg.h         |   8 +-
 drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c   | 205 ++++++++--------
 drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c  |   2 +-
 drivers/net/bnxt/tf_core/v3/tfc_util.c        |  15 ++
 drivers/net/bnxt/tf_core/v3/tfc_util.h        |  11 +
 drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.c   |   3 +-
 drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.h   |   4 +-
 drivers/net/bnxt/tf_core/v3/tfo.c             | 214 ++++++++++++-----
 drivers/net/bnxt/tf_core/v3/tfo.h             |  39 ++--
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c        |  70 ++++--
 .../net/bnxt/tf_ulp/ulp_template_db_enum.h    |   3 +-
 20 files changed, 716 insertions(+), 363 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 4bca2239c3..94bec74c1e 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -6142,37 +6142,6 @@ bnxt_parse_devarg_app_id(__rte_unused const char *key,
 	return 0;
 }
 
-static int
-bnxt_parse_devarg_mpc(__rte_unused const char *key,
-		      const char *value, __rte_unused void *opaque_arg)
-{
-	char *end = NULL;
-
-	if (!value || !opaque_arg) {
-		PMD_DRV_LOG_LINE(ERR,
-				 "Invalid parameter passed to app-id "
-				 "devargs");
-		return -EINVAL;
-	}
-
-	mpc = strtoul(value, &end, 10);
-	if (end == NULL || *end != '\0' ||
-	    (mpc == ULONG_MAX && errno == ERANGE)) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid parameter passed to mpc "
-				 "devargs");
-		return -EINVAL;
-	}
-
-	if (BNXT_DEVARG_MPC_INVALID(mpc)) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid mpc(%d) devargs",
-				 (uint16_t)mpc);
-		return -EINVAL;
-	}
-
-	PMD_DRV_LOG_LINE(INFO, "MPC%d feature enabled", (uint16_t)mpc);
-	return 0;
-}
-
 static int
 bnxt_parse_devarg_ieee_1588(__rte_unused const char *key,
 			    const char *value, void *opaque_arg)
@@ -6209,6 +6178,14 @@ bnxt_parse_devarg_ieee_1588(__rte_unused const char *key,
 	return 0;
 }
 
+static int
+bnxt_parse_devarg_mpc(__rte_unused const char *key,
+		      __rte_unused const char *value, __rte_unused void *opaque_arg)
+{
+	PMD_DRV_LOG_LINE(INFO, "mpc=1 arg not required.");
+	return 0;
+}
+
 static int
 bnxt_parse_devarg_rep_is_pf(__rte_unused const char *key,
 			    const char *value, void *opaque_arg)
@@ -6522,6 +6499,13 @@ bnxt_parse_dev_args(struct bnxt *bp, struct rte_devargs *devargs)
 		goto err;
 
 err:
+	/*
+	 * Handler for "mpc" devarg.
+	 * Invoked as for ex: "-a 000:00:0d.0,mpc=1"
+	 */
+	rte_kvargs_process(kvlist, BNXT_DEVARG_MPC,
+			   bnxt_parse_devarg_mpc, bp);
+
 	/*
 	 * Handler for "app-id" devarg.
 	 * Invoked as for ex: "-a 000:00:0d.0,app-id=1"
@@ -6536,13 +6520,6 @@ bnxt_parse_dev_args(struct bnxt *bp, struct rte_devargs *devargs)
 	rte_kvargs_process(kvlist, BNXT_DEVARG_IEEE_1588,
 			   bnxt_parse_devarg_ieee_1588, bp);
 
-	/*
-	 * Handler for "mpc" devarg.
-	 * Invoked as for ex: "-a 000:00:0d.0,mpc=1"
-	 */
-	rte_kvargs_process(kvlist, BNXT_DEVARG_MPC,
-			   bnxt_parse_devarg_mpc, bp);
-
 	/*
 	 * Handler for "cqe-mode" devarg.
 	 * Invoked as for ex: "-a 000:00:0d.0,cqe-mode=1"
diff --git a/drivers/net/bnxt/hcapi/cfa_v3/include/cfa_types.h b/drivers/net/bnxt/hcapi/cfa_v3/include/cfa_types.h
index 4339fc1053..b00b21385d 100644
--- a/drivers/net/bnxt/hcapi/cfa_v3/include/cfa_types.h
+++ b/drivers/net/bnxt/hcapi/cfa_v3/include/cfa_types.h
@@ -92,6 +92,16 @@ enum cfa_app_type {
 	CFA_APP_TYPE_INVALID = CFA_APP_TYPE_MAX,
 };
 
+/**
+ * CFA table scope types
+ */
+enum cfa_scope_type {
+	CFA_SCOPE_TYPE_NON_SHARED = 0,
+	CFA_SCOPE_TYPE_SHARED_APP = 1,
+	CFA_SCOPE_TYPE_GLOBAL = 2,
+	CFA_SCOPE_TYPE_INVALID = 3
+};
+
 /**
  * CFA FID types
  */
diff --git a/drivers/net/bnxt/hsi_struct_def_dpdk.h b/drivers/net/bnxt/hsi_struct_def_dpdk.h
index 6e540359e3..866fc5379d 100644
--- a/drivers/net/bnxt/hsi_struct_def_dpdk.h
+++ b/drivers/net/bnxt/hsi_struct_def_dpdk.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright (c) 2014-2024 Broadcom Inc.
+ * Copyright (c) 2014-2025 Broadcom Inc.
  * All rights reserved.
  *
  * DO NOT MODIFY!!! This file is automatically generated.
@@ -804,6 +804,20 @@ struct __rte_packed_begin cmd_nums {
 	#define HWRM_MFG_PRVSN_EXPORT_CERT                UINT32_C(0x219)
 	/* Query the statistics for doorbell drops due to various error conditions. */
 	#define HWRM_STAT_DB_ERROR_QSTATS                 UINT32_C(0x21a)
+	/* This command is used to select and run manufacturing tests */
+	#define HWRM_MFG_TESTS                            UINT32_C(0x21b)
+	/* This command is used to write a cert chain from production firmware */
+	#define HWRM_MFG_WRITE_CERT_NVM                   UINT32_C(0x21c)
+	/*
+	 * The command is used to enable/disable the power on ethernet for
+	 * a particular I/O expander port.
+	 */
+	#define HWRM_PORT_POE_CFG                         UINT32_C(0x230)
+	/*
+	 * The command is used to query whether the power on ethernet
+	 * is enabled/disabled for a particular I/O expander port.
+	 */
+	#define HWRM_PORT_POE_QCFG                        UINT32_C(0x231)
 	/*
 	 * This command returns the capabilities related to User Defined
 	 * Congestion Control on a function.
@@ -1252,8 +1266,8 @@ struct __rte_packed_begin hwrm_err_output {
 #define HWRM_VERSION_MINOR 10
 #define HWRM_VERSION_UPDATE 3
 /* non-zero means beta version */
-#define HWRM_VERSION_RSVD 87
-#define HWRM_VERSION_STR "1.10.3.87"
+#define HWRM_VERSION_RSVD 97
+#define HWRM_VERSION_STR "1.10.3.97"
 
 /****************
  * hwrm_ver_get *
@@ -12647,9 +12661,9 @@ struct __rte_packed_begin hwrm_async_event_cmpl_dbg_buf_producer {
 	 * value of 8192. This field rolls over to zero once the firmware
 	 * writes the last page of the host buffer
 	 */
-	#define HWRM_ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURRENT_BUFFER_OFFSET_MASK \
+	#define HWRM_ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_MASK \
 		UINT32_C(0xffffffff)
-	#define HWRM_ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURRENT_BUFFER_OFFSET_SFT \
+	#define HWRM_ASYNC_EVENT_CMPL_DBG_BUF_PRODUCER_EVENT_DATA2_CURR_OFF_SFT \
 		0
 	uint8_t	opaque_v;
 	/*
@@ -15718,6 +15732,18 @@ struct __rte_packed_begin hwrm_func_qcaps_output {
 	 */
 	#define HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT3_RX_RATE_PROFILE_SEL_SUPPORTED \
 		UINT32_C(0x8)
+	/*
+	 * When set to 1, indicates that the device is capable of supporting
+	 * the RoCE bi-directional optimization feature.
+	 */
+	#define HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT3_BIDI_OPT_SUPPORTED \
+		UINT32_C(0x10)
+	/*
+	 * When set to 1, indicates that the device is capable of supporting
+	 * port mirroring on RoCE device.
+	 */
+	#define HWRM_FUNC_QCAPS_OUTPUT_FLAGS_EXT3_MIRROR_ON_ROCE_SUPPORTED \
+		UINT32_C(0x20)
 	/*
 	 * The number of VFs that can be used for RoCE on the function. If less
 	 * than max_vfs, roce vfs will be assigned to the first VF of the
@@ -15725,7 +15751,13 @@ struct __rte_packed_begin hwrm_func_qcaps_output {
 	 * This is valid only on the PF with SR-IOV and RDMA enabled.
 	 */
 	uint16_t	max_roce_vfs;
-	uint8_t	unused_3[5];
+	/*
+	 * The maximum number of Rx flow filters for KTLS and QUIC. If both
+	 * KTLS and QUIC are enabled, then this maximum number is shared
+	 * between them.
+	 */
+	uint16_t	max_crypto_rx_flow_filters;
+	uint8_t	unused_3[3];
 	/*
 	 * This field is used in Output records to indicate that the output
 	 * is completely written to RAM. This field should be read as '1'
@@ -16426,8 +16458,19 @@ struct __rte_packed_begin hwrm_func_qcfg_output {
 	 * value is used if ring MTU is not specified.
 	 */
 	uint16_t	host_mtu;
-	uint8_t	unused_3[2];
-	uint8_t	unused_4[2];
+	uint16_t	flags2;
+	/*
+	 * If set to 1, then VF drivers are requested to insert a DSCP
+	 * value into all outgoing L2 packets such that DSCP=VF ID modulo 64
+	 */
+	#define HWRM_FUNC_QCFG_OUTPUT_FLAGS2_SRIOV_DSCP_INSERT_ENABLED \
+		UINT32_C(0x1)
+	/*
+	 * This value is the S-tag VLAN identifier setting for the function
+	 * when in NPAR 1.2 mode. This field is read from firmware and is
+	 * in LE order.
+	 */
+	uint16_t	stag_vid;
 	/*
 	 * KDNet mode for the port for this function. If a VF, KDNet
 	 * mode is always disabled.
@@ -16450,7 +16493,23 @@ struct __rte_packed_begin hwrm_func_qcfg_output {
 	 * feature, 0xffff will be returned.
 	 */
 	uint16_t	port_kdnet_fid;
-	uint8_t	unused_5[2];
+	uint8_t	unused_5;
+	uint8_t	roce_bidi_opt_mode;
+	/* RoCE bi-directional optimization feature is disabled. */
+	#define HWRM_FUNC_QCFG_OUTPUT_ROCE_BIDI_OPT_MODE_DISABLED \
+		UINT32_C(0x1)
+	/*
+	 * Requester and Responder traffic use separate transmit scheduler
+	 * queues and CoSQs.
+	 */
+	#define HWRM_FUNC_QCFG_OUTPUT_ROCE_BIDI_OPT_MODE_DEDICATED \
+		UINT32_C(0x2)
+	/*
+	 * Requester and Responder traffic use separate transmit scheduler
+	 * queues, but share the same CoSQ.
+	 */
+	#define HWRM_FUNC_QCFG_OUTPUT_ROCE_BIDI_OPT_MODE_SHARED \
+		UINT32_C(0x4)
 	/* Number of KTLS Tx Key Contexts allocated. */
 	uint32_t	num_ktls_tx_key_ctxs;
 	/* Number of KTLS Rx Key Contexts allocated. */
@@ -16525,7 +16584,13 @@ struct __rte_packed_begin hwrm_func_qcfg_output {
 	 * partition on Rx crypto key contexts.
 	 */
 	#define HWRM_FUNC_QCFG_OUTPUT_XID_PARTITION_CFG_RX_CK     UINT32_C(0x2)
-	uint8_t	unused_7;
+	/*
+	 * The VNIC ID used for mirroring. This VNIC is pre-reserved.
+	 * This VNIC could be used for mirroring to a single L2 ring
+	 * or a raw QP.
+	 */
+	uint16_t	mirror_vnic_id;
+	uint8_t	unused_7[7];
 	/*
 	 * This field is used in Output records to indicate that the output
 	 * is completely written to RAM. This field should be read as '1'
@@ -24348,8 +24413,10 @@ struct __rte_packed_begin hwrm_func_backing_store_qcfg_v2_output {
 	uint8_t	valid;
 } __rte_packed_end;
 
-/* Common structure to cast QPC split entries. This casting is required in the
- * following HWRM command inputs/outputs if the backing store type is QPC.
+/*
+ * Common structure to cast QPC split entries. This casting is required
+ * in the following HWRM command inputs/outputs if the backing store
+ * type is QPC.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24368,8 +24435,10 @@ struct __rte_packed_begin qpc_split_entries {
 	uint32_t	rsvd;
 } __rte_packed_end;
 
-/* Common structure to cast SRQ split entries. This casting is required in the
- * following HWRM command inputs/outputs if the backing store type is SRQ.
+/*
+ * Common structure to cast SRQ split entries. This casting is required
+ * in the following HWRM command inputs/outputs if the backing store
+ * type is SRQ.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24382,8 +24451,10 @@ struct __rte_packed_begin srq_split_entries {
 	uint32_t	rsvd2[2];
 } __rte_packed_end;
 
-/* Common structure to cast CQ split entries. This casting is required in the
- * following HWRM command inputs/outputs if the backing store type is CQ.
+/*
+ * Common structure to cast CQ split entries. This casting is required
+ * in the following HWRM command inputs/outputs if the backing store
+ * type is CQ.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24396,8 +24467,10 @@ struct __rte_packed_begin cq_split_entries {
 	uint32_t	rsvd2[2];
 } __rte_packed_end;
 
-/* Common structure to cast VNIC split entries. This casting is required in the
- * following HWRM command inputs/outputs if the backing store type is VNIC.
+/*
+ * Common structure to cast VNIC split entries. This casting is required
+ * in the following HWRM command inputs/outputs if the backing store
+ * type is VNIC.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24410,8 +24483,10 @@ struct __rte_packed_begin vnic_split_entries {
 	uint32_t	rsvd2[2];
 } __rte_packed_end;
 
-/* Common structure to cast MRAV split entries. This casting is required in the
- * following HWRM command inputs/outputs if the backing store type is MRAV.
+/*
+ * Common structure to cast MRAV split entries. This casting is required
+ * in the following HWRM command inputs/outputs if the backing store
+ * type is MRAV.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24424,9 +24499,10 @@ struct __rte_packed_begin mrav_split_entries {
 	uint32_t	rsvd2[2];
 } __rte_packed_end;
 
-/* Common structure to cast TBL_SCOPE split entries. This casting is required
- * in the following HWRM command inputs/outputs if the backing store type is
- * TBL_SCOPE.
+/*
+ * Common structure to cast TBL_SCOPE split entries. This casting is
+ * required in the following HWRM command inputs/outputs if the backing
+ * store type is TBL_SCOPE.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -24442,13 +24518,15 @@ struct __rte_packed_begin ts_split_entries {
 	 * Array is indexed by enum cfa_dir
 	 */
 	uint8_t	lkup_static_bkt_cnt_exp[2];
-	uint8_t	rsvd;
+	/* Indicates the region is locked in the cache */
+	uint8_t	locked;
 	uint32_t	rsvd2[2];
-} __rte_packed_end;
+} __rte_packed;
 
-/* Common structure to cast crypto key split entries. This casting is required
- * in the following HWRM command inputs/outputs if the backing store type is
- * TX_CK or RX_CK.
+/*
+ * Common structure to cast crypto key split entries. This casting is
+ * required in the following HWRM command inputs/outputs if the backing
+ * store type is TX_CK or RX_CK.
  * 1. hwrm_func_backing_store_cfg_v2_input
  * 2. hwrm_func_backing_store_qcfg_v2_output
  * 3. hwrm_func_backing_store_qcaps_v2_output
@@ -42583,13 +42661,20 @@ struct __rte_packed_begin hwrm_vnic_alloc_input {
 	 */
 	#define HWRM_VNIC_ALLOC_INPUT_FLAGS_VIRTIO_NET_FID_VALID \
 		UINT32_C(0x2)
+	/*
+	 * When this bit is '1', firmware will allocate the VNIC
+	 * specified in vnic_id field.
+	 */
+	#define HWRM_VNIC_ALLOC_INPUT_FLAGS_VNIC_ID_VALID \
+		UINT32_C(0x4)
 	/*
 	 * Virtio-net function's FID.
 	 * This virtio-net function is requesting allocation of default
 	 * VNIC through proxy VEE PF.
 	 */
 	uint16_t	virtio_net_fid;
-	uint8_t	unused_0[2];
+	/* VNIC ID to allocate. */
+	uint16_t	vnic_id;
 } __rte_packed_end;
 
 /* hwrm_vnic_alloc_output (size:128b/16B) */
@@ -42958,6 +43043,9 @@ struct __rte_packed_begin hwrm_vnic_cfg_input {
 	/* This bit must be '1' for the l2_cqe_mode field to be configured. */
 	#define HWRM_VNIC_CFG_INPUT_ENABLES_L2_CQE_MODE \
 		UINT32_C(0x200)
+	/* This bit must be '1' for the raw_qp_id field to be configured. */
+	#define HWRM_VNIC_CFG_INPUT_ENABLES_RAW_QP_ID \
+		UINT32_C(0x400)
 	/* Logical vnic ID */
 	uint16_t	vnic_id;
 	/*
@@ -43080,7 +43168,8 @@ struct __rte_packed_begin hwrm_vnic_cfg_input {
 	#define HWRM_VNIC_CFG_INPUT_L2_CQE_MODE_MIXED      UINT32_C(0x2)
 	#define HWRM_VNIC_CFG_INPUT_L2_CQE_MODE_LAST \
 		HWRM_VNIC_CFG_INPUT_L2_CQE_MODE_MIXED
-	uint8_t	unused0[4];
+	/* Raw QP ID to be used for the VNIC. */
+	uint32_t	raw_qp_id;
 } __rte_packed_end;
 
 /* hwrm_vnic_cfg_output (size:128b/16B) */
@@ -44944,6 +45033,8 @@ struct __rte_packed_begin hwrm_vnic_plcmodes_cfg_input {
 	 * Packets with length larger than this value will be
 	 * placed according to the HDS placement algorithm.
 	 * This value shall be in multiple of 4 bytes.
+	 * HW supports only 10-bit value for hds_threshold. If this value is
+	 * more than 0x3FF, FW will fail this command.
 	 */
 	uint16_t	hds_threshold;
 	/*
@@ -44985,6 +45076,24 @@ struct __rte_packed_begin hwrm_vnic_plcmodes_cfg_output {
 	uint8_t	valid;
 } __rte_packed_end;
 
+/* hwrm_vnic_plcmodes_cfg_cmd_err (size:64b/8B) */
+struct hwrm_vnic_plcmodes_cfg_cmd_err {
+	/*
+	 * command specific error codes that goes to
+	 * the cmd_err field in common HWRM Error Response.
+	 */
+	uint8_t	code;
+	/* Unknown error */
+	#define HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_UNKNOWN \
+		UINT32_C(0x0)
+	/* hds_threshold value is invalid */
+	#define HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_INVALID_HDS_THRESHOLD \
+		UINT32_C(0x1)
+	#define HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_LAST \
+		HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_INVALID_HDS_THRESHOLD
+	uint8_t	unused_0[7];
+} __rte_packed;
+
 /***************************
  * hwrm_vnic_plcmodes_qcfg *
  ***************************/
@@ -45408,7 +45517,10 @@ struct __rte_packed_begin hwrm_ring_alloc_input {
 	#define HWRM_RING_ALLOC_INPUT_CMPL_COAL_CNT_COAL_320 UINT32_C(0xd)
 	/* Generates a TX coalesced completion for up to 384 TX packets. */
 	#define HWRM_RING_ALLOC_INPUT_CMPL_COAL_CNT_COAL_384 UINT32_C(0xe)
-	/* Generates a TX coalesced completion up to the last packet. (Maximum coalescing). */
+	/*
+	 * Generates a TX coalesced completion up to the last packet.
+	 * (Maximum coalescing).
+	 */
 	#define HWRM_RING_ALLOC_INPUT_CMPL_COAL_CNT_COAL_MAX UINT32_C(0xf)
 	#define HWRM_RING_ALLOC_INPUT_CMPL_COAL_CNT_LAST \
 		HWRM_RING_ALLOC_INPUT_CMPL_COAL_CNT_COAL_MAX
@@ -59915,8 +60027,32 @@ struct __rte_packed_begin hwrm_tfc_tbl_scope_qcaps_output {
 	 * support. This field is only valid if tbl_scope_capable is not zero.
 	 */
 	uint8_t	max_lkup_static_buckets_exp;
+	/* Control flags. */
+	uint8_t	flags;
+	/* Indicates whether a global scope is supported in the firmware. */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL \
+		UINT32_C(0x1)
+	/* If this bit set to 0, a global scope is not supported */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL_UNSUPPORTED \
+		UINT32_C(0x0)
+	/* If this bit is set to 1, a global scope is supported */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL_SUPPORTED \
+		UINT32_C(0x1)
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL_LAST \
+		HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL_SUPPORTED
+	/* Indicates whether a locked scope is supported in the firmware. */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED \
+		UINT32_C(0x2)
+	/* If this bit set to 0, a locked scope is not supported */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED_UNSUPPORTED \
+		(UINT32_C(0x0) << 1)
+	/* If this bit is set to 1, a locked scope is supported */
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED_SUPPORTED \
+		(UINT32_C(0x1) << 1)
+	#define HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED_LAST \
+		HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED_SUPPORTED
 	/* unused. */
-	uint8_t	unused0[5];
+	uint8_t	unused0[4];
 	/*
 	 * This field is used in Output records to indicate that the output
 	 * is completely written to RAM. This field should be read as '1'
@@ -60001,8 +60137,27 @@ struct __rte_packed_begin hwrm_tfc_tbl_scope_id_alloc_input {
 	uint8_t	act_pool_sz_exp[2];
 	/* Application type. 0 (AFM), 1 (TF) */
 	uint8_t	app_type;
+	/*
+	 * Specifies the type of table scope. Overrides the shared flag if set.
+	 * If set, this field takes precedent over the shared flag.
+	 */
+	uint8_t	scope_type;
+	/* A table scope not shared between functions */
+	#define HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_NON_SHARED \
+		UINT32_C(0x1)
+	/*
+	 * A table scope shared between functions which share the same parent
+	 * PF.
+	 */
+	#define HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_SHARED_APP \
+		UINT32_C(0x2)
+	/* A global table scope accessible by any function (e.g. LAG) */
+	#define HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_GLOBAL \
+		UINT32_C(0x3)
+	#define HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_LAST \
+		HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_GLOBAL
 	/* unused. */
-	uint8_t	unused0[6];
+	uint8_t	unused0[5];
 } __rte_packed_end;
 
 /* hwrm_tfc_tbl_scope_id_alloc_output (size:128b/16B) */
diff --git a/drivers/net/bnxt/tf_core/v3/tfc.h b/drivers/net/bnxt/tf_core/v3/tfc.h
index 54c615edc3..ebe997e711 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc.h
@@ -762,14 +762,12 @@ enum tfc_tbl_scope_bucket_factor {
  * tfc_tbl_scope_size_query API.
  */
 struct tfc_tbl_scope_size_query_parms {
-	/**
-	 * [in] If a shared table scope, dynamic buckets are disabled. This
-	 * affects the calculation for static buckets in this function.
-	 * Initially, if not shared, the size of the static bucket table should
-	 * be double the number of flows supported. Numbers are validated
-	 * against static_cnt and dynamic_cnt
+	/** Scope is one of non-shared, shared-app or global.
+	 * If a shared-app or global table scope, dynamic buckets are disabled.
+	 * this combined with the multiplier affects the calculation for static
+	 * buckets in this function.
 	 */
-	bool shared;
+	enum cfa_scope_type scope_type;
 	/**
 	 * [in] Direction indexed array indicating the number of flows.  Must be
 	 * at least as large as the number entries that the buckets can point
@@ -852,6 +850,12 @@ struct tfc_tbl_scope_size_query_parms {
  * to be used by a table scope.
  */
 struct tfc_tbl_scope_mem_alloc_parms {
+	/** Scope is one of non-shared, shared-app or global.
+	 * If a shared-app or global table scope, dynamic buckets are disabled.
+	 * this combined with the multiplier affects the calculation for static
+	 * buckets in this function.
+	 */
+	enum cfa_scope_type scope_type;
 	/**
 	 * [in] If a shared table scope, indicate whether this is the first
 	 * if, the first, the table scope memory will be allocated.  Otherwise
@@ -920,32 +924,51 @@ struct tfc_tbl_scope_mem_alloc_parms {
 	uint32_t lkup_rec_start_offset[CFA_DIR_MAX];
 };
 
+
+/**
+ * tfc_tbl_scope_qcaps_parms contains the parameters for determining
+ * the table scope capabilities
+ */
+struct tfc_tbl_scope_qcaps_parms {
+	/**
+	 * [out] if true, the device supports a table scope.
+	 */
+	bool tbl_scope_cap;
+	/**
+	 * [out] if true, the device supports a global table scope.
+	 */
+	bool global_cap;
+	/**
+	 * [out] if true, the device supports locked regions.
+	 */
+	bool locked_cap;
+	/**
+	 * [out] the maximum number of static buckets supported.
+	 */
+	uint8_t max_lkup_static_bucket_exp;
+	/**
+	 * [out] The maximum number of minimum sized lkup records supported.
+	 */
+	uint32_t max_lkup_rec_cnt;
+	/**
+	 * [out] The maximum number of  minimum sized action records supported.
+	 */
+	uint32_t max_act_rec_cnt;
+};
+
 /**
  * Determine whether table scopes are supported in the hardware.
  *
  * @param[in] tfcp
  *   Pointer to TFC handle
  *
- * @param[out] tbl_scope_capable
- *   True if table scopes are supported in the firmware.
- *
- * @param[out] max_lkup_rec_cnt
- *   The maximum number of lookup records in a table scope (optional)
- *
- * @param[out] max_act_rec_cnt
- *   The maximum number of action records in a table scope (optional)
- *
- * @param[out] max_lkup_static_buckets_exp
- *   The log2 of the maximum number of lookup static buckets in a table scope
- *   (optional)
+ * @param[in,out] parms
  *
  * @returns
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfc_tbl_scope_qcaps(struct tfc *tfcp, bool *tbl_scope_capable,
-			uint32_t *max_lkup_rec_cnt,
-			uint32_t *max_act_rec_cnt,
-			uint8_t	*max_lkup_static_buckets_exp);
+int tfc_tbl_scope_qcaps(struct tfc *tfcp,
+			struct tfc_tbl_scope_qcaps_parms *parms);
 
 /**
  * Determine table scope sizing
@@ -968,8 +991,8 @@ int tfc_tbl_scope_size_query(struct tfc *tfcp,
  * @param[in] tfcp
  *   Pointer to TFC handle
  *
- * @param[in] shared
- *   Create a shared table scope.
+ * @param[in] scope_type
+ *   non-shared, shared-app or global
  *
  * @param[in] app_type
  *   The application type, TF or AFM
@@ -984,7 +1007,7 @@ int tfc_tbl_scope_size_query(struct tfc *tfcp,
  * @returns
  *	 0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfc_tbl_scope_id_alloc(struct tfc *tfcp, bool shared,
+int tfc_tbl_scope_id_alloc(struct tfc *tfcp, enum cfa_scope_type scope_type,
 			   enum cfa_app_type app_type, uint8_t *tsid,
 			   bool *first);
 
@@ -1023,10 +1046,14 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
  * @param[in] tsid
  *   Table scope identifier
  *
+ * @param[in] fid_cnt
+ *   Used for global scope cleanup.  If a fid remains, do not delete scope
+ *
  * @returns
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid);
+int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
+			   uint16_t fid_cnt);
 
 /**
  * tfc_tbl_scope_cpm_alloc_parms contains the parameters for allocating a
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_act.c b/drivers/net/bnxt/tf_core/v3/tfc_act.c
index 7b1f82b842..3c1c76359b 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_act.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_act.c
@@ -45,12 +45,12 @@ int tfc_act_alloc(struct tfc *tfcp,
 	struct tfc_cmm *cmm;
 	uint32_t entry_offset;
 	struct cfa_mm_alloc_parms aparms;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct tfc_ts_pool_info pi;
 	bool valid;
 	uint16_t max_pools;
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, &max_pools);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, &max_pools);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -67,7 +67,11 @@ int tfc_act_alloc(struct tfc *tfcp,
 		return -EINVAL;
 	}
 
-	tfo_ts_get_pool_info(tfcp->tfo, tsid, cmm_info->dir, &pi);
+	rc = tfo_ts_get_pool_info(tfcp->tfo, tsid, cmm_info->dir, &pi);
+	if (unlikely(rc)) {
+		PMD_DRV_LOG_LINE(ERR, "%s: failed to get pool info: %s",
+				 __func__, strerror(-rc));
+	}
 
 	/* Get CPM instances */
 	rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, cmm_info->dir, &cpm_lkup, &cpm_act);
@@ -99,8 +103,9 @@ int tfc_act_alloc(struct tfc *tfcp,
 		/* There is only 1 pool for a non-shared table scope
 		 * and it is full.
 		 */
-		if (unlikely(!is_shared)) {
-			PMD_DRV_LOG_LINE(ERR, "no records remain");
+		if (unlikely(scope_type == CFA_SCOPE_TYPE_NON_SHARED)) {
+			PMD_DRV_LOG_LINE(ERR, "%s: no records remain",
+					 __func__);
 			return -ENOMEM;
 		}
 		rc = tfc_get_fid(tfcp, &fid);
@@ -157,7 +162,6 @@ int tfc_act_alloc(struct tfc *tfcp,
 			return -EINVAL;
 		}
 	}
-
 	aparms.num_contig_records = 1 << next_pow2(num_contig_rec);
 	rc = cfa_mm_alloc(cmm, &aparms);
 	if (unlikely(rc)) {
@@ -231,7 +235,7 @@ int tfc_act_set(struct tfc *tfcp,
 	struct cfa_bld_mpcinfo *mpc_info;
 	uint32_t record_size;
 	uint8_t tsid;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 
 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
@@ -247,7 +251,7 @@ int tfc_act_set(struct tfc *tfcp,
 					  &record_size,
 					  &entry_offset);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -382,7 +386,7 @@ static int tfc_act_get_only(struct tfc *tfcp,
 	struct bnxt_mpc_mbuf mpc_msg_out;
 	uint32_t record_size;
 	uint8_t tsid;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct cfa_bld_mpcinfo *mpc_info;
 	bool valid;
 
@@ -393,7 +397,7 @@ static int tfc_act_get_only(struct tfc *tfcp,
 					  &record_size,
 					  &entry_offset);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -561,7 +565,7 @@ static int tfc_act_get_clear(struct tfc *tfcp,
 	struct bnxt_mpc_mbuf mpc_msg_out;
 	uint32_t record_size;
 	uint8_t tsid;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct cfa_bld_mpcinfo *mpc_info;
 	bool valid;
 	uint16_t mask = 0;
@@ -573,7 +577,7 @@ static int tfc_act_get_clear(struct tfc *tfcp,
 					  &record_size,
 					  &entry_offset);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s",
 				 strerror(-rc));
@@ -739,7 +743,7 @@ int tfc_act_free(struct tfc *tfcp,
 	uint32_t record_offset;
 	struct cfa_mm_free_parms fparms;
 	uint8_t tsid;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 	bool is_bs_owner;
 	struct tfc_ts_mem_cfg mem_cfg;
@@ -750,7 +754,7 @@ int tfc_act_free(struct tfc *tfcp,
 					  &record_size,
 					  &record_offset);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_cpm.c b/drivers/net/bnxt/tf_core/v3/tfc_cpm.c
index 36a9189805..f58ec48db7 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_cpm.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_cpm.c
@@ -293,6 +293,10 @@ int tfc_cpm_set_cmm_inst(struct tfc_cpm *cpm, uint16_t pool_id, struct tfc_cmm *
 		return -EINVAL;
 	}
 
+	if (pool_id >= cpm->max_pools) {
+		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x > max 0x%x", pool_id, cpm->max_pools);
+		return -EINVAL;
+	}
 	pool = &cpm->pools[pool_id];
 
 	if (pool->valid && cmm != NULL) {
@@ -324,6 +328,11 @@ int tfc_cpm_get_cmm_inst(struct tfc_cpm *cpm, uint16_t pool_id, struct tfc_cmm *
 		return -EINVAL;
 	}
 
+	if (pool_id >= cpm->max_pools) {
+		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x > max 0x%x", pool_id, cpm->max_pools);
+		return -EINVAL;
+	}
+
 	pool = &cpm->pools[pool_id];
 
 	if (!pool->valid) {
@@ -359,6 +368,10 @@ int tfc_cpm_set_usage(struct tfc_cpm *cpm, uint16_t pool_id, uint32_t used_count
 		return -EINVAL;
 	}
 
+	if (pool_id >= cpm->max_pools) {
+		PMD_DRV_LOG_LINE(ERR, "Pool ID:0x%x > max 0x%x", pool_id, cpm->max_pools);
+		return -EINVAL;
+	}
 	pool = &cpm->pools[pool_id];
 
 	if (!pool->valid) {
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_em.c b/drivers/net/bnxt/tf_core/v3/tfc_em.c
index 8264f9a05d..828b7838f5 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_em.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_em.c
@@ -133,19 +133,18 @@ int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
 	uint32_t i;
 	uint32_t hash = 0;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD];
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct cfa_bld_mpcinfo *mpc_info;
 	bool valid;
 	uint16_t max_pools;
 #if TFC_EM_DYNAMIC_BUCKET_EN
 	struct cfa_mm_alloc_parms bucket_aparms;
-	bool shared = false;
 	uint32_t bucket_offset;
 #endif
 
 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, &max_pools);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, &max_pools);
 	if (unlikely(rc)) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -202,8 +201,9 @@ int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
 		/* There is only 1 pool for a non-shared table scope and
 		 * it is full.
 		 */
-		if (!is_shared) {
-			PMD_DRV_LOG_LINE(ERR, "no records remain");
+		if (scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
+			PMD_DRV_LOG_LINE(ERR, "%s: no records remain",
+					 __func__);
 			return -ENOMEM;
 		}
 
@@ -278,7 +278,7 @@ int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
 	}
 
 #if TFC_EM_DYNAMIC_BUCKET_EN
-	if (!shared) {
+	if (scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
 		/* Allocate dynamic bucket */
 		bucket_aparms.num_contig_records = TFC_EM_DYNAMIC_BUCKET_RECORD_SIZE;
 		rc = cfa_mm_alloc(cmm, &bucket_aparms);
@@ -598,7 +598,7 @@ int tfc_em_delete(struct tfc *tfcp, struct tfc_em_delete_parms *parms)
 	uint32_t record_size;
 	struct cfa_mm_free_parms fparms;
 	uint8_t tsid;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct tfc_ts_pool_info pi;
 	bool is_bs_owner;
 	struct tfc_ts_mem_cfg mem_cfg;
@@ -615,7 +615,7 @@ int tfc_em_delete(struct tfc *tfcp, struct tfc_em_delete_parms *parms)
 					&record_offset,
 					&static_bucket);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (rc != 0) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s",
 				 strerror(-rc));
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c b/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
index 5690f072e2..9731127da0 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_mpc_debug.c
@@ -43,7 +43,7 @@ int tfc_mpc_table_read(struct tfc *tfcp,
 	struct cfa_mpc_data_obj fields_cmp[CFA_BLD_MPC_READ_CMP_MAX_FLD];
 	struct bnxt_mpc_mbuf mpc_msg_in;
 	struct bnxt_mpc_mbuf mpc_msg_out;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	struct cfa_bld_mpcinfo *mpc_info;
 	uint64_t host_address;
 	uint8_t discard_data[128];
@@ -53,7 +53,7 @@ int tfc_mpc_table_read(struct tfc *tfcp,
 
 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (rc != 0) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -212,12 +212,12 @@ int tfc_mpc_table_write_zero(struct tfc *tfcp,
 	struct bnxt_mpc_mbuf mpc_msg_in;
 	struct bnxt_mpc_mbuf mpc_msg_out;
 	struct cfa_bld_mpcinfo *mpc_info;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 
 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (rc != 0) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -340,12 +340,12 @@ int tfc_mpc_table_invalidate(struct tfc *tfcp,
 	struct bnxt_mpc_mbuf mpc_msg_in;
 	struct bnxt_mpc_mbuf mpc_msg_out;
 	struct cfa_bld_mpcinfo *mpc_info;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 
 	tfo_mpcinfo_get(tfcp->tfo, &mpc_info);
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (rc != 0) {
 		PMD_DRV_LOG_LINE(ERR, "failed to get tsid: %s", strerror(-rc));
 		return -EINVAL;
@@ -1288,7 +1288,7 @@ static void bucket_show(FILE *fd, struct bucket_info_t *bucket_info, uint32_t of
 int tfc_em_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir)
 {
 	int rc = 0;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool is_bs_owner;
 	struct tfc_ts_mem_cfg *lkup_mem_cfg;
 	struct tfc_ts_mem_cfg *act_mem_cfg;
@@ -1299,7 +1299,7 @@ int tfc_em_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir)
 	uint32_t bucket_offset = 0;
 	bool valid;
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, &valid, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
 	if (rc != 0) {
 		fprintf(fd, "%s: failed to get tsid: %d\n",
 			   __func__, rc);
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_msg.c b/drivers/net/bnxt/tf_core/v3/tfc_msg.c
index 7ec7e9a054..cf72d09184 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_msg.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_msg.c
@@ -181,6 +181,8 @@ tfc_msg_free_dma_buf(struct tfc_msg_dma_buf *buf)
 int
 tfc_msg_tbl_scope_qcaps(struct tfc *tfcp,
 			bool *tbl_scope_capable,
+			bool *global_scope_capable,
+			bool *locked_scope_capable,
 			uint32_t *max_lkup_rec_cnt,
 			uint32_t *max_act_rec_cnt,
 			uint8_t	*max_lkup_static_buckets_exp)
@@ -200,8 +202,24 @@ tfc_msg_tbl_scope_qcaps(struct tfc *tfcp,
 		return -EINVAL;
 	}
 
+	if (global_scope_capable == NULL) {
+		PMD_DRV_LOG_LINE(ERR,
+				 "%s: Invalid global_scope_capable pointer",
+				 __func__);
+		return -EINVAL;
+	}
+
+	if (tbl_scope_capable == NULL) {
+		PMD_DRV_LOG_LINE(ERR,
+				 "%s: Invalid locked_scope_capable pointer",
+				 __func__);
+		return -EINVAL;
+	}
+
 	bp = tfcp->bp;
 	*tbl_scope_capable = false;
+	*global_scope_capable = false;
+	*locked_scope_capable = false;
 
 	rc = bnxt_hwrm_tf_message_direct(bp, false, HWRM_TFC_TBL_SCOPE_QCAPS,
 					 &req, sizeof(req), &resp,
@@ -211,6 +229,10 @@ tfc_msg_tbl_scope_qcaps(struct tfc *tfcp,
 
 	if (resp.tbl_scope_capable) {
 		*tbl_scope_capable = true;
+		if (resp.flags & HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_GLOBAL)
+			*global_scope_capable = true;
+		if (resp.flags & HWRM_TFC_TBL_SCOPE_QCAPS_OUTPUT_FLAGS_LOCKED)
+			*locked_scope_capable = true;
 		if (max_lkup_rec_cnt)
 			*max_lkup_rec_cnt =
 				rte_le_to_cpu_32(resp.max_lkup_rec_cnt);
@@ -226,7 +248,7 @@ tfc_msg_tbl_scope_qcaps(struct tfc *tfcp,
 }
 int
 tfc_msg_tbl_scope_id_alloc(struct tfc *tfcp, uint16_t fid,
-			   bool shared, enum cfa_app_type app_type,
+			   enum cfa_scope_type scope_type, enum cfa_app_type app_type,
 			   uint8_t *tsid,
 			   bool *first)
 {
@@ -247,8 +269,21 @@ tfc_msg_tbl_scope_id_alloc(struct tfc *tfcp, uint16_t fid,
 
 	bp = tfcp->bp;
 	req.app_type = app_type;
-	req.shared = shared;
-
+	switch (scope_type) {
+	case CFA_SCOPE_TYPE_NON_SHARED:
+		req.scope_type = HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_NON_SHARED;
+		break;
+	case CFA_SCOPE_TYPE_SHARED_APP:
+		req.scope_type = HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_SHARED_APP;
+		break;
+	case CFA_SCOPE_TYPE_GLOBAL:
+		req.scope_type = HWRM_TFC_TBL_SCOPE_ID_ALLOC_INPUT_SCOPE_TYPE_GLOBAL;
+		break;
+	default:
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid scope_type",
+				 __func__);
+		return -EINVAL;
+	}
 	rc = tfc_msg_set_fid(bp, fid, &req.fid);
 	if (rc)
 		return rc;
@@ -393,28 +428,6 @@ tfc_msg_backing_store_cfg_v2(struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir,
 	return rc;
 }
 
-int
-tfc_msg_tbl_scope_deconfig(struct tfc *tfcp, uint8_t tsid)
-{
-	struct hwrm_tfc_tbl_scope_deconfig_input req = { 0 };
-	struct hwrm_tfc_tbl_scope_deconfig_output resp = { 0 };
-	struct bnxt *bp;
-	int rc;
-
-	if (tfcp == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tfcp pointer");
-		return -EINVAL;
-	}
-
-	bp = tfcp->bp;
-	req.tsid = tsid;
-	rc = bnxt_hwrm_tf_message_direct(bp, false, HWRM_TFC_TBL_SCOPE_DECONFIG,
-					 &req, sizeof(req), &resp,
-					 sizeof(resp));
-
-	return rc;
-}
-
 int
 tfc_msg_tbl_scope_fid_add(struct tfc *tfcp, uint16_t fid,
 			  uint8_t tsid, uint16_t *fid_cnt)
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_msg.h b/drivers/net/bnxt/tf_core/v3/tfc_msg.h
index 3bf6b04a12..6f07890cd6 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_msg.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_msg.h
@@ -16,11 +16,14 @@
 int
 tfc_msg_tbl_scope_qcaps(struct tfc *tfcp,
 			bool *tbl_scope_capable,
+			bool *global_scope_capable,
+			bool *locked_scope_capable,
 			uint32_t *max_lkup_rec_cnt,
 			uint32_t *max_act_rec_cnt,
 			uint8_t	*max_lkup_static_buckets_exp);
 
-int tfc_msg_tbl_scope_id_alloc(struct tfc *tfcp, uint16_t fid, bool shared,
+int tfc_msg_tbl_scope_id_alloc(struct tfc *tfcp, uint16_t fid,
+			       enum cfa_scope_type scope_type,
 			       enum cfa_app_type app_type, uint8_t *tsid,
 			       bool *first);
 
@@ -31,9 +34,6 @@ tfc_msg_backing_store_cfg_v2(struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir,
 			     uint32_t rec_cnt, uint8_t static_bkt_cnt_exp,
 			     bool cfg_done);
 
-int
-tfc_msg_tbl_scope_deconfig(struct tfc *tfcp, uint8_t tsid);
-
 int
 tfc_msg_tbl_scope_fid_add(struct tfc *tfcp, uint16_t fid,
 			  uint8_t tsid, uint16_t *fid_cnt);
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c b/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
index ac805916cc..b229f07596 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
@@ -56,9 +56,8 @@
  * @param[in] key_sz_in_bytes
  *   The lookup key size in bytes
  *
- * @param[in] shared
- *   True if the table scope will be shared.  Shared table scopes cannot have
- *   dynamic buckets.
+ * @param[in] scope_type
+ *   Shared-app or global table scopes cannot have dynamic buckets.
  *
  * @param[in] factor
  *   This indicates a multiplier factor for determining the static and dynamic
@@ -76,7 +75,7 @@
  *
  */
 static int calc_lkup_rec_cnt(uint32_t flow_cnt, uint16_t key_sz_in_bytes,
-			     __rte_unused bool shared,
+			     __rte_unused enum cfa_scope_type scope_type,
 			     enum tfc_tbl_scope_bucket_factor factor,
 			     uint32_t *lkup_rec_cnt,
 			     uint8_t *static_bucket_cnt_exp,
@@ -127,7 +126,7 @@ static int calc_lkup_rec_cnt(uint32_t flow_cnt, uint16_t key_sz_in_bytes,
 	key_rec_cnt = flow_cnt * entry_size;
 
 #ifdef DYNAMIC_BUCKETS_SUPPORTED
-	if (shared) {
+	if (scope_type != CFA_SCOPE_TYPE_NON_SHARED) {
 #endif
 		*static_bucket_cnt_exp =
 			next_pow2(flow_adj / ENTRIES_PER_BUCKET);
@@ -531,9 +530,9 @@ static int alloc_link_pbl(struct tfc_ts_mem_cfg *mem_cfg, uint32_t page_size,
  */
 struct tbl_scope_pools_create_parms {
 	/**
-	 * [in] Indicates if the table scope will be shared.
+	 * [in] Indicates non-shared, shared-app or global scope.
 	 */
-	bool shared;
+	enum cfa_scope_type scope_type;
 	/**
 	 * [in] The number of pools the table scope will be divided into. (set
 	 * to 1 if not shared).
@@ -599,7 +598,7 @@ static int tbl_scope_pools_create(struct tfc *tfcp, uint8_t tsid,
 		return -EINVAL;
 	}
 
-	rc = tfo_tim_get(tfcp->tfo, &tim);
+	rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
 	if (rc)
 		return -EINVAL;
 
@@ -703,7 +702,7 @@ static int tbl_scope_pools_destroy(struct tfc *tfcp, uint8_t tsid)
 		return -EINVAL;
 	}
 
-	rc = tfo_tim_get(tfcp->tfo, &tim);
+	rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
 	if (rc)
 		return -EINVAL;
 
@@ -755,7 +754,7 @@ static int tbl_scope_tpm_fid_rem(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 				 uint16_t *pool_cnt)
 {
 	int rc = 0;
-	bool shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 	enum cfa_dir dir;
 	uint16_t pool_id;
@@ -783,15 +782,16 @@ static int tbl_scope_tpm_fid_rem(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 		PMD_DRV_LOG_LINE(ERR, "only valid for PF");
 		return -EINVAL;
 	}
-	rc = tfo_ts_get(tfcp->tfo, tsid, &shared, NULL, &valid, NULL);
-	if (!valid || !shared) {
-		PMD_DRV_LOG_LINE(ERR, "tsid(%d) valid(%s) shared(%s)",
-				 tsid, valid ? "TRUE" : "FALSE",
-				 shared ? "TRUE" : "FALSE");
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, &valid, NULL);
+	if (!valid || scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
+		PMD_DRV_LOG_LINE(ERR,
+				 "%s: tsid(%d) valid(%s) scope_type(%s)",
+				 __func__, tsid, valid ? "TRUE" : "FALSE",
+				 tfc_scope_type_2_str(scope_type));
 		return -EINVAL;
 	}
 
-	rc = tfo_tim_get(tfcp->tfo, &tim);
+	rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
 	if (rc) {
 		PMD_DRV_LOG_LINE(ERR, "Failed to get TIM");
 		return -EINVAL;
@@ -879,10 +879,7 @@ static int tbl_scope_tpm_fid_rem(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 
 /* Public APIs */
 
-int tfc_tbl_scope_qcaps(struct tfc *tfcp, bool *tbl_scope_capable,
-			uint32_t *max_lkup_rec_cnt,
-			uint32_t *max_act_rec_cnt,
-			uint8_t	*max_lkup_static_buckets_exp)
+int tfc_tbl_scope_qcaps(struct tfc *tfcp, struct tfc_tbl_scope_qcaps_parms *parms)
 {
 	int rc = 0;
 
@@ -890,14 +887,17 @@ int tfc_tbl_scope_qcaps(struct tfc *tfcp, bool *tbl_scope_capable,
 		PMD_DRV_LOG_LINE(ERR, "Invalid tfcp pointer");
 		return -EINVAL;
 	}
-	if (tbl_scope_capable == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tbl_scope_capable pointer");
+	if (parms == NULL) {
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid parms", __func__);
 		return -EINVAL;
 	}
 
-	rc = tfc_msg_tbl_scope_qcaps(tfcp, tbl_scope_capable, max_lkup_rec_cnt,
-				     max_act_rec_cnt,
-				     max_lkup_static_buckets_exp);
+	rc = tfc_msg_tbl_scope_qcaps(tfcp, &parms->tbl_scope_cap,
+				     &parms->global_cap,
+				     &parms->locked_cap,
+				     &parms->max_lkup_rec_cnt,
+				     &parms->max_act_rec_cnt,
+				     &parms->max_lkup_static_bucket_exp);
 	if (rc)
 		PMD_DRV_LOG_LINE(ERR,
 				 "table scope qcaps message failed, rc:%s",
@@ -927,15 +927,15 @@ int tfc_tbl_scope_size_query(struct tfc *tfcp,
 	}
 
 	if (is_pow2(parms->max_pools)) {
-		PMD_DRV_LOG(ERR, "%s: Invalid max_pools %u not pow2\n",
-			    __func__, parms->max_pools);
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid max_pools %u not pow2",
+				 __func__, parms->max_pools);
 		return -EINVAL;
 	}
 
 	for (dir = CFA_DIR_RX; dir < CFA_DIR_MAX; dir++) {
 		rc = calc_lkup_rec_cnt(parms->flow_cnt[dir],
 				       parms->key_sz_in_bytes[dir],
-				       parms->shared, parms->factor,
+				       parms->scope_type, parms->factor,
 				       &parms->lkup_rec_cnt[dir],
 				       &parms->static_bucket_cnt_exp[dir],
 				       &parms->dynamic_bucket_cnt[dir]);
@@ -970,7 +970,7 @@ int tfc_tbl_scope_size_query(struct tfc *tfcp,
 	return rc;
 }
 
-int tfc_tbl_scope_id_alloc(struct tfc *tfcp, bool shared,
+int tfc_tbl_scope_id_alloc(struct tfc *tfcp, enum cfa_scope_type scope_type,
 			   enum cfa_app_type app_type, uint8_t *tsid,
 			   bool *first)
 {
@@ -994,13 +994,13 @@ int tfc_tbl_scope_id_alloc(struct tfc *tfcp, bool shared,
 		return -EINVAL;
 	}
 	rc = tfc_msg_tbl_scope_id_alloc(tfcp, ((struct bnxt *)tfcp->bp)->fw_fid,
-					shared, app_type, tsid, first);
+					scope_type, app_type, tsid, first);
 	if (rc) {
 		PMD_DRV_LOG_LINE(ERR,
 				 "table scope ID alloc message failed, rc:%s",
 				 strerror(-rc));
 	} else {
-		rc = tfo_ts_set(tfcp->tfo, *tsid, shared, app_type, valid, 0);
+		rc = tfo_ts_set(tfcp->tfo, *tsid, scope_type, app_type, valid, 0);
 	}
 	return rc;
 }
@@ -1014,7 +1014,6 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 	uint64_t act_base_addr[2];
 	int dir;
 	int rc = 0;
-	bool shared = false;
 	uint32_t page_sz;
 	uint16_t pfid;
 	uint8_t lkup_pbl_level[2];
@@ -1044,8 +1043,8 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 	}
 
 	if (is_pow2(parms->max_pools)) {
-		PMD_DRV_LOG(ERR, "%s: Invalid max_pools %u not pow2\n",
-			    __func__, parms->max_pools);
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid max_pools %u not pow2",
+				 __func__, parms->max_pools);
 		return -EINVAL;
 	}
 
@@ -1083,12 +1082,6 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 			return rc;
 	}
 
-	/*
-	 * A shared table scope will have more than 1 pool
-	 */
-	if (parms->max_pools > 1)
-		shared = true;
-
 	/* If we are running on a PF, we will allocate memory locally
 	 */
 	if (is_pf) {
@@ -1176,9 +1169,9 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 				goto cleanup;
 			}
 
-			/* Set shared and valid in local state */
+			/* Set scope_type and valid in local state */
 			valid = true;
-			rc = tfo_ts_set(tfcp->tfo, tsid, shared, CFA_APP_TYPE_TF,
+			rc = tfo_ts_set(tfcp->tfo, tsid, parms->scope_type, CFA_APP_TYPE_TF,
 					valid, parms->max_pools);
 			if (rc)
 				goto cleanup;
@@ -1190,7 +1183,7 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 
 			cfg_cnt++;
 		}
-		cparms.shared = shared;
+		cparms.scope_type = parms->scope_type;
 		cparms.max_pools = parms->max_pools;
 
 		for (dir = 0; dir < CFA_DIR_MAX; dir++) {
@@ -1205,7 +1198,7 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 		/* If not shared, allocate the single pool_id in each region
 		 * so that we can save the associated fid for the table scope
 		 */
-		if (!shared) {
+		if (parms->scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
 			uint16_t pool_id;
 			enum cfa_region_type region;
 			uint16_t max_vf;
@@ -1239,7 +1232,7 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 
 	} else /* this is a VF */ {
 		/* If first or !shared, send message to PF to allocate the memory */
-		if (parms->first || !shared) {
+		if (parms->first || parms->scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
 			struct tfc_vf2pf_tbl_scope_mem_alloc_cfg_cmd req = { { 0 } };
 			struct tfc_vf2pf_tbl_scope_mem_alloc_cfg_resp resp = { { 0 } };
 			uint16_t fid;
@@ -1252,6 +1245,7 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 			req.hdr.fid = fid;
 			req.tsid = tsid;
 			req.max_pools = parms->max_pools;
+			req.scope_type = parms->scope_type;
 			for (dir = CFA_DIR_RX; dir < CFA_DIR_MAX; dir++) {
 				req.static_bucket_cnt_exp[dir] = parms->static_bucket_cnt_exp[dir];
 				req.dynamic_bucket_cnt[dir] = parms->dynamic_bucket_cnt[dir];
@@ -1298,9 +1292,9 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 			if (rc)
 				goto cleanup;
 
-			/* Set shared and valid in local state */
+			/* Set scope_type and valid in local state */
 			valid = true;
-			rc = tfo_ts_set(tfcp->tfo, tsid, shared, CFA_APP_TYPE_TF,
+			rc = tfo_ts_set(tfcp->tfo, tsid, parms->scope_type, CFA_APP_TYPE_TF,
 					valid, parms->max_pools);
 		}
 	}
@@ -1330,7 +1324,8 @@ int tfc_tbl_scope_mem_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 	return rc;
 }
 
-int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
+int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
+			   uint16_t fid_cnt)
 {
 	struct tfc_ts_mem_cfg mem_cfg;
 	bool local;
@@ -1338,7 +1333,9 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 	int lrc = 0;
 	int rc = 0;
 	bool is_pf = false;
-	bool shared;
+	enum cfa_scope_type scope_type;
+	struct tfc_cpm *cpm_lkup;
+	struct tfc_cpm *cpm_act;
 
 	if (tfcp == NULL) {
 		PMD_DRV_LOG_LINE(ERR, "Invalid tfcp pointer");
@@ -1355,7 +1352,7 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 		return -EINVAL;
 	}
 
-	rc = tfo_ts_get(tfcp->tfo, tsid, &shared, NULL, NULL, NULL);
+	rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, NULL, NULL);
 	if (rc)
 		return rc;
 
@@ -1370,7 +1367,6 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 		return rc;
 
 	if (!is_pf) {
-		PMD_DRV_LOG_LINE(DEBUG, "Send VF2PF message and await response");
 		struct tfc_vf2pf_tbl_scope_mem_free_cmd req = { { 0 } };
 		struct tfc_vf2pf_tbl_scope_mem_free_resp resp = { { 0 } };
 		uint16_t fid;
@@ -1382,22 +1378,44 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 		req.hdr.type = TFC_VF2PF_TYPE_TBL_SCOPE_MEM_FREE_CMD;
 		req.hdr.fid = fid;
 		req.tsid = tsid;
-
 		rc = tfc_vf2pf_mem_free(tfcp, &req, &resp);
-		if (rc != 0) {
-			PMD_DRV_LOG_LINE(ERR, "tfc_vf2pf_mem_free failed");
-			/* continue cleanup regardless */
-		}
-		PMD_DRV_LOG_LINE(DEBUG, "%s: tsid: %d, status %d",
-				 __func__, resp.tsid, resp.status);
-		if (shared) {
+		if (rc != 0)
+			PMD_DRV_LOG_LINE(ERR, "%s: tfc_vf2pf_mem_free failed",
+					 __func__);
+		/* continue cleanup regardless */
+
+		if (scope_type == CFA_SCOPE_TYPE_SHARED_APP) {
+			/*
+			 * Check if any direction has a CPM instance and, if so, free
+			 * it.
+			 */
+			rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, CFA_DIR_RX, &cpm_lkup,
+						 &cpm_act);
+			if (rc == 0 && (cpm_lkup != NULL || cpm_act != NULL))
+				(void)tfc_tbl_scope_cpm_free(tfcp, tsid);
+
 			/* reset scope */
-			tfo_ts_set(tfcp->tfo, tsid, false, CFA_APP_TYPE_INVALID, false, 0);
+			tfo_ts_set(tfcp->tfo, tsid, CFA_SCOPE_TYPE_INVALID,
+				   CFA_APP_TYPE_INVALID, false, 0);
+			return rc;
+		} else if (scope_type == CFA_SCOPE_TYPE_GLOBAL) {
+			if (fid_cnt == 0) {
+				/*
+				 * Check if any direction has a CPM instance and, if so, free
+				 * it.
+				 */
+				rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, CFA_DIR_RX, &cpm_lkup,
+							 &cpm_act);
+				if (rc == 0 && (cpm_lkup != NULL || cpm_act != NULL))
+					(void)tfc_tbl_scope_cpm_free(tfcp, tsid);
+				/* reset scope */
+				tfo_ts_set(tfcp->tfo, tsid, CFA_SCOPE_TYPE_INVALID,
+					   CFA_APP_TYPE_INVALID, false, 0);
+			}
 			return rc;
 		}
 	}
-
-	if (shared && is_pf) {
+	if (scope_type != CFA_SCOPE_TYPE_NON_SHARED && is_pf) {
 		uint16_t pool_cnt;
 		uint16_t max_vf;
 
@@ -1423,13 +1441,6 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 		}
 	}
 
-	/* Send Deconfig HWRM before freeing memory */
-	rc = tfc_msg_tbl_scope_deconfig(tfcp, tsid);
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "deconfig failure: %s", strerror(-rc));
-		return rc;
-	}
-
 	for (region = 0; region < CFA_REGION_TYPE_MAX; region++) {
 		for (dir = 0; dir < CFA_DIR_MAX; dir++) {
 			lrc = tfo_ts_get_mem_cfg(tfcp->tfo, tsid, dir, region, &local,
@@ -1462,8 +1473,7 @@ int tfc_tbl_scope_mem_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid)
 		}
 	}
 	/* cleanup state */
-	rc = tfo_ts_set(tfcp->tfo, tsid, false, CFA_APP_TYPE_INVALID, false, 0);
-
+	rc = tfo_ts_set(tfcp->tfo, tsid, CFA_SCOPE_TYPE_INVALID, CFA_APP_TYPE_INVALID, false, 0);
 	return rc;
 }
 
@@ -1499,8 +1509,6 @@ int tfc_tbl_scope_fid_add(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 int tfc_tbl_scope_fid_rem(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 			  uint16_t *fid_cnt)
 {
-	struct tfc_cpm *cpm_lkup;
-	struct tfc_cpm *cpm_act;
 	int rc = 0;
 
 	if (tfcp == NULL) {
@@ -1529,16 +1537,6 @@ int tfc_tbl_scope_fid_rem(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 				 "table scope fid rem message failed, rc:%s",
 				 strerror(-rc));
 
-	/*
-	 * Check if any direction has a CPM instance and, if so, free
-	 * it.
-	 */
-	rc = tfo_ts_get_cpm_inst(tfcp->tfo, tsid, CFA_DIR_RX, &cpm_lkup,
-				 &cpm_act);
-	if (rc == 0 && (cpm_lkup != NULL || cpm_act != NULL))
-		(void)tfc_tbl_scope_cpm_free(tfcp, tsid);
-
-	/* tbl_scope_mem_free() will reset the remaining tsid state */
 	return rc;
 }
 
@@ -1547,7 +1545,7 @@ int tfc_tbl_scope_cpm_alloc(struct tfc *tfcp, uint8_t tsid,
 {
 	int dir;
 	struct tfc_ts_pool_info pi;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	int rc;
 	struct tfc_cmm *cmm_lkup = NULL;
 	struct tfc_cmm *cmm_act = NULL;
@@ -1560,8 +1558,9 @@ int tfc_tbl_scope_cpm_alloc(struct tfc *tfcp, uint8_t tsid,
 		PMD_DRV_LOG_LINE(ERR, "tsid(%d) invalid", tsid);
 		return -EINVAL;
 	}
-	if (tfo_ts_get(tfcp->tfo, tsid, &is_shared, NULL, NULL, NULL)) {
-		PMD_DRV_LOG_LINE(ERR, "tsid(%d) info get failed", tsid);
+	if (tfo_ts_get(tfcp->tfo, tsid, &scope_type, NULL, NULL, NULL)) {
+		PMD_DRV_LOG_LINE(ERR, "%s: tsid(%d) info get failed",
+				 __func__, tsid);
 		return -EINVAL;
 	}
 
@@ -1569,6 +1568,14 @@ int tfc_tbl_scope_cpm_alloc(struct tfc *tfcp, uint8_t tsid,
 	 */
 	for (dir = 0; dir < CFA_DIR_MAX; dir++) {
 		tfo_ts_get_pool_info(tfcp->tfo, tsid, dir, &pi);
+
+		/* If global scope, do not overwrite the CPM instance
+		 * already configured
+		 */
+		if (scope_type == CFA_SCOPE_TYPE_GLOBAL &&
+		    pi.act_cpm)
+			return 0;
+
 		pi.lkup_max_contig_rec = parms->lkup_max_contig_rec[dir];
 		pi.act_max_contig_rec = parms->act_max_contig_rec[dir];
 		tfc_cpm_open(&pi.lkup_cpm, parms->max_pools);
@@ -1578,12 +1585,13 @@ int tfc_tbl_scope_cpm_alloc(struct tfc *tfcp, uint8_t tsid,
 		tfo_ts_set_cpm_inst(tfcp->tfo, tsid, dir, pi.lkup_cpm, pi.act_cpm);
 		tfo_ts_set_pool_info(tfcp->tfo, tsid, dir, &pi);
 
+
 		/* If not shared create CMM instance for and populate CPM with pool_id 0.
 		 * If shared, a pool_id will be allocated during tfc_act_alloc() or
 		 * tfc_em_insert() and the CMM instance will be created on the first
 		 * call.
 		 */
-		if (!is_shared) {
+		if (scope_type == CFA_SCOPE_TYPE_NON_SHARED) {
 			struct cfa_mm_query_parms qparms;
 			struct cfa_mm_open_parms oparms;
 			uint32_t pool_id = 0;
@@ -1704,7 +1712,6 @@ int tfc_tbl_scope_cpm_free(struct tfc *tfcp, uint8_t tsid)
 		return -EINVAL;
 	}
 
-
 	for (dir = 0; dir < CFA_DIR_MAX; dir++) {
 		uint16_t pool_id;
 		struct tfc_cmm *cmm;
@@ -1801,7 +1808,7 @@ int tfc_tbl_scope_pool_alloc(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 	}
 
 	if (is_pf) {
-		rc = tfo_tim_get(tfcp->tfo, &tim);
+		rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
 		if (rc) {
 			PMD_DRV_LOG_LINE(ERR, "Failed to get TIM");
 			return -EINVAL;
@@ -1895,7 +1902,7 @@ int tfc_tbl_scope_pool_free(struct tfc *tfcp, uint16_t fid, uint8_t tsid,
 	}
 
 	if (is_pf) {
-		rc = tfo_tim_get(tfcp->tfo, &tim);
+		rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
 		if (rc)
 			return -EINVAL;
 
@@ -2000,7 +2007,7 @@ static void tfc_tbl_scope_delete_by_pool(uint16_t *found_cnt,
 int tfc_tbl_scope_func_reset(struct tfc *tfcp, uint16_t fid)
 {
 	int rc = 0;
-	bool shared;
+	enum cfa_scope_type scope_type;
 	enum cfa_app_type app;
 	bool valid;
 	uint8_t tsid;
@@ -2026,20 +2033,20 @@ int tfc_tbl_scope_func_reset(struct tfc *tfcp, uint16_t fid)
 		return -EINVAL;
 	}
 
-	rc = tfo_tim_get(tfcp->tfo, &tim);
-	if (rc) {
-		PMD_DRV_LOG_LINE(ERR, "Failed to get TIM");
-		return -EINVAL;
-	}
-
 	data = rte_zmalloc("data", 32 * TFC_MPC_BYTES_PER_WORD, 32);
 
 	for (tsid = 1; tsid < TFC_TBL_SCOPE_MAX; tsid++) {
-		rc = tfo_ts_get(tfcp->tfo, tsid, &shared, &app, &valid, NULL);
+		rc = tfo_ts_get(tfcp->tfo, tsid, &scope_type, &app, &valid, NULL);
 		if (rc)
 			continue; /* TS is not used, move on to the next */
 
-		if (!shared || !valid)
+		rc = tfo_tim_get(tfcp->tfo, &tim, tsid);
+		if (rc) {
+			PMD_DRV_LOG_LINE(INFO, "%s: Failed to get TIM", __func__);
+			continue;
+		}
+
+		if (scope_type == CFA_SCOPE_TYPE_NON_SHARED || !valid)
 			continue; /* TS invalid or not shared, move on */
 
 		for (dir = 0; dir < CFA_DIR_MAX; dir++) {
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c b/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c
index 0527e34525..b0b3daab69 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_tcam_debug.c
@@ -1804,7 +1804,7 @@ int tfc_wc_show(FILE *fd, struct tfc *tfcp, uint8_t tsid, enum cfa_dir dir)
 	struct wc_frp_context wc_frp;
 	bool is_bs_owner;
 	struct bnxt *bp;
-	bool is_shared;
+	enum cfa_scope_type scope_type;
 	bool valid;
 	int rc = 0;
 
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_util.c b/drivers/net/bnxt/tf_core/v3/tfc_util.c
index 91ad3ad657..ac6f9cc565 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_util.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_util.c
@@ -145,6 +145,21 @@ tfc_ts_region_2_str(enum cfa_region_type region, enum cfa_dir dir)
 	}
 }
 
+const char *
+tfc_scope_type_2_str(enum cfa_scope_type scope_type)
+{
+	switch (scope_type) {
+	case CFA_SCOPE_TYPE_NON_SHARED:
+		return "non_shared";
+	case CFA_SCOPE_TYPE_SHARED_APP:
+		return "shared_app";
+	case CFA_SCOPE_TYPE_GLOBAL:
+		return "global";
+	default:
+		return "Invalid scope type";
+	}
+}
+
 uint32_t
 tfc_getbits(uint32_t *data, int offset, int blen)
 {
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_util.h b/drivers/net/bnxt/tf_core/v3/tfc_util.h
index 5114517792..f71ade5c59 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_util.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_util.h
@@ -87,6 +87,17 @@ const char *tfc_ts_region_2_str(enum cfa_region_type region, enum cfa_dir dir);
  */
 const char *tfc_if_tbl_2_str(enum cfa_resource_subtype_if_tbl if_tbl_stype);
 
+/**
+ * Helper function converting the scope type to text string
+ *
+ * [in] scope_type: table scope type
+ *
+ * Returns:
+ *   Pointer to a char string holding the string for scope type
+ */
+const char *tfc_scope_type_2_str(enum cfa_scope_type scope_type);
+
+
 /**
  * Helper function retrieving field value from the buffer
  *
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.c b/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.c
index cbe243e79c..7550ed4e84 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.c
@@ -179,6 +179,7 @@ tfc_vf2pf_mem_alloc_process(struct tfc *tfcp,
 	/* This is not for local use if we are getting a message from the VF */
 	ma_parms.local = false;
 	ma_parms.max_pools = req->max_pools;
+	ma_parms.scope_type = req->scope_type;
 	rc = tfc_tbl_scope_mem_alloc(tfcp, req->hdr.fid, req->tsid, &ma_parms);
 	if (rc == 0) {
 		PMD_DRV_LOG_LINE(ERR, "tsid(%d) PF allocation succeeds",
@@ -222,7 +223,7 @@ tfc_vf2pf_mem_free_process(struct tfc *tfcp,
 	PMD_DRV_LOG_LINE(ERR, "Table scope mem free cfg cmd:");
 	PMD_DRV_LOG_LINE(ERR, "\ttsid: 0x%x", req->tsid);
 
-	rc = tfc_tbl_scope_mem_free(tfcp, req->hdr.fid, req->tsid);
+	rc = tfc_tbl_scope_mem_free(tfcp, req->hdr.fid, req->tsid, 0);
 	if (rc == 0) {
 		PMD_DRV_LOG_LINE(ERR, "tsid(%d) PF free succeeds", req->tsid);
 	} else {
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.h b/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.h
index efa35665f6..5bc592de9b 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_vf2pf_msg.h
@@ -73,6 +73,8 @@ struct tfc_vf2pf_tbl_scope_mem_alloc_cfg_cmd {
 	uint8_t act_pool_sz_exp[CFA_DIR_MAX];
 	/** start offset in 32B records of the lkup recs (after buckets) */
 	uint32_t lkup_rec_start_offset[CFA_DIR_MAX];
+	/** scope type non-shared, shared-app or global */
+	enum cfa_scope_type scope_type;
 };
 /**
  * Truflow VF2PF Table Scope Memory allocate/config response
@@ -103,7 +105,7 @@ struct tfc_vf2pf_tbl_scope_mem_free_resp {
 	struct tfc_vf2pf_hdr hdr;
 	/** status of request */
 	enum tfc_vf2pf_status status;
-	/** tsid memory freed */
+	/** table scope identifier */
 	uint8_t tsid;
 };
 
diff --git a/drivers/net/bnxt/tf_core/v3/tfo.c b/drivers/net/bnxt/tf_core/v3/tfo.c
index 21146d1daa..4b1f545476 100644
--- a/drivers/net/bnxt/tf_core/v3/tfo.c
+++ b/drivers/net/bnxt/tf_core/v3/tfo.c
@@ -14,8 +14,8 @@
  */
 struct tfc_tsid_db {
 	bool ts_valid; /**< Table scope is valid */
-	bool ts_is_shared; /**< Table scope is shared */
-	bool ts_is_bs_owner; /**< Backing store allocated by this instance (PF) */
+	enum cfa_scope_type scope_type; /**< non-shared, shared-app, global */
+	bool ts_is_bs_owner; /**< Backing store alloced by this instance (PF) */
 	uint16_t ts_max_pools; /**< maximum pools per CPM instance */
 	enum cfa_app_type ts_app; /**< application type TF/AFM */
 	/** backing store memory config */
@@ -24,6 +24,22 @@ struct tfc_tsid_db {
 	struct tfc_ts_pool_info ts_pool[CFA_DIR_MAX];
 };
 
+/* Only a single global scope is allowed
+ */
+#define TFC_GLOBAL_SCOPE_MAX 1
+
+/* TFC Global Object
+ * The global object is not per port, it is global.  It is only
+ * used when a global table scope is created.
+ */
+struct tfc_global_object {
+	uint8_t gtsid;
+	struct tfc_tsid_db gtsid_db;
+	void *gts_tim;
+};
+
+struct tfc_global_object tfc_global;
+
 /** TFC Object Signature
  * This signature identifies the tfc object database and
  * is used for pointer validation
@@ -48,12 +64,14 @@ struct tfc_object {
 	 *  table scope.  Only valid on a PF.
 	 */
 	void *ts_tim;
+	struct tfc_global_object *tfgo; /**< pointer to global */
 };
 
 void tfo_open(void **tfo, bool is_pf)
 {
 	int rc;
 	struct tfc_object *tfco = NULL;
+	struct tfc_global_object *tfgo;
 	uint32_t tim_db_size;
 
 	if (tfo == NULL) {
@@ -77,7 +95,7 @@ void tfo_open(void **tfo, bool is_pf)
 		goto cleanup;
 	}
 	if (is_pf) {
-		/* Allocate TIM */
+		/* Allocate per bp TIM database */
 		rc = cfa_tim_query(TFC_TBL_SCOPE_MAX, CFA_REGION_TYPE_MAX,
 				   &tim_db_size);
 		if (rc)
@@ -97,7 +115,31 @@ void tfo_open(void **tfo, bool is_pf)
 			goto cleanup;
 		}
 	}
+	tfco->tfgo = &tfc_global;
+	tfgo = tfco->tfgo;
 
+	if (is_pf && !tfgo->gts_tim) {
+		/* Allocate global scope TIM database */
+		rc = cfa_tim_query(TFC_GLOBAL_SCOPE_MAX + 1, CFA_REGION_TYPE_MAX,
+				   &tim_db_size);
+		if (rc)
+			goto cleanup;
+
+		tfgo->gts_tim = rte_zmalloc("GTIM", tim_db_size, 0);
+		if (!tfgo->gts_tim)
+			goto cleanup;
+
+		rc = cfa_tim_open(tfgo->gts_tim,
+				  tim_db_size,
+				  TFC_GLOBAL_SCOPE_MAX + 1,
+				  CFA_REGION_TYPE_MAX);
+		if (rc) {
+			rte_free(tfgo->gts_tim);
+			tfgo->gts_tim = NULL;
+			goto cleanup;
+		}
+	}
+	tfgo->gtsid = INVALID_TSID;
 	*tfo = tfco;
 	return;
 
@@ -117,13 +159,11 @@ void tfo_close(void **tfo)
 
 	if (*tfo && tfco->signature == TFC_OBJ_SIGNATURE) {
 		/*  If TIM is setup free it and any TPMs */
-		if (tfo_tim_get(*tfo, &tim))
-			goto done;
-
-		if (!tim)
-			goto done;
-
 		for (tsid = 0; tsid < TFC_TBL_SCOPE_MAX; tsid++) {
+			if (tfo_tim_get(*tfo, &tim, tsid))
+				continue;
+			if (!tim)
+				continue;
 			for (region = 0; region < CFA_REGION_TYPE_MAX; region++) {
 				for (dir = 0; dir < CFA_DIR_MAX; dir++) {
 					tpm = NULL;
@@ -143,10 +183,13 @@ void tfo_close(void **tfo)
 				}
 			}
 		}
-		rte_free(tim);
+		if (tim)
+			rte_free(tim);
 		tfco->ts_tim = NULL;
-done:
-		rte_free(*tfo);
+		tfco->tfgo = NULL;
+
+		if (*tfo)
+			rte_free(*tfo);
 		*tfo = NULL;
 	}
 }
@@ -174,6 +217,7 @@ int tfo_mpcinfo_get(void *tfo, struct cfa_bld_mpcinfo **mpc_info)
 int tfo_ts_validate(void *tfo, uint8_t ts_tsid, bool *ts_valid)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 
 	if (tfo == NULL) {
@@ -190,7 +234,11 @@ int tfo_ts_validate(void *tfo, uint8_t ts_tsid, bool *ts_valid)
 		PMD_DRV_LOG_LINE(ERR, "Invalid tsid %d", ts_tsid);
 		return -EINVAL;
 	}
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	if (ts_valid)
 		*ts_valid = tsid_db->ts_valid;
@@ -198,10 +246,11 @@ int tfo_ts_validate(void *tfo, uint8_t ts_tsid, bool *ts_valid)
 	return 0;
 }
 
-int tfo_ts_set(void *tfo, uint8_t ts_tsid, bool ts_is_shared,
+int tfo_ts_set(void *tfo, uint8_t ts_tsid, enum cfa_scope_type scope_type,
 	       enum cfa_app_type ts_app, bool ts_valid, uint16_t ts_max_pools)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 
 	if (tfo == NULL) {
@@ -218,21 +267,32 @@ int tfo_ts_set(void *tfo, uint8_t ts_tsid, bool ts_is_shared,
 		return -EINVAL;
 	}
 
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (scope_type == CFA_SCOPE_TYPE_GLOBAL) {
+		tsid_db = &tfgo->gtsid_db;
+		tfgo->gtsid = ts_tsid;
+	} else if (scope_type == CFA_SCOPE_TYPE_INVALID && tfgo &&
+		   ts_tsid == tfgo->gtsid) {
+		tfgo->gtsid = INVALID_TSID;
+		tsid_db = &tfgo->gtsid_db;
+	} else {
+		tsid_db = &tfco->tsid_db[ts_tsid];
+	}
 
 	tsid_db->ts_valid = ts_valid;
-	tsid_db->ts_is_shared = ts_is_shared;
+	tsid_db->scope_type = scope_type;
 	tsid_db->ts_app = ts_app;
 	tsid_db->ts_max_pools = ts_max_pools;
 
 	return 0;
 }
 
-int tfo_ts_get(void *tfo, uint8_t ts_tsid, bool *ts_is_shared,
+int tfo_ts_get(void *tfo, uint8_t ts_tsid, enum cfa_scope_type *scope_type,
 	       enum cfa_app_type *ts_app, bool *ts_valid,
 	       uint16_t *ts_max_pools)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 
 	if (tfo == NULL) {
@@ -248,13 +308,17 @@ int tfo_ts_get(void *tfo, uint8_t ts_tsid, bool *ts_is_shared,
 		return -EINVAL;
 	}
 
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (ts_tsid == tfgo->gtsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	if (ts_valid)
 		*ts_valid = tsid_db->ts_valid;
 
-	if (ts_is_shared)
-		*ts_is_shared = tsid_db->ts_is_shared;
+	if (scope_type)
+		*scope_type = tsid_db->scope_type;
 
 	if (ts_app)
 		*ts_app = tsid_db->ts_app;
@@ -272,6 +336,7 @@ int tfo_ts_set_mem_cfg(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		       struct tfc_ts_mem_cfg *mem_cfg)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	int rc = 0;
 	struct tfc_tsid_db *tsid_db;
 
@@ -292,7 +357,11 @@ int tfo_ts_set_mem_cfg(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		return -EINVAL;
 	}
 
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	tsid_db->ts_mem[region][dir] = *mem_cfg;
 	tsid_db->ts_is_bs_owner = is_bs_owner;
@@ -307,6 +376,7 @@ int tfo_ts_get_mem_cfg(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		       struct tfc_ts_mem_cfg *mem_cfg)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	int rc = 0;
 	struct tfc_tsid_db *tsid_db;
 
@@ -327,7 +397,11 @@ int tfo_ts_get_mem_cfg(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		return -EINVAL;
 	}
 
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	*mem_cfg = tsid_db->ts_mem[region][dir];
 	if (is_bs_owner)
@@ -343,6 +417,7 @@ int tfo_ts_get_cpm_inst(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 {
 	int rc = 0;
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 
 	if (tfo == NULL) {
@@ -366,7 +441,11 @@ int tfo_ts_get_cpm_inst(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		return -EINVAL;
 	}
 
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	*cpm_lkup = tsid_db->ts_pool[dir].lkup_cpm;
 	*cpm_act = tsid_db->ts_pool[dir].act_cpm;
@@ -380,6 +459,7 @@ int tfo_ts_set_cpm_inst(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 {
 	int rc = 0;
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 
 	if (tfo == NULL) {
@@ -394,7 +474,11 @@ int tfo_ts_set_cpm_inst(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		PMD_DRV_LOG_LINE(ERR, "Invalid tsid %d", ts_tsid);
 		return -EINVAL;
 	}
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	tsid_db->ts_pool[dir].lkup_cpm = cpm_lkup;
 	tsid_db->ts_pool[dir].act_cpm = cpm_act;
@@ -407,6 +491,7 @@ int tfo_ts_set_pool_info(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 			 struct tfc_ts_pool_info *ts_pool)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	int rc = 0;
 	struct tfc_tsid_db *tsid_db;
 
@@ -426,7 +511,12 @@ int tfo_ts_set_pool_info(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		PMD_DRV_LOG_LINE(ERR, "Invalid tsid %d", ts_tsid);
 		return -EINVAL;
 	}
-	tsid_db = &tfco->tsid_db[ts_tsid];
+
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	tsid_db->ts_pool[dir] = *ts_pool;
 
@@ -439,6 +529,7 @@ int tfo_ts_get_pool_info(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 			 struct tfc_ts_pool_info *ts_pool)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	int rc = 0;
 	struct tfc_tsid_db *tsid_db;
 
@@ -458,7 +549,11 @@ int tfo_ts_get_pool_info(void *tfo, uint8_t ts_tsid, enum cfa_dir dir,
 		PMD_DRV_LOG_LINE(ERR, "Invalid tsid %d", ts_tsid);
 		return -EINVAL;
 	}
-	tsid_db = &tfco->tsid_db[ts_tsid];
+	tfgo = tfco->tfgo;
+	if (tfgo && tfgo->gtsid == ts_tsid)
+		tsid_db = &tfgo->gtsid_db;
+	else
+		tsid_db = &tfco->tsid_db[ts_tsid];
 
 	*ts_pool = tsid_db->ts_pool[dir];
 
@@ -517,9 +612,10 @@ int tfo_sid_get(void *tfo, uint16_t *sid)
 	return 0;
 }
 
-int tfo_tim_set(void *tfo, void *tim)
+int tfo_tim_get(void *tfo, void **tim, uint8_t ts_tsid)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 
 	if (tfo == NULL) {
 		PMD_DRV_LOG_LINE(ERR, "Invalid tfo pointer");
@@ -530,68 +626,60 @@ int tfo_tim_set(void *tfo, void *tim)
 		return -EINVAL;
 	}
 	if (tim == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tim pointer");
-		return -EINVAL;
-	}
-
-	if (tfco->ts_tim != NULL &&
-	    tfco->ts_tim != tim) {
-		PMD_DRV_LOG_LINE(ERR,
-				 "Cannot set TS TIM, TIM is already set");
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid tim pointer to pointer",
+				 __func__);
 		return -EINVAL;
 	}
 
-	tfco->ts_tim = tim;
+	*tim = NULL;
+	tfgo = tfco->tfgo;
 
-	return 0;
-}
-
-int tfo_tim_get(void *tfo, void **tim)
-{
-	struct tfc_object *tfco = (struct tfc_object *)tfo;
-
-	if (tfo == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tfo pointer");
-		return -EINVAL;
-	}
-	if (tfco->signature != TFC_OBJ_SIGNATURE) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tfo object");
-		return -EINVAL;
-	}
-	if (tim == NULL) {
-		PMD_DRV_LOG_LINE(ERR, "Invalid tim pointer to pointer");
-		return -EINVAL;
-	}
-	if (tfco->ts_tim == NULL) {
+	if (ts_tsid == tfgo->gtsid) {
+		if (!tfgo->gts_tim)
 		/* ts tim could be null, no need to log error message */
-		return -ENODEV;
+			return -ENOENT;
+		*tim = tfgo->gts_tim;
+	} else {
+		if (!tfco->ts_tim)
+			/* ts tim could be null, no need to log error message */
+			return -ENOENT;
+		*tim = tfco->ts_tim;
 	}
 
-	*tim = tfco->ts_tim;
-
 	return 0;
 }
 
-
 int tfo_tsid_get(void *tfo, uint8_t *tsid)
 {
 	struct tfc_object *tfco = (struct tfc_object *)tfo;
+	struct tfc_global_object *tfgo;
 	struct tfc_tsid_db *tsid_db;
 	uint8_t i;
 
 	if (tfo == NULL) {
-		PMD_DRV_LOG(ERR, "%s: Invalid tfo pointer", __func__);
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid tfo pointer",
+				 __func__);
 		return -EINVAL;
 	}
 	if (tfco->signature != TFC_OBJ_SIGNATURE) {
-		PMD_DRV_LOG(ERR, "%s: Invalid tfo object", __func__);
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid tfo object",
+				 __func__);
 		return -EINVAL;
 	}
 	if (tsid == NULL) {
-		PMD_DRV_LOG(ERR, "%s: Invalid tsid pointer", __func__);
+		PMD_DRV_LOG_LINE(ERR, "%s: Invalid tsid pointer",
+				 __func__);
 		return -EINVAL;
 	}
 
+	tfgo = tfco->tfgo;
+	if (tfgo) {
+		tsid_db = &tfgo->gtsid_db;
+		if (tsid_db->ts_valid && tfgo->gtsid != INVALID_TSID) {
+			*tsid = tfgo->gtsid;
+			return 0;
+		}
+	}
 	for (i = 1; i < TFC_TBL_SCOPE_MAX; i++) {
 		tsid_db = &tfco->tsid_db[i];
 
diff --git a/drivers/net/bnxt/tf_core/v3/tfo.h b/drivers/net/bnxt/tf_core/v3/tfo.h
index e572db5991..93a6a5c064 100644
--- a/drivers/net/bnxt/tf_core/v3/tfo.h
+++ b/drivers/net/bnxt/tf_core/v3/tfo.h
@@ -50,6 +50,10 @@
  * @ref tfo_sid_set
  *
  * @ref tfo_sid_get
+ *
+ * @ref tfo_tim_get
+ *
+ * @ref tfo_tsid_get
  */
 
 /** Invalid Table Scope ID */
@@ -161,8 +165,8 @@ int tfo_ts_validate(void *tfo, uint8_t ts_tsid, bool *ts_valid);
  * @param[in] ts_tsid
  *   The table scope ID
  *
- * @param[in] ts_is_shared
- *   True if the table scope is shared
+ * @param[in] scope_type
+ *   non-shared, shared-app or global
  *
  * @param[in] ts_app
  *   Application type TF/AFM
@@ -171,12 +175,12 @@ int tfo_ts_validate(void *tfo, uint8_t ts_tsid, bool *ts_valid);
  *   True if the table scope is valid
  *
  * @param[in] ts_max_pools
- *   Maximum number of pools if shared.
+ *   Maximum number of pools
  *
  * @return
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfo_ts_set(void *tfo, uint8_t ts_tsid, bool ts_is_shared,
+int tfo_ts_set(void *tfo, uint8_t ts_tsid, enum cfa_scope_type scope_type,
 	       enum cfa_app_type ts_app, bool ts_valid,
 	       uint16_t ts_max_pools);
 
@@ -189,8 +193,8 @@ int tfo_ts_set(void *tfo, uint8_t ts_tsid, bool ts_is_shared,
  * @param[in] ts_tsid
  *   The table scope ID
  *
- * @param[out] ts_is_shared
- *   True if the table scope is shared
+ * @param[out] scope_type
+ *   True if the table scope is sharednon-shared, shared-app, global
  *
  * @param[out] ts_app
  *   Application type TF/AFM
@@ -199,12 +203,12 @@ int tfo_ts_set(void *tfo, uint8_t ts_tsid, bool ts_is_shared,
  *   True if the table scope is valid
  *
  * @param[out] ts_max_pools
- *   Maximum number of pools returned if shared.
+ *   Maximum number of pools.
  *
  * @return
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfo_ts_get(void *tfo, uint8_t ts_tsid, bool *ts_is_shared,
+int tfo_ts_get(void *tfo, uint8_t ts_tsid, enum cfa_scope_type *scope_type,
 	       enum cfa_app_type *ts_app, bool *ts_valid,
 	       uint16_t *ts_max_pools);
 
@@ -399,32 +403,35 @@ int tfo_sid_set(void *tfo, uint16_t sid);
 int tfo_sid_get(void *tfo, uint16_t *sid);
 
 /**
- * Set the table scope instance manager.
+ * Get the table scope instance manager.
  *
  * @param[in] tfo
  *   Pointer to TFC object
  *
- * @param[in] tim
- *   Pointer to the table scope instance manager
+ * @param[out] tim
+ *   Pointer to a pointer to the table scope instance manager
+ *
+ * @param[in] ts_tsid
+ *   Table scope id
  *
  * @return
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfo_tim_set(void *tfo, void *tim);
+int tfo_tim_get(void *tfo, void **tim, uint8_t ts_tsid);
 
 /**
- * Get the table scope instance manager.
+ * Get the table scope
  *
  * @param[in] tfo
  *   Pointer to TFC object
  *
- * @param[out] tim
- *   Pointer to a pointer to the table scope instance manager
+ * @param[out] tsid
+ *   Pointer to the returned table scope
  *
  * @return
  *   0 for SUCCESS, negative error value for FAILURE (errno.h)
  */
-int tfo_tim_get(void *tfo, void **tim);
+int tfo_tsid_get(void *tfo, uint8_t *tsid);
 
 /**
  * Get the table scope
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
index 281c32dff8..65df4ecd79 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
@@ -20,6 +20,7 @@
 #include "bnxt_tf_common.h"
 #include "hsi_struct_def_dpdk.h"
 #include "tf_core.h"
+#include "tfc_util.h"
 #include "tf_ext_flow_handle.h"
 
 #include "ulp_template_db_enum.h"
@@ -313,14 +314,6 @@ ulp_tfc_tbl_scope_deinit(struct bnxt *bp)
 	if (rc)
 		return;
 
-	rc = tfc_tbl_scope_cpm_free(tfcp, tsid);
-	if (rc)
-		BNXT_DRV_DBG(ERR, "Failed Freeing CPM TSID:%d FID:%d\n",
-			     tsid, fid);
-	else
-		BNXT_DRV_DBG(DEBUG, "Freed CPM TSID:%d FID: %d\n", tsid, fid);
-
-
 	rc = tfc_tbl_scope_fid_rem(tfcp, fid, tsid, &fid_cnt);
 	if (rc)
 		BNXT_DRV_DBG(ERR, "Failed removing FID from TSID:%d FID:%d",
@@ -329,7 +322,14 @@ ulp_tfc_tbl_scope_deinit(struct bnxt *bp)
 		BNXT_DRV_DBG(DEBUG, "Removed FID from TSID:%d FID:%d",
 			     tsid, fid);
 
-	rc = tfc_tbl_scope_mem_free(tfcp, fid, tsid);
+	rc = tfc_tbl_scope_cpm_free(tfcp, tsid);
+	if (rc)
+		BNXT_DRV_DBG(ERR, "Failed Freeing CPM TSID:%d FID:%d",
+			     tsid, fid);
+	else
+		BNXT_DRV_DBG(DEBUG, "Freed CPM TSID:%d FID: %d", tsid, fid);
+
+	rc = tfc_tbl_scope_mem_free(tfcp, fid, tsid, fid_cnt);
 	if (rc)
 		BNXT_DRV_DBG(ERR, "Failed freeing tscope mem TSID:%d FID:%d",
 			     tsid, fid);
@@ -345,8 +345,10 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 	struct tfc_tbl_scope_size_query_parms qparms =  { 0 };
 	uint16_t max_lkup_sz[CFA_DIR_MAX], max_act_sz[CFA_DIR_MAX];
 	struct tfc_tbl_scope_cpm_alloc_parms cparms;
+	struct tfc_tbl_scope_qcaps_parms qcparms;
 	uint16_t fid, max_pools;
-	bool first = true, shared = false;
+	bool first = true;
+	enum cfa_scope_type scope_type = CFA_SCOPE_TYPE_NON_SHARED;
 	uint64_t feat_bits;
 	uint8_t tsid = 0;
 	struct tfc *tfcp;
@@ -368,18 +370,37 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 	max_act_sz[CFA_DIR_TX] =
 		bnxt_ulp_cntxt_act_rec_tx_max_sz_get(bp->ulp_ctx);
 
-	shared = bnxt_ulp_cntxt_shared_tbl_scope_enabled(bp->ulp_ctx);
+	if (bnxt_ulp_cntxt_shared_tbl_scope_enabled(bp->ulp_ctx))
+		scope_type = CFA_SCOPE_TYPE_SHARED_APP;
 
 	feat_bits = bnxt_ulp_feature_bits_get(bp->ulp_ctx);
 	if ((feat_bits & BNXT_ULP_FEATURE_BIT_MULTI_INSTANCE)) {
 		if (!BNXT_PF(bp)) {
-			shared = true;
+			scope_type = CFA_SCOPE_TYPE_SHARED_APP;
 			max_pools = 32;
 		}
 	}
 
+	rc = tfc_tbl_scope_qcaps(tfcp, &qcparms);
+	if (rc) {
+		PMD_DRV_LOG_LINE(ERR,
+				 "Failed obtaining table scope capabilities");
+		return rc;
+	}
+
+	if (feat_bits & BNXT_ULP_FEATURE_BIT_SOCKET_DIRECT) {
+		if (qcparms.global_cap) {
+			scope_type = CFA_SCOPE_TYPE_GLOBAL;
+			max_pools = 4;
+		} else {
+			PMD_DRV_LOG_LINE(ERR,
+					 "Socket direct requires global scope");
+			return -EINVAL;
+		}
+	}
+
 	/* Calculate the sizes for setting up memory */
-	qparms.shared = shared;
+	qparms.scope_type = scope_type;
 	qparms.max_pools = max_pools;
 	qparms.factor = bnxt_ulp_cntxt_em_mulitplier_get(bp->ulp_ctx);
 	qparms.flow_cnt[CFA_DIR_RX] =
@@ -394,15 +415,12 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 	if (rc)
 		return rc;
 
-
-
-	rc = tfc_tbl_scope_id_alloc(tfcp, shared, CFA_APP_TYPE_TF, &tsid,
+	rc = tfc_tbl_scope_id_alloc(tfcp, scope_type, CFA_APP_TYPE_TF, &tsid,
 				    &first);
 	if (rc) {
 		BNXT_DRV_DBG(ERR, "Failed to allocate tscope\n");
 		return rc;
 	}
-	BNXT_DRV_DBG(DEBUG, "Allocated tscope TSID:%d\n", tsid);
 
 	rc = bnxt_ulp_cntxt_tsid_set(bp->ulp_ctx, tsid);
 	if (rc)
@@ -410,7 +428,7 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 
 	/* If we are shared and not the first table scope creator
 	 */
-	if (shared && !first) {
+	if (scope_type != CFA_SCOPE_TYPE_NON_SHARED && !first) {
 		bool configured;
 		#define ULP_SHARED_TSID_WAIT_TIMEOUT 5000
 		#define ULP_SHARED_TSID_WAIT_TIME 50
@@ -426,12 +444,12 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 			}
 			timeout -= ULP_SHARED_TSID_WAIT_TIME;
 			BNXT_DRV_DBG(INFO,
-				     "Waiting %d ms for shared tsid(%d)\n",
-				     timeout, tsid);
+				     "Waiting %d ms for %s tsid(%d)",
+				     timeout, tfc_scope_type_2_str(scope_type), tsid);
 		} while (!configured && timeout > 0);
 		if (timeout <= 0) {
-			BNXT_DRV_DBG(ERR, "Timed out on shared tsid(%d)\n",
-				     tsid);
+			BNXT_DRV_DBG(ERR, "Timed out on %s tsid(%d)",
+				     tfc_scope_type_2_str(scope_type), tsid);
 			return -ETIMEDOUT;
 		}
 	}
@@ -457,8 +475,9 @@ ulp_tfc_tbl_scope_init(struct bnxt *bp)
 		qparms.act_pool_sz_exp[CFA_DIR_RX];
 	mem_parms.act_pool_sz_exp[CFA_DIR_TX] =
 		qparms.act_pool_sz_exp[CFA_DIR_TX];
+	mem_parms.scope_type = scope_type;
 
-	if (shared)
+	if (scope_type != CFA_SCOPE_TYPE_NON_SHARED)
 		mem_parms.local = false;
 	else
 		mem_parms.local = true;
@@ -540,7 +559,10 @@ ulp_tfc_cntxt_app_caps_init(struct bnxt *bp, uint8_t app_id, uint32_t dev_id)
 				ulp_ctx->cfg_data->ulp_flags |=
 					BNXT_ULP_APP_SOCKET_DIRECT;
 				BNXT_DRV_DBG(DEBUG,
-					    "Socket Direct feature is enabled\n");
+					    "Socket Direct feature is enabled");
+			} else {
+				BNXT_DRV_DBG(DEBUG,
+					     "No Socket Direct feature - must enable multiroot");
 			}
 		}
 		/* Update the capability feature bits*/
diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
index 02534d8fe8..c30a43568b 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
@@ -911,7 +911,8 @@ enum bnxt_ulp_feature_bit {
 	BNXT_ULP_FEATURE_BIT_SOCKET_DIRECT = 0x00000008,
 	BNXT_ULP_FEATURE_BIT_MULTI_INSTANCE = 0x00000010,
 	BNXT_ULP_FEATURE_BIT_SPECIAL_VXLAN = 0x00000020,
-	BNXT_ULP_FEATURE_BIT_HOT_UPGRADE = 0x00000040
+	BNXT_ULP_FEATURE_BIT_HOT_UPGRADE = 0x00000040,
+	BNXT_ULP_FEATURE_BIT_GLOBAL_TBL_SCOPE = 0x00000080
 };
 
 enum bnxt_ulp_flow_dir_bitmask {
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 34/57] net/bnxt/tf_ulp: ulp parser support to handle gre key
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 33/57] net/bnxt/tf_core: truflow global table scope Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 35/57] net/bnxt/tf_core: handle out of order MPC completions Manish Kurup
                   ` (17 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Shahaji Bhosle, Kishore Padmanabha

From: Shahaji Bhosle <shahaji.bhosle@broadcom.com>

1. Added a new handler to GRE key input from the parser
2. Add a new pattern to match on GRE with KEY id.

Signed-off-by: Shahaji Bhosle <shahaji.bhosle@broadcom.com>
Reviewed-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/ulp_rte_handler_tbl.c |  4 +-
 drivers/net/bnxt/tf_ulp/ulp_rte_parser.c      | 45 ++++++++++++++++++-
 drivers/net/bnxt/tf_ulp/ulp_rte_parser.h      |  5 +++
 .../net/bnxt/tf_ulp/ulp_template_db_enum.h    |  3 +-
 drivers/net/bnxt/tf_ulp/ulp_template_struct.h |  2 +
 5 files changed, 55 insertions(+), 4 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/ulp_rte_handler_tbl.c b/drivers/net/bnxt/tf_ulp/ulp_rte_handler_tbl.c
index 6e1115b985..4a7c7e437c 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_rte_handler_tbl.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_rte_handler_tbl.c
@@ -373,8 +373,8 @@ struct bnxt_ulp_rte_hdr_info ulp_hdr_info[] = {
 	.proto_hdr_func          = NULL
 	},
 	[RTE_FLOW_ITEM_TYPE_GRE_KEY] = {
-	.hdr_type                = BNXT_ULP_HDR_TYPE_NOT_SUPPORTED,
-	.proto_hdr_func          = NULL
+	.hdr_type                = BNXT_ULP_HDR_TYPE_SUPPORTED,
+	.proto_hdr_func          = ulp_rte_gre_key_hdr_handler
 	},
 	[RTE_FLOW_ITEM_TYPE_GTP_PSC] = {
 	.hdr_type                = BNXT_ULP_HDR_TYPE_NOT_SUPPORTED,
diff --git a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
index af7f8b7ab4..ceda1ff5ef 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
@@ -31,6 +31,9 @@
 #define ULP_UDP_PORT_GENEVE		6081
 #define ULP_UDP_PORT_GENEVE_MASK	0xFFFF
 
+/* GRE cks_rsvd0_ver bits */
+#define ULP_GRE_CKS_RSVD0_VER_HDR_KEY_BIT 0x2000
+
 /**
  * Geneve header first 16Bit
  * Version (2b), length of the options fields (6b), OAM packet (1b),
@@ -1887,14 +1890,51 @@ ulp_rte_geneve_hdr_handler(const struct rte_flow_item *item,
 	return BNXT_TF_RC_SUCCESS;
 }
 
+/* Function to handle the parsing of RTE Flow item GRE Key Header. */
+int32_t
+ulp_rte_gre_key_hdr_handler(const struct rte_flow_item *item,
+			    struct ulp_rte_parser_params *params)
+{
+	const rte_be32_t *gre_key_spec = item->spec;
+	const rte_be32_t *gre_key_mask = item->mask;
+	rte_be32_t gre_key_full_mask = RTE_BE32(UINT32_MAX);
+	struct ulp_rte_hdr_bitmap *hdr_bitmap = &params->hdr_bitmap;
+	uint32_t idx = 0;
+	uint32_t size;
+
+	if (unlikely(ulp_rte_prsr_fld_size_validate(params, &idx,
+						    BNXT_ULP_PROTO_HDR_GRE_KEY_NUM))) {
+		BNXT_DRV_DBG(ERR, "Error parsing protocol header");
+		return BNXT_TF_RC_ERROR;
+	}
+
+	if (unlikely(!(params->gre_cks_rsvd0_ver & RTE_BE16(ULP_GRE_CKS_RSVD0_VER_HDR_KEY_BIT)))) {
+		BNXT_DRV_DBG(ERR, "Error GRE K bit is not set");
+		return BNXT_TF_RC_ERROR;
+	}
+
+	if (gre_key_spec && !gre_key_mask)
+		gre_key_mask = &gre_key_full_mask;
+
+	size = sizeof(uint32_t);
+	ulp_rte_prsr_fld_mask(params, &idx, size,
+			      gre_key_spec,
+			      gre_key_mask,
+			      ULP_PRSR_ACT_DEFAULT);
+
+	/* Update the hdr_bitmap with GRE */
+	ULP_BITMAP_SET(hdr_bitmap->bits, BNXT_ULP_HDR_BIT_T_GRE_OPT);
+	return BNXT_TF_RC_SUCCESS;
+}
+
 /* Function to handle the parsing of RTE Flow item GRE Header. */
 int32_t
 ulp_rte_gre_hdr_handler(const struct rte_flow_item *item,
 			struct ulp_rte_parser_params *params)
 {
+	struct ulp_rte_hdr_bitmap *hdr_bitmap = &params->hdr_bitmap;
 	const struct rte_flow_item_gre *gre_spec = item->spec;
 	const struct rte_flow_item_gre *gre_mask = item->mask;
-	struct ulp_rte_hdr_bitmap *hdr_bitmap = &params->hdr_bitmap;
 	uint32_t idx = 0;
 	uint32_t size;
 
@@ -1907,6 +1947,9 @@ ulp_rte_gre_hdr_handler(const struct rte_flow_item *item,
 	if (gre_spec && !gre_mask)
 		gre_mask = &rte_flow_item_gre_mask;
 
+	params->gre_cks_rsvd0_ver = (gre_spec && gre_mask) ?
+		(gre_spec->c_rsvd0_ver & gre_mask->c_rsvd0_ver) : 0;
+
 	size = sizeof(((struct rte_flow_item_gre *)NULL)->c_rsvd0_ver);
 	ulp_rte_prsr_fld_mask(params, &idx, size,
 			      ulp_deference_struct(gre_spec, c_rsvd0_ver),
diff --git a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.h b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.h
index 5f451ba404..92c34394ae 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.h
@@ -140,6 +140,11 @@ int32_t
 ulp_rte_geneve_hdr_handler(const struct rte_flow_item *item,
 			      struct ulp_rte_parser_params *params);
 
+/* Function to handle the parsing of RTE Flow item GRE KEY Header. */
+int32_t
+ulp_rte_gre_key_hdr_handler(const struct rte_flow_item *item,
+			    struct ulp_rte_parser_params *params);
+
 /* Function to handle the parsing of RTE Flow item GRE Header. */
 int32_t
 ulp_rte_gre_hdr_handler(const struct rte_flow_item *item,
diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
index c30a43568b..3ce43f4c92 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
@@ -119,7 +119,8 @@ enum bnxt_ulp_hdr_bit {
 	BNXT_ULP_HDR_BIT_NON_GENERIC         = 0x0000000400000000,
 	BNXT_ULP_HDR_BIT_GENERIC             = 0x0000000800000000,
 	BNXT_ULP_HDR_BIT_T_MPLS              = 0x0000001000000000,
-	BNXT_ULP_HDR_BIT_LAST                = 0x0000002000000000
+	BNXT_ULP_HDR_BIT_T_GRE_OPT           = 0x0000002000000000,
+	BNXT_ULP_HDR_BIT_LAST                = 0x0000004000000000
 };
 
 enum bnxt_ulp_accept_opc {
diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_struct.h b/drivers/net/bnxt/tf_ulp/ulp_template_struct.h
index 5b3e82f336..f38ebcea9a 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_template_struct.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_template_struct.h
@@ -32,6 +32,7 @@
 #define BNXT_ULP_PROTO_HDR_VXLAN_GPE_NUM 5
 #define BNXT_ULP_PROTO_HDR_GENEVE_NUM 4
 #define BNXT_ULP_PROTO_HDR_GRE_NUM	2
+#define BNXT_ULP_PROTO_HDR_GRE_KEY_NUM	1
 #define BNXT_ULP_PROTO_HDR_ICMP_NUM	5
 #define BNXT_ULP_PROTO_HDR_ECPRI_NUM	2
 #define	BNXT_ULP_PROTO_HDR_IPV6_EXT_NUM	1
@@ -100,6 +101,7 @@ struct ulp_rte_parser_params {
 	uint32_t			act_pattern_id;
 	uint8_t				app_id;
 	uint8_t				tun_idx;
+	uint16_t			gre_cks_rsvd0_ver; /* GRE C, K, S bits and version */
 	uint16_t			class_info_idx;
 	uint64_t			wc_field_bitmap;
 	uint64_t			cf_bitmap;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 35/57] net/bnxt/tf_core: handle out of order MPC completions
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 33/57] net/bnxt/tf_core: truflow global table scope Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 34/57] net/bnxt/tf_ulp: ulp parser support to handle gre key Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 36/57] net/bnxt/tf_ulp: socket direct enable Manish Kurup
                   ` (16 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Peter Spreadborough, Jay Ding, Farah Smith

From: Peter Spreadborough <peter.spreadborough@broadcom.com>

It is possible for MPC completions to be returned in an order
different to the corresponding MPC requests. This change adds
using the MPC opaque field to uniquely associate a completion
with a request and handling of out of order completions to
the batch-end processing.

Signed-off-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Jay Ding <jay.ding@broadcom.com>
Reviewed-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
---
 drivers/net/bnxt/bnxt_mpc.c           |  26 +++++-
 drivers/net/bnxt/bnxt_mpc.h           |   7 +-
 drivers/net/bnxt/tf_core/v3/tfc_act.c |  12 +--
 drivers/net/bnxt/tf_core/v3/tfc_em.c  | 126 +++++++++++++++++++++-----
 drivers/net/bnxt/tf_core/v3/tfc_em.h  |   4 +-
 5 files changed, 138 insertions(+), 37 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_mpc.c b/drivers/net/bnxt/bnxt_mpc.c
index 2582b50782..259066fa61 100644
--- a/drivers/net/bnxt/bnxt_mpc.c
+++ b/drivers/net/bnxt/bnxt_mpc.c
@@ -575,7 +575,9 @@ int bnxt_mpc_open(struct bnxt *bp)
 	return rc;
 }
 
-int bnxt_mpc_cmd_cmpl(struct bnxt_mpc_txq *mpc_queue, struct bnxt_mpc_mbuf *out_msg)
+int bnxt_mpc_cmd_cmpl(struct bnxt_mpc_txq *mpc_queue,
+		      struct bnxt_mpc_mbuf *out_msg,
+		      uint16_t *opaque)
 {
 	struct bnxt_cp_ring_info *cpr = mpc_queue->cp_ring;
 	uint32_t raw_cons = cpr->cp_raw_cons;
@@ -665,12 +667,13 @@ int bnxt_mpc_cmd_cmpl(struct bnxt_mpc_txq *mpc_queue, struct bnxt_mpc_mbuf *out_
 		bnxt_db_mpc_cq(cpr);
 	}
 
+	*opaque = (uint16_t)mpc_cmpl->info2;
 	return nb_mpc_cmds;
 }
 
 static uint16_t bnxt_mpc_xmit(struct bnxt_mpc_mbuf *mpc_cmd,
 			      struct bnxt_mpc_txq *mpc_queue,
-			      uint32_t *opaque)
+			      uint16_t *opaque)
 {
 	struct bnxt_mpc_ring_info *mpr = mpc_queue->mpc_ring;
 	struct bnxt_ring *ring = mpr->mpc_ring_struct;
@@ -715,13 +718,14 @@ static uint16_t bnxt_mpc_xmit(struct bnxt_mpc_mbuf *mpc_cmd,
 int bnxt_mpc_send(struct bnxt *bp,
 		  struct bnxt_mpc_mbuf *in_msg,
 		  struct bnxt_mpc_mbuf *out_msg,
-		  uint32_t *opaque,
+		  uint16_t *opaque,
 		  bool batch)
 {
 	int rc;
 	struct bnxt_mpc_txq *mpc_queue = bp->mpc->mpc_txq[in_msg->chnl_id];
 	int retry = BNXT_MPC_RX_RETRY;
 	uint32_t pi = 0;
+	uint16_t rx_opaque;
 
 	if (out_msg->cmp_type != CMPL_BASE_TYPE_MID_PATH_SHORT &&
 	    out_msg->cmp_type != CMPL_BASE_TYPE_MID_PATH_LONG)
@@ -737,6 +741,8 @@ int bnxt_mpc_send(struct bnxt *bp,
 	 * it can be detected.
 	 */
 	pi = mpc_queue->mpc_ring->raw_prod;
+	*opaque = mpc_queue->seq_num;
+	mpc_queue->seq_num++;
 	rc = bnxt_mpc_xmit(in_msg, mpc_queue, opaque);
 
 	if (unlikely(rc))
@@ -761,10 +767,20 @@ int bnxt_mpc_send(struct bnxt *bp,
 	do {
 		rte_delay_us_block(BNXT_MPC_RX_US_DELAY);
 
-		rc =  bnxt_mpc_cmd_cmpl(mpc_queue, out_msg);
+		rc =  bnxt_mpc_cmd_cmpl(mpc_queue, out_msg, &rx_opaque);
 
-		if (rc == 1)
+		if (rc == 1) {
+			if (rx_opaque != *opaque)
+				PMD_DRV_LOG_LINE(ERR,
+					    "%s: Out of order completion. Opaque Expected:%d Got:%d",
+					    __func__,
+					    *opaque,
+					    rx_opaque);
 			return 0;
+		}
+#ifdef MPC_DEBUG
+		PMD_DRV_LOG_LINE("Received zero or more than one completion:%d", rc);
+#endif
 		retry--;
 	} while (retry);
 
diff --git a/drivers/net/bnxt/bnxt_mpc.h b/drivers/net/bnxt/bnxt_mpc.h
index b089ddd4bb..da3672e493 100644
--- a/drivers/net/bnxt/bnxt_mpc.h
+++ b/drivers/net/bnxt/bnxt_mpc.h
@@ -93,6 +93,7 @@ struct bnxt_mpc_txq {
 	struct bnxt_cp_ring_info	*cp_ring;
 	const struct rte_memzone *mz;
 	struct bnxt_mpc_mbuf **free;
+	uint16_t	seq_num;
 
 	void (*cmpl_handler_cb)(struct bnxt_mpc_txq *mpc_queue,
 				uint32_t nb_mpc_cmds);
@@ -109,9 +110,11 @@ int bnxt_mpc_close(struct bnxt *bp);
 int bnxt_mpc_send(struct bnxt *bp,
 		  struct bnxt_mpc_mbuf *in_msg,
 		  struct bnxt_mpc_mbuf *out_msg,
-		  uint32_t *opaque,
+		  uint16_t *opaque,
 		  bool batch);
-int bnxt_mpc_cmd_cmpl(struct bnxt_mpc_txq *mpc_queue, struct bnxt_mpc_mbuf *out_msg);
+int bnxt_mpc_cmd_cmpl(struct bnxt_mpc_txq *mpc_queue,
+		      struct bnxt_mpc_mbuf *out_msg,
+		      uint16_t *opaque);
 int bnxt_mpc_poll_cmd_cmpls(struct bnxt_mpc_txq *mpc_queue);
 
 #endif
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_act.c b/drivers/net/bnxt/tf_core/v3/tfc_act.c
index 3c1c76359b..d93064dbc6 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_act.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_act.c
@@ -225,7 +225,7 @@ int tfc_act_set(struct tfc *tfcp,
 	int rc = 0;
 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	uint16_t opaque;
 	uint32_t i;
 	uint32_t buff_len;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_WRITE_CMD_MAX_FLD];
@@ -311,7 +311,7 @@ int tfc_act_set(struct tfc *tfcp,
 	rc = tfc_mpc_send(tfcp->bp,
 			  &mpc_msg_in,
 			  &mpc_msg_out,
-			  &msg_count,
+			  &opaque,
 			  TFC_MPC_TABLE_WRITE,
 			  batch_info);
 
@@ -377,7 +377,7 @@ static int tfc_act_get_only(struct tfc *tfcp,
 	int rc = 0;
 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES] = { 0 };
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES] = { 0 };
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	uint16_t opaque;
 	int i;
 	uint32_t buff_len;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_READ_CMD_MAX_FLD] = { {0} };
@@ -477,7 +477,7 @@ static int tfc_act_get_only(struct tfc *tfcp,
 	rc = tfc_mpc_send(tfcp->bp,
 			  &mpc_msg_in,
 			  &mpc_msg_out,
-			  &msg_count,
+			  &opaque,
 			  TFC_MPC_TABLE_READ,
 			  batch_info);
 
@@ -556,7 +556,7 @@ static int tfc_act_get_clear(struct tfc *tfcp,
 	int rc = 0;
 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES] = { 0 };
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES] = { 0 };
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	uint16_t opaque;
 	int i;
 	uint32_t buff_len;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_READ_CLR_CMD_MAX_FLD] = { {0} };
@@ -665,7 +665,7 @@ static int tfc_act_get_clear(struct tfc *tfcp,
 	rc = tfc_mpc_send(tfcp->bp,
 			  &mpc_msg_in,
 			  &mpc_msg_out,
-			  &msg_count,
+			  &opaque,
 			  TFC_MPC_TABLE_READ_CLEAR,
 			  batch_info);
 
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_em.c b/drivers/net/bnxt/tf_core/v3/tfc_em.c
index 828b7838f5..47870747e1 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_em.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_em.c
@@ -129,7 +129,7 @@ int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
 	uint32_t buff_len;
 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	uint16_t opaque;
 	uint32_t i;
 	uint32_t hash = 0;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_INSERT_CMD_MAX_FLD];
@@ -354,7 +354,7 @@ int tfc_em_insert(struct tfc *tfcp, uint8_t tsid,
 	rc = tfc_mpc_send(tfcp->bp,
 			  &mpc_msg_in,
 			  &mpc_msg_out,
-			  &msg_count,
+			  &opaque,
 			  TFC_MPC_EM_INSERT,
 			  parms->batch_info);
 
@@ -500,7 +500,7 @@ int tfc_em_delete_raw(struct tfc *tfcp,
 	struct bnxt_mpc_mbuf mpc_msg_out;
 	uint8_t tx_msg[TFC_MPC_MAX_TX_BYTES];
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
-	uint32_t msg_count = BNXT_MPC_COMP_MSG_COUNT;
+	uint16_t opaque = 0;
 	int i;
 	struct cfa_mpc_data_obj fields_cmd[CFA_BLD_MPC_EM_DELETE_CMD_MAX_FLD];
 	struct cfa_bld_mpcinfo *mpc_info;
@@ -565,7 +565,7 @@ int tfc_em_delete_raw(struct tfc *tfcp,
 	rc = tfc_mpc_send(tfcp->bp,
 			  &mpc_msg_in,
 			  &mpc_msg_out,
-			  &msg_count,
+			  &opaque,
 			  TFC_MPC_EM_DELETE,
 			  batch_info);
 	if (rc) {
@@ -834,7 +834,7 @@ int tfc_em_delete_entries_by_pool_id(struct tfc *tfcp,
 int tfc_mpc_send(struct bnxt *bp,
 		 struct bnxt_mpc_mbuf *in_msg,
 		 struct bnxt_mpc_mbuf *out_msg,
-		 uint32_t *opaque,
+		 uint16_t *opaque,
 		 int type,
 		 struct tfc_mpc_batch_info_t *batch_info)
 {
@@ -856,6 +856,8 @@ int tfc_mpc_send(struct bnxt *bp,
 		batch_info->comp_info[batch_info->count].mpc_queue =
 			bp->mpc->mpc_txq[in_msg->chnl_id];
 		batch_info->comp_info[batch_info->count].type = type;
+		batch_info->comp_info[batch_info->count].opaque = *opaque;
+		batch_info->comp_info[batch_info->count].valid = true;
 		batch_info->count++;
 	}
 
@@ -863,7 +865,8 @@ int tfc_mpc_send(struct bnxt *bp,
 }
 
 static int tfc_mpc_process_completions(uint8_t *rx_msg,
-				       struct tfc_mpc_comp_info_t *comp_info)
+				       struct tfc_mpc_comp_info_t *comp_info,
+				       uint16_t *opaque)
 {
 	int rc;
 	int retry = BNXT_MPC_RX_RETRY;
@@ -872,7 +875,8 @@ static int tfc_mpc_process_completions(uint8_t *rx_msg,
 
 	do {
 		rc =  bnxt_mpc_cmd_cmpl(comp_info->mpc_queue,
-					&comp_info->out_msg);
+					&comp_info->out_msg,
+					opaque);
 
 		if (likely(rc == 1)) {
 #ifdef MPC_DEBUG
@@ -913,14 +917,41 @@ bool tfc_mpc_batch_started(struct tfc_mpc_batch_info_t *batch_info)
 	return (batch_info->enabled && batch_info->count > 0);
 }
 
+/* Test out of order handling */
+/*#define MPC_OOO_DEBUG */
+
+#ifdef MPC_OOO_DEBUG
+static void swap_entries(struct tfc_mpc_batch_info_t *batch_info, int count)
+{
+	struct tfc_mpc_comp_info_t tmp;
+	int i1;
+	int i2;
+
+	i1 = rand() % (count - 1);
+	i2 = rand() % (count - 1);
+
+	PMD_DRV_LOG(ERR, "%s: Swapping index %d and %d",
+		    __func__,
+		    i1,
+		    i2);
+
+	memcpy(&tmp, &batch_info->comp_info[i1], sizeof(tmp));
+	memcpy(&batch_info->comp_info[i1], &batch_info->comp_info[i2], sizeof(tmp));
+	memcpy(&batch_info->comp_info[i2], &tmp, sizeof(tmp));
+}
+#endif
+
 int tfc_mpc_batch_end(struct tfc *tfcp,
 		      struct tfc_mpc_batch_info_t *batch_info)
 {
-	uint32_t i;
+	uint32_t j;
+	uint32_t start_index = 0;
 	int rc;
 	uint8_t rx_msg[TFC_MPC_MAX_RX_BYTES];
 	struct cfa_bld_mpcinfo *mpc_info;
 	uint32_t hash = 0;
+	uint16_t opaque = 0;
+	uint32_t count;
 #if TFC_EM_DYNAMIC_BUCKET_EN
 	bool *db_unused;
 	uint32_t *db_offset;
@@ -945,17 +976,65 @@ int tfc_mpc_batch_end(struct tfc *tfcp,
 	if (batch_info->count < (BNXT_MPC_COMP_MAX_COUNT / 4))
 		rte_delay_us_block(BNXT_MPC_RX_US_DELAY * 4);
 
-	for (i = 0; i < batch_info->count; i++) {
+#ifdef MPC_OOO_DEBUG
+	/* force out of order in large batches */
+	if (batch_info->count > 10)
+		swap_entries(batch_info, batch_info->count);
+#endif
+
+	count = batch_info->count;
+
+	while (count) {
 		rc = tfc_mpc_process_completions(&rx_msg[TFC_MPC_HEADER_SIZE_BYTES],
-						 &batch_info->comp_info[i]);
+						 &batch_info->comp_info[start_index],
+						 &opaque);
 		if (unlikely(rc))
 			return -1;
 
+#ifdef MPC_DEBUG
+		PMD_DRV_LOG(ERR, "%s: count:%d start_index:%d bo:%d op:%d ci:%p type:%d",
+			    __func__,
+			    count,
+			    start_index,
+			    batch_info->comp_info[start_index].opaque,
+			    opaque,
+			    batch_info->comp_info[start_index].mpc_queue,
+			    batch_info->comp_info[start_index].type);
+#endif
+
+		/* Find batch entry that has a matching opaque value */
+		for (j = start_index; j < batch_info->count; j++) {
+			if (!batch_info->comp_info[j].valid ||
+			    opaque != batch_info->comp_info[j].opaque ||
+			    batch_info->comp_info[start_index].mpc_queue !=
+			    batch_info->comp_info[j].mpc_queue)
+				continue;
+
+			count--;
+
+			if (j != start_index) {
+				PMD_DRV_LOG_LINE(INFO,
+						 "%s: OOO comp. Opq Exp:%d Got:%d j:%d",
+						 __func__,
+						 batch_info->comp_info[j].opaque,
+						 opaque, j);
+			} else {
+				start_index++;
+
+				while (count &&
+				       start_index < batch_info->count &&
+				       !batch_info->comp_info[start_index].valid)
+					start_index++;
+			}
+
+			batch_info->comp_info[j].out_msg.msg_data = rx_msg;
+			break;
+		}
 
-		switch (batch_info->comp_info[i].type) {
+		switch (batch_info->comp_info[j].type) {
 		case TFC_MPC_EM_INSERT:
 			rc = tfc_em_insert_response(mpc_info,
-						    &batch_info->comp_info[i].out_msg,
+						    &batch_info->comp_info[j].out_msg,
 						    rx_msg,
 						    &hash);
 			/*
@@ -963,14 +1042,14 @@ int tfc_mpc_batch_end(struct tfc *tfcp,
 			 * flow DB entry that requires the flow_handle
 			 * contained within to be updated.
 			 */
-			batch_info->em_hdl[i] =
-				tfc_create_flow_handle2(batch_info->em_hdl[i],
+			batch_info->em_hdl[j] =
+				tfc_create_flow_handle2(batch_info->em_hdl[j],
 							hash);
 			batch_info->em_error = rc;
 			break;
 		case TFC_MPC_EM_DELETE:
 			rc = tfc_em_delete_response(mpc_info,
-						    &batch_info->comp_info[i].out_msg,
+						    &batch_info->comp_info[j].out_msg,
 						    rx_msg
 #if TFC_EM_DYNAMIC_BUCKET_EN
 						    , bool *db_unused,
@@ -980,30 +1059,31 @@ int tfc_mpc_batch_end(struct tfc *tfcp,
 			break;
 		case TFC_MPC_TABLE_WRITE:
 			rc = tfc_act_set_response(mpc_info,
-						  &batch_info->comp_info[i].out_msg,
+						  &batch_info->comp_info[j].out_msg,
 						  rx_msg);
 			break;
 		case TFC_MPC_TABLE_READ:
 			rc = tfc_act_get_only_response(mpc_info,
-						       &batch_info->comp_info[i].out_msg,
+						       &batch_info->comp_info[j].out_msg,
 						       rx_msg,
-						       &batch_info->comp_info[i].read_words);
+						       &batch_info->comp_info[j].read_words);
 			break;
 
 		case TFC_MPC_TABLE_READ_CLEAR:
 			rc = tfc_act_get_clear_response(mpc_info,
-							&batch_info->comp_info[i].out_msg,
+							&batch_info->comp_info[j].out_msg,
 							rx_msg,
-							&batch_info->comp_info[i].read_words);
+							&batch_info->comp_info[j].read_words);
 			break;
 
 		default:
-			PMD_DRV_LOG_LINE(ERR, "MPC Batch not supported for type: %d",
-					 batch_info->comp_info[i].type);
+			PMD_DRV_LOG_LINE(ERR, "%s: MPC Batch not supported for type: %d",
+				    __func__, batch_info->comp_info[j].type);
 			return -1;
 		}
 
-		batch_info->result[i] = rc;
+		batch_info->comp_info[j].valid = false;
+		batch_info->result[j] = rc;
 		if (rc)
 			batch_info->error = true;
 	}
diff --git a/drivers/net/bnxt/tf_core/v3/tfc_em.h b/drivers/net/bnxt/tf_core/v3/tfc_em.h
index 52589ea9c3..659cebe907 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_em.h
+++ b/drivers/net/bnxt/tf_core/v3/tfc_em.h
@@ -21,6 +21,8 @@ struct tfc_mpc_comp_info_t {
 	struct bnxt_mpc_mbuf out_msg;
 	int type;
 	uint16_t read_words;
+	uint16_t opaque;
+	bool valid;
 };
 
 struct tfc_mpc_batch_info_t {
@@ -249,7 +251,7 @@ int tfc_act_get_clear_response(struct cfa_bld_mpcinfo *mpc_info,
 int tfc_mpc_send(struct bnxt *bp,
 		 struct bnxt_mpc_mbuf *in_msg,
 		 struct bnxt_mpc_mbuf *out_msg,
-		 uint32_t *opaque,
+		 uint16_t *opaque,
 		 int type,
 		 struct tfc_mpc_batch_info_t *batch_info);
 
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 36/57] net/bnxt/tf_ulp: socket direct enable
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (2 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 35/57] net/bnxt/tf_core: handle out of order MPC completions Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 37/57] net/bnxt: fix adding udp_tunnel_port Manish Kurup
                   ` (15 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Farah Smith, Kishore Padmanabha

From: Farah Smith <farah.smith@broadcom.com>

1. Remove code which requires multi-root to be configured in order for
the socket direct feature be enabled.  This is not required and was
a customer specific implementation.

2. Always enable the global table scope for Thor2 when the socket
direct feature is enabled.

3. Remove global table scope feature bit.

Signed-off-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c    | 12 +++---------
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c   | 16 ++++------------
 drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h |  5 +++--
 3 files changed, 10 insertions(+), 23 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
index e3eb9107ab..de87ce0349 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
@@ -420,15 +420,9 @@ ulp_tf_cntxt_app_caps_init(struct bnxt *bp,
 		if (info[i].flags & BNXT_ULP_APP_CAP_BC_MC_SUPPORT)
 			ulp_ctx->cfg_data->ulp_flags |=
 				BNXT_ULP_APP_BC_MC_SUPPORT;
-		if (info[i].flags & BNXT_ULP_APP_CAP_SOCKET_DIRECT) {
-			/* Enable socket direction only if MR is enabled in fw*/
-			if (BNXT_MULTIROOT_EN(bp)) {
-				ulp_ctx->cfg_data->ulp_flags |=
-					BNXT_ULP_APP_SOCKET_DIRECT;
-				BNXT_DRV_DBG(INFO,
-					     "Socket Direct feature is enabled\n");
-			}
-		}
+		if (info[i].flags & BNXT_ULP_APP_CAP_SOCKET_DIRECT)
+			ulp_ctx->cfg_data->ulp_flags |=
+				BNXT_ULP_APP_SOCKET_DIRECT;
 		if (info[i].flags & BNXT_ULP_APP_CAP_HA_DYNAMIC) {
 			/* Read the environment variable to determine hot up */
 			if (!bnxt_pmd_get_hot_up_config()) {
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
index 65df4ecd79..772dd69035 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
@@ -553,18 +553,10 @@ ulp_tfc_cntxt_app_caps_init(struct bnxt *bp, uint8_t app_id, uint32_t dev_id)
 		if (info[i].flags & BNXT_ULP_APP_CAP_BC_MC_SUPPORT)
 			ulp_ctx->cfg_data->ulp_flags |=
 				BNXT_ULP_APP_BC_MC_SUPPORT;
-		if (info[i].flags & BNXT_ULP_APP_CAP_SOCKET_DIRECT) {
-			/* Enable socket direction only if MR is enabled in fw*/
-			if (BNXT_MULTIROOT_EN(bp)) {
-				ulp_ctx->cfg_data->ulp_flags |=
-					BNXT_ULP_APP_SOCKET_DIRECT;
-				BNXT_DRV_DBG(DEBUG,
-					    "Socket Direct feature is enabled");
-			} else {
-				BNXT_DRV_DBG(DEBUG,
-					     "No Socket Direct feature - must enable multiroot");
-			}
-		}
+		if (info[i].flags & BNXT_ULP_APP_CAP_SOCKET_DIRECT)
+			ulp_ctx->cfg_data->ulp_flags |=
+				BNXT_ULP_APP_SOCKET_DIRECT;
+
 		/* Update the capability feature bits*/
 		if (bnxt_ulp_cap_feat_process(info[i].feature_bits,
 					      &ulp_ctx->cfg_data->feature_bits))
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
index c3f3bcd59d..c46340b1a4 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
@@ -1061,8 +1061,9 @@ bnxt_ulp_cap_feat_process(uint64_t feat_bits, uint64_t *out_bits)
 	if (bit & BNXT_ULP_FEATURE_BIT_SPECIAL_VXLAN)
 		BNXT_DRV_DBG(ERR, "Special VXLAN Feature is enabled\n");
 	if (bit & BNXT_ULP_FEATURE_BIT_HOT_UPGRADE)
-		BNXT_DRV_DBG(ERR, "Hot Upgrade Feature is enabled\n");
-
+		BNXT_DRV_DBG(ERR, "Hot Upgrade Feature is enabled");
+	if (bit & BNXT_ULP_FEATURE_BIT_SOCKET_DIRECT)
+		BNXT_DRV_DBG(ERR, "Socket Direct Feature is enabled");
 	*out_bits =  bit;
 	return 0;
 }
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 37/57] net/bnxt: fix adding udp_tunnel_port
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (3 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 36/57] net/bnxt/tf_ulp: socket direct enable Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 38/57] net/bnxt/tf_ulp: add non vfr mode capability Manish Kurup
                   ` (14 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Farah Smith, Kalesh AP, Peter Spreadborough

From: Farah Smith <farah.smith@broadcom.com>

Do not increment the port count if adding the same value multiple
times.

Signed-off-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/bnxt_ethdev.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 94bec74c1e..54613076b0 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -2622,7 +2622,6 @@ bnxt_udp_tunnel_port_add_op(struct rte_eth_dev *eth_dev,
 				PMD_DRV_LOG_LINE(ERR, "Only one port allowed");
 				return -ENOSPC;
 			}
-			bp->vxlan_port_cnt++;
 			return 0;
 		}
 		tunnel_type =
@@ -2636,7 +2635,6 @@ bnxt_udp_tunnel_port_add_op(struct rte_eth_dev *eth_dev,
 				PMD_DRV_LOG_LINE(ERR, "Only one port allowed");
 				return -ENOSPC;
 			}
-			bp->geneve_port_cnt++;
 			return 0;
 		}
 		tunnel_type =
@@ -2650,7 +2648,6 @@ bnxt_udp_tunnel_port_add_op(struct rte_eth_dev *eth_dev,
 				PMD_DRV_LOG_LINE(ERR, "Only one port allowed");
 				return -ENOSPC;
 			}
-			bp->ecpri_port_cnt++;
 			return 0;
 		}
 		tunnel_type =
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 38/57] net/bnxt/tf_ulp: add non vfr mode capability
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (4 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 37/57] net/bnxt: fix adding udp_tunnel_port Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 39/57] net/bnxt: avoid iova range check when external memory is used Manish Kurup
                   ` (13 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Kishore Padmanabha, Shuanglin Wang

From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

For Wh+ platform, the generic template support representor
and non representor mode, this flag shall be controlled by the
newly added capability flag that is added during the compile time.
The flag enables the testpmd forward mode, so testpmd application
can forward packets from one port to another port.

Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Shuanglin Wang <shuanglin.wang@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c          | 5 ++++-
 drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h       | 3 +++
 drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h | 3 ++-
 3 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
index de87ce0349..54a5e6968c 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
@@ -1049,6 +1049,7 @@ ulp_tf_ctx_init(struct bnxt *bp,
 	int32_t			rc = 0;
 	enum bnxt_ulp_device_id devid;
 	enum bnxt_ulp_session_type stype;
+	uint64_t feat_bits;
 	struct tf *tfp;
 
 	/* Initialize the context entries list */
@@ -1101,7 +1102,9 @@ ulp_tf_ctx_init(struct bnxt *bp,
 		goto error_deinit;
 	}
 
-	if (BNXT_TESTPMD_EN(bp)) {
+	feat_bits = bnxt_ulp_feature_bits_get(bp->ulp_ctx);
+	if ((feat_bits & BNXT_ULP_FEATURE_BIT_NON_VFR_MODE) &&
+	    !BNXT_REP_MODE_EN(bp)) {
 		ulp_data->ulp_flags &= ~BNXT_ULP_VF_REP_ENABLED;
 		BNXT_DRV_DBG(ERR, "Enabled Testpmd forward mode\n");
 	}
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
index c46340b1a4..14ee1e05fb 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
@@ -1064,6 +1064,9 @@ bnxt_ulp_cap_feat_process(uint64_t feat_bits, uint64_t *out_bits)
 		BNXT_DRV_DBG(ERR, "Hot Upgrade Feature is enabled");
 	if (bit & BNXT_ULP_FEATURE_BIT_SOCKET_DIRECT)
 		BNXT_DRV_DBG(ERR, "Socket Direct Feature is enabled");
+	if (bit & BNXT_ULP_FEATURE_BIT_NON_VFR_MODE)
+		BNXT_DRV_DBG(ERR, "Non VFR Feature is enabled");
+
 	*out_bits =  bit;
 	return 0;
 }
diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
index 3ce43f4c92..d63862ffba 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
@@ -913,7 +913,8 @@ enum bnxt_ulp_feature_bit {
 	BNXT_ULP_FEATURE_BIT_MULTI_INSTANCE = 0x00000010,
 	BNXT_ULP_FEATURE_BIT_SPECIAL_VXLAN = 0x00000020,
 	BNXT_ULP_FEATURE_BIT_HOT_UPGRADE = 0x00000040,
-	BNXT_ULP_FEATURE_BIT_GLOBAL_TBL_SCOPE = 0x00000080
+	BNXT_ULP_FEATURE_BIT_GLOBAL_TBL_SCOPE = 0x00000080,
+	BNXT_ULP_FEATURE_BIT_NON_VFR_MODE = 0x00000100
 };
 
 enum bnxt_ulp_flow_dir_bitmask {
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 39/57] net/bnxt: avoid iova range check when external memory is used
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (5 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 38/57] net/bnxt/tf_ulp: add non vfr mode capability Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 40/57] net/bnxt: avoid potential segfault in VFR handling Manish Kurup
                   ` (12 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev
  Cc: ajit.khaparde, Sriharsha Basavapatna, Andy Gospodarek, Ning Wang,
	Kalesh AP, Somnath Kotur

From: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>

The function checks if the iova is in the valid range. But this check
is not relevant to external memory; avoid it when external memory is
in use.

Signed-off-by: Sriharsha Basavapatna <sriharsha.basavapatna@broadcom.com>
Reviewed-by: Andy Gospodarek <andrew.gospodarek@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Ning Wang <ning-nw.wang@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
---
 drivers/net/bnxt/bnxt_txr.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_txr.c b/drivers/net/bnxt/bnxt_txr.c
index f88e214790..27758898b0 100644
--- a/drivers/net/bnxt/bnxt_txr.c
+++ b/drivers/net/bnxt/bnxt_txr.c
@@ -221,8 +221,9 @@ static int bnxt_invalid_mbuf(struct rte_mbuf *mbuf)
 	if (unlikely(rte_mbuf_check(mbuf, 1, &reason)))
 		return -EINVAL;
 
-	if (unlikely(mbuf->buf_iova < mbuf_size ||
-		     (mbuf->buf_iova != rte_mempool_virt2iova(mbuf) + mbuf_size)))
+	if (unlikely(!(mbuf->ol_flags & RTE_MBUF_F_EXTERNAL) &&
+		     (mbuf->buf_iova < mbuf_size ||
+		      (mbuf->buf_iova != rte_mempool_virt2iova(mbuf) + mbuf_size))))
 		return -EINVAL;
 
 	return 0;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 40/57] net/bnxt: avoid potential segfault in VFR handling
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (6 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 39/57] net/bnxt: avoid iova range check when external memory is used Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 41/57] net/bnxt/tf_ulp: change rte_mem_virt2iova to rte_mem_virt2phys Manish Kurup
                   ` (11 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev
  Cc: ajit.khaparde, Peter Spreadborough, Stephen Shi, Shuanglin Wang,
	Damodharam Ammepalli

From: Peter Spreadborough <peter.spreadborough@broadcom.com>

1. Addresses crashes that were seen when using invalid
   representor arguments. The crash would occur when unwinding
   after a bnxt_pci_probe() failure.
2. If a representor port exists and an attempt is made to attach
   the same port a crash would occur. This change adds a check
   for an already existing port.

Signed-off-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Tested-by: Stephen Shi <stephen.shi@broadcom.com>
Reviewed-by: Shuanglin Wang <shuanglin.wang@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Damodharam Ammepalli <damodharam.ammepalli@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
---
 drivers/net/bnxt/bnxt_ethdev.c | 28 +++++++++++++++++-----------
 1 file changed, 17 insertions(+), 11 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 54613076b0..4ed2bf2a1a 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -6900,16 +6900,9 @@ static int bnxt_rep_port_probe(struct rte_pci_device *pci_dev,
 		return -ENOTSUP;
 	}
 	num_rep = eth_da->nb_representor_ports;
-	if (num_rep > max_vf_reps) {
-		PMD_DRV_LOG_LINE(ERR, "nb_representor_ports = %d > %d MAX VF REPS",
-			    num_rep, max_vf_reps);
-		return -EINVAL;
-	}
-
-	if (num_rep >= RTE_MAX_ETHPORTS) {
-		PMD_DRV_LOG_LINE(ERR,
-			    "nb_representor_ports = %d > %d MAX ETHPORTS",
-			    num_rep, RTE_MAX_ETHPORTS);
+	if (num_rep > max_vf_reps || num_rep > RTE_MAX_ETHPORTS) {
+		PMD_DRV_LOG_LINE(ERR, "nb_representor_ports = %d > %d OR %d MAX VF REPS",
+			    num_rep, max_vf_reps, RTE_MAX_ETHPORTS);
 		return -EINVAL;
 	}
 
@@ -6942,6 +6935,13 @@ static int bnxt_rep_port_probe(struct rte_pci_device *pci_dev,
 		snprintf(name, sizeof(name), "net_%s_representor_%d",
 			 pci_dev->device.name, eth_da->representor_ports[i]);
 
+		if (rte_eth_dev_allocated(name) != NULL) {
+			PMD_DRV_LOG_LINE(ERR,
+					 "Ethernet device with name %s already allocated",
+					 name);
+			return -EEXIST;
+		}
+
 		kvlist = rte_kvargs_parse(dev_args, bnxt_dev_args);
 		if (kvlist) {
 			/*
@@ -7078,7 +7078,13 @@ static int bnxt_pci_probe(struct rte_pci_driver *pci_drv __rte_unused,
 
 	num_rep = eth_da.nb_representor_ports;
 	PMD_DRV_LOG_LINE(DEBUG, "nb_representor_ports = %d",
-		    num_rep);
+			 num_rep);
+	if (num_rep >= RTE_MAX_ETHPORTS) {
+		PMD_DRV_LOG_LINE(ERR,
+				 "nb_representor_ports = %d > %d MAX ETHPORTS",
+				 num_rep, RTE_MAX_ETHPORTS);
+		return -EINVAL;
+	}
 
 	/* We could come here after first level of probe is already invoked
 	 * as part of an application bringup(OVS-DPDK vswitchd), so first check
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 41/57] net/bnxt/tf_ulp: change rte_mem_virt2iova to rte_mem_virt2phys
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (7 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 40/57] net/bnxt: avoid potential segfault in VFR handling Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 42/57] net/bnxt: thor2 truflow memory manager bug Manish Kurup
                   ` (10 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Shahaji Bhosle

From: Shahaji Bhosle <shahaji.bhosle@broadcom.com>

Need to support --no-huge mode which allows application
to run as unprivileged user and does not have access to
hugepage mount point and files within it.

rte_mem_virt2phy() does not have access to physical
addresses(PA) without hugepages, so use rte_mem_virt2iova()
with vfio-pci kernel driver.

Signed-off-by: Shahaji Bhosle <shahaji.bhosle@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/ulp_fc_mgr.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/ulp_fc_mgr.c b/drivers/net/bnxt/tf_ulp/ulp_fc_mgr.c
index 4be2703740..c765e123fe 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_fc_mgr.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_fc_mgr.c
@@ -62,9 +62,9 @@ ulp_fc_mgr_shadow_mem_alloc(struct hw_fc_mem_info *parms, int size)
 
 	rte_mem_lock_page(parms->mem_va);
 
-	parms->mem_pa = (void *)(uintptr_t)rte_mem_virt2phy(parms->mem_va);
+	parms->mem_pa = (void *)(uintptr_t)rte_mem_virt2iova(parms->mem_va);
 	if (parms->mem_pa == (void *)RTE_BAD_IOVA) {
-		BNXT_DRV_DBG(ERR, "Allocate failed mem_pa\n");
+		BNXT_DRV_DBG(ERR, "virt2iova failed for mem_va 0x%p", parms->mem_va);
 		return -ENOMEM;
 	}
 
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 42/57] net/bnxt: thor2 truflow memory manager bug
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (8 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 41/57] net/bnxt/tf_ulp: change rte_mem_virt2iova to rte_mem_virt2phys Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 43/57] net/bnxt: fix stats collection when rx queue is not set Manish Kurup
                   ` (9 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Farah Smith

From: Farah Smith <farah.smith@broadcom.com>

A performance optimization was made based upon the belief that blocks
in the memory manager always had non-full blocks prior to full blocks.
But this is not the case.  The performance optimization stopped looking
for space in the block list as soon as the first full block was found
in the list.  This fix adds code so that whenever a block is full, it is
moved to the end of the list so that the search can stop upon reaching
the first full block.  Remove current_blk_idx.  Adjust max_records based
upon max contiguous.

Signed-off-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
---
 drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm.c     | 83 ++++++++++++-------
 .../net/bnxt/hcapi/cfa_v3/mm/cfa_mm_priv.h    |  2 +-
 2 files changed, 56 insertions(+), 29 deletions(-)

diff --git a/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm.c b/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm.c
index 05528dd3e4..6e21d513ac 100644
--- a/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm.c
+++ b/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm.c
@@ -48,6 +48,10 @@ int cfa_mm_query(struct cfa_mm_query_parms *parms)
 	max_records = parms->max_records;
 	max_contig_records = (uint16_t)parms->max_contig_records;
 
+	/* Align to max_contig_records */
+	max_records = (max_records + (max_contig_records - 1)) &
+		      ~(max_contig_records - 1);
+
 	if (unlikely(!(CFA_CHECK_BOUNDS(max_records, 1, CFA_MM_MAX_RECORDS) &&
 	      IS_POWER_2(max_contig_records) &&
 	      CFA_CHECK_BOUNDS(max_contig_records, 1,
@@ -79,6 +83,10 @@ int cfa_mm_open(void *cmm, struct cfa_mm_open_parms *parms)
 	max_records = parms->max_records;
 	max_contig_records = (uint16_t)parms->max_contig_records;
 
+	/* Align to max_contig_records */
+	max_records = (max_records + (max_contig_records - 1)) &
+		      ~(max_contig_records - 1);
+
 	if (unlikely(!(CFA_CHECK_BOUNDS(max_records, 1, CFA_MM_MAX_RECORDS) &&
 	      IS_POWER_2(max_contig_records) &&
 	      CFA_CHECK_BOUNDS(max_contig_records, 1,
@@ -115,11 +123,11 @@ int cfa_mm_open(void *cmm, struct cfa_mm_open_parms *parms)
 	context->blk_bmap_tbl = (uint8_t *)(context->blk_tbl + num_blocks);
 
 	context->blk_list_tbl[0].first_blk_idx = 0;
-	context->blk_list_tbl[0].current_blk_idx = 0;
+	context->blk_list_tbl[0].last_blk_idx = 0;
 
 	for (i = 1; i < num_lists; i++) {
 		context->blk_list_tbl[i].first_blk_idx = CFA_MM_INVALID32;
-		context->blk_list_tbl[i].current_blk_idx = CFA_MM_INVALID32;
+		context->blk_list_tbl[i].last_blk_idx = CFA_MM_INVALID32;
 	}
 
 	for (i = 0; i < num_blocks; i++) {
@@ -162,6 +170,7 @@ int cfa_mm_close(void *cmm)
 	return 0;
 }
 
+/* Allocate a block idx from the free list */
 static uint32_t cfa_mm_blk_alloc(struct cfa_mm *context)
 {
 	uint32_t blk_idx;
@@ -179,8 +188,6 @@ static uint32_t cfa_mm_blk_alloc(struct cfa_mm *context)
 	free_list->first_blk_idx =
 		context->blk_tbl[free_list->first_blk_idx].next_blk_idx;
 
-	free_list->current_blk_idx = free_list->first_blk_idx;
-
 	if (free_list->first_blk_idx != CFA_MM_INVALID32) {
 		context->blk_tbl[free_list->first_blk_idx].prev_blk_idx =
 			CFA_MM_INVALID32;
@@ -192,6 +199,7 @@ static uint32_t cfa_mm_blk_alloc(struct cfa_mm *context)
 	return blk_idx;
 }
 
+/* Return a block index to the free list */
 static void cfa_mm_blk_free(struct cfa_mm *context, uint32_t blk_idx)
 {
 	struct cfa_mm_blk_list *free_list = context->blk_list_tbl;
@@ -208,16 +216,17 @@ static void cfa_mm_blk_free(struct cfa_mm *context, uint32_t blk_idx)
 	}
 
 	free_list->first_blk_idx = blk_idx;
-	free_list->current_blk_idx = blk_idx;
 }
 
+/* insert at the top of a non-free list */
 static void cfa_mm_blk_insert(struct cfa_mm *context,
 			      struct cfa_mm_blk_list *blk_list,
 			      uint32_t blk_idx)
 {
+	/* there are no entries in the list so init all to this one */
 	if (blk_list->first_blk_idx == CFA_MM_INVALID32) {
 		blk_list->first_blk_idx = blk_idx;
-		blk_list->current_blk_idx = blk_idx;
+		blk_list->last_blk_idx = blk_idx;
 	} else {
 		struct cfa_mm_blk *blk_info = &context->blk_tbl[blk_idx];
 
@@ -226,10 +235,29 @@ static void cfa_mm_blk_insert(struct cfa_mm *context,
 		context->blk_tbl[blk_list->first_blk_idx].prev_blk_idx =
 			blk_idx;
 		blk_list->first_blk_idx = blk_idx;
-		blk_list->current_blk_idx = blk_idx;
 	}
 }
 
+/* insert at the bottom of a non-free list */
+static void cfa_mm_blk_insert_last(struct cfa_mm *context,
+				   struct cfa_mm_blk_list *blk_list,
+				   uint32_t blk_idx)
+{
+	if (blk_list->last_blk_idx == CFA_MM_INVALID32) {
+		blk_list->first_blk_idx = blk_idx;
+		blk_list->last_blk_idx = blk_idx;
+	} else {
+		struct cfa_mm_blk *blk_info = &context->blk_tbl[blk_idx];
+
+		blk_info->prev_blk_idx = blk_list->last_blk_idx;
+		blk_info->next_blk_idx = CFA_MM_INVALID32;
+		context->blk_tbl[blk_list->last_blk_idx].next_blk_idx =
+			blk_idx;
+		blk_list->last_blk_idx = blk_idx;
+	}
+}
+
+/* delete from anywhere in the list */
 static void cfa_mm_blk_delete(struct cfa_mm *context,
 			      struct cfa_mm_blk_list *blk_list,
 			      uint32_t blk_idx)
@@ -239,15 +267,20 @@ static void cfa_mm_blk_delete(struct cfa_mm *context,
 	if (blk_list->first_blk_idx == CFA_MM_INVALID32)
 		return;
 
+	if (blk_list->last_blk_idx == blk_idx) {
+		blk_list->last_blk_idx = blk_info->prev_blk_idx;
+		if (blk_list->last_blk_idx != CFA_MM_INVALID32) {
+			context->blk_tbl[blk_list->last_blk_idx].next_blk_idx =
+				CFA_MM_INVALID32;
+		}
+	}
+
 	if (blk_list->first_blk_idx == blk_idx) {
 		blk_list->first_blk_idx = blk_info->next_blk_idx;
 		if (blk_list->first_blk_idx != CFA_MM_INVALID32) {
 			context->blk_tbl[blk_list->first_blk_idx].prev_blk_idx =
 				CFA_MM_INVALID32;
 		}
-		if (blk_list->current_blk_idx == blk_idx)
-			blk_list->current_blk_idx = blk_list->first_blk_idx;
-
 		return;
 	}
 
@@ -260,20 +293,6 @@ static void cfa_mm_blk_delete(struct cfa_mm *context,
 		context->blk_tbl[blk_info->next_blk_idx].prev_blk_idx =
 			blk_info->prev_blk_idx;
 	}
-
-	if (blk_list->current_blk_idx == blk_idx) {
-		if (blk_info->next_blk_idx != CFA_MM_INVALID32) {
-			blk_list->current_blk_idx = blk_info->next_blk_idx;
-		} else {
-			if (blk_info->prev_blk_idx != CFA_MM_INVALID32) {
-				blk_list->current_blk_idx =
-					blk_info->prev_blk_idx;
-			} else {
-				blk_list->current_blk_idx =
-					blk_list->first_blk_idx;
-			}
-		}
-	}
 }
 
 /* Returns true if the bit in the bitmap is set to 'val' else returns false */
@@ -413,12 +432,19 @@ int cfa_mm_alloc(void *cmm, struct cfa_mm_alloc_parms *parms)
 
 		blk_info->num_contig_records = num_records;
 	} else {
-		blk_idx = blk_list->current_blk_idx;
+		blk_idx = blk_list->first_blk_idx;
 		blk_info = &context->blk_tbl[blk_idx];
 	}
 
 	while (blk_info->num_free_records < num_records) {
-		if (blk_info->next_blk_idx == CFA_MM_INVALID32 || !blk_info->num_free_records) {
+		/*
+		 * All non-full entries precede full entries so
+		 * upon seeing the first full entry, allocate
+		 * new block as this means all following records
+		 * are full.
+		 */
+		if (blk_info->next_blk_idx == CFA_MM_INVALID32 ||
+		    !blk_info->num_free_records) {
 			blk_idx = cfa_mm_blk_alloc(context);
 			if (unlikely(blk_idx == CFA_MM_INVALID32)) {
 				ret = -ENOMEM;
@@ -433,8 +459,6 @@ int cfa_mm_alloc(void *cmm, struct cfa_mm_alloc_parms *parms)
 		} else {
 			blk_idx = blk_info->next_blk_idx;
 			blk_info = &context->blk_tbl[blk_idx];
-
-			blk_list->current_blk_idx = blk_idx;
 		}
 	}
 
@@ -459,6 +483,9 @@ int cfa_mm_alloc(void *cmm, struct cfa_mm_alloc_parms *parms)
 	blk_info->num_free_records -= num_records;
 
 	if (!blk_info->num_free_records) {
+		/* move block to the end of the list if it is full */
+		cfa_mm_blk_delete(context, blk_list, blk_idx);
+		cfa_mm_blk_insert_last(context, blk_list, blk_idx);
 		blk_info->first_free_record = context->records_per_block;
 	} else {
 		cnt = NUM_ALIGN_UNITS(context->records_per_block,
diff --git a/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm_priv.h b/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm_priv.h
index 2a646217ec..dbac1c3cf2 100644
--- a/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm_priv.h
+++ b/drivers/net/bnxt/hcapi/cfa_v3/mm/cfa_mm_priv.h
@@ -47,7 +47,7 @@ struct cfa_mm_blk_list {
 	/* Index of the first block in the list */
 	uint32_t first_blk_idx;
 	/* Index of the current block having free records */
-	uint32_t current_blk_idx;
+	uint32_t last_blk_idx;
 };
 
 /**
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 43/57] net/bnxt: fix stats collection when rx queue is not set
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (9 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 42/57] net/bnxt: thor2 truflow memory manager bug Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 44/57] net/bnxt: fix rss configuration when set to none Manish Kurup
                   ` (8 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Kishore Padmanabha, Kalesh AP

From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

When rx queue is not started and the stats context id is not
allocated then skip the stats collection.

Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
---
 drivers/net/bnxt/bnxt_stats.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/net/bnxt/bnxt_stats.c b/drivers/net/bnxt/bnxt_stats.c
index 9d7cdf925d..697f9ad9fe 100644
--- a/drivers/net/bnxt/bnxt_stats.c
+++ b/drivers/net/bnxt/bnxt_stats.c
@@ -656,6 +656,9 @@ static int bnxt_stats_get_ext(struct rte_eth_dev *eth_dev,
 		if (!rxq->rx_started)
 			continue;
 
+		if (cpr->hw_stats_ctx_id == HWRM_NA_SIGNATURE)
+			continue;
+
 		rc = bnxt_hwrm_ring_stats_ext(bp, cpr->hw_stats_ctx_id, i,
 					      &ring_stats, true);
 		if (unlikely(rc))
@@ -717,6 +720,8 @@ int bnxt_stats_get_op(struct rte_eth_dev *eth_dev,
 
 		if (!rxq->rx_started)
 			continue;
+		if (cpr->hw_stats_ctx_id == HWRM_NA_SIGNATURE)
+			continue;
 
 		rc = bnxt_hwrm_ring_stats(bp, cpr->hw_stats_ctx_id, i,
 					  &ring_stats, true);
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 44/57] net/bnxt: fix rss configuration when set to none
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (10 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 43/57] net/bnxt: fix stats collection when rx queue is not set Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 45/57] net/bnxt: packet drop after port stop and start Manish Kurup
                   ` (7 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Kishore Padmanabha

From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

If the rss hash type is set to none and the ports are stopped and
started again, the check for rss hash type was not allowing the
bnxt driver to populate the correct rx rings in the vnic rss list.
This causes the subsequent calls to rss configuration fail since
the rss list is not configured and have stale data causing the
firmware to reject the rss configuration.

The rss hash type of none should not be ignored during configuration,
it is a valid configuration and should be applied. When rss hash
type is none, the rss context is disabled and there should be no
rss algorithm applied to the incoming traffic.

Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/bnxt_hwrm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/bnxt/bnxt_hwrm.c b/drivers/net/bnxt/bnxt_hwrm.c
index 00b02821c9..939f35e3da 100644
--- a/drivers/net/bnxt/bnxt_hwrm.c
+++ b/drivers/net/bnxt/bnxt_hwrm.c
@@ -6331,7 +6331,7 @@ int bnxt_vnic_rss_configure(struct bnxt *bp, struct bnxt_vnic_info *vnic)
 	if (vnic->fw_vnic_id == INVALID_HW_RING_ID)
 		return 0;
 
-	if (!(vnic->rss_table && vnic->hash_type))
+	if (vnic->rss_table == NULL)
 		return 0;
 
 	if (BNXT_CHIP_P5_P7(bp))
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 45/57] net/bnxt: packet drop after port stop and start
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (11 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 44/57] net/bnxt: fix rss configuration when set to none Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 46/57] net/bnxt/tf_core: fix truflow crash on memory allocation failure Manish Kurup
                   ` (6 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev
  Cc: ajit.khaparde, Kishore Padmanabha, Somnath Kotur,
	Peter Spreadborough, Kalesh AP

From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

The packets are getting dropped if some of the queues are configured
to stop and if the bnxt driver is reset due to port stop all and
port start all then when the bnxt driver comes up, the driver is
overwriting the queue configuration to operationally started
instead of stopping the queues that was previously stopped. The
stopped queues were getting added to the rss context resulting in
the packet drops.

Added a fix to address this issue, the rxq structure is not cleared
during the stop and start process and retains the context, that flag
is used to set the queue state. Thus stopped queues shall not be added
to the rss context on recovery from a stop and start. The queues that
were configured to be stopped have to explicitly started to see
traffic on those queues.

Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Somnath Kotur <somnath.kotur@broadcom.com>
Reviewed-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Kalesh AP <kalesh-anakkur.purayil@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/bnxt_ethdev.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 4ed2bf2a1a..50bc0f1f9e 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -925,11 +925,13 @@ static int bnxt_start_nic(struct bnxt *bp)
 	for (j = 0; j < bp->rx_nr_rings; j++) {
 		struct bnxt_rx_queue *rxq = bp->rx_queues[j];
 
+		__rte_assume(j < RTE_MAX_QUEUES_PER_PORT);
+		/* If not deferred start then change only the state of the */
+		/* queue based on the queue rx_started flag */
 		if (!rxq->rx_deferred_start) {
-			__rte_assume(j < RTE_MAX_QUEUES_PER_PORT);
-			bp->eth_dev->data->rx_queue_state[j] =
+			if (rxq->rx_started)
+				bp->eth_dev->data->rx_queue_state[j] =
 				RTE_ETH_QUEUE_STATE_STARTED;
-			rxq->rx_started = true;
 		}
 	}
 
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 46/57] net/bnxt/tf_core: fix truflow crash on memory allocation failure
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (12 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 45/57] net/bnxt: packet drop after port stop and start Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 47/57] net/bnxt: truflow remove RTE devarg processing for mpc=1 Manish Kurup
                   ` (5 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Peter Spreadborough

From: Peter Spreadborough <peter.spreadborough@broadcom.com>

A backing store table allocation failed due to lack of memory and
resulted in a crash because the result of the allocation was not
checked for validity.

Signed-off-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Manish Kurup <manish.kurup@broadcom.com>
---
 drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c b/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
index b229f07596..878f62c115 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_tbl_scope.c
@@ -505,6 +505,8 @@ static int alloc_link_pbl(struct tfc_ts_mem_cfg *mem_cfg, uint32_t page_size,
 								RTE_MEMZONE_SIZE_HINT_ONLY |
 								RTE_MEMZONE_IOVA_CONTIG,
 								page_size);
+		if (!mem_cfg->ts_mz.mz)
+			return -ENOMEM;
 	}
 	memset(mem_cfg->ts_mz.mz->addr, 0, mem_cfg->ts_mz.mz->len);
 	mem_cfg->ts_mz.page_count = total_pages;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 47/57] net/bnxt: truflow remove RTE devarg processing for mpc=1
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (13 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 46/57] net/bnxt/tf_core: fix truflow crash on memory allocation failure Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 48/57] net/bnxt: add meson build options for TruFlow Manish Kurup
                   ` (4 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Sangtani Parag Satishbhai

From: Sangtani Parag Satishbhai <parag-satishbhai.sangtani@broadcom.com>

Now as the mpc is initialized for P7 platform regardless
of mpc=1 devarg, RTE and bnxt argument processing APIs
for mpc devarg are redundant. This patch removes such RTE
and bnxt APIs. The "mpc=1" devarg is now invalid and should
not be used while launching an application.

Before:
     ./dpdk-testpmd -c 0xff -a 0000:0a:00.0,mpc=1,app-id=0
After:
     ./dpdk-testpmd -c 0xff -a 0000:0a:00.0,app-id=0

Signed-off-by: Sangtani Parag Satishbhai <parag-satishbhai.sangtani@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/bnxt.h        |  3 ---
 drivers/net/bnxt/bnxt_ethdev.c | 19 ++++---------------
 2 files changed, 4 insertions(+), 18 deletions(-)

diff --git a/drivers/net/bnxt/bnxt.h b/drivers/net/bnxt/bnxt.h
index 90352d537c..83ae151066 100644
--- a/drivers/net/bnxt/bnxt.h
+++ b/drivers/net/bnxt/bnxt.h
@@ -854,9 +854,6 @@ struct bnxt {
 	((bp)->flags2 & BNXT_FLAGS2_MULTIROOT_EN)
 
 #define	BNXT_FLAGS2_COMPRESSED_RX_CQE		BIT(5)
-#define	BNXT_FLAGS2_USE_MPC			BIT(6)
-#define BNXT_USE_MPC(bp)			\
-	((bp)->flags2 & BNXT_FLAGS2_USE_MPC)
 #define	BNXT_FLAGS2_REP_MODE			BIT(7)
 #define BNXT_REP_MODE_EN(bp)			\
 	((bp)->flags2 & BNXT_FLAGS2_REP_MODE)
diff --git a/drivers/net/bnxt/bnxt_ethdev.c b/drivers/net/bnxt/bnxt_ethdev.c
index 50bc0f1f9e..7a2dd08951 100644
--- a/drivers/net/bnxt/bnxt_ethdev.c
+++ b/drivers/net/bnxt/bnxt_ethdev.c
@@ -152,11 +152,6 @@ static const struct rte_eth_speed_lanes_capa speed_lanes_capa_tbl[] = {
  */
 #define BNXT_DEVARG_CQE_MODE_INVALID(val)		((val) > 1)
 
-/*
- * mpc = an non-negative 8-bit number
- */
-#define BNXT_DEVARG_MPC_INVALID(val)			((val) > 1)
-
 /*
  * app-id = an non-negative 8-bit number
  */
@@ -207,7 +202,6 @@ static const struct rte_eth_speed_lanes_capa speed_lanes_capa_tbl[] = {
 #define BNXT_DEVARG_REP_FC_F2R_INVALID(rep_fc_f2r)	((rep_fc_f2r) > 1)
 
 int bnxt_cfa_code_dynfield_offset = -1;
-unsigned long mpc;
 
 /*
  * max_num_kflows must be >= 32
@@ -1759,8 +1753,7 @@ static int bnxt_dev_stop(struct rte_eth_dev *eth_dev)
 	/* Process any remaining notifications in default completion queue */
 	bnxt_int_handler(eth_dev);
 
-	if (mpc != 0)
-		bnxt_mpc_close(bp);
+	bnxt_mpc_close(bp);
 
 	bnxt_shutdown_nic(bp);
 	bnxt_hwrm_if_change(bp, false);
@@ -1856,11 +1849,9 @@ int bnxt_dev_start_op(struct rte_eth_dev *eth_dev)
 	if (rc)
 		goto error;
 
-	if (mpc != 0) {
-		rc = bnxt_mpc_open(bp);
-		if (rc != 0)
-			PMD_DRV_LOG_LINE(DEBUG, "MPC open failed");
-	}
+	rc = bnxt_mpc_open(bp);
+	if (rc != 0)
+		PMD_DRV_LOG_LINE(DEBUG, "MPC open failed");
 
 	rc = bnxt_alloc_prev_ring_stats(bp);
 	if (rc)
@@ -7208,8 +7199,6 @@ static bool bnxt_enable_ulp(struct bnxt *bp)
 	/* not enabling ulp for cli and no truflow apps */
 	if (BNXT_TRUFLOW_EN(bp) && bp->app_id != 254 &&
 	    bp->app_id != 255) {
-		if (BNXT_CHIP_P7(bp) && !mpc)
-			return false;
 		return true;
 	}
 	return false;
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 48/57] net/bnxt: add meson build options for TruFlow
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (14 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 47/57] net/bnxt: truflow remove RTE devarg processing for mpc=1 Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 49/57] net/bnxt: truflow HSI struct fixes Manish Kurup
                   ` (3 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde

Add meson options for
1. TF template
2. TF feature bits

Signed-off-by: Manish Kurup <manish.kurup@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 meson_options.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/meson_options.txt b/meson_options.txt
index e28d24054c..3354ef2b4f 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -58,3 +58,7 @@ option('tests', type: 'boolean', value: true, description:
        'build unit tests')
 option('use_hpet', type: 'boolean', value: false, description:
        'use HPET timer in EAL')
+option('bnxt_tf_template', type: 'string', value: 'default', description:
+       'Truflow template selection')
+option('bnxt_tf_feat_bits', type: 'integer', value: 0, description:
+       'Truflow feature bits')
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 49/57] net/bnxt: truflow HSI struct fixes
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (15 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 48/57] net/bnxt: add meson build options for TruFlow Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 50/57] net/bnxt/tf_ulp: truflow add pf action handler Manish Kurup
                   ` (2 subsequent siblings)
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde

Fix struct definitions in HSI to add __rte_packed_end

Signed-off-by: Manish Kurup <manish.kurup@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
---
 drivers/net/bnxt/hsi_struct_def_dpdk.h | 26 +++++++++++++-------------
 1 file changed, 13 insertions(+), 13 deletions(-)

diff --git a/drivers/net/bnxt/hsi_struct_def_dpdk.h b/drivers/net/bnxt/hsi_struct_def_dpdk.h
index 866fc5379d..06c61cba8f 100644
--- a/drivers/net/bnxt/hsi_struct_def_dpdk.h
+++ b/drivers/net/bnxt/hsi_struct_def_dpdk.h
@@ -24521,7 +24521,7 @@ struct __rte_packed_begin ts_split_entries {
 	/* Indicates the region is locked in the cache */
 	uint8_t	locked;
 	uint32_t	rsvd2[2];
-} __rte_packed;
+} __rte_packed_end;
 
 /*
  * Common structure to cast crypto key split entries. This casting is
@@ -45077,7 +45077,7 @@ struct __rte_packed_begin hwrm_vnic_plcmodes_cfg_output {
 } __rte_packed_end;
 
 /* hwrm_vnic_plcmodes_cfg_cmd_err (size:64b/8B) */
-struct hwrm_vnic_plcmodes_cfg_cmd_err {
+struct __rte_packed_begin hwrm_vnic_plcmodes_cfg_cmd_err {
 	/*
 	 * command specific error codes that goes to
 	 * the cmd_err field in common HWRM Error Response.
@@ -45092,7 +45092,7 @@ struct hwrm_vnic_plcmodes_cfg_cmd_err {
 	#define HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_LAST \
 		HWRM_VNIC_PLCMODES_CFG_CMD_ERR_CODE_INVALID_HDS_THRESHOLD
 	uint8_t	unused_0[7];
-} __rte_packed;
+} __rte_packed_end;
 
 /***************************
  * hwrm_vnic_plcmodes_qcfg *
@@ -62717,7 +62717,7 @@ struct __rte_packed_begin hwrm_tfc_resc_usage_query_output {
 
 
 /* hwrm_tfc_tcam_pri_update_input (size:256b/32B) */
-struct hwrm_tfc_tcam_pri_update_input {
+struct __rte_packed_begin hwrm_tfc_tcam_pri_update_input {
 	/* The HWRM command request type. */
 	uint16_t	req_type;
 	/*
@@ -62794,10 +62794,10 @@ struct hwrm_tfc_tcam_pri_update_input {
 		HWRM_TFC_TCAM_PRI_UPDATE_INPUT_TRACK_TYPE_TRACK_TYPE_FID
 	/* unused. */
 	uint8_t	unused0[5];
-} __rte_packed;
+} __rte_packed_end;
 
 /* hwrm_tfc_tcam_pri_update_output (size:128b/16B) */
-struct hwrm_tfc_tcam_pri_update_output {
+struct __rte_packed_begin hwrm_tfc_tcam_pri_update_output {
 	/* The specific error status for the command. */
 	uint16_t	error_code;
 	/* The HWRM command request type. */
@@ -62817,7 +62817,7 @@ struct hwrm_tfc_tcam_pri_update_output {
 	 * to be such that this field is written last.
 	 */
 	uint8_t	valid;
-} __rte_packed;
+} __rte_packed_end;
 
 /********************************
  * hwrm_tfc_hot_upgrade_process *
@@ -62825,7 +62825,7 @@ struct hwrm_tfc_tcam_pri_update_output {
 
 
 /* hwrm_tfc_hot_upgrade_process_input (size:192b/24B) */
-struct hwrm_tfc_hot_upgrade_process_input {
+struct __rte_packed_begin hwrm_tfc_hot_upgrade_process_input {
 	/* The HWRM command request type. */
 	uint16_t	req_type;
 	/*
@@ -62887,10 +62887,10 @@ struct hwrm_tfc_hot_upgrade_process_input {
 	uint8_t	cur_session_cnt;
 	/* unused. */
 	uint8_t	unused0;
-} __rte_packed;
+} __rte_packed_end;
 
 /* hwrm_tfc_hot_upgrade_process_output (size:128b/16B) */
-struct hwrm_tfc_hot_upgrade_process_output {
+struct __rte_packed_begin hwrm_tfc_hot_upgrade_process_output {
 	/* The specific error status for the command. */
 	uint16_t	error_code;
 	/* The HWRM command request type. */
@@ -62912,7 +62912,7 @@ struct hwrm_tfc_hot_upgrade_process_output {
 	 * to be such that this field is written last.
 	 */
 	uint8_t	valid;
-} __rte_packed;
+} __rte_packed_end;
 
 /******************************
  * hwrm_tunnel_dst_port_query *
@@ -64280,7 +64280,7 @@ struct __rte_packed_begin pcie_ctx_hw_stats {
  * identical up to and including the pcie_recovery_histogram field.
  */
 /* pcie_ctx_hw_stats_v2 (size:4096b/512B) */
-struct pcie_ctx_hw_stats_v2 {
+struct __rte_packed_begin pcie_ctx_hw_stats_v2 {
 	/* Number of physical layer receiver errors */
 	uint64_t	pcie_pl_signal_integrity;
 	/* Number of DLLP CRC errors detected by Data Link Layer */
@@ -64385,7 +64385,7 @@ struct pcie_ctx_hw_stats_v2 {
 	uint64_t	pcie_blocked_packet_count;
 	/* The count of completion packets sent to the PCI-e. */
 	uint64_t	pcie_cmpl_packet_count;
-} __rte_packed;
+} __rte_packed_end;
 
 /****************************
  * hwrm_stat_generic_qstats *
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 50/57] net/bnxt/tf_ulp: truflow add pf action handler
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (16 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 49/57] net/bnxt: truflow HSI struct fixes Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 51/57] net/bnxt/tf_ulp: add support for unicast only feature Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 52/57] net/bnxt/tf_core: remove excessive debug logging Manish Kurup
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Shahaji Bhosle, Kishore Padmanabha

From: Shahaji Bhosle <shahaji.bhosle@broadcom.com>

Update pf action handler callback to use parent PF vnic

Signed-off-by: Shahaji Bhosle <shahaji.bhosle@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/ulp_rte_parser.c | 42 ++++++++++++++++--------
 1 file changed, 28 insertions(+), 14 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
index ceda1ff5ef..82baf722cd 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_rte_parser.c
@@ -2946,30 +2946,44 @@ int32_t
 ulp_rte_pf_act_handler(const struct rte_flow_action *action_item __rte_unused,
 		       struct ulp_rte_parser_params *params)
 {
+	struct bnxt *bp;
 	uint32_t port_id;
-	uint32_t ifindex;
-	enum bnxt_ulp_intf_type intf_type;
+	enum bnxt_ulp_direction_type dir;
+	struct ulp_rte_act_prop *act = &params->act_prop;
 
 	/* Get the port id of the current device */
 	port_id = ULP_COMP_FLD_IDX_RD(params, BNXT_ULP_CF_IDX_INCOMING_IF);
 
-	/* Get the port db ifindex */
-	if (ulp_port_db_dev_port_to_ulp_index(params->ulp_ctx, port_id,
-					      &ifindex)) {
-		BNXT_DRV_DBG(ERR, "Invalid port id\n");
+	params->port_id = port_id;
+	bp = bnxt_pmd_get_bp(params->port_id);
+	if (bp == NULL) {
+		BNXT_DRV_DBG(ERR, "Invalid bp");
 		return BNXT_TF_RC_ERROR;
 	}
 
-	/* Check the port is PF port */
-	intf_type = ulp_port_db_port_type_get(params->ulp_ctx, ifindex);
-	if (intf_type != BNXT_ULP_INTF_TYPE_PF) {
-		BNXT_DRV_DBG(ERR, "Port is not a PF port\n");
+	ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_ACT_PORT_TYPE, BNXT_ULP_INTF_TYPE_PF);
+
+	/* Get the direction */
+	dir = ULP_COMP_FLD_IDX_RD(params, BNXT_ULP_CF_IDX_DIRECTION);
+	if (dir == BNXT_ULP_DIR_EGRESS) {
+		BNXT_DRV_DBG(ERR, "Invalid direction");
 		return BNXT_TF_RC_ERROR;
+	} else {
+		uint16_t pid_s = bp->parent->vnic;
+		uint32_t pid = pid_s;
+		pid = rte_cpu_to_be_32(pid);
+		memcpy(&act->act_details[BNXT_ULP_ACT_PROP_IDX_VNIC],
+		       &pid, BNXT_ULP_ACT_PROP_SZ_VNIC);
+		/*
+		 * Update appropriate port (A/B) VNIC based on multi-port
+		 * indication.
+		 */
+		ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_MP_VNIC_A, pid_s);
 	}
-	/* Update the action properties */
-	ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_ACT_PORT_TYPE, intf_type);
-	return ulp_rte_parser_act_port_set(params, ifindex, false,
-					   BNXT_ULP_DIR_INVALID);
+
+	/* Update the action port set bit */
+	ULP_COMP_FLD_IDX_WR(params, BNXT_ULP_CF_IDX_ACT_PORT_IS_SET, 1);
+	return BNXT_TF_RC_SUCCESS;
 }
 
 /* Function to handle the parsing of RTE Flow action VF. */
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 51/57] net/bnxt/tf_ulp: add support for unicast only feature
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (17 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 50/57] net/bnxt/tf_ulp: truflow add pf action handler Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  2025-10-21 18:56 ` [PATCH v4 52/57] net/bnxt/tf_core: remove excessive debug logging Manish Kurup
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Kishore Padmanabha, Shahaji Bhosle

From: Kishore Padmanabha <kishore.padmanabha@broadcom.com>

Added support for unicast only feature bit in the truflow application.
This enables the application to not receive broadcast, multicast or
unknown mac addresses to the ports that are participating in the
application.

Signed-off-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
Reviewed-by: Ajit Khaparde <ajit.khaparde@broadcom.com>
Reviewed-by: Shahaji Bhosle <shahaji.bhosle@broadcom.com>
---
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c          | 5 +++++
 drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c         | 5 +++++
 drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h       | 2 ++
 drivers/net/bnxt/tf_ulp/ulp_def_rules.c        | 3 ---
 drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h | 3 ++-
 5 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
index 54a5e6968c..d2d97d9cf0 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tf.c
@@ -475,6 +475,11 @@ ulp_tf_cntxt_app_caps_init(struct bnxt *bp,
 					      &ulp_ctx->cfg_data->feature_bits))
 			return -EINVAL;
 
+		if ((ulp_ctx->cfg_data->feature_bits &
+		     BNXT_ULP_FEATURE_BIT_UNICAST_ONLY))
+			ulp_ctx->cfg_data->ulp_flags |=
+			BNXT_ULP_APP_UNICAST_ONLY;
+
 		bnxt_ulp_cntxt_ptr2_default_class_bits_set(ulp_ctx,
 							   info[i].default_class_bits);
 		bnxt_ulp_cntxt_ptr2_default_act_bits_set(ulp_ctx,
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
index 772dd69035..ad44ec93ca 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_tfc.c
@@ -562,6 +562,11 @@ ulp_tfc_cntxt_app_caps_init(struct bnxt *bp, uint8_t app_id, uint32_t dev_id)
 					      &ulp_ctx->cfg_data->feature_bits))
 			return -EINVAL;
 
+		if ((ulp_ctx->cfg_data->feature_bits &
+		     BNXT_ULP_FEATURE_BIT_UNICAST_ONLY))
+			ulp_ctx->cfg_data->ulp_flags |=
+			BNXT_ULP_APP_UNICAST_ONLY;
+
 		bnxt_ulp_default_app_priority_set(ulp_ctx,
 						  info[i].default_priority);
 		bnxt_ulp_max_def_priority_set(ulp_ctx,
diff --git a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
index 14ee1e05fb..84d0315399 100644
--- a/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
+++ b/drivers/net/bnxt/tf_ulp/bnxt_ulp_utils.h
@@ -1066,6 +1066,8 @@ bnxt_ulp_cap_feat_process(uint64_t feat_bits, uint64_t *out_bits)
 		BNXT_DRV_DBG(ERR, "Socket Direct Feature is enabled");
 	if (bit & BNXT_ULP_FEATURE_BIT_NON_VFR_MODE)
 		BNXT_DRV_DBG(ERR, "Non VFR Feature is enabled");
+	if (bit & BNXT_ULP_FEATURE_BIT_UNICAST_ONLY)
+		BNXT_DRV_DBG(ERR, "Unicast only Feature is enabled");
 
 	*out_bits =  bit;
 	return 0;
diff --git a/drivers/net/bnxt/tf_ulp/ulp_def_rules.c b/drivers/net/bnxt/tf_ulp/ulp_def_rules.c
index 30cd944362..4d96882087 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_def_rules.c
+++ b/drivers/net/bnxt/tf_ulp/ulp_def_rules.c
@@ -829,9 +829,6 @@ bnxt_ulp_promisc_mode_set(struct bnxt *bp, uint8_t enable)
 	    !bp->ulp_ctx)
 		return rc;
 
-	if (!BNXT_CHIP_P5(bp))
-		return rc;
-
 	port_id = bp->eth_dev->data->port_id;
 	info = &bp->ulp_ctx->cfg_data->df_rule_info[port_id];
 
diff --git a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
index d63862ffba..4e9b11e437 100644
--- a/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
+++ b/drivers/net/bnxt/tf_ulp/ulp_template_db_enum.h
@@ -914,7 +914,8 @@ enum bnxt_ulp_feature_bit {
 	BNXT_ULP_FEATURE_BIT_SPECIAL_VXLAN = 0x00000020,
 	BNXT_ULP_FEATURE_BIT_HOT_UPGRADE = 0x00000040,
 	BNXT_ULP_FEATURE_BIT_GLOBAL_TBL_SCOPE = 0x00000080,
-	BNXT_ULP_FEATURE_BIT_NON_VFR_MODE = 0x00000100
+	BNXT_ULP_FEATURE_BIT_NON_VFR_MODE = 0x00000100,
+	BNXT_ULP_FEATURE_BIT_UNICAST_ONLY = 0x00000200
 };
 
 enum bnxt_ulp_flow_dir_bitmask {
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

* [PATCH v4 52/57] net/bnxt/tf_core: remove excessive debug logging
  2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
                   ` (18 preceding siblings ...)
  2025-10-21 18:56 ` [PATCH v4 51/57] net/bnxt/tf_ulp: add support for unicast only feature Manish Kurup
@ 2025-10-21 18:56 ` Manish Kurup
  19 siblings, 0 replies; 21+ messages in thread
From: Manish Kurup @ 2025-10-21 18:56 UTC (permalink / raw)
  To: dev; +Cc: ajit.khaparde, Peter Spreadborough, Farah Smith, Kishore Padmanabha

From: Peter Spreadborough <peter.spreadborough@broadcom.com>

This change removes a debug message of questionable usefulness
that can spam the terminal if more than 5K flows are created.

Signed-off-by: Peter Spreadborough <peter.spreadborough@broadcom.com>
Reviewed-by: Farah Smith <farah.smith@broadcom.com>
Reviewed-by: Kishore Padmanabha <kishore.padmanabha@broadcom.com>
---
 drivers/net/bnxt/tf_core/v3/tfc_em.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/drivers/net/bnxt/tf_core/v3/tfc_em.c b/drivers/net/bnxt/tf_core/v3/tfc_em.c
index 47870747e1..3fe4dbe3fe 100644
--- a/drivers/net/bnxt/tf_core/v3/tfc_em.c
+++ b/drivers/net/bnxt/tf_core/v3/tfc_em.c
@@ -1012,13 +1012,7 @@ int tfc_mpc_batch_end(struct tfc *tfcp,
 
 			count--;
 
-			if (j != start_index) {
-				PMD_DRV_LOG_LINE(INFO,
-						 "%s: OOO comp. Opq Exp:%d Got:%d j:%d",
-						 __func__,
-						 batch_info->comp_info[j].opaque,
-						 opaque, j);
-			} else {
+			if (j == start_index) {
 				start_index++;
 
 				while (count &&
-- 
2.39.5 (Apple Git-154)


^ permalink raw reply	[flat|nested] 21+ messages in thread

end of thread, other threads:[~2025-10-21 18:59 UTC | newest]

Thread overview: 21+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-10-21 18:56 [PATCH v4 32/57] net/bnxt/tf_core: add backing store debug to dpdk Manish Kurup
2025-10-21 18:56 ` [PATCH v4 33/57] net/bnxt/tf_core: truflow global table scope Manish Kurup
2025-10-21 18:56 ` [PATCH v4 34/57] net/bnxt/tf_ulp: ulp parser support to handle gre key Manish Kurup
2025-10-21 18:56 ` [PATCH v4 35/57] net/bnxt/tf_core: handle out of order MPC completions Manish Kurup
2025-10-21 18:56 ` [PATCH v4 36/57] net/bnxt/tf_ulp: socket direct enable Manish Kurup
2025-10-21 18:56 ` [PATCH v4 37/57] net/bnxt: fix adding udp_tunnel_port Manish Kurup
2025-10-21 18:56 ` [PATCH v4 38/57] net/bnxt/tf_ulp: add non vfr mode capability Manish Kurup
2025-10-21 18:56 ` [PATCH v4 39/57] net/bnxt: avoid iova range check when external memory is used Manish Kurup
2025-10-21 18:56 ` [PATCH v4 40/57] net/bnxt: avoid potential segfault in VFR handling Manish Kurup
2025-10-21 18:56 ` [PATCH v4 41/57] net/bnxt/tf_ulp: change rte_mem_virt2iova to rte_mem_virt2phys Manish Kurup
2025-10-21 18:56 ` [PATCH v4 42/57] net/bnxt: thor2 truflow memory manager bug Manish Kurup
2025-10-21 18:56 ` [PATCH v4 43/57] net/bnxt: fix stats collection when rx queue is not set Manish Kurup
2025-10-21 18:56 ` [PATCH v4 44/57] net/bnxt: fix rss configuration when set to none Manish Kurup
2025-10-21 18:56 ` [PATCH v4 45/57] net/bnxt: packet drop after port stop and start Manish Kurup
2025-10-21 18:56 ` [PATCH v4 46/57] net/bnxt/tf_core: fix truflow crash on memory allocation failure Manish Kurup
2025-10-21 18:56 ` [PATCH v4 47/57] net/bnxt: truflow remove RTE devarg processing for mpc=1 Manish Kurup
2025-10-21 18:56 ` [PATCH v4 48/57] net/bnxt: add meson build options for TruFlow Manish Kurup
2025-10-21 18:56 ` [PATCH v4 49/57] net/bnxt: truflow HSI struct fixes Manish Kurup
2025-10-21 18:56 ` [PATCH v4 50/57] net/bnxt/tf_ulp: truflow add pf action handler Manish Kurup
2025-10-21 18:56 ` [PATCH v4 51/57] net/bnxt/tf_ulp: add support for unicast only feature Manish Kurup
2025-10-21 18:56 ` [PATCH v4 52/57] net/bnxt/tf_core: remove excessive debug logging Manish Kurup

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).