diff --git a/drivers/net/bnxt/tf_core/hwrm_tf.h b/drivers/net/bnxt/tf_core/hwrm_tf.h
index d342c695c..c04d1034a 100644
--- a/drivers/net/bnxt/tf_core/hwrm_tf.h
+++ b/drivers/net/bnxt/tf_core/hwrm_tf.h
@@ -1,5 +1,5 @@
 /* SPDX-License-Identifier: BSD-3-Clause
- * Copyright(c) 2019 Broadcom
+ * Copyright(c) 2019-2020 Broadcom
  * All rights reserved.
  */
 #ifndef _HWRM_TF_H_
@@ -27,7 +27,8 @@ typedef enum tf_subtype {
 	HWRM_TFT_REG_SET = 822,
 	HWRM_TFT_TBL_TYPE_SET = 823,
 	HWRM_TFT_TBL_TYPE_GET = 824,
-	TF_SUBTYPE_LAST = HWRM_TFT_TBL_TYPE_GET,
+	HWRM_TFT_TBL_TYPE_GET_BULK = 825,
+	TF_SUBTYPE_LAST = HWRM_TFT_TBL_TYPE_GET_BULK,
 } tf_subtype_t;
 
 /* Request and Response compile time checking */
@@ -81,6 +82,8 @@ struct tf_session_sram_resc_flush_input;
 struct tf_tbl_type_set_input;
 struct tf_tbl_type_get_input;
 struct tf_tbl_type_get_output;
