diff --git a/drivers/net/qede/base/ecore.h b/drivers/net/qede/base/ecore.h
index b9f5993..524a1dd 100644
--- a/drivers/net/qede/base/ecore.h
+++ b/drivers/net/qede/base/ecore.h
@@ -19,6 +19,7 @@
 #include <zlib.h>
 #endif
 
+#include "ecore_status.h"
 #include "ecore_hsi_common.h"
 #include "ecore_hsi_debug_tools.h"
 #include "ecore_hsi_init_func.h"
@@ -207,6 +208,7 @@ enum DP_MODULE {
 struct ecore_igu_info;
 struct ecore_mcp_info;
 struct ecore_dcbx_info;
+struct ecore_llh_info;
 
 struct ecore_rt_data {
 	u32	*init_val;
@@ -743,6 +745,7 @@ struct ecore_dev {
 #endif
 #define ECORE_IS_AH(dev)	((dev)->type == ECORE_DEV_TYPE_AH)
 #define ECORE_IS_K2(dev)	ECORE_IS_AH(dev)
+#define ECORE_IS_E4(dev)	(ECORE_IS_BB(dev) || ECORE_IS_AH(dev))
 
 	u16 vendor_id;
 	u16 device_id;
@@ -837,8 +840,26 @@ struct ecore_dev {
 	/* HW functions */
 	u8				num_hwfns;
 	struct ecore_hwfn		hwfns[MAX_HWFNS_PER_DEVICE];
+#define ECORE_LEADING_HWFN(dev)		(&dev->hwfns[0])
 #define ECORE_IS_CMT(dev)		((dev)->num_hwfns > 1)
 
+	/* Engine affinity */
+	u8				l2_affin_hint;
+	u8				fir_affin;
+	u8				iwarp_affin;
+	/* Macro for getting the engine-affinitized hwfn for FCoE/iSCSI/RoCE */
+#define ECORE_FIR_AFFIN_HWFN(dev)	(&dev->hwfns[dev->fir_affin])
+	/* Macro for getting the engine-affinitized hwfn for iWARP */
+#define ECORE_IWARP_AFFIN_HWFN(dev)	(&dev->hwfns[dev->iwarp_affin])
+	/* Generic macro for getting the engine-affinitized hwfn */
+#define ECORE_AFFIN_HWFN(dev) \
+	(ECORE_IS_IWARP_PERSONALITY(ECORE_LEADING_HWFN(dev)) ? \
+	 ECORE_IWARP_AFFIN_HWFN(dev) : \
+	 ECORE_FIR_AFFIN_HWFN(dev))
+	/* Macro for getting the index (0/1) of the engine-affinitized hwfn */
+#define ECORE_AFFIN_HWFN_IDX(dev) \
+	(IS_LEAD_HWFN(ECORE_AFFIN_HWFN(dev)) ? 0 : 1)
+
 	/* SRIOV */
 	struct ecore_hw_sriov_info	*p_iov_info;
 #define IS_ECORE_SRIOV(p_dev)		(!!(p_dev)->p_iov_info)
@@ -873,6 +894,9 @@ struct ecore_dev {
 #ifndef ASIC_ONLY
 	bool				b_is_emul_full;
 #endif
+	/* LLH info */
+	u8				ppfid_bitmap;
+	struct ecore_llh_info		*p_llh_info;
 
 	/* Indicates whether this PF serves a storage target */
 	bool				b_is_target;
@@ -974,6 +998,29 @@ void ecore_db_recovery_execute(struct ecore_hwfn *p_hwfn,
 u16 ecore_init_qm_get_num_vports(struct ecore_hwfn *p_hwfn);
 u16 ecore_init_qm_get_num_pqs(struct ecore_hwfn *p_hwfn);
 
-#define ECORE_LEADING_HWFN(dev)	(&dev->hwfns[0])
+#define MFW_PORT(_p_hwfn)	((_p_hwfn)->abs_pf_id % \
+				 ecore_device_num_ports((_p_hwfn)->p_dev))
+
+/* The PFID<->PPFID calculation is based on the relative index of a PF on its
+ * port. In BB there is a bug in the LLH in which the PPFID is actually engine
+ * based, and thus it equals the PFID.
+ */
+#define ECORE_PFID_BY_PPFID(_p_hwfn, abs_ppfid) \
+	(ECORE_IS_BB((_p_hwfn)->p_dev) ? \
+	 (abs_ppfid) : \
+	 (abs_ppfid) * (_p_hwfn)->p_dev->num_ports_in_engine + \
+	 MFW_PORT(_p_hwfn))
+#define ECORE_PPFID_BY_PFID(_p_hwfn) \
+	(ECORE_IS_BB((_p_hwfn)->p_dev) ? \
+	 (_p_hwfn)->rel_pf_id : \
+	 (_p_hwfn)->rel_pf_id / (_p_hwfn)->p_dev->num_ports_in_engine)
+
+enum _ecore_status_t ecore_all_ppfids_wr(struct ecore_hwfn *p_hwfn,
+					 struct ecore_ptt *p_ptt, u32 addr,
+					 u32 val);
+
+/* Utility functions for dumping the content of the NIG LLH filters */
+enum _ecore_status_t ecore_llh_dump_ppfid(struct ecore_dev *p_dev, u8 ppfid);
+enum _ecore_status_t ecore_llh_dump_all(struct ecore_dev *p_dev);
 
 #endif /* __ECORE_H */
diff --git a/drivers/net/qede/base/ecore_cxt.c b/drivers/net/qede/base/ecore_cxt.c
index 6bc6348..5c3370e 100644
--- a/drivers/net/qede/base/ecore_cxt.c
+++ b/drivers/net/qede/base/ecore_cxt.c
@@ -2114,7 +2114,7 @@ enum _ecore_status_t
 
 	ecore_dmae_host2grc(p_hwfn, p_ptt, (u64)(osal_uintptr_t)&ilt_hw_entry,
 			    reg_offset, sizeof(ilt_hw_entry) / sizeof(u32),
-			    0 /* no flags */);
+			    OSAL_NULL /* default parameters */);
 
 	if (elem_type == ECORE_ELEM_CXT) {
 		u32 last_cid_allocated = (1 + (iid / elems_per_p)) *
@@ -2221,7 +2221,7 @@ enum _ecore_status_t
 				    (u64)(osal_uintptr_t)&ilt_hw_entry,
 				    reg_offset,
 				    sizeof(ilt_hw_entry) / sizeof(u32),
-				    0 /* no flags */);
+				    OSAL_NULL /* default parameters */);
 	}
 
 	ecore_ptt_release(p_hwfn, p_ptt);
diff --git a/drivers/net/qede/base/ecore_dcbx.c b/drivers/net/qede/base/ecore_dcbx.c
index 9667874..7668ad6 100644
--- a/drivers/net/qede/base/ecore_dcbx.c
+++ b/drivers/net/qede/base/ecore_dcbx.c
@@ -893,12 +893,19 @@ enum _ecore_status_t
 
 	ecore_dcbx_get_params(p_hwfn, &p_hwfn->p_dcbx_info->get, type);
 
-	/* Update the DSCP to TC mapping bit if required */
+	/* Update the DSCP to TC mapping enable bit if required */
 	if ((type == ECORE_DCBX_OPERATIONAL_MIB) &&
 	    p_hwfn->p_dcbx_info->dscp_nig_update) {
 		u8 val = !!p_hwfn->p_dcbx_info->get.dscp.enabled;
+		u32 addr = NIG_REG_DSCP_TO_TC_MAP_ENABLE;
+
+		rc = ecore_all_ppfids_wr(p_hwfn, p_ptt, addr, val);
+		if (rc != ECORE_SUCCESS) {
+			DP_NOTICE(p_hwfn, false,
+				  "Failed to update the DSCP to TC mapping enable bit\n");
+			return rc;
+		}
 
-		ecore_wr(p_hwfn, p_ptt, NIG_REG_DSCP_TO_TC_MAP_ENABLE, val);
 		p_hwfn->p_dcbx_info->dscp_nig_update = false;
 	}
 
diff --git a/drivers/net/qede/base/ecore_dev.c b/drivers/net/qede/base/ecore_dev.c
index 30e12e9..cf454b1 100644
--- a/drivers/net/qede/base/ecore_dev.c
+++ b/drivers/net/qede/base/ecore_dev.c
@@ -352,6 +352,1189 @@ void ecore_db_recovery_execute(struct ecore_hwfn *p_hwfn,
 }
 /******************** Doorbell Recovery end ****************/
 
+/********************************** NIG LLH ***********************************/
+
+enum ecore_llh_filter_type {
+	ECORE_LLH_FILTER_TYPE_MAC,
+	ECORE_LLH_FILTER_TYPE_PROTOCOL,
+};
+
+struct ecore_llh_mac_filter {
+	u8 addr[ETH_ALEN];
+};
+
+struct ecore_llh_protocol_filter {
+	enum ecore_llh_prot_filter_type_t type;
+	u16 source_port_or_eth_type;
+	u16 dest_port;
+};
+
+union ecore_llh_filter {
+	struct ecore_llh_mac_filter mac;
+	struct ecore_llh_protocol_filter protocol;
+};
+
+struct ecore_llh_filter_info {
+	bool b_enabled;
+	u32 ref_cnt;
+	enum ecore_llh_filter_type type;
+	union ecore_llh_filter filter;
+};
+
+struct ecore_llh_info {
+	/* Number of LLH filters banks */
+	u8 num_ppfid;
+
+#define MAX_NUM_PPFID	8
+	u8 ppfid_array[MAX_NUM_PPFID];
+
+	/* Array of filters arrays:
+	 * "num_ppfid" elements of filters banks, where each is an array of
+	 * "NIG_REG_LLH_FUNC_FILTER_EN_SIZE" filters.
+	 */
+	struct ecore_llh_filter_info **pp_filters;
+};
+
+static void ecore_llh_free(struct ecore_dev *p_dev)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	u32 i;
+
+	if (p_llh_info != OSAL_NULL) {
+		if (p_llh_info->pp_filters != OSAL_NULL) {
+			for (i = 0; i < p_llh_info->num_ppfid; i++)
+				OSAL_FREE(p_dev, p_llh_info->pp_filters[i]);
+		}
+
+		OSAL_FREE(p_dev, p_llh_info->pp_filters);
+	}
+
+	OSAL_FREE(p_dev, p_llh_info);
+	p_dev->p_llh_info = OSAL_NULL;
+}
+
+static enum _ecore_status_t ecore_llh_alloc(struct ecore_dev *p_dev)
+{
+	struct ecore_llh_info *p_llh_info;
+	u32 size;
+	u8 i;
+
+	p_llh_info = OSAL_ZALLOC(p_dev, GFP_KERNEL, sizeof(*p_llh_info));
+	if (!p_llh_info)
+		return ECORE_NOMEM;
+	p_dev->p_llh_info = p_llh_info;
+
+	for (i = 0; i < MAX_NUM_PPFID; i++) {
+		if (!(p_dev->ppfid_bitmap & (0x1 << i)))
+			continue;
+
+		p_llh_info->ppfid_array[p_llh_info->num_ppfid] = i;
+		DP_VERBOSE(p_dev, ECORE_MSG_SP, "ppfid_array[%d] = %hhd\n",
+			   p_llh_info->num_ppfid, i);
+		p_llh_info->num_ppfid++;
+	}
+
+	size = p_llh_info->num_ppfid * sizeof(*p_llh_info->pp_filters);
+	p_llh_info->pp_filters = OSAL_ZALLOC(p_dev, GFP_KERNEL, size);
+	if (!p_llh_info->pp_filters)
+		return ECORE_NOMEM;
+
+	size = NIG_REG_LLH_FUNC_FILTER_EN_SIZE *
+	       sizeof(**p_llh_info->pp_filters);
+	for (i = 0; i < p_llh_info->num_ppfid; i++) {
+		p_llh_info->pp_filters[i] = OSAL_ZALLOC(p_dev, GFP_KERNEL,
+							size);
+		if (!p_llh_info->pp_filters[i])
+			return ECORE_NOMEM;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t ecore_llh_shadow_sanity(struct ecore_dev *p_dev,
+						    u8 ppfid, u8 filter_idx,
+						    const char *action)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+
+	if (ppfid >= p_llh_info->num_ppfid) {
+		DP_NOTICE(p_dev, false,
+			  "LLH shadow [%s]: using ppfid %d while only %d ppfids are available\n",
+			  action, ppfid, p_llh_info->num_ppfid);
+		return ECORE_INVAL;
+	}
+
+	if (filter_idx >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
+		DP_NOTICE(p_dev, false,
+			  "LLH shadow [%s]: using filter_idx %d while only %d filters are available\n",
+			  action, filter_idx, NIG_REG_LLH_FUNC_FILTER_EN_SIZE);
+		return ECORE_INVAL;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+#define ECORE_LLH_INVALID_FILTER_IDX	0xff
+
+static enum _ecore_status_t
+ecore_llh_shadow_search_filter(struct ecore_dev *p_dev, u8 ppfid,
+			       union ecore_llh_filter *p_filter,
+			       u8 *p_filter_idx)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	struct ecore_llh_filter_info *p_filters;
+	enum _ecore_status_t rc;
+	u8 i;
+
+	rc = ecore_llh_shadow_sanity(p_dev, ppfid, 0, "search");
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	*p_filter_idx = ECORE_LLH_INVALID_FILTER_IDX;
+
+	p_filters = p_llh_info->pp_filters[ppfid];
+	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+		if (!OSAL_MEMCMP(p_filter, &p_filters[i].filter,
+				 sizeof(*p_filter))) {
+			*p_filter_idx = i;
+			break;
+		}
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_shadow_get_free_idx(struct ecore_dev *p_dev, u8 ppfid,
+			      u8 *p_filter_idx)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	struct ecore_llh_filter_info *p_filters;
+	enum _ecore_status_t rc;
+	u8 i;
+
+	rc = ecore_llh_shadow_sanity(p_dev, ppfid, 0, "get_free_idx");
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	*p_filter_idx = ECORE_LLH_INVALID_FILTER_IDX;
+
+	p_filters = p_llh_info->pp_filters[ppfid];
+	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
+		if (!p_filters[i].b_enabled) {
+			*p_filter_idx = i;
+			break;
+		}
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+__ecore_llh_shadow_add_filter(struct ecore_dev *p_dev, u8 ppfid, u8 filter_idx,
+			      enum ecore_llh_filter_type type,
+			      union ecore_llh_filter *p_filter, u32 *p_ref_cnt)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	struct ecore_llh_filter_info *p_filters;
+	enum _ecore_status_t rc;
+
+	rc = ecore_llh_shadow_sanity(p_dev, ppfid, filter_idx, "add");
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	p_filters = p_llh_info->pp_filters[ppfid];
+	if (!p_filters[filter_idx].ref_cnt) {
+		p_filters[filter_idx].b_enabled = true;
+		p_filters[filter_idx].type = type;
+		OSAL_MEMCPY(&p_filters[filter_idx].filter, p_filter,
+			    sizeof(p_filters[filter_idx].filter));
+	}
+
+	*p_ref_cnt = ++p_filters[filter_idx].ref_cnt;
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_shadow_add_filter(struct ecore_dev *p_dev, u8 ppfid,
+			    enum ecore_llh_filter_type type,
+			    union ecore_llh_filter *p_filter,
+			    u8 *p_filter_idx, u32 *p_ref_cnt)
+{
+	enum _ecore_status_t rc;
+
+	/* Check if the same filter already exist */
+	rc = ecore_llh_shadow_search_filter(p_dev, ppfid, p_filter,
+					    p_filter_idx);
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	/* Find a new entry in case of a new filter */
+	if (*p_filter_idx == ECORE_LLH_INVALID_FILTER_IDX) {
+		rc = ecore_llh_shadow_get_free_idx(p_dev, ppfid, p_filter_idx);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+	}
+
+	/* No free entry was found */
+	if (*p_filter_idx == ECORE_LLH_INVALID_FILTER_IDX) {
+		DP_NOTICE(p_dev, false,
+			  "Failed to find an empty LLH filter to utilize [ppfid %d]\n",
+			  ppfid);
+		return ECORE_NORESOURCES;
+	}
+
+	return __ecore_llh_shadow_add_filter(p_dev, ppfid, *p_filter_idx, type,
+					     p_filter, p_ref_cnt);
+}
+
+static enum _ecore_status_t
+__ecore_llh_shadow_remove_filter(struct ecore_dev *p_dev, u8 ppfid,
+				 u8 filter_idx, u32 *p_ref_cnt)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	struct ecore_llh_filter_info *p_filters;
+	enum _ecore_status_t rc;
+
+	rc = ecore_llh_shadow_sanity(p_dev, ppfid, filter_idx, "remove");
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	p_filters = p_llh_info->pp_filters[ppfid];
+	if (!p_filters[filter_idx].ref_cnt) {
+		DP_NOTICE(p_dev, false,
+			  "LLH shadow: trying to remove a filter with ref_cnt=0\n");
+		return ECORE_INVAL;
+	}
+
+	*p_ref_cnt = --p_filters[filter_idx].ref_cnt;
+	if (!p_filters[filter_idx].ref_cnt)
+		OSAL_MEM_ZERO(&p_filters[filter_idx],
+			      sizeof(p_filters[filter_idx]));
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_shadow_remove_filter(struct ecore_dev *p_dev, u8 ppfid,
+			       union ecore_llh_filter *p_filter,
+			       u8 *p_filter_idx, u32 *p_ref_cnt)
+{
+	enum _ecore_status_t rc;
+
+	rc = ecore_llh_shadow_search_filter(p_dev, ppfid, p_filter,
+					    p_filter_idx);
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	/* No matching filter was found */
+	if (*p_filter_idx == ECORE_LLH_INVALID_FILTER_IDX) {
+		DP_NOTICE(p_dev, false,
+			  "Failed to find a filter in the LLH shadow\n");
+		return ECORE_INVAL;
+	}
+
+	return __ecore_llh_shadow_remove_filter(p_dev, ppfid, *p_filter_idx,
+						p_ref_cnt);
+}
+
+static enum _ecore_status_t
+ecore_llh_shadow_remove_all_filters(struct ecore_dev *p_dev, u8 ppfid)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	struct ecore_llh_filter_info *p_filters;
+	enum _ecore_status_t rc;
+
+	rc = ecore_llh_shadow_sanity(p_dev, ppfid, 0, "remove_all");
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	p_filters = p_llh_info->pp_filters[ppfid];
+	OSAL_MEM_ZERO(p_filters,
+		      NIG_REG_LLH_FUNC_FILTER_EN_SIZE * sizeof(*p_filters));
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t ecore_abs_ppfid(struct ecore_dev *p_dev,
+					    u8 rel_ppfid, u8 *p_abs_ppfid)
+{
+	struct ecore_llh_info *p_llh_info = p_dev->p_llh_info;
+	u8 ppfids = p_llh_info->num_ppfid - 1;
+
+	if (rel_ppfid >= p_llh_info->num_ppfid) {
+		DP_NOTICE(p_dev, false,
+			  "rel_ppfid %d is not valid, available indices are 0..%hhd\n",
+			  rel_ppfid, ppfids);
+		return ECORE_INVAL;
+	}
+
+	*p_abs_ppfid = p_llh_info->ppfid_array[rel_ppfid];
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+__ecore_llh_set_engine_affin(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	enum ecore_eng eng;
+	u8 ppfid;
+	enum _ecore_status_t rc;
+
+	rc = ecore_mcp_get_engine_config(p_hwfn, p_ptt);
+	if (rc != ECORE_SUCCESS && rc != ECORE_NOTIMPL) {
+		DP_NOTICE(p_hwfn, false,
+			  "Failed to get the engine affinity configuration\n");
+		return rc;
+	}
+
+	/* RoCE PF is bound to a single engine */
+	if (ECORE_IS_ROCE_PERSONALITY(p_hwfn)) {
+		eng = p_dev->fir_affin ? ECORE_ENG1 : ECORE_ENG0;
+		rc = ecore_llh_set_roce_affinity(p_dev, eng);
+		if (rc != ECORE_SUCCESS) {
+			DP_NOTICE(p_dev, false,
+				  "Failed to set the RoCE engine affinity\n");
+			return rc;
+		}
+
+		DP_VERBOSE(p_dev, ECORE_MSG_SP,
+			   "LLH: Set the engine affinity of RoCE packets as %d\n",
+			   eng);
+	}
+
+	/* Storage PF is bound to a single engine while L2 PF uses both */
+	if (ECORE_IS_FCOE_PERSONALITY(p_hwfn) ||
+	    ECORE_IS_ISCSI_PERSONALITY(p_hwfn))
+		eng = p_dev->fir_affin ? ECORE_ENG1 : ECORE_ENG0;
+	else /* L2_PERSONALITY */
+		eng = ECORE_BOTH_ENG;
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+		rc = ecore_llh_set_ppfid_affinity(p_dev, ppfid, eng);
+		if (rc != ECORE_SUCCESS) {
+			DP_NOTICE(p_dev, false,
+				  "Failed to set the engine affinity of ppfid %d\n",
+				  ppfid);
+			return rc;
+		}
+	}
+
+	DP_VERBOSE(p_dev, ECORE_MSG_SP,
+		   "LLH: Set the engine affinity of non-RoCE packets as %d\n",
+		   eng);
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_set_engine_affin(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+			   bool avoid_eng_affin)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	enum _ecore_status_t rc;
+
+	/* Backwards compatible mode:
+	 * - RoCE packets     - Use engine 0.
+	 * - Non-RoCE packets - Use connection based classification for L2 PFs,
+	 *                      and engine 0 otherwise.
+	 */
+	if (avoid_eng_affin) {
+		enum ecore_eng eng;
+		u8 ppfid;
+
+		if (ECORE_IS_ROCE_PERSONALITY(p_hwfn)) {
+			eng = ECORE_ENG0;
+			rc = ecore_llh_set_roce_affinity(p_dev, eng);
+			if (rc != ECORE_SUCCESS) {
+				DP_NOTICE(p_dev, false,
+					  "Failed to set the RoCE engine affinity\n");
+				return rc;
+			}
+
+			DP_VERBOSE(p_dev, ECORE_MSG_SP,
+				   "LLH [backwards compatible mode]: Set the engine affinity of RoCE packets as %d\n",
+				   eng);
+		}
+
+		eng = (ECORE_IS_FCOE_PERSONALITY(p_hwfn) ||
+		       ECORE_IS_ISCSI_PERSONALITY(p_hwfn)) ? ECORE_ENG0
+							   : ECORE_BOTH_ENG;
+		for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+			rc = ecore_llh_set_ppfid_affinity(p_dev, ppfid, eng);
+			if (rc != ECORE_SUCCESS) {
+				DP_NOTICE(p_dev, false,
+					  "Failed to set the engine affinity of ppfid %d\n",
+					  ppfid);
+				return rc;
+			}
+		}
+
+		DP_VERBOSE(p_dev, ECORE_MSG_SP,
+			   "LLH [backwards compatible mode]: Set the engine affinity of non-RoCE packets as %d\n",
+			   eng);
+
+		return ECORE_SUCCESS;
+	}
+
+	return __ecore_llh_set_engine_affin(p_hwfn, p_ptt);
+}
+
+static enum _ecore_status_t ecore_llh_hw_init_pf(struct ecore_hwfn *p_hwfn,
+						 struct ecore_ptt *p_ptt,
+						 bool avoid_eng_affin)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	u8 ppfid, abs_ppfid;
+	enum _ecore_status_t rc;
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+		u32 addr;
+
+		rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+
+		addr = NIG_REG_LLH_PPFID2PFID_TBL_0 + abs_ppfid * 0x4;
+		ecore_wr(p_hwfn, p_ptt, addr, p_hwfn->rel_pf_id);
+	}
+
+	if (OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits) &&
+	    !ECORE_IS_FCOE_PERSONALITY(p_hwfn)) {
+		rc = ecore_llh_add_mac_filter(p_dev, 0,
+					      p_hwfn->hw_info.hw_mac_addr);
+		if (rc != ECORE_SUCCESS)
+			DP_NOTICE(p_dev, false,
+				  "Failed to add an LLH filter with the primary MAC\n");
+	}
+
+	if (ECORE_IS_CMT(p_dev)) {
+		rc = ecore_llh_set_engine_affin(p_hwfn, p_ptt, avoid_eng_affin);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+u8 ecore_llh_get_num_ppfid(struct ecore_dev *p_dev)
+{
+	return p_dev->p_llh_info->num_ppfid;
+}
+
+enum ecore_eng ecore_llh_get_l2_affinity_hint(struct ecore_dev *p_dev)
+{
+	return p_dev->l2_affin_hint ? ECORE_ENG1 : ECORE_ENG0;
+}
+
+/* TBD - should be removed when these definitions are available in reg_addr.h */
+#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_MASK		0x3
+#define NIG_REG_PPF_TO_ENGINE_SEL_ROCE_SHIFT		0
+#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_MASK		0x3
+#define NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE_SHIFT	2
+
+enum _ecore_status_t ecore_llh_set_ppfid_affinity(struct ecore_dev *p_dev,
+						  u8 ppfid, enum ecore_eng eng)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	u32 addr, val, eng_sel;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+	u8 abs_ppfid;
+
+	if (p_ptt == OSAL_NULL)
+		return ECORE_AGAIN;
+
+	if (!ECORE_IS_CMT(p_dev))
+		goto out;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto out;
+
+	switch (eng) {
+	case ECORE_ENG0:
+		eng_sel = 0;
+		break;
+	case ECORE_ENG1:
+		eng_sel = 1;
+		break;
+	case ECORE_BOTH_ENG:
+		eng_sel = 2;
+		break;
+	default:
+		DP_NOTICE(p_dev, false,
+			  "Invalid affinity value for ppfid [%d]\n", eng);
+		rc = ECORE_INVAL;
+		goto out;
+	}
+
+	addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
+	val = ecore_rd(p_hwfn, p_ptt, addr);
+	SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_NON_ROCE, eng_sel);
+	ecore_wr(p_hwfn, p_ptt, addr, val);
+
+	/* The iWARP affinity is set as the affinity of ppfid 0 */
+	if (!ppfid && ECORE_IS_IWARP_PERSONALITY(p_hwfn))
+		p_dev->iwarp_affin = (eng == ECORE_ENG1) ? 1 : 0;
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+
+	return rc;
+}
+
+enum _ecore_status_t ecore_llh_set_roce_affinity(struct ecore_dev *p_dev,
+						 enum ecore_eng eng)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	u32 addr, val, eng_sel;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+	u8 ppfid, abs_ppfid;
+
+	if (p_ptt == OSAL_NULL)
+		return ECORE_AGAIN;
+
+	if (!ECORE_IS_CMT(p_dev))
+		goto out;
+
+	switch (eng) {
+	case ECORE_ENG0:
+		eng_sel = 0;
+		break;
+	case ECORE_ENG1:
+		eng_sel = 1;
+		break;
+	case ECORE_BOTH_ENG:
+		eng_sel = 2;
+		ecore_wr(p_hwfn, p_ptt, NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL,
+			 0xf /* QP bit 15 */);
+		break;
+	default:
+		DP_NOTICE(p_dev, false,
+			  "Invalid affinity value for RoCE [%d]\n", eng);
+		rc = ECORE_INVAL;
+		goto out;
+	}
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+		rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+		if (rc != ECORE_SUCCESS)
+			goto out;
+
+		addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
+		val = ecore_rd(p_hwfn, p_ptt, addr);
+		SET_FIELD(val, NIG_REG_PPF_TO_ENGINE_SEL_ROCE, eng_sel);
+		ecore_wr(p_hwfn, p_ptt, addr, val);
+	}
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+
+	return rc;
+}
+
+struct ecore_llh_filter_e4_details {
+	u64 value;
+	u32 mode;
+	u32 protocol_type;
+	u32 hdr_sel;
+	u32 enable;
+};
+
+static enum _ecore_status_t
+ecore_llh_access_filter_e4(struct ecore_hwfn *p_hwfn,
+			   struct ecore_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx,
+			   struct ecore_llh_filter_e4_details *p_details,
+			   bool b_write_access)
+{
+	u8 pfid = ECORE_PFID_BY_PPFID(p_hwfn, abs_ppfid);
+	struct ecore_dmae_params params;
+	enum _ecore_status_t rc;
+	u32 addr;
+
+	/* The NIG/LLH registers that are accessed in this function have only 16
+	 * rows which are exposed to a PF. I.e. only the 16 filters of its
+	 * default ppfid
+	 * Accessing filters of other ppfids requires pretending to other PFs,
+	 * and thus the usage of the ecore_ppfid_rd/wr() functions.
+	 */
+
+	/* Filter enable - should be done first when removing a filter */
+	if (b_write_access && !p_details->enable) {
+		addr = NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 + filter_idx * 0x4;
+		ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr,
+			       p_details->enable);
+	}
+
+	/* Filter value */
+	addr = NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 + 2 * filter_idx * 0x4;
+	OSAL_MEMSET(&params, 0, sizeof(params));
+
+	if (b_write_access) {
+		params.flags = ECORE_DMAE_FLAG_PF_DST;
+		params.dst_pfid = pfid;
+		rc = ecore_dmae_host2grc(p_hwfn, p_ptt,
+					 (u64)(osal_uintptr_t)&p_details->value,
+					 addr, 2 /* size_in_dwords */, &params);
+	} else {
+		params.flags = ECORE_DMAE_FLAG_PF_SRC |
+			       ECORE_DMAE_FLAG_COMPLETION_DST;
+		params.src_pfid = pfid;
+		rc = ecore_dmae_grc2host(p_hwfn, p_ptt, addr,
+					 (u64)(osal_uintptr_t)&p_details->value,
+					 2 /* size_in_dwords */, &params);
+	}
+
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	/* Filter mode */
+	addr = NIG_REG_LLH_FUNC_FILTER_MODE_BB_K2 + filter_idx * 0x4;
+	if (b_write_access)
+		ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr, p_details->mode);
+	else
+		p_details->mode = ecore_ppfid_rd(p_hwfn, p_ptt, abs_ppfid,
+						 addr);
+
+	/* Filter protocol type */
+	addr = NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_BB_K2 + filter_idx * 0x4;
+	if (b_write_access)
+		ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr,
+			       p_details->protocol_type);
+	else
+		p_details->protocol_type = ecore_ppfid_rd(p_hwfn, p_ptt,
+							  abs_ppfid, addr);
+
+	/* Filter header select */
+	addr = NIG_REG_LLH_FUNC_FILTER_HDR_SEL_BB_K2 + filter_idx * 0x4;
+	if (b_write_access)
+		ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr,
+			       p_details->hdr_sel);
+	else
+		p_details->hdr_sel = ecore_ppfid_rd(p_hwfn, p_ptt, abs_ppfid,
+						    addr);
+
+	/* Filter enable - should be done last when adding a filter */
+	if (!b_write_access || p_details->enable) {
+		addr = NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 + filter_idx * 0x4;
+		if (b_write_access)
+			ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr,
+				       p_details->enable);
+		else
+			p_details->enable = ecore_ppfid_rd(p_hwfn, p_ptt,
+							   abs_ppfid, addr);
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_add_filter_e4(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+			u8 abs_ppfid, u8 filter_idx, u8 filter_prot_type,
+			u32 high, u32 low)
+{
+	struct ecore_llh_filter_e4_details filter_details;
+
+	filter_details.enable = 1;
+	filter_details.value = ((u64)high << 32) | low;
+	filter_details.hdr_sel =
+		OSAL_TEST_BIT(ECORE_MF_OVLAN_CLSS, &p_hwfn->p_dev->mf_bits) ?
+		1 : /* inner/encapsulated header */
+		0;  /* outer/tunnel header */
+	filter_details.protocol_type = filter_prot_type;
+	filter_details.mode = filter_prot_type ?
+			      1 : /* protocol-based classification */
+			      0;  /* MAC-address based classification */
+
+	return ecore_llh_access_filter_e4(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+					  &filter_details,
+					  true /* write access */);
+}
+
+static enum _ecore_status_t
+ecore_llh_remove_filter_e4(struct ecore_hwfn *p_hwfn,
+			   struct ecore_ptt *p_ptt, u8 abs_ppfid, u8 filter_idx)
+{
+	struct ecore_llh_filter_e4_details filter_details;
+
+	OSAL_MEMSET(&filter_details, 0, sizeof(filter_details));
+
+	return ecore_llh_access_filter_e4(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+					  &filter_details,
+					  true /* write access */);
+}
+
+static enum _ecore_status_t
+ecore_llh_add_filter(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		     u8 abs_ppfid, u8 filter_idx, u8 filter_prot_type, u32 high,
+		     u32 low)
+{
+	return ecore_llh_add_filter_e4(p_hwfn, p_ptt, abs_ppfid,
+				       filter_idx, filter_prot_type,
+				       high, low);
+}
+
+static enum _ecore_status_t
+ecore_llh_remove_filter(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+			u8 abs_ppfid, u8 filter_idx)
+{
+	return ecore_llh_remove_filter_e4(p_hwfn, p_ptt, abs_ppfid,
+					  filter_idx);
+}
+
+enum _ecore_status_t ecore_llh_add_mac_filter(struct ecore_dev *p_dev, u8 ppfid,
+					      u8 mac_addr[ETH_ALEN])
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	union ecore_llh_filter filter;
+	u8 filter_idx, abs_ppfid;
+	u32 high, low, ref_cnt;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+
+	if (p_ptt == OSAL_NULL)
+		return ECORE_AGAIN;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits))
+		goto out;
+
+	OSAL_MEM_ZERO(&filter, sizeof(filter));
+	OSAL_MEMCPY(filter.mac.addr, mac_addr, ETH_ALEN);
+	rc = ecore_llh_shadow_add_filter(p_dev, ppfid,
+					 ECORE_LLH_FILTER_TYPE_MAC,
+					 &filter, &filter_idx, &ref_cnt);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	/* Configure the LLH only in case of a new the filter */
+	if (ref_cnt == 1) {
+		high = mac_addr[1] | (mac_addr[0] << 8);
+		low = mac_addr[5] | (mac_addr[4] << 8) | (mac_addr[3] << 16) |
+		      (mac_addr[2] << 24);
+		rc = ecore_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+					  0, high, low);
+		if (rc != ECORE_SUCCESS)
+			goto err;
+	}
+
+	DP_VERBOSE(p_dev, ECORE_MSG_SP,
+		   "LLH: Added MAC filter [%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+		   mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		   mac_addr[4], mac_addr[5], ppfid, abs_ppfid, filter_idx,
+		   ref_cnt);
+
+	goto out;
+
+err:
+	DP_NOTICE(p_dev, false,
+		  "LLH: Failed to add MAC filter [%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx] to ppfid %hhd\n",
+		  mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		  mac_addr[4], mac_addr[5], ppfid);
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+
+	return rc;
+}
+
+static enum _ecore_status_t
+ecore_llh_protocol_filter_stringify(struct ecore_dev *p_dev,
+				    enum ecore_llh_prot_filter_type_t type,
+				    u16 source_port_or_eth_type, u16 dest_port,
+				    char *str, osal_size_t str_len)
+{
+	switch (type) {
+	case ECORE_LLH_FILTER_ETHERTYPE:
+		OSAL_SNPRINTF(str, str_len, "Ethertype 0x%04x",
+			      source_port_or_eth_type);
+		break;
+	case ECORE_LLH_FILTER_TCP_SRC_PORT:
+		OSAL_SNPRINTF(str, str_len, "TCP src port 0x%04x",
+			      source_port_or_eth_type);
+		break;
+	case ECORE_LLH_FILTER_UDP_SRC_PORT:
+		OSAL_SNPRINTF(str, str_len, "UDP src port 0x%04x",
+			      source_port_or_eth_type);
+		break;
+	case ECORE_LLH_FILTER_TCP_DEST_PORT:
+		OSAL_SNPRINTF(str, str_len, "TCP dst port 0x%04x", dest_port);
+		break;
+	case ECORE_LLH_FILTER_UDP_DEST_PORT:
+		OSAL_SNPRINTF(str, str_len, "UDP dst port 0x%04x", dest_port);
+		break;
+	case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
+		OSAL_SNPRINTF(str, str_len, "TCP src/dst ports 0x%04x/0x%04x",
+			      source_port_or_eth_type, dest_port);
+		break;
+	case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
+		OSAL_SNPRINTF(str, str_len, "UDP src/dst ports 0x%04x/0x%04x",
+			      source_port_or_eth_type, dest_port);
+		break;
+	default:
+		DP_NOTICE(p_dev, true,
+			  "Non valid LLH protocol filter type %d\n", type);
+		return ECORE_INVAL;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_protocol_filter_to_hilo(struct ecore_dev *p_dev,
+				  enum ecore_llh_prot_filter_type_t type,
+				  u16 source_port_or_eth_type, u16 dest_port,
+				  u32 *p_high, u32 *p_low)
+{
+	*p_high = 0;
+	*p_low = 0;
+
+	switch (type) {
+	case ECORE_LLH_FILTER_ETHERTYPE:
+		*p_high = source_port_or_eth_type;
+		break;
+	case ECORE_LLH_FILTER_TCP_SRC_PORT:
+	case ECORE_LLH_FILTER_UDP_SRC_PORT:
+		*p_low = source_port_or_eth_type << 16;
+		break;
+	case ECORE_LLH_FILTER_TCP_DEST_PORT:
+	case ECORE_LLH_FILTER_UDP_DEST_PORT:
+		*p_low = dest_port;
+		break;
+	case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
+	case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
+		*p_low = (source_port_or_eth_type << 16) | dest_port;
+		break;
+	default:
+		DP_NOTICE(p_dev, true,
+			  "Non valid LLH protocol filter type %d\n", type);
+		return ECORE_INVAL;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+enum _ecore_status_t
+ecore_llh_add_protocol_filter(struct ecore_dev *p_dev, u8 ppfid,
+			      enum ecore_llh_prot_filter_type_t type,
+			      u16 source_port_or_eth_type, u16 dest_port)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	u8 filter_idx, abs_ppfid, type_bitmap;
+	char str[32];
+	union ecore_llh_filter filter;
+	u32 high, low, ref_cnt;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+
+	if (p_ptt == OSAL_NULL)
+		return ECORE_AGAIN;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS, &p_dev->mf_bits))
+		goto out;
+
+	rc = ecore_llh_protocol_filter_stringify(p_dev, type,
+						 source_port_or_eth_type,
+						 dest_port, str, sizeof(str));
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	OSAL_MEM_ZERO(&filter, sizeof(filter));
+	filter.protocol.type = type;
+	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
+	filter.protocol.dest_port = dest_port;
+	rc = ecore_llh_shadow_add_filter(p_dev, ppfid,
+					 ECORE_LLH_FILTER_TYPE_PROTOCOL,
+					 &filter, &filter_idx, &ref_cnt);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	/* Configure the LLH only in case of a new the filter */
+	if (ref_cnt == 1) {
+		rc = ecore_llh_protocol_filter_to_hilo(p_dev, type,
+						       source_port_or_eth_type,
+						       dest_port, &high, &low);
+		if (rc != ECORE_SUCCESS)
+			goto err;
+
+		type_bitmap = 0x1 << type;
+		rc = ecore_llh_add_filter(p_hwfn, p_ptt, abs_ppfid, filter_idx,
+					  type_bitmap, high, low);
+		if (rc != ECORE_SUCCESS)
+			goto err;
+	}
+
+	DP_VERBOSE(p_dev, ECORE_MSG_SP,
+		   "LLH: Added protocol filter [%s] to ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+	goto out;
+
+err:
+	DP_NOTICE(p_hwfn, false,
+		  "LLH: Failed to add protocol filter [%s] to ppfid %hhd\n",
+		  str, ppfid);
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+
+	return rc;
+}
+
+void ecore_llh_remove_mac_filter(struct ecore_dev *p_dev, u8 ppfid,
+				 u8 mac_addr[ETH_ALEN])
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	union ecore_llh_filter filter;
+	u8 filter_idx, abs_ppfid;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+	u32 ref_cnt;
+
+	if (p_ptt == OSAL_NULL)
+		return;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits))
+		goto out;
+
+	OSAL_MEM_ZERO(&filter, sizeof(filter));
+	OSAL_MEMCPY(filter.mac.addr, mac_addr, ETH_ALEN);
+	rc = ecore_llh_shadow_remove_filter(p_dev, ppfid, &filter, &filter_idx,
+					    &ref_cnt);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	/* Remove from the LLH in case the filter is not in use */
+	if (!ref_cnt) {
+		rc = ecore_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
+					     filter_idx);
+		if (rc != ECORE_SUCCESS)
+			goto err;
+	}
+
+	DP_VERBOSE(p_dev, ECORE_MSG_SP,
+		   "LLH: Removed MAC filter [%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+		   mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		   mac_addr[4], mac_addr[5], ppfid, abs_ppfid, filter_idx,
+		   ref_cnt);
+
+	goto out;
+
+err:
+	DP_NOTICE(p_dev, false,
+		  "LLH: Failed to remove MAC filter [%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx] from ppfid %hhd\n",
+		  mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3],
+		  mac_addr[4], mac_addr[5], ppfid);
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+}
+
+void ecore_llh_remove_protocol_filter(struct ecore_dev *p_dev, u8 ppfid,
+				      enum ecore_llh_prot_filter_type_t type,
+				      u16 source_port_or_eth_type,
+				      u16 dest_port)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	u8 filter_idx, abs_ppfid;
+	char str[32];
+	union ecore_llh_filter filter;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+	u32 ref_cnt;
+
+	if (p_ptt == OSAL_NULL)
+		return;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS, &p_dev->mf_bits))
+		goto out;
+
+	rc = ecore_llh_protocol_filter_stringify(p_dev, type,
+						 source_port_or_eth_type,
+						 dest_port, str, sizeof(str));
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	OSAL_MEM_ZERO(&filter, sizeof(filter));
+	filter.protocol.type = type;
+	filter.protocol.source_port_or_eth_type = source_port_or_eth_type;
+	filter.protocol.dest_port = dest_port;
+	rc = ecore_llh_shadow_remove_filter(p_dev, ppfid, &filter, &filter_idx,
+					    &ref_cnt);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto err;
+
+	/* Remove from the LLH in case the filter is not in use */
+	if (!ref_cnt) {
+		rc = ecore_llh_remove_filter(p_hwfn, p_ptt, abs_ppfid,
+					     filter_idx);
+		if (rc != ECORE_SUCCESS)
+			goto err;
+	}
+
+	DP_VERBOSE(p_dev, ECORE_MSG_SP,
+		   "LLH: Removed protocol filter [%s] from ppfid %hhd [abs %hhd] at idx %hhd [ref_cnt %d]\n",
+		   str, ppfid, abs_ppfid, filter_idx, ref_cnt);
+
+	goto out;
+
+err:
+	DP_NOTICE(p_dev, false,
+		  "LLH: Failed to remove protocol filter [%s] from ppfid %hhd\n",
+		  str, ppfid);
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+}
+
+void ecore_llh_clear_ppfid_filters(struct ecore_dev *p_dev, u8 ppfid)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	u8 filter_idx, abs_ppfid;
+	enum _ecore_status_t rc = ECORE_SUCCESS;
+
+	if (p_ptt == OSAL_NULL)
+		return;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS, &p_dev->mf_bits) &&
+	    !OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits))
+		goto out;
+
+	rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto out;
+
+	rc = ecore_llh_shadow_remove_all_filters(p_dev, ppfid);
+	if (rc != ECORE_SUCCESS)
+		goto out;
+
+	for (filter_idx = 0; filter_idx < NIG_REG_LLH_FUNC_FILTER_EN_SIZE;
+	     filter_idx++) {
+		rc = ecore_llh_remove_filter_e4(p_hwfn, p_ptt,
+						abs_ppfid, filter_idx);
+		if (rc != ECORE_SUCCESS)
+			goto out;
+	}
+out:
+	ecore_ptt_release(p_hwfn, p_ptt);
+}
+
+void ecore_llh_clear_all_filters(struct ecore_dev *p_dev)
+{
+	u8 ppfid;
+
+	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS, &p_dev->mf_bits) &&
+	    !OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits))
+		return;
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++)
+		ecore_llh_clear_ppfid_filters(p_dev, ppfid);
+}
+
+enum _ecore_status_t ecore_all_ppfids_wr(struct ecore_hwfn *p_hwfn,
+					 struct ecore_ptt *p_ptt, u32 addr,
+					 u32 val)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	u8 ppfid, abs_ppfid;
+	enum _ecore_status_t rc;
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+		rc = ecore_abs_ppfid(p_dev, ppfid, &abs_ppfid);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+
+		ecore_ppfid_wr(p_hwfn, p_ptt, abs_ppfid, addr, val);
+	}
+
+	return ECORE_SUCCESS;
+}
+
+static enum _ecore_status_t
+ecore_llh_dump_ppfid_e4(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+			u8 ppfid)
+{
+	struct ecore_llh_filter_e4_details filter_details;
+	u8 abs_ppfid, filter_idx;
+	u32 addr;
+	enum _ecore_status_t rc;
+
+	rc = ecore_abs_ppfid(p_hwfn->p_dev, ppfid, &abs_ppfid);
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	addr = NIG_REG_PPF_TO_ENGINE_SEL + abs_ppfid * 0x4;
+	DP_NOTICE(p_hwfn, false,
+		  "[rel_pf_id %hhd, ppfid={rel %hhd, abs %hhd}, engine_sel 0x%x]\n",
+		  p_hwfn->rel_pf_id, ppfid, abs_ppfid,
+		  ecore_rd(p_hwfn, p_ptt, addr));
+
+	for (filter_idx = 0; filter_idx < NIG_REG_LLH_FUNC_FILTER_EN_SIZE;
+	     filter_idx++) {
+		OSAL_MEMSET(&filter_details, 0, sizeof(filter_details));
+		rc =  ecore_llh_access_filter_e4(p_hwfn, p_ptt, abs_ppfid,
+						 filter_idx, &filter_details,
+						 false /* read access */);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+
+		DP_NOTICE(p_hwfn, false,
+			  "filter %2hhd: enable %d, value 0x%016lx, mode %d, protocol_type 0x%x, hdr_sel 0x%x\n",
+			  filter_idx, filter_details.enable,
+			  (unsigned long)filter_details.value,
+			  filter_details.mode,
+			  filter_details.protocol_type, filter_details.hdr_sel);
+	}
+
+	return ECORE_SUCCESS;
+}
+
+enum _ecore_status_t ecore_llh_dump_ppfid(struct ecore_dev *p_dev, u8 ppfid)
+{
+	struct ecore_hwfn *p_hwfn = ECORE_LEADING_HWFN(p_dev);
+	struct ecore_ptt *p_ptt = ecore_ptt_acquire(p_hwfn);
+	enum _ecore_status_t rc;
+
+	if (p_ptt == OSAL_NULL)
+		return ECORE_AGAIN;
+
+	rc = ecore_llh_dump_ppfid_e4(p_hwfn, p_ptt, ppfid);
+
+	ecore_ptt_release(p_hwfn, p_ptt);
+
+	return rc;
+}
+
+enum _ecore_status_t ecore_llh_dump_all(struct ecore_dev *p_dev)
+{
+	u8 ppfid;
+	enum _ecore_status_t rc;
+
+	for (ppfid = 0; ppfid < p_dev->p_llh_info->num_ppfid; ppfid++) {
+		rc = ecore_llh_dump_ppfid(p_dev, ppfid);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+	}
+
+	return ECORE_SUCCESS;
+}
+
+/******************************* NIG LLH - End ********************************/
+
 /* Configurable */
 #define ECORE_MIN_DPIS		(4)	/* The minimal num of DPIs required to
 					 * load the driver. The number was
@@ -476,6 +1659,8 @@ void ecore_resc_free(struct ecore_dev *p_dev)
 
 	OSAL_FREE(p_dev, p_dev->reset_stats);
 
+	ecore_llh_free(p_dev);
+
 	for_each_hwfn(p_dev, i) {
 		struct ecore_hwfn *p_hwfn = &p_dev->hwfns[i];
 
@@ -1349,6 +2534,13 @@ enum _ecore_status_t ecore_resc_alloc(struct ecore_dev *p_dev)
 		}
 	} /* hwfn loop */
 
+	rc = ecore_llh_alloc(p_dev);
+	if (rc != ECORE_SUCCESS) {
+		DP_NOTICE(p_dev, true,
+			  "Failed to allocate memory for the llh_info structure\n");
+		goto alloc_err;
+	}
+
 	p_dev->reset_stats = OSAL_ZALLOC(p_dev, GFP_KERNEL,
 					 sizeof(*p_dev->reset_stats));
 	if (!p_dev->reset_stats) {
@@ -1489,8 +2681,7 @@ static enum _ecore_status_t ecore_calc_hw_mode(struct ecore_hwfn *p_hwfn)
 		return ECORE_INVAL;
 	}
 
-	if (OSAL_TEST_BIT(ECORE_MF_OVLAN_CLSS,
-			  &p_hwfn->p_dev->mf_bits))
+	if (OSAL_TEST_BIT(ECORE_MF_OVLAN_CLSS, &p_hwfn->p_dev->mf_bits))
 		hw_mode |= 1 << MODE_MF_SD;
 	else
 		hw_mode |= 1 << MODE_MF_SI;