+struct tf_tbl_type_get_bulk_input;
+struct tf_tbl_type_get_bulk_output;
 /* Input params for session attach */
 typedef struct tf_session_attach_input {
 	/* Firmware session id returned when HWRM_TF_SESSION_OPEN is sent */
@@ -902,6 +905,8 @@ typedef struct tf_tbl_type_get_input {
 #define TF_TBL_TYPE_GET_INPUT_FLAGS_DIR_RX			(0x0)
 	/* When set to 1, indicates the get apply to TX */
 #define TF_TBL_TYPE_GET_INPUT_FLAGS_DIR_TX			(0x1)
+	/* When set to 1, indicates the clear entry on read */
+#define TF_TBL_TYPE_GET_INPUT_FLAGS_CLEAR_ON_READ	  (0x2)
 	/* Type of the object to set */
 	uint32_t			 type;
 	/* Index to get */
@@ -916,4 +921,32 @@ typedef struct tf_tbl_type_get_output {
 	uint8_t			  data[TF_BULK_RECV];
 } tf_tbl_type_get_output_t, *ptf_tbl_type_get_output_t;
 
+/* Input params for table type get */
+typedef struct tf_tbl_type_get_bulk_input {
+	/* Session Id */
+	uint32_t			 fw_session_id;
+	/* flags */
+	uint16_t			 flags;
+	/* When set to 0, indicates the get apply to RX */
+#define TF_TBL_TYPE_GET_BULK_INPUT_FLAGS_DIR_RX	   (0x0)
+	/* When set to 1, indicates the get apply to TX */
+#define TF_TBL_TYPE_GET_BULK_INPUT_FLAGS_DIR_TX	   (0x1)
+	/* When set to 1, indicates the clear entry on read */
+#define TF_TBL_TYPE_GET_BULK_INPUT_FLAGS_CLEAR_ON_READ	  (0x2)
+	/* Type of the object to set */
+	uint32_t			 type;
+	/* Starting index to get from */
+	uint32_t			 start_index;
+	/* Number of entries to get */
+	uint32_t			 num_entries;
+	/* Host memory where data will be stored */
+	uint64_t			 host_addr;
+} tf_tbl_type_get_bulk_input_t, *ptf_tbl_type_get_bulk_input_t;
+
+/* Output params for table type get */
+typedef struct tf_tbl_type_get_bulk_output {
+	/* Size of the total data read in bytes */
+	uint16_t			 size;
+} tf_tbl_type_get_bulk_output_t, *ptf_tbl_type_get_bulk_output_t;
+
 #endif /* _HWRM_TF_H_ */
diff --git a/drivers/net/bnxt/tf_core/tf_common.h b/drivers/net/bnxt/tf_core/tf_common.h
new file mode 100644
index 000000000..2aa4b8640
--- /dev/null
+++ b/drivers/net/bnxt/tf_core/tf_common.h
@@ -0,0 +1,54 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2020 Broadcom
+ * All rights reserved.
+ */
+
+#ifndef _TF_COMMON_H_
+#define _TF_COMMON_H_
+
+/* Helper to check the parms */
+#define TF_CHECK_PARMS_SESSION(tfp, parms) do {	\
+		if ((parms) == NULL || (tfp) == NULL) { \
+			TFP_DRV_LOG(ERR, "Invalid Argument(s)\n"); \
+			return -EINVAL; \
+		} \
+		if ((tfp)->session == NULL || \
+		    (tfp)->session->core_data == NULL) { \
+			TFP_DRV_LOG(ERR, "%s: session error\n", \
+				    tf_dir_2_str((parms)->dir)); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define TF_CHECK_PARMS_SESSION_NO_DIR(tfp, parms) do {	\
+		if ((parms) == NULL || (tfp) == NULL) { \
+			TFP_DRV_LOG(ERR, "Invalid Argument(s)\n"); \
+			return -EINVAL; \
+		} \
+		if ((tfp)->session == NULL || \
+		    (tfp)->session->core_data == NULL) { \
+			TFP_DRV_LOG(ERR, "Session error\n"); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define TF_CHECK_PARMS(tfp, parms) do {	\
+		if ((parms) == NULL || (tfp) == NULL) { \
+			TFP_DRV_LOG(ERR, "Invalid Argument(s)\n"); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#define TF_CHECK_TFP_SESSION(tfp) do { \
+		if ((tfp) == NULL) { \
+			TFP_DRV_LOG(ERR, "Invalid Argument(s)\n"); \
+			return -EINVAL; \
+		} \
+		if ((tfp)->session == NULL || \
+		    (tfp)->session->core_data == NULL) { \
+			TFP_DRV_LOG(ERR, "Session error\n"); \
+			return -EINVAL; \
+		} \
+	} while (0)
+
+#endif /* _TF_COMMON_H_ */
diff --git a/drivers/net/bnxt/tf_core/tf_core.c b/drivers/net/bnxt/tf_core/tf_core.c
index 6e15a4c5c..a8236aec9 100644
--- a/drivers/net/bnxt/tf_core/tf_core.c
+++ b/drivers/net/bnxt/tf_core/tf_core.c
@@ -16,6 +16,8 @@
 #include "bitalloc.h"
 #include "bnxt.h"
 #include "rand.h"
+#include "tf_common.h"
+#include "hwrm_tf.h"
 
 static inline uint32_t SWAP_WORDS32(uint32_t val32)
 {
diff --git a/drivers/net/bnxt/tf_core/tf_core.h b/drivers/net/bnxt/tf_core/tf_core.h
index becc50c7f..96a1a794f 100644
--- a/drivers/net/bnxt/tf_core/tf_core.h
+++ b/drivers/net/bnxt/tf_core/tf_core.h
@@ -1165,7 +1165,7 @@ struct tf_get_tbl_entry_parms {
 	 */
 	uint8_t *data;
 	/**
-	 * [out] Entry size
+	 * [in] Entry size
 	 */
 	uint16_t data_sz_in_bytes;
 	/**
@@ -1188,6 +1188,59 @@ struct tf_get_tbl_entry_parms {
 int tf_get_tbl_entry(struct tf *tfp,
 		     struct tf_get_tbl_entry_parms *parms);
 
+/**
+ * tf_get_bulk_tbl_entry parameter definition
+ */
+struct tf_get_bulk_tbl_entry_parms {
+	/**
+	 * [in] Receive or transmit direction
+	 */
+	enum tf_dir dir;
+	/**
+	 * [in] Type of object to get
+	 */
+	enum tf_tbl_type type;
+	/**
+	 * [in] Clear hardware entries on reads only
+	 * supported for TF_TBL_TYPE_ACT_STATS_64
+	 */
+	bool clear_on_read;
+	/**
+	 * [in] Starting index to read from
+	 */
+	uint32_t starting_idx;
+	/**
+	 * [in] Number of sequential entries
+	 */
+	uint16_t num_entries;
+	/**
+	 * [in] Size of the single entry
+	 */
+	uint16_t entry_sz_in_bytes;
+	/**
+	 * [out] Host physical address, where the data
+	 * will be copied to by the firmware.
+	 * Use tfp_calloc() API and mem_pa
+	 * variable of the tfp_calloc_parms
+	 * structure for the physical address.
+	 */
+	uint64_t physical_mem_addr;
+};
+
+/**
+ * Bulk get index table entry
+ *
+ * Used to retrieve a previous set index table entry.
+ *
+ * Reads and compares with the shadow table copy (if enabled) (only
+ * for internal objects).
+ *
+ * Returns success or failure code. Failure will be returned if the
+ * provided data buffer is too small for the data type requested.
+ */
+int tf_get_bulk_tbl_entry(struct tf *tfp,
+		     struct tf_get_bulk_tbl_entry_parms *parms);
+
 /**
  * @page exact_match Exact Match Table
  *
diff --git a/drivers/net/bnxt/tf_core/tf_msg.c b/drivers/net/bnxt/tf_core/tf_msg.c
index c8f6b88d3..c755c8555 100644
--- a/drivers/net/bnxt/tf_core/tf_msg.c
+++ b/drivers/net/bnxt/tf_core/tf_msg.c
@@ -1216,12 +1216,8 @@ tf_msg_get_tbl_entry(struct tf *tfp,
 	return tfp_le_to_cpu_32(parms.tf_resp_code);
 }
 
-#define TF_BYTES_PER_SLICE(tfp) 12
-#define NUM_SLICES(tfp, bytes) \
-	(((bytes) + TF_BYTES_PER_SLICE(tfp) - 1) / TF_BYTES_PER_SLICE(tfp))
-
 static int
-tf_msg_get_dma_buf(struct tf_msg_dma_buf *buf, int size)
+tf_msg_alloc_dma_buf(struct tf_msg_dma_buf *buf, int size)
 {
 	struct tfp_calloc_parms alloc_parms;
 	int rc;
@@ -1229,15 +1225,10 @@ tf_msg_get_dma_buf(struct tf_msg_dma_buf *buf, int size)
 	/* Allocate session */
 	alloc_parms.nitems = 1;
 	alloc_parms.size = size;
-	alloc_parms.alignment = 0;
+	alloc_parms.alignment = 4096;
 	rc = tfp_calloc(&alloc_parms);
-	if (rc) {
-		/* Log error */
-		PMD_DRV_LOG(ERR,
-			    "Failed to allocate tcam dma entry, rc:%d\n",
-			    rc);
+	if (rc)
 		return -ENOMEM;
-	}
 
 	buf->pa_addr = (uintptr_t)alloc_parms.mem_pa;
 	buf->va_addr = alloc_parms.mem_va;
@@ -1245,6 +1236,52 @@ tf_msg_get_dma_buf(struct tf_msg_dma_buf *buf, int size)
 	return 0;
 }
 
+int
+tf_msg_get_bulk_tbl_entry(struct tf *tfp,
+			  struct tf_get_bulk_tbl_entry_parms *params)
+{
+	int rc;
+	struct tfp_send_msg_parms parms = { 0 };
+	struct tf_tbl_type_get_bulk_input req = { 0 };
+	struct tf_tbl_type_get_bulk_output resp = { 0 };
+	struct tf_session *tfs = (struct tf_session *)(tfp->session->core_data);
+	int data_size = 0;
+
+	/* Populate the request */
+	req.fw_session_id =
+		tfp_cpu_to_le_32(tfs->session_id.internal.fw_session_id);
+	req.flags = tfp_cpu_to_le_16((params->dir) |
+		((params->clear_on_read) ?
+		 TF_TBL_TYPE_GET_BULK_INPUT_FLAGS_CLEAR_ON_READ : 0x0));
+	req.type = tfp_cpu_to_le_32(params->type);
+	req.start_index = tfp_cpu_to_le_32(params->starting_idx);
+	req.num_entries = tfp_cpu_to_le_32(params->num_entries);
+
+	data_size = (params->num_entries * params->entry_sz_in_bytes);
+	req.host_addr = tfp_cpu_to_le_64(params->physical_mem_addr);
+
+	MSG_PREP(parms,
+		 TF_KONG_MB,
+		 HWRM_TF,
+		 HWRM_TFT_TBL_TYPE_GET_BULK,
+		 req,
+		 resp);
+
+	rc = tfp_send_msg_tunneled(tfp, &parms);
+	if (rc)
+		return rc;
+
+	/* Verify that we got enough buffer to return the requested data */
+	if (resp.size < data_size)
+		return -EINVAL;
+
+	return tfp_le_to_cpu_32(parms.tf_resp_code);
+}
+
+#define TF_BYTES_PER_SLICE(tfp) 12
+#define NUM_SLICES(tfp, bytes) \
+	(((bytes) + TF_BYTES_PER_SLICE(tfp) - 1) / TF_BYTES_PER_SLICE(tfp))
+
 int
 tf_msg_tcam_entry_set(struct tf *tfp,
 		      struct tf_set_tcam_entry_parms *parms)
@@ -1282,9 +1319,9 @@ tf_msg_tcam_entry_set(struct tf *tfp,
 	} else {
 		/* use dma buffer */
 		req.flags |= HWRM_TF_TCAM_SET_INPUT_FLAGS_DMA;
-		rc = tf_msg_get_dma_buf(&buf, data_size);
-		if (rc != 0)
-			return rc;
+		rc = tf_msg_alloc_dma_buf(&buf, data_size);
+		if (rc)
+			goto cleanup;
 		data = buf.va_addr;
 		memcpy(&req.dev_data[0], &buf.pa_addr, sizeof(buf.pa_addr));
 	}
@@ -1303,8 +1340,9 @@ tf_msg_tcam_entry_set(struct tf *tfp,
 	rc = tfp_send_msg_direct(tfp,
 				 &mparms);
 	if (rc)
-		return rc;
+		goto cleanup;
 
+cleanup:
 	if (buf.va_addr != NULL)
 		tfp_free(buf.va_addr);
 
diff --git a/drivers/net/bnxt/tf_core/tf_msg.h b/drivers/net/bnxt/tf_core/tf_msg.h
index 89f7370cc..8d050c402 100644
--- a/drivers/net/bnxt/tf_core/tf_msg.h
+++ b/drivers/net/bnxt/tf_core/tf_msg.h
@@ -267,4 +267,19 @@ int tf_msg_get_tbl_entry(struct tf *tfp,
 			 uint8_t *data,
 			 uint32_t index);
 
+/**
+ * Sends bulk get message of a Table Type element to the firmware.
+ *
+ * [in] tfp
+ *   Pointer to session handle
+ *
+ * [in] parms
+ *   Pointer to table get bulk parameters
+ *
+ * Returns:
+ *  0 on Success else internal Truflow error
+ */
+int tf_msg_get_bulk_tbl_entry(struct tf *tfp,
+			  struct tf_get_bulk_tbl_entry_parms *parms);
+
 #endif  /* _TF_MSG_H_ */
diff --git a/drivers/net/bnxt/tf_core/tf_resources.h b/drivers/net/bnxt/tf_core/tf_resources.h
index 05e131f8b..9b7f5a069 100644
--- a/drivers/net/bnxt/tf_core/tf_resources.h
+++ b/drivers/net/bnxt/tf_core/tf_resources.h
@@ -149,11 +149,10 @@
 #define TF_RSVD_METER_INST_END_IDX_TX             0
 
 /* Mirror */
-/* Not yet supported fully in the infra */
-#define TF_RSVD_MIRROR_RX                         0
+#define TF_RSVD_MIRROR_RX                         1
 #define TF_RSVD_MIRROR_BEGIN_IDX_RX               0
 #define TF_RSVD_MIRROR_END_IDX_RX                 0
-#define TF_RSVD_MIRROR_TX                         0
+#define TF_RSVD_MIRROR_TX                         1
 #define TF_RSVD_MIRROR_BEGIN_IDX_TX               0
 #define TF_RSVD_MIRROR_END_IDX_TX                 0
 
diff --git a/drivers/net/bnxt/tf_core/tf_tbl.c b/drivers/net/bnxt/tf_core/tf_tbl.c
index 17399a5b2..26313ed3c 100644
--- a/drivers/net/bnxt/tf_core/tf_tbl.c
+++ b/drivers/net/bnxt/tf_core/tf_tbl.c
@@ -23,6 +23,7 @@
 #include "bnxt.h"
 #include "tf_resources.h"
 #include "tf_rm.h"
+#include "tf_common.h"
 
 #define PTU_PTE_VALID          0x1UL
 #define PTU_PTE_LAST           0x2UL
@@ -794,6 +795,7 @@ tf_set_tbl_entry_internal(struct tf *tfp,
 
 	if (parms->type != TF_TBL_TYPE_FULL_ACT_RECORD &&
 	    parms->type != TF_TBL_TYPE_ACT_SP_SMAC_IPV4 &&
+	    parms->type != TF_TBL_TYPE_MIRROR_CONFIG &&
 	    parms->type != TF_TBL_TYPE_ACT_STATS_64) {
 		PMD_DRV_LOG(ERR,
 			    "dir:%d, Type not supported, type:%d\n",
@@ -915,6 +917,76 @@ tf_get_tbl_entry_internal(struct tf *tfp,
 	return rc;
 }
 
+/**
+ * Internal function to get a Table Entry. Supports all Table Types
+ * except the TF_TBL_TYPE_EXT as that is handled as a table scope.
+ *
+ * [in] tfp
+ *   Pointer to TruFlow handle
+ *
+ * [in] parms
+ *   Pointer to input parameters
+ *
+ * Returns:
+ *   0       - Success
+ *   -EINVAL - Parameter error
+ */
+static int
+tf_get_bulk_tbl_entry_internal(struct tf *tfp,
+			  struct tf_get_bulk_tbl_entry_parms *parms)
+{
+	int rc;
+	int id;
+	uint32_t index;
+	struct bitalloc *session_pool;
+	struct tf_session *tfs = (struct tf_session *)(tfp->session->core_data);
+
+	/* Lookup the pool using the table type of the element */
+	rc = tf_rm_lookup_tbl_type_pool(tfs,
+					parms->dir,
+					parms->type,
+					&session_pool);
+	/* Error logging handled by tf_rm_lookup_tbl_type_pool */
+	if (rc)
+		return rc;
+
+	index = parms->starting_idx;
+
+	/*
+	 * Adjust the returned index/offset as there is no guarantee
+	 * that the start is 0 at time of RM allocation
+	 */
+	tf_rm_convert_index(tfs,
+			    parms->dir,
+			    parms->type,
+			    TF_RM_CONVERT_RM_BASE,
+			    parms->starting_idx,
+			    &index);
+
+	/* Verify that the entry has been previously allocated */
+	id = ba_inuse(session_pool, index);
+	if (id != 1) {
+		TFP_DRV_LOG(ERR,
+		   "%s, Invalid or not allocated index, type:%d, starting_idx:%d\n",
+		   tf_dir_2_str(parms->dir),
+		   parms->type,
+		   index);
+		return -EINVAL;
+	}
+
+	/* Get the entry */
+	rc = tf_msg_get_bulk_tbl_entry(tfp, parms);
+	if (rc) {
+		TFP_DRV_LOG(ERR,
+			    "%s, Bulk get failed, type:%d, rc:%s\n",
+			    tf_dir_2_str(parms->dir),
+			    parms->type,
+			    strerror(-rc));
+	}
+
+	return rc;
+}
+
 #if (TF_SHADOW == 1)
 /**
  * Allocate Tbl entry from the Shadow DB. Shadow DB is searched for
@@ -1182,6 +1254,7 @@ tf_alloc_tbl_entry_pool_internal(struct tf *tfp,
 	    parms->type != TF_TBL_TYPE_ACT_ENCAP_8B &&
 	    parms->type != TF_TBL_TYPE_ACT_ENCAP_16B &&
 	    parms->type != TF_TBL_TYPE_ACT_ENCAP_64B &&
+	    parms->type != TF_TBL_TYPE_MIRROR_CONFIG &&
 	    parms->type != TF_TBL_TYPE_ACT_STATS_64) {
 		PMD_DRV_LOG(ERR,
 			    "dir:%d, Type not supported, type:%d\n",
@@ -1663,6 +1736,36 @@ tf_get_tbl_entry(struct tf *tfp,
 	return rc;
 }
 
+/* API defined in tf_core.h */
+int
+tf_get_bulk_tbl_entry(struct tf *tfp,
+		 struct tf_get_bulk_tbl_entry_parms *parms)
+{
+	int rc = 0;
+
+	TF_CHECK_PARMS_SESSION(tfp, parms);
+
+	if (parms->type == TF_TBL_TYPE_EXT) {
+		/* Not supported, yet */
+		TFP_DRV_LOG(ERR,
+			    "%s, External table type not supported\n",
+			    tf_dir_2_str(parms->dir));
+
+		rc = -EOPNOTSUPP;
+	} else {
+		/* Internal table type processing */
+		rc = tf_get_bulk_tbl_entry_internal(tfp, parms);
+		if (rc)
+			TFP_DRV_LOG(ERR,
+				    "%s, Bulk get failed, type:%d, rc:%s\n",
+				    tf_dir_2_str(parms->dir),
+				    parms->type,
+				    strerror(-rc));
+	}
+
+	return rc;
+}
+
 /* API defined in tf_core.h */
 int
 tf_alloc_tbl_scope(struct tf *tfp,