@@ -2094,17 +3285,7 @@ static enum _ecore_status_t ecore_hw_init_port(struct ecore_hwfn *p_hwfn,
 					       struct ecore_ptt *p_ptt,
 					       int hw_mode)
 {
-	u32 ppf_to_eng_sel[NIG_REG_PPF_TO_ENGINE_SEL_RT_SIZE];
-	u32 val;
 	enum _ecore_status_t rc	= ECORE_SUCCESS;
-	u8 i;
-
-	/* In CMT for non-RoCE packets - use connection based classification */
-	val = ECORE_IS_CMT(p_hwfn->p_dev) ? 0x8 : 0x0;
-	for (i = 0; i < NIG_REG_PPF_TO_ENGINE_SEL_RT_SIZE; i++)
-		ppf_to_eng_sel[i] = val;
-	STORE_RT_REG_AGG(p_hwfn, NIG_REG_PPF_TO_ENGINE_SEL_RT_OFFSET,
-			 ppf_to_eng_sel);
 
 	/* In CMT the gate should be cleared by the 2nd hwfn */
 	if (!ECORE_IS_CMT(p_hwfn->p_dev) || !IS_LEAD_HWFN(p_hwfn))
@@ -2156,12 +3337,8 @@ static enum _ecore_status_t ecore_hw_init_port(struct ecore_hwfn *p_hwfn,
 }
 
 static enum _ecore_status_t
-ecore_hw_init_pf(struct ecore_hwfn *p_hwfn,
-		 struct ecore_ptt *p_ptt,
-		 struct ecore_tunnel_info *p_tunn,
-		 int hw_mode,
-		 bool b_hw_start,
-		 enum ecore_int_mode int_mode, bool allow_npar_tx_switch)
+ecore_hw_init_pf(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		 int hw_mode, struct ecore_hw_init_params *p_params)
 {
 	u8 rel_pf_id = p_hwfn->rel_pf_id;
 	u32 prs_reg;
@@ -2249,17 +3426,18 @@ static enum _ecore_status_t ecore_hw_init_port(struct ecore_hwfn *p_hwfn,
 	*/
 
 	rc = ecore_hw_init_pf_doorbell_bar(p_hwfn, p_ptt);
-	if (rc)
+	if (rc != ECORE_SUCCESS)
 		return rc;
-	if (b_hw_start) {
+
+	if (p_params->b_hw_start) {
 		/* enable interrupts */
-		rc = ecore_int_igu_enable(p_hwfn, p_ptt, int_mode);
+		rc = ecore_int_igu_enable(p_hwfn, p_ptt, p_params->int_mode);
 		if (rc != ECORE_SUCCESS)
 			return rc;
 
 		/* send function start command */
-		rc = ecore_sp_pf_start(p_hwfn, p_ptt, p_tunn,
-				       allow_npar_tx_switch);
+		rc = ecore_sp_pf_start(p_hwfn, p_ptt, p_params->p_tunn,
+				       p_params->allow_npar_tx_switch);
 		if (rc) {
 			DP_NOTICE(p_hwfn, true,
 				  "Function start ramrod failed\n");
@@ -2583,11 +3761,8 @@ enum _ecore_status_t ecore_hw_init(struct ecore_dev *p_dev,
 			/* Fall into */
 		case FW_MSG_CODE_DRV_LOAD_FUNCTION:
 			rc = ecore_hw_init_pf(p_hwfn, p_hwfn->p_main_ptt,
-					      p_params->p_tunn,
 					      p_hwfn->hw_info.hw_mode,
-					      p_params->b_hw_start,
-					      p_params->int_mode,
-					      p_params->allow_npar_tx_switch);
+					      p_params);
 			break;
 		default:
 			DP_NOTICE(p_hwfn, false,
@@ -2859,6 +4034,12 @@ enum _ecore_status_t ecore_hw_stop(struct ecore_dev *p_dev)
 		/* Need to wait 1ms to guarantee SBs are cleared */
 		OSAL_MSLEEP(1);
 
+		if (IS_LEAD_HWFN(p_hwfn) &&
+		    OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS, &p_dev->mf_bits) &&
+		    !ECORE_IS_FCOE_PERSONALITY(p_hwfn))
+			ecore_llh_remove_mac_filter(p_dev, 0,
+						   p_hwfn->hw_info.hw_mac_addr);
+
 		if (!p_dev->recov_in_prog) {
 			ecore_verify_reg_val(p_hwfn, p_ptt,
 					     QM_REG_USG_CNT_PF_TX, 0);
@@ -3372,6 +4553,59 @@ static enum _ecore_status_t ecore_hw_set_resc_info(struct ecore_hwfn *p_hwfn,
 	return ECORE_SUCCESS;
 }
 
+#define ECORE_NONUSED_PPFID_MASK_BB_4P_LO_PORTS	0xaa
+#define ECORE_NONUSED_PPFID_MASK_BB_4P_HI_PORTS	0x55
+#define ECORE_NONUSED_PPFID_MASK_AH_4P		0xf0
+
+static enum _ecore_status_t ecore_hw_get_ppfid_bitmap(struct ecore_hwfn *p_hwfn,
+						      struct ecore_ptt *p_ptt)
+{
+	u8 native_ppfid_idx = ECORE_PPFID_BY_PFID(p_hwfn), new_bitmap;
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	enum _ecore_status_t rc;
+
+	rc = ecore_mcp_get_ppfid_bitmap(p_hwfn, p_ptt);
+	if (rc != ECORE_SUCCESS && rc != ECORE_NOTIMPL)
+		return rc;
+	else if (rc == ECORE_NOTIMPL)
+		p_dev->ppfid_bitmap = 0x1 << native_ppfid_idx;
+
+	/* 4-ports mode has limitations that should be enforced:
+	 * - BB: the MFW can access only PPFIDs which their corresponding PFIDs
+	 *       belong to this certain port.
+	 * - AH/E5: only 4 PPFIDs per port are available.
+	 */
+	if (ecore_device_num_ports(p_dev) == 4) {
+		u8 mask;
+
+		if (ECORE_IS_BB(p_dev))
+			mask = MFW_PORT(p_hwfn) > 1 ?
+			       ECORE_NONUSED_PPFID_MASK_BB_4P_HI_PORTS :
+			       ECORE_NONUSED_PPFID_MASK_BB_4P_LO_PORTS;
+		else
+			mask = ECORE_NONUSED_PPFID_MASK_AH_4P;
+
+		if (p_dev->ppfid_bitmap & mask) {
+			new_bitmap = p_dev->ppfid_bitmap & ~mask;
+			DP_INFO(p_hwfn,
+				"Fix the PPFID bitmap for 4-ports mode: 0x%hhx -> 0x%hhx\n",
+				p_dev->ppfid_bitmap, new_bitmap);
+			p_dev->ppfid_bitmap = new_bitmap;
+		}
+	}
+
+	/* The native PPFID is expected to be part of the allocated bitmap */
+	if (!(p_dev->ppfid_bitmap & (0x1 << native_ppfid_idx))) {
+		new_bitmap = 0x1 << native_ppfid_idx;
+		DP_INFO(p_hwfn,
+			"Fix the PPFID bitmap to inculde the native PPFID: %hhd -> 0x%hhx\n",
+			p_dev->ppfid_bitmap, new_bitmap);
+		p_dev->ppfid_bitmap = new_bitmap;
+	}
+
+	return ECORE_SUCCESS;
+}
+
 static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn,
 					      struct ecore_ptt *p_ptt,
 					      bool drv_resc_alloc)
@@ -3446,6 +4680,13 @@ static enum _ecore_status_t ecore_hw_get_resc(struct ecore_hwfn *p_hwfn,
 				"Failed to release the resource lock for the resource allocation commands\n");
 	}
 
+	/* PPFID bitmap */
+	if (IS_LEAD_HWFN(p_hwfn)) {
+		rc = ecore_hw_get_ppfid_bitmap(p_hwfn, p_ptt);
+		if (rc != ECORE_SUCCESS)
+			return rc;
+	}
+
 #ifndef ASIC_ONLY
 	if (CHIP_REV_IS_SLOW(p_hwfn->p_dev)) {
 		/* Reduced build contains less PQs */
@@ -4236,9 +5477,8 @@ void ecore_prepare_hibernate(struct ecore_dev *p_dev)
 #endif
 
 static enum _ecore_status_t
-ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn,
-			void OSAL_IOMEM * p_regview,
-			void OSAL_IOMEM * p_doorbells,
+ecore_hw_prepare_single(struct ecore_hwfn *p_hwfn, void OSAL_IOMEM *p_regview,
+			void OSAL_IOMEM *p_doorbells, u64 db_phys_addr,
 			struct ecore_hw_prepare_params *p_params)
 {
 	struct ecore_mdump_retain_data mdump_retain;
@@ -4249,6 +5489,7 @@ void ecore_prepare_hibernate(struct ecore_dev *p_dev)
 	/* Split PCI bars evenly between hwfns */
 	p_hwfn->regview = p_regview;
 	p_hwfn->doorbells = p_doorbells;
+	p_hwfn->db_phys_addr = db_phys_addr;
 
 	if (IS_VF(p_dev))
 		return ecore_vf_hw_prepare(p_hwfn);
@@ -4401,9 +5642,9 @@ enum _ecore_status_t ecore_hw_prepare(struct ecore_dev *p_dev,
 		ecore_init_iro_array(p_dev);
 
 	/* Initialize the first hwfn - will learn number of hwfns */
-	rc = ecore_hw_prepare_single(p_hwfn,
-				     p_dev->regview,
-				     p_dev->doorbells, p_params);
+	rc = ecore_hw_prepare_single(p_hwfn, p_dev->regview,
+				     p_dev->doorbells, p_dev->db_phys_addr,
+				     p_params);
 	if (rc != ECORE_SUCCESS)
 		return rc;
 
@@ -4413,24 +5654,26 @@ enum _ecore_status_t ecore_hw_prepare(struct ecore_dev *p_dev,
 	if (ECORE_IS_CMT(p_dev)) {
 		void OSAL_IOMEM *p_regview, *p_doorbell;
 		u8 OSAL_IOMEM *addr;
+		u64 db_phys_addr;
+		u32 offset;
 
 		/* adjust bar offset for second engine */
-		addr = (u8 OSAL_IOMEM *)p_dev->regview +
-					ecore_hw_bar_size(p_hwfn,
-							  p_hwfn->p_main_ptt,
-							  BAR_ID_0) / 2;
+		offset = ecore_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+					   BAR_ID_0) / 2;
+		addr = (u8 OSAL_IOMEM *)p_dev->regview + offset;
 		p_regview = (void OSAL_IOMEM *)addr;
 
-		addr = (u8 OSAL_IOMEM *)p_dev->doorbells +
-					ecore_hw_bar_size(p_hwfn,
-							  p_hwfn->p_main_ptt,
-							  BAR_ID_1) / 2;
+		offset = ecore_hw_bar_size(p_hwfn, p_hwfn->p_main_ptt,
+					   BAR_ID_1) / 2;
+		addr = (u8 OSAL_IOMEM *)p_dev->doorbells + offset;
 		p_doorbell = (void OSAL_IOMEM *)addr;
+		db_phys_addr = p_dev->db_phys_addr + offset;
 
 		p_dev->hwfns[1].b_en_pacing = p_params->b_en_pacing;
 		/* prepare second hw function */
 		rc = ecore_hw_prepare_single(&p_dev->hwfns[1], p_regview,
-					     p_doorbell, p_params);
+					     p_doorbell, db_phys_addr,
+					     p_params);
 
 		/* in case of error, need to free the previously
 		 * initiliazed hwfn 0.
@@ -4827,419 +6070,6 @@ enum _ecore_status_t ecore_fw_rss_eng(struct ecore_hwfn *p_hwfn,
 	return ECORE_SUCCESS;
 }
 
-static enum _ecore_status_t
-ecore_llh_add_mac_filter_bb_ah(struct ecore_hwfn *p_hwfn,
-			       struct ecore_ptt *p_ptt, u32 high, u32 low,
-			       u32 *p_entry_num)
-{
-	u32 en;
-	int i;
-
-	/* Find a free entry and utilize it */
-	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
-		en = ecore_rd(p_hwfn, p_ptt,
-			      NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 +
-			      i * sizeof(u32));
-		if (en)
-			continue;
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 2 * i * sizeof(u32), low);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 (2 * i + 1) * sizeof(u32), high);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_MODE_BB_K2 +
-			 i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_BB_K2 +
-			 i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 +
-			 i * sizeof(u32), 1);
-		break;
-	}
-
-	if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
-		return ECORE_NORESOURCES;
-
-	*p_entry_num = i;
-
-	return ECORE_SUCCESS;
-}
-
-enum _ecore_status_t ecore_llh_add_mac_filter(struct ecore_hwfn *p_hwfn,
-					  struct ecore_ptt *p_ptt, u8 *p_filter)
-{
-	u32 high, low, entry_num;
-	enum _ecore_status_t rc = ECORE_SUCCESS;
-
-	if (!OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS,
-			   &p_hwfn->p_dev->mf_bits))
-		return ECORE_SUCCESS;
-
-	high = p_filter[1] | (p_filter[0] << 8);
-	low = p_filter[5] | (p_filter[4] << 8) |
-	      (p_filter[3] << 16) | (p_filter[2] << 24);
-
-	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev))
-		rc = ecore_llh_add_mac_filter_bb_ah(p_hwfn, p_ptt, high, low,
-						    &entry_num);
-	if (rc != ECORE_SUCCESS) {
-		DP_NOTICE(p_hwfn, false,
-			  "Failed to find an empty LLH filter to utilize\n");
-		return rc;
-	}
-
-	DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-		   "MAC: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx is added at %d\n",
-		   p_filter[0], p_filter[1], p_filter[2], p_filter[3],
-		   p_filter[4], p_filter[5], entry_num);
-
-	return rc;
-}
-
-static enum _ecore_status_t
-ecore_llh_remove_mac_filter_bb_ah(struct ecore_hwfn *p_hwfn,
-				  struct ecore_ptt *p_ptt, u32 high, u32 low,
-				  u32 *p_entry_num)
-{
-	int i;
-
-	/* Find the entry and clean it */
-	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
-		if (ecore_rd(p_hwfn, p_ptt,
-			     NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			     2 * i * sizeof(u32)) != low)
-			continue;
-		if (ecore_rd(p_hwfn, p_ptt,
-			     NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			     (2 * i + 1) * sizeof(u32)) != high)
-			continue;
-
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 + i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 2 * i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 (2 * i + 1) * sizeof(u32), 0);
-		break;
-	}
-
-	if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
-		return ECORE_INVAL;
-
-	*p_entry_num = i;
-
-	return ECORE_SUCCESS;
-}
-
-void ecore_llh_remove_mac_filter(struct ecore_hwfn *p_hwfn,
-			     struct ecore_ptt *p_ptt, u8 *p_filter)
-{
-	u32 high, low, entry_num;
-	enum _ecore_status_t rc = ECORE_SUCCESS;
-
-	if (!OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS,
-			   &p_hwfn->p_dev->mf_bits))
-		return;
-
-	high = p_filter[1] | (p_filter[0] << 8);
-	low = p_filter[5] | (p_filter[4] << 8) |
-	      (p_filter[3] << 16) | (p_filter[2] << 24);
-
-	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev))
-		rc = ecore_llh_remove_mac_filter_bb_ah(p_hwfn, p_ptt, high,
-						       low, &entry_num);
-	if (rc != ECORE_SUCCESS) {
-		DP_NOTICE(p_hwfn, false,
-			  "Tried to remove a non-configured filter\n");
-		return;
-	}
-
-
-	DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-		   "MAC: %02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx was removed from %d\n",
-		   p_filter[0], p_filter[1], p_filter[2], p_filter[3],
-		   p_filter[4], p_filter[5], entry_num);
-}
-
-static enum _ecore_status_t
-ecore_llh_add_protocol_filter_bb_ah(struct ecore_hwfn *p_hwfn,
-				    struct ecore_ptt *p_ptt,
-				    enum ecore_llh_port_filter_type_t type,
-				    u32 high, u32 low, u32 *p_entry_num)
-{
-	u32 en;
-	int i;
-
-	/* Find a free entry and utilize it */
-	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
-		en = ecore_rd(p_hwfn, p_ptt,
-			      NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 +
-			      i * sizeof(u32));
-		if (en)
-			continue;
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 2 * i * sizeof(u32), low);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 (2 * i + 1) * sizeof(u32), high);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_MODE_BB_K2 +
-			 i * sizeof(u32), 1);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_BB_K2 +
-			 i * sizeof(u32), 1 << type);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 + i * sizeof(u32), 1);
-		break;
-	}
-
-	if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
-		return ECORE_NORESOURCES;
-
-	*p_entry_num = i;
-
-	return ECORE_SUCCESS;
-}
-
-enum _ecore_status_t
-ecore_llh_add_protocol_filter(struct ecore_hwfn *p_hwfn,
-			      struct ecore_ptt *p_ptt,
-			      u16 source_port_or_eth_type,
-			      u16 dest_port,
-			      enum ecore_llh_port_filter_type_t type)
-{
-	u32 high, low, entry_num;
-	enum _ecore_status_t rc = ECORE_SUCCESS;
-
-	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS,
-			   &p_hwfn->p_dev->mf_bits))
-		return rc;
-
-	high = 0;
-	low = 0;
-
-	switch (type) {
-	case ECORE_LLH_FILTER_ETHERTYPE:
-		high = source_port_or_eth_type;
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_PORT:
-	case ECORE_LLH_FILTER_UDP_SRC_PORT:
-		low = source_port_or_eth_type << 16;
-		break;
-	case ECORE_LLH_FILTER_TCP_DEST_PORT:
-	case ECORE_LLH_FILTER_UDP_DEST_PORT:
-		low = dest_port;
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
-	case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
-		low = (source_port_or_eth_type << 16) | dest_port;
-		break;
-	default:
-		DP_NOTICE(p_hwfn, true,
-			  "Non valid LLH protocol filter type %d\n", type);
-		return ECORE_INVAL;
-	}
-
-	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev))
-		rc = ecore_llh_add_protocol_filter_bb_ah(p_hwfn, p_ptt, type,
-							 high, low, &entry_num);
-	if (rc != ECORE_SUCCESS) {
-		DP_NOTICE(p_hwfn, false,
-			  "Failed to find an empty LLH filter to utilize\n");
-		return rc;
-	}
-	switch (type) {
-	case ECORE_LLH_FILTER_ETHERTYPE:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "ETH type %x is added at %d\n",
-			   source_port_or_eth_type, entry_num);
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "TCP src port %x is added at %d\n",
-			   source_port_or_eth_type, entry_num);
-		break;
-	case ECORE_LLH_FILTER_UDP_SRC_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "UDP src port %x is added at %d\n",
-			   source_port_or_eth_type, entry_num);
-		break;
-	case ECORE_LLH_FILTER_TCP_DEST_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "TCP dst port %x is added at %d\n", dest_port,
-			   entry_num);
-		break;
-	case ECORE_LLH_FILTER_UDP_DEST_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "UDP dst port %x is added at %d\n", dest_port,
-			   entry_num);
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "TCP src/dst ports %x/%x are added at %d\n",
-			   source_port_or_eth_type, dest_port, entry_num);
-		break;
-	case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
-		DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-			   "UDP src/dst ports %x/%x are added at %d\n",
-			   source_port_or_eth_type, dest_port, entry_num);
-		break;
-	}
-
-	return rc;
-}
-
-static enum _ecore_status_t
-ecore_llh_remove_protocol_filter_bb_ah(struct ecore_hwfn *p_hwfn,
-				       struct ecore_ptt *p_ptt,
-				       enum ecore_llh_port_filter_type_t type,
-				       u32 high, u32 low, u32 *p_entry_num)
-{
-	int i;
-
-	/* Find the entry and clean it */
-	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
-		if (!ecore_rd(p_hwfn, p_ptt,
-			      NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 +
-			      i * sizeof(u32)))
-			continue;
-		if (!ecore_rd(p_hwfn, p_ptt,
-			      NIG_REG_LLH_FUNC_FILTER_MODE_BB_K2 +
-			      i * sizeof(u32)))
-			continue;
-		if (!(ecore_rd(p_hwfn, p_ptt,
-			       NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_BB_K2 +
-			       i * sizeof(u32)) & (1 << type)))
-			continue;
-		if (ecore_rd(p_hwfn, p_ptt,
-			     NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			     2 * i * sizeof(u32)) != low)
-			continue;
-		if (ecore_rd(p_hwfn, p_ptt,
-			     NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			     (2 * i + 1) * sizeof(u32)) != high)
-			continue;
-
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_EN_BB_K2 + i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_MODE_BB_K2 +
-			 i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE_BB_K2 +
-			 i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 2 * i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 (2 * i + 1) * sizeof(u32), 0);
-		break;
-	}
-
-	if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
-		return ECORE_INVAL;
-
-	*p_entry_num = i;
-
-	return ECORE_SUCCESS;
-}
-
-void
-ecore_llh_remove_protocol_filter(struct ecore_hwfn *p_hwfn,
-				 struct ecore_ptt *p_ptt,
-				 u16 source_port_or_eth_type,
-				 u16 dest_port,
-				 enum ecore_llh_port_filter_type_t type)
-{
-	u32 high, low, entry_num;
-	enum _ecore_status_t rc = ECORE_SUCCESS;
-
-	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS,
-			   &p_hwfn->p_dev->mf_bits))
-		return;
-
-	high = 0;
-	low = 0;
-
-	switch (type) {
-	case ECORE_LLH_FILTER_ETHERTYPE:
-		high = source_port_or_eth_type;
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_PORT:
-	case ECORE_LLH_FILTER_UDP_SRC_PORT:
-		low = source_port_or_eth_type << 16;
-		break;
-	case ECORE_LLH_FILTER_TCP_DEST_PORT:
-	case ECORE_LLH_FILTER_UDP_DEST_PORT:
-		low = dest_port;
-		break;
-	case ECORE_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
-	case ECORE_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
-		low = (source_port_or_eth_type << 16) | dest_port;
-		break;
-	default:
-		DP_NOTICE(p_hwfn, true,
-			  "Non valid LLH protocol filter type %d\n", type);
-		return;
-	}
-
-	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev))
-		rc = ecore_llh_remove_protocol_filter_bb_ah(p_hwfn, p_ptt, type,
-							    high, low,
-							    &entry_num);
-	if (rc != ECORE_SUCCESS) {
-		DP_NOTICE(p_hwfn, false,
-			  "Tried to remove a non-configured filter [type %d, source_port_or_eth_type 0x%x, dest_port 0x%x]\n",
-			  type, source_port_or_eth_type, dest_port);
-		return;
-	}
-
-	DP_VERBOSE(p_hwfn, ECORE_MSG_HW,
-		   "Protocol filter [type %d, source_port_or_eth_type 0x%x, dest_port 0x%x] was removed from %d\n",
-		   type, source_port_or_eth_type, dest_port, entry_num);
-}
-
-static void ecore_llh_clear_all_filters_bb_ah(struct ecore_hwfn *p_hwfn,
-					      struct ecore_ptt *p_ptt)
-{
-	int i;
-
-	if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn)))
-		return;
-
-	for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_EN_BB_K2  +
-			 i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 2 * i * sizeof(u32), 0);
-		ecore_wr(p_hwfn, p_ptt,
-			 NIG_REG_LLH_FUNC_FILTER_VALUE_BB_K2 +
-			 (2 * i + 1) * sizeof(u32), 0);
-	}
-}
-
-void ecore_llh_clear_all_filters(struct ecore_hwfn *p_hwfn,
-			     struct ecore_ptt *p_ptt)
-{
-	if (!OSAL_TEST_BIT(ECORE_MF_LLH_PROTO_CLSS,
-			   &p_hwfn->p_dev->mf_bits) &&
-	    !OSAL_TEST_BIT(ECORE_MF_LLH_MAC_CLSS,
-			   &p_hwfn->p_dev->mf_bits))
-		return;
-
-	if (ECORE_IS_BB(p_hwfn->p_dev) || ECORE_IS_AH(p_hwfn->p_dev))
-		ecore_llh_clear_all_filters_bb_ah(p_hwfn, p_ptt);
-}
-
 enum _ecore_status_t
 ecore_llh_set_function_as_default(struct ecore_hwfn *p_hwfn,
 				  struct ecore_ptt *p_ptt)
diff --git a/drivers/net/qede/base/ecore_dev_api.h b/drivers/net/qede/base/ecore_dev_api.h
index ab80b52..7308063 100644
--- a/drivers/net/qede/base/ecore_dev_api.h
+++ b/drivers/net/qede/base/ecore_dev_api.h
@@ -114,6 +114,9 @@ struct ecore_hw_init_params {
 	/* Driver load parameters */
 	struct ecore_drv_load_params *p_drv_load_params;
 
+	/* Avoid engine affinity for RoCE/storage in case of CMT mode */
+	bool avoid_eng_affin;
+
 	/* SPQ block timeout in msec */
 	u32 spq_timeout_ms;
 };
@@ -428,11 +431,17 @@ enum ecore_dmae_address_type_t {
 #define ECORE_DMAE_FLAG_VF_SRC		0x00000002
 #define ECORE_DMAE_FLAG_VF_DST		0x00000004
 #define ECORE_DMAE_FLAG_COMPLETION_DST	0x00000008
+#define ECORE_DMAE_FLAG_PORT		0x00000010
+#define ECORE_DMAE_FLAG_PF_SRC		0x00000020
+#define ECORE_DMAE_FLAG_PF_DST		0x00000040
 
 struct ecore_dmae_params {
 	u32 flags; /* consists of ECORE_DMAE_FLAG_* values */
 	u8 src_vfid;
 	u8 dst_vfid;
+	u8 port_id;
+	u8 src_pfid;
+	u8 dst_pfid;
 };
 
 /**
@@ -444,7 +453,9 @@ struct ecore_dmae_params {
  * @param source_addr
  * @param grc_addr (dmae_data_offset)
  * @param size_in_dwords
- * @param flags (one of the flags defined above)
+ * @param p_params (default parameters will be used in case of OSAL_NULL)
+ *
+ * @return enum _ecore_status_t
  */
 enum _ecore_status_t
 ecore_dmae_host2grc(struct ecore_hwfn *p_hwfn,
@@ -452,7 +463,7 @@ enum _ecore_status_t
 		    u64 source_addr,
 		    u32 grc_addr,
 		    u32 size_in_dwords,
-		    u32 flags);
+		    struct ecore_dmae_params *p_params);
 
 /**
  * @brief ecore_dmae_grc2host - Read data from dmae data offset
@@ -462,7 +473,9 @@ enum _ecore_status_t
  * @param grc_addr (dmae_data_offset)
  * @param dest_addr
  * @param size_in_dwords
- * @param flags - one of the flags defined above
+ * @param p_params (default parameters will be used in case of OSAL_NULL)
+ *
+ * @return enum _ecore_status_t
  */
 enum _ecore_status_t
 ecore_dmae_grc2host(struct ecore_hwfn *p_hwfn,
@@ -470,7 +483,7 @@ enum _ecore_status_t
 		    u32 grc_addr,
 		    dma_addr_t dest_addr,
 		    u32 size_in_dwords,
-		    u32 flags);
+		    struct ecore_dmae_params *p_params);
 
 /**
  * @brief ecore_dmae_host2host - copy data from to source address
@@ -481,7 +494,9 @@ enum _ecore_status_t
  * @param source_addr
  * @param dest_addr
  * @param size_in_dwords
- * @param params
+ * @param p_params (default parameters will be used in case of OSAL_NULL)
+ *
+ * @return enum _ecore_status_t
  */
 enum _ecore_status_t
 ecore_dmae_host2host(struct ecore_hwfn *p_hwfn,
@@ -562,28 +577,79 @@ enum _ecore_status_t ecore_fw_rss_eng(struct ecore_hwfn *p_hwfn,
 				      u8 *dst_id);
 
 /**
- * @brief ecore_llh_add_mac_filter - configures a MAC filter in llh
+ * @brief ecore_llh_get_num_ppfid - Return the allocated number of LLH filter
+ *	banks that are allocated to the PF.
  *
- * @param p_hwfn
- * @param p_ptt
- * @param p_filter - MAC to add
+ * @param p_dev
+ *
+ * @return u8 - Number of LLH filter banks
  */
-enum _ecore_status_t ecore_llh_add_mac_filter(struct ecore_hwfn *p_hwfn,
-					  struct ecore_ptt *p_ptt,
-					  u8 *p_filter);
+u8 ecore_llh_get_num_ppfid(struct ecore_dev *p_dev);
+
+enum ecore_eng {
+	ECORE_ENG0,
+	ECORE_ENG1,
+	ECORE_BOTH_ENG,
+};
 
 /**
- * @brief ecore_llh_remove_mac_filter - removes a MAC filtre from llh
+ * @brief ecore_llh_get_l2_affinity_hint - Return the hint for the L2 affinity
  *
- * @param p_hwfn
- * @param p_ptt
- * @param p_filter - MAC to remove
+ * @param p_dev
+ *
+ * @return enum ecore_eng - L2 affintiy hint
+ */
+enum ecore_eng ecore_llh_get_l2_affinity_hint(struct ecore_dev *p_dev);
+
+/**
+ * @brief ecore_llh_set_ppfid_affinity - Set the engine affinity for the given
+ *	LLH filter bank.
+ *
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param eng
+ *
+ * @return enum _ecore_status_t
  */
-void ecore_llh_remove_mac_filter(struct ecore_hwfn *p_hwfn,
-			     struct ecore_ptt *p_ptt,
-			     u8 *p_filter);
+enum _ecore_status_t ecore_llh_set_ppfid_affinity(struct ecore_dev *p_dev,
+						  u8 ppfid, enum ecore_eng eng);
 
-enum ecore_llh_port_filter_type_t {
+/**
+ * @brief ecore_llh_set_roce_affinity - Set the RoCE engine affinity
+ *
+ * @param p_dev
+ * @param eng
+ *
+ * @return enum _ecore_status_t
+ */
+enum _ecore_status_t ecore_llh_set_roce_affinity(struct ecore_dev *p_dev,
+						 enum ecore_eng eng);
+
+/**
+ * @brief ecore_llh_add_mac_filter - Add a LLH MAC filter into the given filter
+ *	bank.
+ *
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param mac_addr - MAC to add
+ *
+ * @return enum _ecore_status_t
+ */
+enum _ecore_status_t ecore_llh_add_mac_filter(struct ecore_dev *p_dev, u8 ppfid,
+					      u8 mac_addr[ETH_ALEN]);
+
+/**
+ * @brief ecore_llh_remove_mac_filter - Remove a LLH MAC filter from the given
+ *	filter bank.
+ *
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param mac_addr - MAC to remove
+ */
+void ecore_llh_remove_mac_filter(struct ecore_dev *p_dev, u8 ppfid,
+				 u8 mac_addr[ETH_ALEN]);
+
+enum ecore_llh_prot_filter_type_t {
 	ECORE_LLH_FILTER_ETHERTYPE,
 	ECORE_LLH_FILTER_TCP_SRC_PORT,
 	ECORE_LLH_FILTER_TCP_DEST_PORT,
@@ -594,45 +660,52 @@ enum ecore_llh_port_filter_type_t {
 };
 
 /**
- * @brief ecore_llh_add_protocol_filter - configures a protocol filter in llh
+ * @brief ecore_llh_add_protocol_filter - Add a LLH protocol filter into the
+ *	given filter bank.
  *
- * @param p_hwfn
- * @param p_ptt
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param type - type of filters and comparing
  * @param source_port_or_eth_type - source port or ethertype to add
  * @param dest_port - destination port to add
- * @param type - type of filters and comparing
+ *
+ * @return enum _ecore_status_t
  */
 enum _ecore_status_t
-ecore_llh_add_protocol_filter(struct ecore_hwfn *p_hwfn,
-			      struct ecore_ptt *p_ptt,
-			      u16 source_port_or_eth_type,
-			      u16 dest_port,
-			      enum ecore_llh_port_filter_type_t type);
+ecore_llh_add_protocol_filter(struct ecore_dev *p_dev, u8 ppfid,
+			      enum ecore_llh_prot_filter_type_t type,
+			      u16 source_port_or_eth_type, u16 dest_port);
 
 /**
- * @brief ecore_llh_remove_protocol_filter - remove a protocol filter in llh
+ * @brief ecore_llh_remove_protocol_filter - Remove a LLH protocol filter from
+ *	the given filter bank.
  *
- * @param p_hwfn
- * @param p_ptt
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ * @param type - type of filters and comparing
  * @param source_port_or_eth_type - source port or ethertype to add
  * @param dest_port - destination port to add
- * @param type - type of filters and comparing
  */
-void
-ecore_llh_remove_protocol_filter(struct ecore_hwfn *p_hwfn,
-				 struct ecore_ptt *p_ptt,
-				 u16 source_port_or_eth_type,
-				 u16 dest_port,
-				 enum ecore_llh_port_filter_type_t type);
+void ecore_llh_remove_protocol_filter(struct ecore_dev *p_dev, u8 ppfid,
+				      enum ecore_llh_prot_filter_type_t type,
+				      u16 source_port_or_eth_type,
+				      u16 dest_port);
 
 /**
- * @brief ecore_llh_clear_all_filters - removes all MAC filters from llh
+ * @brief ecore_llh_clear_ppfid_filters - Remove all LLH filters from the given
+ *	filter bank.
  *
- * @param p_hwfn
- * @param p_ptt
+ * @param p_dev
+ * @param ppfid - relative within the allocated ppfids ('0' is the default one).
+ */
+void ecore_llh_clear_ppfid_filters(struct ecore_dev *p_dev, u8 ppfid);
+
+/**
+ * @brief ecore_llh_clear_all_filters - Remove all LLH filters
+ *
+ * @param p_dev
  */
-void ecore_llh_clear_all_filters(struct ecore_hwfn *p_hwfn,
-			     struct ecore_ptt *p_ptt);
+void ecore_llh_clear_all_filters(struct ecore_dev *p_dev);
 
 /**
  * @brief ecore_llh_set_function_as_default - set function as default per port
diff --git a/drivers/net/qede/base/ecore_hw.c b/drivers/net/qede/base/ecore_hw.c
index 6cfbbab..72cd7e9 100644
--- a/drivers/net/qede/base/ecore_hw.c
+++ b/drivers/net/qede/base/ecore_hw.c
@@ -450,14 +450,17 @@ u32 ecore_vfid_to_concrete(struct ecore_hwfn *p_hwfn, u8 vfid)
  * If this changes, this needs to be revisted.
  */
 
-/* Ecore DMAE
- * =============
- */
+/* DMAE */
+
+#define ECORE_DMAE_FLAGS_IS_SET(params, flag)	\
+	((params) != OSAL_NULL && ((params)->flags & ECORE_DMAE_FLAG_##flag))
+
 static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
 			      const u8 is_src_type_grc,
 			      const u8 is_dst_type_grc,
 			      struct ecore_dmae_params *p_params)
 {
+	u8 src_pfid, dst_pfid, port_id;
 	u16 opcode_b = 0;
 	u32 opcode = 0;
 
@@ -467,16 +470,20 @@ static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
 	 */
 	opcode |= (is_src_type_grc ? DMAE_CMD_SRC_MASK_GRC
 		   : DMAE_CMD_SRC_MASK_PCIE) << DMAE_CMD_SRC_SHIFT;
-	opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_SRC_PF_ID_MASK) <<
-	    DMAE_CMD_SRC_PF_ID_SHIFT;
+	src_pfid = ECORE_DMAE_FLAGS_IS_SET(p_params, PF_SRC) ?
+		   p_params->src_pfid : p_hwfn->rel_pf_id;
+	opcode |= (src_pfid & DMAE_CMD_SRC_PF_ID_MASK) <<
+		  DMAE_CMD_SRC_PF_ID_SHIFT;
 
 	/* The destination of the DMA can be: 0-None 1-PCIe 2-GRC 3-None */
 	opcode |= (is_dst_type_grc ? DMAE_CMD_DST_MASK_GRC
 		   : DMAE_CMD_DST_MASK_PCIE) << DMAE_CMD_DST_SHIFT;
-	opcode |= (p_hwfn->rel_pf_id & DMAE_CMD_DST_PF_ID_MASK) <<
-	    DMAE_CMD_DST_PF_ID_SHIFT;
+	dst_pfid = ECORE_DMAE_FLAGS_IS_SET(p_params, PF_DST) ?
+		   p_params->dst_pfid : p_hwfn->rel_pf_id;
+	opcode |= (dst_pfid & DMAE_CMD_DST_PF_ID_MASK) <<
+		  DMAE_CMD_DST_PF_ID_SHIFT;
 
-	/* DMAE_E4_TODO need to check which value to specifiy here. */
+	/* DMAE_E4_TODO need to check which value to specify here. */
 	/* opcode |= (!b_complete_to_host)<< DMAE_CMD_C_DST_SHIFT; */
 
 	/* Whether to write a completion word to the completion destination:
@@ -486,7 +493,7 @@ static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
 	opcode |= DMAE_CMD_COMP_WORD_EN_MASK << DMAE_CMD_COMP_WORD_EN_SHIFT;
 	opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK << DMAE_CMD_SRC_ADDR_RESET_SHIFT;
 
-	if (p_params->flags & ECORE_DMAE_FLAG_COMPLETION_DST)
+	if (ECORE_DMAE_FLAGS_IS_SET(p_params, COMPLETION_DST))
 		opcode |= 1 << DMAE_CMD_COMP_FUNC_SHIFT;
 
 	/* swapping mode 3 - big endian there should be a define ifdefed in
@@ -494,7 +501,9 @@ static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
 	 */
 	opcode |= DMAE_CMD_ENDIANITY << DMAE_CMD_ENDIANITY_MODE_SHIFT;
 
-	opcode |= p_hwfn->port_id << DMAE_CMD_PORT_ID_SHIFT;
+	port_id = (ECORE_DMAE_FLAGS_IS_SET(p_params, PORT)) ?
+		  p_params->port_id : p_hwfn->port_id;
+	opcode |= port_id << DMAE_CMD_PORT_ID_SHIFT;
 
 	/* reset source address in next go */
 	opcode |= DMAE_CMD_SRC_ADDR_RESET_MASK << DMAE_CMD_SRC_ADDR_RESET_SHIFT;
@@ -503,14 +512,14 @@ static void ecore_dmae_opcode(struct ecore_hwfn *p_hwfn,
 	opcode |= DMAE_CMD_DST_ADDR_RESET_MASK << DMAE_CMD_DST_ADDR_RESET_SHIFT;
 
 	/* SRC/DST VFID: all 1's - pf, otherwise VF id */
-	if (p_params->flags & ECORE_DMAE_FLAG_VF_SRC) {
+	if (ECORE_DMAE_FLAGS_IS_SET(p_params, VF_SRC)) {
 		opcode |= (1 << DMAE_CMD_SRC_VF_ID_VALID_SHIFT);
 		opcode_b |= (p_params->src_vfid << DMAE_CMD_SRC_VF_ID_SHIFT);
 	} else {
 		opcode_b |= (DMAE_CMD_SRC_VF_ID_MASK <<
 			     DMAE_CMD_SRC_VF_ID_SHIFT);
 	}
-	if (p_params->flags & ECORE_DMAE_FLAG_VF_DST) {
+	if (ECORE_DMAE_FLAGS_IS_SET(p_params, VF_DST)) {
 		opcode |= 1 << DMAE_CMD_DST_VF_ID_VALID_SHIFT;
 		opcode_b |= p_params->dst_vfid << DMAE_CMD_DST_VF_ID_SHIFT;
 	} else {
@@ -855,7 +864,7 @@ static enum _ecore_status_t ecore_dmae_operation_wait(struct ecore_hwfn *p_hwfn)
 	for (i = 0; i <= cnt_split; i++) {
 		offset = length_limit * i;
 
-		if (!(p_params->flags & ECORE_DMAE_FLAG_RW_REPL_SRC)) {
+		if (!ECORE_DMAE_FLAGS_IS_SET(p_params, RW_REPL_SRC)) {
 			if (src_type == ECORE_DMAE_ADDRESS_GRC)
 				src_addr_split = src_addr + offset;
 			else
@@ -896,51 +905,45 @@ static enum _ecore_status_t ecore_dmae_operation_wait(struct ecore_hwfn *p_hwfn)
 	return ecore_status;
 }
 
-enum _ecore_status_t
-ecore_dmae_host2grc(struct ecore_hwfn *p_hwfn,
-		    struct ecore_ptt *p_ptt,
-		    u64 source_addr,
-		    u32 grc_addr, u32 size_in_dwords, u32 flags)
+enum _ecore_status_t ecore_dmae_host2grc(struct ecore_hwfn *p_hwfn,
+					 struct ecore_ptt *p_ptt,
+					 u64 source_addr,
+					 u32 grc_addr,
+					 u32 size_in_dwords,
+					 struct ecore_dmae_params *p_params)
 {
 	u32 grc_addr_in_dw = grc_addr / sizeof(u32);
-	struct ecore_dmae_params params;
 	enum _ecore_status_t rc;
 
-	OSAL_MEMSET(&params, 0, sizeof(struct ecore_dmae_params));
-	params.flags = flags;
-
 	OSAL_SPIN_LOCK(&p_hwfn->dmae_info.lock);
 
 	rc = ecore_dmae_execute_command(p_hwfn, p_ptt, source_addr,
 					grc_addr_in_dw,
 					ECORE_DMAE_ADDRESS_HOST_VIRT,
 					ECORE_DMAE_ADDRESS_GRC,
-					size_in_dwords, &params);
+					size_in_dwords, p_params);
 
 	OSAL_SPIN_UNLOCK(&p_hwfn->dmae_info.lock);
 
 	return rc;
 }
 
-enum _ecore_status_t
-ecore_dmae_grc2host(struct ecore_hwfn *p_hwfn,
-		    struct ecore_ptt *p_ptt,
-		    u32 grc_addr,
-		    dma_addr_t dest_addr, u32 size_in_dwords, u32 flags)
+enum _ecore_status_t ecore_dmae_grc2host(struct ecore_hwfn *p_hwfn,
+					 struct ecore_ptt *p_ptt,
+					 u32 grc_addr,
+					 dma_addr_t dest_addr,
+					 u32 size_in_dwords,
+					 struct ecore_dmae_params *p_params)
 {
 	u32 grc_addr_in_dw = grc_addr / sizeof(u32);
-	struct ecore_dmae_params params;
 	enum _ecore_status_t rc;
 
-	OSAL_MEMSET(&params, 0, sizeof(struct ecore_dmae_params));
-	params.flags = flags;
-
 	OSAL_SPIN_LOCK(&p_hwfn->dmae_info.lock);
 
 	rc = ecore_dmae_execute_command(p_hwfn, p_ptt, grc_addr_in_dw,
 					dest_addr, ECORE_DMAE_ADDRESS_GRC,
 					ECORE_DMAE_ADDRESS_HOST_VIRT,
-					size_in_dwords, &params);
+					size_in_dwords, p_params);
 
 	OSAL_SPIN_UNLOCK(&p_hwfn->dmae_info.lock);
 
@@ -989,7 +992,6 @@ enum _ecore_status_t ecore_dmae_sanity(struct ecore_hwfn *p_hwfn,
 				       const char *phase)
 {
 	u32 size = OSAL_PAGE_SIZE / 2, val;
-	struct ecore_dmae_params params;
 	enum _ecore_status_t rc = ECORE_SUCCESS;
 	dma_addr_t p_phys;
 	void *p_virt;
@@ -1021,9 +1023,9 @@ enum _ecore_status_t ecore_dmae_sanity(struct ecore_hwfn *p_hwfn,
 		   (unsigned long)(p_phys + size),
 		   (u8 *)p_virt + size, size);
 
-	OSAL_MEMSET(&params, 0, sizeof(params));
 	rc = ecore_dmae_host2host(p_hwfn, p_ptt, p_phys, p_phys + size,
-				  size / 4 /* size_in_dwords */, &params);
+				  size / 4 /* size_in_dwords */,
+				  OSAL_NULL /* default parameters */);
 	if (rc != ECORE_SUCCESS) {
 		DP_NOTICE(p_hwfn, false,
 			  "DMAE sanity [%s]: ecore_dmae_host2host() failed. rc = %d.\n",
@@ -1054,3 +1056,32 @@ enum _ecore_status_t ecore_dmae_sanity(struct ecore_hwfn *p_hwfn,
 	OSAL_DMA_FREE_COHERENT(p_hwfn->p_dev, p_virt, p_phys, 2 * size);
 	return rc;
 }
+
+void ecore_ppfid_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		    u8 abs_ppfid, u32 hw_addr, u32 val)
+{
+	u8 pfid = ECORE_PFID_BY_PPFID(p_hwfn, abs_ppfid);
+
+	ecore_fid_pretend(p_hwfn, p_ptt,
+			  pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+	ecore_wr(p_hwfn, p_ptt, hw_addr, val);
+	ecore_fid_pretend(p_hwfn, p_ptt,
+			  p_hwfn->rel_pf_id <<
+			  PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+}
+
+u32 ecore_ppfid_rd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		   u8 abs_ppfid, u32 hw_addr)
+{
+	u8 pfid = ECORE_PFID_BY_PPFID(p_hwfn, abs_ppfid);
+	u32 val;
+
+	ecore_fid_pretend(p_hwfn, p_ptt,
+			  pfid << PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+	val = ecore_rd(p_hwfn, p_ptt, hw_addr);
+	ecore_fid_pretend(p_hwfn, p_ptt,
+			  p_hwfn->rel_pf_id <<
+			  PXP_PRETEND_CONCRETE_FID_PFID_SHIFT);
+
+	return val;
+}
diff --git a/drivers/net/qede/base/ecore_hw.h b/drivers/net/qede/base/ecore_hw.h
index a62ba39..0b5b40c 100644
--- a/drivers/net/qede/base/ecore_hw.h
+++ b/drivers/net/qede/base/ecore_hw.h
@@ -134,8 +134,8 @@ struct ecore_ptt *ecore_get_reserved_ptt(struct ecore_hwfn	*p_hwfn,
  *
  * @param p_hwfn
  * @param p_ptt
- * @param val
  * @param hw_addr
+ * @param val
  */
 void ecore_wr(struct ecore_hwfn	*p_hwfn,
 	      struct ecore_ptt	*p_ptt,
@@ -147,7 +147,6 @@ void ecore_wr(struct ecore_hwfn	*p_hwfn,
  *
  * @param p_hwfn
  * @param p_ptt
- * @param val
  * @param hw_addr
  */
 u32 ecore_rd(struct ecore_hwfn	*p_hwfn,
@@ -269,4 +268,29 @@ enum _ecore_status_t ecore_dmae_sanity(struct ecore_hwfn *p_hwfn,
 				       struct ecore_ptt *p_ptt,
 				       const char *phase);
 
+/**
+ * @brief ecore_ppfid_wr - Write value to BAR using the given ptt while
+ *	pretending to a PF to which the given PPFID pertains.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ * @param abs_ppfid
+ * @param hw_addr
+ * @param val
+ */
+void ecore_ppfid_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		    u8 abs_ppfid, u32 hw_addr, u32 val);
+
+/**
+ * @brief ecore_ppfid_rd - Read value from BAR using the given ptt while
+ *	 pretending to a PF to which the given PPFID pertains.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ * @param abs_ppfid
+ * @param hw_addr
+ */
+u32 ecore_ppfid_rd(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
+		   u8 abs_ppfid, u32 hw_addr);
+
 #endif /* __ECORE_HW_H__ */
diff --git a/drivers/net/qede/base/ecore_init_ops.c b/drivers/net/qede/base/ecore_init_ops.c
index b7636f3..47c1be2 100644
--- a/drivers/net/qede/base/ecore_init_ops.c
+++ b/drivers/net/qede/base/ecore_init_ops.c
@@ -101,7 +101,8 @@ static enum _ecore_status_t ecore_init_rt(struct ecore_hwfn *p_hwfn,
 
 		rc = ecore_dmae_host2grc(p_hwfn, p_ptt,
 					 (osal_uintptr_t)(p_init_val + i),
-					 addr + (i << 2), segment, 0);
+					 addr + (i << 2), segment,
+					 OSAL_NULL /* default parameters */);
 		if (rc != ECORE_SUCCESS)
 			return rc;
 
@@ -165,8 +166,9 @@ static enum _ecore_status_t ecore_init_array_dmae(struct ecore_hwfn *p_hwfn,
 	} else {
 		rc = ecore_dmae_host2grc(p_hwfn, p_ptt,
 					 (osal_uintptr_t)(p_buf +
-							   dmae_data_offset),
-					 addr, size, 0);
+							  dmae_data_offset),
+					 addr, size,
+					 OSAL_NULL /* default parameters */);
 	}
 
 	return rc;
@@ -177,13 +179,15 @@ static enum _ecore_status_t ecore_init_fill_dmae(struct ecore_hwfn *p_hwfn,
 						 u32 addr, u32 fill_count)
 {
 	static u32 zero_buffer[DMAE_MAX_RW_SIZE];
+	struct ecore_dmae_params params;
 
 	OSAL_MEMSET(zero_buffer, 0, sizeof(u32) * DMAE_MAX_RW_SIZE);
 
+	OSAL_MEMSET(&params, 0, sizeof(params));
+	params.flags = ECORE_DMAE_FLAG_RW_REPL_SRC;
 	return ecore_dmae_host2grc(p_hwfn, p_ptt,
 				   (osal_uintptr_t)&zero_buffer[0],
-				   addr, fill_count,
-				   ECORE_DMAE_FLAG_RW_REPL_SRC);
+				   addr, fill_count, &params);
 }
 
 static void ecore_init_fill(struct ecore_hwfn *p_hwfn,
diff --git a/drivers/net/qede/base/ecore_int.c b/drivers/net/qede/base/ecore_int.c
index fd8f657..e48a7bc 100644
--- a/drivers/net/qede/base/ecore_int.c
+++ b/drivers/net/qede/base/ecore_int.c
@@ -1561,11 +1561,13 @@ void ecore_int_cau_conf_sb(struct ecore_hwfn *p_hwfn,
 		ecore_dmae_host2grc(p_hwfn, p_ptt,
 				    (u64)(osal_uintptr_t)&phys_addr,
 				    CAU_REG_SB_ADDR_MEMORY +
-				    igu_sb_id * sizeof(u64), 2, 0);
+				    igu_sb_id * sizeof(u64), 2,
+				    OSAL_NULL /* default parameters */);
 		ecore_dmae_host2grc(p_hwfn, p_ptt,
 				    (u64)(osal_uintptr_t)&sb_entry,
 				    CAU_REG_SB_VAR_MEMORY +
-				    igu_sb_id * sizeof(u64), 2, 0);
+				    igu_sb_id * sizeof(u64), 2,
+				    OSAL_NULL /* default parameters */);
 	} else {
 		/* Initialize Status Block Address */
 		STORE_RT_REG_AGG(p_hwfn,
@@ -2646,7 +2648,8 @@ enum _ecore_status_t ecore_int_set_timer_res(struct ecore_hwfn *p_hwfn,
 
 	rc = ecore_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
 				 sb_id * sizeof(u64),
-				 (u64)(osal_uintptr_t)&sb_entry, 2, 0);
+				 (u64)(osal_uintptr_t)&sb_entry, 2,
+				 OSAL_NULL /* default parameters */);
 	if (rc != ECORE_SUCCESS) {
 		DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
 		return rc;
@@ -2659,8 +2662,8 @@ enum _ecore_status_t ecore_int_set_timer_res(struct ecore_hwfn *p_hwfn,
 
 	rc = ecore_dmae_host2grc(p_hwfn, p_ptt,
 				 (u64)(osal_uintptr_t)&sb_entry,
-				 CAU_REG_SB_VAR_MEMORY +
-				 sb_id * sizeof(u64), 2, 0);
+				 CAU_REG_SB_VAR_MEMORY + sb_id * sizeof(u64), 2,
+				 OSAL_NULL /* default parameters */);
 	if (rc != ECORE_SUCCESS) {
 		DP_ERR(p_hwfn, "dmae_host2grc failed %d\n", rc);
 		return rc;
diff --git a/drivers/net/qede/base/ecore_l2.c b/drivers/net/qede/base/ecore_l2.c
index c17082e..5a0905e 100644
--- a/drivers/net/qede/base/ecore_l2.c
+++ b/drivers/net/qede/base/ecore_l2.c
@@ -2217,7 +2217,8 @@ int ecore_get_rxq_coalesce(struct ecore_hwfn *p_hwfn,
 
 	rc = ecore_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
 				 p_cid->sb_igu_id * sizeof(u64),
-				 (u64)(osal_uintptr_t)&sb_entry, 2, 0);
+				 (u64)(osal_uintptr_t)&sb_entry, 2,
+				 OSAL_NULL /* default parameters */);
 	if (rc != ECORE_SUCCESS) {
 		DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
 		return rc;
@@ -2251,7 +2252,8 @@ int ecore_get_txq_coalesce(struct ecore_hwfn *p_hwfn,
 
 	rc = ecore_dmae_grc2host(p_hwfn, p_ptt, CAU_REG_SB_VAR_MEMORY +
 				 p_cid->sb_igu_id * sizeof(u64),
-				 (u64)(osal_uintptr_t)&sb_entry, 2, 0);
+				 (u64)(osal_uintptr_t)&sb_entry, 2,
+				 OSAL_NULL /* default parameters */);
 	if (rc != ECORE_SUCCESS) {
 		DP_ERR(p_hwfn, "dmae_grc2host failed %d\n", rc);
 		return rc;
diff --git a/drivers/net/qede/base/ecore_mcp.c b/drivers/net/qede/base/ecore_mcp.c
index 3811d27..202db13 100644
--- a/drivers/net/qede/base/ecore_mcp.c
+++ b/drivers/net/qede/base/ecore_mcp.c
@@ -4144,6 +4144,75 @@ enum _ecore_status_t
 	return ECORE_SUCCESS;
 }
 
+enum _ecore_status_t ecore_mcp_get_engine_config(struct ecore_hwfn *p_hwfn,
+						 struct ecore_ptt *p_ptt)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	struct ecore_mcp_mb_params mb_params;
+	u8 fir_valid, l2_valid;
+	enum _ecore_status_t rc;
+
+	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
+	mb_params.cmd = DRV_MSG_CODE_GET_ENGINE_CONFIG;
+	rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+		DP_INFO(p_hwfn,
+			"The get_engine_config command is unsupported by the MFW\n");
+		return ECORE_NOTIMPL;
+	}
+
+	fir_valid = GET_MFW_FIELD(mb_params.mcp_param,
+				  FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID);
+	if (fir_valid)
+		p_dev->fir_affin =
+			GET_MFW_FIELD(mb_params.mcp_param,
+				      FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE);
+
+	l2_valid = GET_MFW_FIELD(mb_params.mcp_param,
+				 FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID);
+	if (l2_valid)
+		p_dev->l2_affin_hint =
+			GET_MFW_FIELD(mb_params.mcp_param,
+				      FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE);
+
+	DP_INFO(p_hwfn,
+		"Engine affinity config: FIR={valid %hhd, value %hhd}, L2_hint={valid %hhd, value %hhd}\n",
+		fir_valid, p_dev->fir_affin, l2_valid, p_dev->l2_affin_hint);
+
+	return ECORE_SUCCESS;
+}
+
+enum _ecore_status_t ecore_mcp_get_ppfid_bitmap(struct ecore_hwfn *p_hwfn,
+						struct ecore_ptt *p_ptt)
+{
+	struct ecore_dev *p_dev = p_hwfn->p_dev;
+	struct ecore_mcp_mb_params mb_params;
+	enum _ecore_status_t rc;
+
+	OSAL_MEM_ZERO(&mb_params, sizeof(mb_params));
+	mb_params.cmd = DRV_MSG_CODE_GET_PPFID_BITMAP;
+	rc = ecore_mcp_cmd_and_union(p_hwfn, p_ptt, &mb_params);
+	if (rc != ECORE_SUCCESS)
+		return rc;
+
+	if (mb_params.mcp_resp == FW_MSG_CODE_UNSUPPORTED) {
+		DP_INFO(p_hwfn,
+			"The get_ppfid_bitmap command is unsupported by the MFW\n");
+		return ECORE_NOTIMPL;
+	}
+
+	p_dev->ppfid_bitmap = GET_MFW_FIELD(mb_params.mcp_param,
+					    FW_MB_PARAM_PPFID_BITMAP);
+
+	DP_VERBOSE(p_hwfn, ECORE_MSG_SP, "PPFID bitmap 0x%hhx\n",
+		   p_dev->ppfid_bitmap);
+
+	return ECORE_SUCCESS;
+}
+
 void ecore_mcp_wol_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 		      u32 offset, u32 val)
 {
diff --git a/drivers/net/qede/base/ecore_mcp.h b/drivers/net/qede/base/ecore_mcp.h
index 8e12531..2c052b7 100644
--- a/drivers/net/qede/base/ecore_mcp.h
+++ b/drivers/net/qede/base/ecore_mcp.h
@@ -25,9 +25,6 @@
 					     rel_pfid)
 #define MCP_PF_ID(p_hwfn)	MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id)
 
-#define MFW_PORT(_p_hwfn)	((_p_hwfn)->abs_pf_id % \
-				 ecore_device_num_ports((_p_hwfn)->p_dev))
-
 struct ecore_mcp_info {
 	/* List for mailbox commands which were sent and wait for a response */
 	osal_list_t cmd_list;
@@ -566,4 +563,22 @@ enum _ecore_status_t
 void ecore_mcp_wol_wr(struct ecore_hwfn *p_hwfn, struct ecore_ptt *p_ptt,
 		      u32 offset, u32 val);
 
+/**
+ * @brief Get the engine affinity configuration.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+enum _ecore_status_t ecore_mcp_get_engine_config(struct ecore_hwfn *p_hwfn,
+						 struct ecore_ptt *p_ptt);
+
+/**
+ * @brief Get the PPFID bitmap.
+ *
+ * @param p_hwfn
+ * @param p_ptt
+ */
+enum _ecore_status_t ecore_mcp_get_ppfid_bitmap(struct ecore_hwfn *p_hwfn,
+						struct ecore_ptt *p_ptt);
+
 #endif /* __ECORE_MCP_H__ */
diff --git a/drivers/net/qede/base/ecore_sriov.c b/drivers/net/qede/base/ecore_sriov.c
index 3ac1085..9e937e2 100644
--- a/drivers/net/qede/base/ecore_sriov.c
+++ b/drivers/net/qede/base/ecore_sriov.c
@@ -979,10 +979,12 @@ static u8 ecore_iov_alloc_vf_igu_sbs(struct ecore_hwfn *p_hwfn,
 		ecore_init_cau_sb_entry(p_hwfn, &sb_entry,
 					p_hwfn->rel_pf_id,
 					vf->abs_vf_id, 1);
+
 		ecore_dmae_host2grc(p_hwfn, p_ptt,
 				    (u64)(osal_uintptr_t)&sb_entry,
 				    CAU_REG_SB_VAR_MEMORY +
-				    p_block->igu_sb_id * sizeof(u64), 2, 0);
+				    p_block->igu_sb_id * sizeof(u64), 2,
+				    OSAL_NULL /* default parameters */);
 	}
 
 	vf->num_sbs = (u8)num_rx_queues;
diff --git a/drivers/net/qede/base/mcp_public.h b/drivers/net/qede/base/mcp_public.h
index 46ec984..13c2e2d 100644
--- a/drivers/net/qede/base/mcp_public.h
+++ b/drivers/net/qede/base/mcp_public.h
@@ -1267,6 +1267,8 @@ struct public_drv_mb {
 #define DRV_MSG_CODE_OEM_RESET_TO_DEFAULT	0x3f000000
 #define DRV_MSG_CODE_OV_GET_CURR_CFG		0x40000000
 #define DRV_MSG_CODE_GET_OEM_UPDATES		0x41000000
+/* params [31:8] - reserved, [7:0] - bitmap */
+#define DRV_MSG_CODE_GET_PPFID_BITMAP		0x43000000
 
 /*deprecated don't use*/
 #define DRV_MSG_CODE_INITIATE_FLR_DEPRECATED    0x02000000
@@ -1476,6 +1478,7 @@ struct public_drv_mb {
 
 /* Param: Password len. Union: Plain Password */
 #define DRV_MSG_CODE_ENCRYPT_PASSWORD		0x00360000
+#define DRV_MSG_CODE_GET_ENGINE_CONFIG		0x00370000 /* Param: None */
 
 #define DRV_MSG_SEQ_NUMBER_MASK                 0x0000ffff
 
@@ -1812,6 +1815,18 @@ struct public_drv_mb {
 #define FW_MB_PARAM_OEM_UPDATE_S_TAG		0x02
 #define FW_MB_PARAM_OEM_UPDATE_CFG		0x04
 
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID_MASK   0x00000001
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALID_OFFSET 0
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE_MASK   0x00000002
+#define FW_MB_PARAM_ENG_CFG_FIR_AFFIN_VALUE_OFFSET 1
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID_MASK    0x00000004
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALID_OFFSET  2
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE_MASK    0x00000008
+#define FW_MB_PARAM_ENG_CFG_L2_AFFIN_VALUE_OFFSET  3
+
+#define FW_MB_PARAM_PPFID_BITMAP_MASK   0xFF
+#define FW_MB_PARAM_PPFID_BITMAP_OFFSET    0
+
 	u32 drv_pulse_mb;
 #define DRV_PULSE_SEQ_MASK                      0x00007fff
 #define DRV_PULSE_SYSTEM_TIME_MASK              0xffff0000
diff --git a/drivers/net/qede/base/reg_addr.h b/drivers/net/qede/base/reg_addr.h
index c3e0bd2..612337f 100644
--- a/drivers/net/qede/base/reg_addr.h
+++ b/drivers/net/qede/base/reg_addr.h
@@ -1235,3 +1235,7 @@
 #define DORQ_REG_TAG1_OVRD_MODE 0x1008b4UL
 #define DORQ_REG_PF_EXT_VID_BB_K2 0x1008c8UL
 #define PRS_REG_SEARCH_NON_IP_AS_GFT 0x1f11c0UL
+#define NIG_REG_LLH_PPFID2PFID_TBL_0 0x501970UL
+#define NIG_REG_PPF_TO_ENGINE_SEL 0x508900UL
+#define NIG_REG_LLH_ENG_CLS_ROCE_QP_SEL 0x501b98UL
+#define NIG_REG_LLH_FUNC_FILTER_HDR_SEL_BB_K2 0x501b40UL
