diff --git a/drivers/net/ethernet/mellanox/mlxsw/Kconfig b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
index 8a291eb..7e6b518 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/Kconfig
+++ b/drivers/net/ethernet/mellanox/mlxsw/Kconfig
@@ -80,6 +80,7 @@ config MLXSW_SPECTRUM
 	depends on IPV6_GRE || IPV6_GRE=n
 	select GENERIC_ALLOCATOR
 	select PARMAN
+	select PRUNE
 	select MLXFW
 	default m
 	---help---
diff --git a/drivers/net/ethernet/mellanox/mlxsw/reg.h b/drivers/net/ethernet/mellanox/mlxsw/reg.h
index 6e8b619..4931cdf 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/reg.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/reg.h
@@ -2760,13 +2760,24 @@ MLXSW_ITEM32(reg, ptce3, large_entry_key_id, 0x98, 0, 24);
  */
 MLXSW_ITEM32(reg, ptce3, action_pointer, 0xA0, 0, 24);
 
+static inline void
+mlxsw_reg_ptce3_prune_vector_pack(char *payload,
+				  unsigned long *prune_vector,
+				  unsigned long size)
+{
+	unsigned long bit;
+
+	for_each_set_bit(bit, prune_vector, size)
+		mlxsw_reg_ptce3_prune_vector_set(payload, bit, true);
+}
+
 static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
 					enum mlxsw_reg_ptce3_op op,
 					u32 priority,
 					const char *tcam_region_info,
 					const char *key, u8 erp_id,
-					bool large_exists, u32 lkey_id,
-					u32 action_pointer)
+					bool prune_ctcam, bool large_exists,
+					u32 lkey_id, u32 action_pointer)
 {
 	MLXSW_REG_ZERO(ptce3, payload);
 	mlxsw_reg_ptce3_v_set(payload, valid);
@@ -2775,6 +2786,7 @@ static inline void mlxsw_reg_ptce3_pack(char *payload, bool valid,
 	mlxsw_reg_ptce3_tcam_region_info_memcpy_to(payload, tcam_region_info);
 	mlxsw_reg_ptce3_flex2_key_blocks_memcpy_to(payload, key);
 	mlxsw_reg_ptce3_erp_id_set(payload, erp_id);
+	mlxsw_reg_ptce3_prune_ctcam_set(payload, prune_ctcam);
 	mlxsw_reg_ptce3_large_exists_set(payload, large_exists);
 	mlxsw_reg_ptce3_large_entry_key_id_set(payload, lkey_id);
 	mlxsw_reg_ptce3_action_pointer_set(payload, action_pointer);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
index 2a9eac9..e1ddaf4 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum1_acl_tcam.c
@@ -30,7 +30,8 @@ struct mlxsw_sp1_acl_tcam_entry {
 static int
 mlxsw_sp1_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion,
 					struct mlxsw_sp_acl_ctcam_entry *centry,
-					const char *mask)
+					const char *key, const char *mask,
+					u32 priority)
 {
 	return 0;
 }
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
index 8ca77f3..835108a 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.c
@@ -2,6 +2,7 @@
 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
 
 #include <linux/kernel.h>
+#include <linux/prune.h>
 
 #include "spectrum.h"
 #include "spectrum_acl_tcam.h"
@@ -27,14 +28,139 @@ struct mlxsw_sp2_acl_tcam_entry {
 	struct mlxsw_afa_block *act_block;
 };
 
+struct  mlxsw_afa_block *
+mlxsw_sp2_acl_tcam_aentry_act_block(struct mlxsw_sp_acl_atcam_entry *aentry)
+{
+	struct mlxsw_sp2_acl_tcam_entry *entry;
+
+	entry = container_of(aentry, struct mlxsw_sp2_acl_tcam_entry, aentry);
+	return entry->act_block;
+}
+
+void
+mlxsw_sp2_acl_tcam_prune_vector_bit_set(struct mlxsw_sp_acl_erp *erp,
+					struct mlxsw_sp_acl_atcam_entry *aentry,
+					bool pruned)
+{
+	if (pruned)
+		__set_bit(mlxsw_sp_acl_erp_index(erp), aentry->prune_bitmap);
+	else
+		__clear_bit(mlxsw_sp_acl_erp_index(erp), aentry->prune_bitmap);
+}
+
+static void
+mlxsw_sp2_acl_tcam_prune_update(struct mlxsw_sp_acl_erp *erp,
+				struct mlxsw_sp_acl_atcam_entry *aentry)
+{
+	struct mlxsw_sp_acl_atcam_region *aregion;
+	struct mlxsw_sp *mlxsw_sp;
+	u32 priority;
+	int err;
+
+	aregion = mlxsw_sp_acl_erp_aregion(erp);
+	mlxsw_sp = aregion->region->mlxsw_sp;
+	priority = aentry->prune_item->priority;
+
+	err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp,
+					     aentry->prune_item->priority,
+					     &priority, true);
+	if (err) {
+		WARN(err, "Failed to retrieve rule priority while updating rule with priority %u\n",
+		     aentry->prune_item->priority);
+		return;
+	}
+	err = mlxsw_sp_acl_atcam_region_entry_update(mlxsw_sp, aregion, aentry,
+						     priority);
+	if (err) {
+		WARN(err, "Failed to updating prune vector while update rule with priority %u\n",
+		     aentry->prune_item->priority);
+		return;
+	}
+}
+
+static void
+mlxsw_sp2_acl_tcam_prune_ctcam_update(struct mlxsw_sp_acl_erp *erp,
+				      struct mlxsw_sp_acl_atcam_entry *aentry,
+				      bool pruned)
+{
+	bool ctcam_pruned = aentry->num_ctcam_erps_scan > 0 ? true : false;
+
+	pruned ? aentry->num_ctcam_erps_scan-- : aentry->num_ctcam_erps_scan++;
+
+	if ((aentry->num_ctcam_erps_scan > 0 && !ctcam_pruned) ||
+	    (ctcam_pruned & !aentry->num_ctcam_erps_scan))
+		mlxsw_sp2_acl_tcam_prune_update(erp, aentry);
+}
+
+static void
+mlxsw_sp2_acl_tcam_prune_vector_update(struct mlxsw_sp_acl_erp *erp,
+				       struct mlxsw_sp_acl_atcam_entry *aentry,
+				       bool pruned)
+{
+	mlxsw_sp2_acl_tcam_prune_vector_bit_set(erp, aentry, pruned);
+	mlxsw_sp2_acl_tcam_prune_update(erp, aentry);
+}
+
+static void
+mlxsw_sp2_acl_tcam_prune_notification_handler(struct mlxsw_sp_acl_erp *erp,
+					      struct mlxsw_sp_acl_atcam_entry
+					      *aentry,
+					      bool pruned)
+{
+	enum mlxsw_sp_acl_atcam_region_type region_type;
+	bool ctcam_erp, ctcam_entry;
+
+	region_type = mlxsw_sp_acl_erp_region_type(aentry->erp);
+	ctcam_entry = mlxsw_sp_acl_erp_is_ctcam_erp(aentry->erp);
+	ctcam_erp = mlxsw_sp_acl_erp_is_ctcam_erp(erp);
+
+	/* Discard notification:
+	 * For ctcam rule prune vector is irrelevant
+	 * For 8KB region type we should always not prune
+	 */
+	if (!ctcam_entry && region_type != MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB) {
+		if (ctcam_erp)
+			mlxsw_sp2_acl_tcam_prune_ctcam_update(erp, aentry,
+							      pruned);
+		else
+			mlxsw_sp2_acl_tcam_prune_vector_update(erp, aentry,
+							       pruned);
+	}
+}
+
+static void
+mlxsw_sp2_acl_atcam_entry_prune_notify(struct list_head *prune_item_notify_list,
+				       struct prune_table *table, bool pruned)
+{
+	struct mlxsw_sp_acl_atcam_entry *aentry;
+	struct mlxsw_sp_acl_erp *erp;
+	struct prune_item *item;
+
+	list_for_each_entry(item, prune_item_notify_list, list) {
+		aentry = item->priv;
+		erp = prune_table_priv(table);
+		mlxsw_sp2_acl_tcam_prune_notification_handler(erp, aentry,
+							      pruned);
+	}
+}
+
+static const struct prune_ops mlxsw_sp2_acl_atcam_prune_ops = {
+	.prune_item_notify = mlxsw_sp2_acl_atcam_entry_prune_notify
+};
+
 static int
 mlxsw_sp2_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion,
 					struct mlxsw_sp_acl_ctcam_entry *centry,
-					const char *mask)
+					const char *key,
+					const char *mask,
+					u32 priority)
 {
 	struct mlxsw_sp_acl_atcam_region *aregion;
 	struct mlxsw_sp_acl_atcam_entry *aentry;
+	struct prune_item *prune_item;
 	struct mlxsw_sp_acl_erp *erp;
+	bool non_def_prune_vector;
+	int err;
 
 	aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
 	aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
@@ -44,7 +170,25 @@ mlxsw_sp2_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregio
 		return PTR_ERR(erp);
 	aentry->erp = erp;
 
+	bitmap_from_arr32(aentry->key_bitmap, (void *) key,
+			  MLXSW_SP_ACL_TCAM_MASK_LEN);
+
+	prune_item = prune_item_create(aregion->region->prune,
+				       mlxsw_sp_acl_erp_prune_table(erp),
+				       priority, aentry->key_bitmap, aentry,
+				       &non_def_prune_vector);
+	if (IS_ERR(prune_item)) {
+		err = PTR_ERR(prune_item);
+		goto err_prune_item_create;
+	}
+	aentry->prune_item = prune_item;
+	aentry->num_ctcam_erps_scan = 0;
+
 	return 0;
+
+err_prune_item_create:
+	mlxsw_sp_acl_erp_put(aregion, erp);
+	return err;
 }
 
 static void
@@ -53,10 +197,15 @@ mlxsw_sp2_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregio
 {
 	struct mlxsw_sp_acl_atcam_region *aregion;
 	struct mlxsw_sp_acl_atcam_entry *aentry;
+	int err;
 
 	aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
 	aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
 
+	err = prune_item_destroy(aentry->prune_item);
+	WARN(err, "Failed to destroy prune item while removing rule with priority %u\n",
+	     aentry->prune_item->priority);
+
 	mlxsw_sp_acl_erp_put(aregion, aentry->erp);
 }
 
@@ -148,7 +297,8 @@ mlxsw_sp2_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
 
 	return mlxsw_sp_acl_atcam_region_init(mlxsw_sp, &tcam->atcam,
 					      &region->aregion, _region,
-					      &mlxsw_sp2_acl_ctcam_region_ops);
+					      &mlxsw_sp2_acl_ctcam_region_ops,
+					      &mlxsw_sp2_acl_atcam_prune_ops);
 }
 
 static void
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
index 2658a51..ed8270d 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl.c
@@ -8,6 +8,7 @@
 #include <linux/string.h>
 #include <linux/rhashtable.h>
 #include <linux/netdevice.h>
+#include <linux/prune.h>
 #include <net/net_namespace.h>
 #include <net/tc_act/tc_vlan.h>
 
@@ -847,6 +848,10 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
 	if (err)
 		goto err_acl_ops_init;
 
+	err = prune_init();
+	if (err)
+		goto err_prune_init;
+
 	/* Create the delayed work for the rule activity_update */
 	INIT_DELAYED_WORK(&acl->rule_activity_update.dw,
 			  mlxsw_sp_acl_rul_activity_update_work);
@@ -854,6 +859,8 @@ int mlxsw_sp_acl_init(struct mlxsw_sp *mlxsw_sp)
 	mlxsw_core_schedule_dw(&acl->rule_activity_update.dw, 0);
 	return 0;
 
+err_prune_init:
+	mlxsw_sp_acl_tcam_fini(mlxsw_sp, &acl->tcam);
 err_acl_ops_init:
 	mlxsw_sp_fid_put(fid);
 err_fid_get:
@@ -870,6 +877,7 @@ void mlxsw_sp_acl_fini(struct mlxsw_sp *mlxsw_sp)
 	struct mlxsw_sp_acl *acl = mlxsw_sp->acl;
 
 	cancel_delayed_work_sync(&mlxsw_sp->acl->rule_activity_update.dw);
+	prune_fini();
 	mlxsw_sp_acl_tcam_fini(mlxsw_sp, &acl->tcam);
 	WARN_ON(!list_empty(&acl->rules));
 	mlxsw_sp_fid_put(acl->dummy_fid);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
index 2dda028..97dedbf 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
@@ -7,6 +7,7 @@
 #include <linux/gfp.h>
 #include <linux/refcount.h>
 #include <linux/rhashtable.h>
+#include <linux/prune.h>
 
 #include "reg.h"
 #include "core.h"
@@ -317,7 +318,9 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
 			       struct mlxsw_sp_acl_atcam *atcam,
 			       struct mlxsw_sp_acl_atcam_region *aregion,
 			       struct mlxsw_sp_acl_tcam_region *region,
-			       const struct mlxsw_sp_acl_ctcam_region_ops *ops)
+			       const struct mlxsw_sp_acl_ctcam_region_ops *ops,
+			       const struct prune_ops
+			       *mlxsw_acl_atcam_prune_ops)
 {
 	int err;
 
@@ -339,9 +342,17 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
 					     region, ops);
 	if (err)
 		goto err_ctcam_region_init;
+	region->prune = prune_create(MLXSW_SP_ACL_TCAM_MASK_LEN,
+				     mlxsw_acl_atcam_prune_ops, region);
+	if (IS_ERR(region->prune)) {
+		err = PTR_ERR(region->prune);
+		goto err_prune_create;
+	}
 
 	return 0;
 
+err_prune_create:
+	mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion);
 err_ctcam_region_init:
 	mlxsw_sp_acl_erp_region_fini(aregion);
 err_erp_region_init:
@@ -353,6 +364,7 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
 
 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
 {
+	prune_destroy(aregion->region->prune);
 	mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion);
 	mlxsw_sp_acl_erp_region_fini(aregion);
 	aregion->ops->fini(aregion);
@@ -376,19 +388,16 @@ static int
 mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_atcam_region *aregion,
 				       struct mlxsw_sp_acl_atcam_entry *aentry,
-				       struct mlxsw_sp_acl_rule_info *rulei)
+				       struct mlxsw_sp_acl_rule_info *rulei,
+				       u32 priority)
 {
 	struct mlxsw_sp_acl_tcam_region *region = aregion->region;
 	u8 erp_id = mlxsw_sp_acl_erp_id(aentry->erp);
 	struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
 	char ptce3_pl[MLXSW_REG_PTCE3_LEN];
-	u32 kvdl_index, priority;
+	u32 kvdl_index;
 	int err;
 
-	err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
-	if (err)
-		return err;
-
 	lkey_id = aregion->ops->lkey_id_get(aregion, rulei, erp_id);
 	if (IS_ERR(lkey_id))
 		return PTR_ERR(lkey_id);
@@ -398,8 +407,11 @@ mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 	mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE,
 			     priority, region->tcam_region_info,
 			     aentry->ht_key.enc_key, erp_id,
+			     !(aentry->num_ctcam_erps_scan > 0),
 			     refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
 			     kvdl_index);
+	mlxsw_reg_ptce3_prune_vector_pack(ptce3_pl, aentry->prune_bitmap,
+					  MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 	err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
 	if (err)
 		goto err_ptce3_write;
@@ -411,6 +423,35 @@ mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 	return err;
 }
 
+int
+mlxsw_sp_acl_atcam_region_entry_update(struct mlxsw_sp *mlxsw_sp,
+				       struct mlxsw_sp_acl_atcam_region *aregion,
+				       struct mlxsw_sp_acl_atcam_entry *aentry,
+				       u32 priority)
+{
+	struct mlxsw_sp_acl_tcam_region *region = aregion->region;
+	struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
+	char ptce3_pl[MLXSW_REG_PTCE3_LEN];
+	struct mlxsw_afa_block *act_block;
+	u32 kvdl_index;
+	u8 erp_id;
+
+	erp_id = mlxsw_sp_acl_erp_id(aentry->erp);
+	lkey_id = aentry->lkey_id;
+	act_block = mlxsw_sp2_acl_tcam_aentry_act_block(aentry);
+	kvdl_index = mlxsw_afa_block_first_kvdl_index(act_block);
+
+	mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE,
+			     priority, region->tcam_region_info,
+			     aentry->ht_key.enc_key, erp_id,
+			     !(aentry->num_ctcam_erps_scan > 0),
+			     refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
+			     kvdl_index);
+	mlxsw_reg_ptce3_prune_vector_pack(ptce3_pl, aentry->prune_bitmap,
+					  MLXSW_SP_ACL_ERP_MAX_PER_REGION);
+	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
+}
+
 static void
 mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
 				       struct mlxsw_sp_acl_atcam_region *aregion,
@@ -423,12 +464,56 @@ mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
 
 	mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0,
 			     region->tcam_region_info, aentry->ht_key.enc_key,
-			     erp_id, refcount_read(&lkey_id->refcnt) != 1,
+			     erp_id, !(aentry->num_ctcam_erps_scan > 0),
+			     refcount_read(&lkey_id->refcnt) != 1,
 			     lkey_id->id, 0);
 	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
 	aregion->ops->lkey_id_put(aregion, lkey_id);
 }
 
+void mlxsw_sp_acl_atcam_prune_vector_to_bitmap(bool non_def_prune_vector,
+					       struct mlxsw_sp_acl_atcam_entry
+					       *aentry)
+{
+	enum mlxsw_sp_acl_atcam_region_type region_type;
+	struct prune_vector_item *vector_item;
+	struct list_head *prune_vector_list;
+	struct mlxsw_sp_acl_erp *erp;
+	struct prune_table *table;
+
+	region_type = mlxsw_sp_acl_erp_region_type(aentry->erp);
+	if (region_type == MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB) {
+		/* Note: For SP-2 a region with 8 key blocks must be set to
+		 * either to all 1's or all 0's.
+		 * The driver set it to all 0's so this rule doesn't prune
+		 * any other rules.
+		 */
+		bitmap_zero(aentry->prune_bitmap,
+			    MLXSW_SP_ACL_ERP_MAX_PER_REGION);
+		return;
+	}
+	bitmap_fill(aentry->prune_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
+
+	if (!non_def_prune_vector) /* prune all erps */
+		return;
+
+	/* set the relevant erps for further lookups */
+	prune_vector_list = prune_item_prune_vector(aentry->prune_item);
+	list_for_each_entry(vector_item, prune_vector_list, list) {
+		if (!vector_item->pruned) {
+			table = vector_item->table;
+			erp = prune_table_priv(table);
+			if (mlxsw_sp_acl_erp_is_ctcam_erp(erp)) {
+				/* look-up towards the CTCAM */
+				aentry->num_ctcam_erps_scan++;
+				continue;
+			}
+			mlxsw_sp2_acl_tcam_prune_vector_bit_set(erp, aentry,
+								false);
+		}
+	}
+}
+
 static int
 __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
 			       struct mlxsw_sp_acl_atcam_region *aregion,
@@ -436,21 +521,32 @@ __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
 			       struct mlxsw_sp_acl_rule_info *rulei)
 {
 	struct mlxsw_sp_acl_tcam_region *region = aregion->region;
-	char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
 	struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
+	char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
+	struct prune_item *prune_item;
 	struct mlxsw_sp_acl_erp *erp;
 	unsigned int blocks_count;
+	bool non_def_prune_vector;
+	u32 priority;
 	int err;
 
 	blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info);
 	mlxsw_afk_encode(afk, region->key_info, &rulei->values,
 			 aentry->ht_key.enc_key, mask, 0, blocks_count - 1);
 
+	err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei->priority,
+					     &priority, true);
+	if (err)
+		return err;
+
 	erp = mlxsw_sp_acl_erp_get(aregion, mask, false);
 	if (IS_ERR(erp))
 		return PTR_ERR(erp);
+
 	aentry->erp = erp;
 	aentry->ht_key.erp_id = mlxsw_sp_acl_erp_id(erp);
+	bitmap_from_arr32(aentry->key_bitmap, (void *) aentry->ht_key.enc_key,
+			  MLXSW_SP_ACL_TCAM_MASK_LEN);
 
 	/* We can't insert identical rules into the A-TCAM, so fail and
 	 * let the rule spill into C-TCAM
@@ -461,14 +557,30 @@ __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
 	if (err)
 		goto err_rhashtable_insert;
 
+	prune_item = prune_item_create(aregion->region->prune,
+				       mlxsw_sp_acl_erp_prune_table(erp),
+				       rulei->priority, aentry->key_bitmap,
+				       aentry, &non_def_prune_vector);
+	if (IS_ERR(prune_item)) {
+		err = PTR_ERR(prune_item);
+		goto err_prune_item_create;
+	}
+	aentry->prune_item = prune_item;
+	aentry->num_ctcam_erps_scan = 0;
+
+	mlxsw_sp_acl_atcam_prune_vector_to_bitmap(non_def_prune_vector,
+						  aentry);
 	err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry,
-						     rulei);
+						     rulei, priority);
 	if (err)
 		goto err_rule_insert;
 
 	return 0;
 
 err_rule_insert:
+	if (!prune_item_destroy(aentry->prune_item))
+		WARN(1, "Failed to destroy prune item\n");
+err_prune_item_create:
 	rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
 			       mlxsw_sp_acl_atcam_entries_ht_params);
 err_rhashtable_insert:
@@ -481,7 +593,13 @@ __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
 			       struct mlxsw_sp_acl_atcam_region *aregion,
 			       struct mlxsw_sp_acl_atcam_entry *aentry)
 {
+	int err;
+
 	mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry);
+	err = prune_item_destroy(aentry->prune_item);
+	WARN(err, "Failed to destroy prune item while removing rule with priority %u\n",
+	     aentry->prune_item->priority);
+
 	rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
 			       mlxsw_sp_acl_atcam_entries_ht_params);
 	mlxsw_sp_acl_erp_put(aregion, aentry->erp);
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c
index e3c6fe8..79c7a7f 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c
@@ -53,8 +53,8 @@ mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 	char *key;
 	int err;
 
-	err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority,
-					     fillup_priority);
+	err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei->priority,
+					     &priority, fillup_priority);
 	if (err)
 		return err;
 
@@ -67,7 +67,8 @@ mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
 	mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask, 0,
 			 blocks_count - 1);
 
-	err = cregion->ops->entry_insert(cregion, centry, mask);
+	err = cregion->ops->entry_insert(cregion, centry, key, mask,
+					 rulei->priority);
 	if (err)
 		return err;
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
index 0a4fd3c..762af2d11 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
@@ -10,6 +10,7 @@
 #include <linux/rhashtable.h>
 #include <linux/rtnetlink.h>
 #include <linux/slab.h>
+#include <linux/prune.h>
 
 #include "core.h"
 #include "reg.h"
@@ -18,7 +19,6 @@
 
 /* gen_pool_alloc() returns 0 when allocation fails, so use an offset */
 #define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100
-#define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
 
 struct mlxsw_sp_acl_erp_core {
 	unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1];
@@ -35,12 +35,13 @@ struct mlxsw_sp_acl_erp_key {
 struct mlxsw_sp_acl_erp {
 	struct mlxsw_sp_acl_erp_key key;
 	u8 id;
-	u8 index;
+	u8 index; /* used for erp index in prune vector */
 	refcount_t refcnt;
 	DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
 	struct list_head list;
 	struct rhash_head ht_node;
 	struct mlxsw_sp_acl_erp_table *erp_table;
+	struct prune_table *prune_table;
 };
 
 struct mlxsw_sp_acl_erp_master_mask {
@@ -129,6 +130,28 @@ u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp)
 	return erp->id;
 }
 
+u8 mlxsw_sp_acl_erp_index(const struct mlxsw_sp_acl_erp *erp)
+{
+	return erp->index;
+}
+struct prune_table *
+mlxsw_sp_acl_erp_prune_table(const struct mlxsw_sp_acl_erp *erp)
+{
+	return erp->prune_table;
+}
+
+enum mlxsw_sp_acl_atcam_region_type
+mlxsw_sp_acl_erp_region_type(const struct mlxsw_sp_acl_erp *erp)
+{
+	return erp->erp_table->aregion->type;
+}
+
+struct mlxsw_sp_acl_atcam_region *
+mlxsw_sp_acl_erp_aregion(const struct mlxsw_sp_acl_erp *erp)
+{
+	return erp->erp_table->aregion;
+}
+
 static unsigned int
 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
 {
@@ -245,6 +268,7 @@ mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
 				struct mlxsw_sp_acl_erp_key *key)
 {
 	struct mlxsw_sp_acl_erp *erp;
+	struct prune *prune;
 	int err;
 
 	erp = kzalloc(sizeof(*erp), GFP_KERNEL);
@@ -272,8 +296,19 @@ mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
 	if (err)
 		goto err_rhashtable_insert;
 
+	prune = erp_table->aregion->region->prune;
+	erp->prune_table = prune_table_create(prune, erp->mask_bitmap,
+					      MLXSW_SP_ACL_TCAM_MASK_LEN,
+					      erp);
+	if (IS_ERR(erp->prune_table)) {
+		err = PTR_ERR(erp->prune_table);
+		goto err_prune_table_create;
+	}
 	return erp;
 
+err_prune_table_create:
+	rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
+			       mlxsw_sp_acl_erp_ht_params);
 err_rhashtable_insert:
 	mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
 err_master_mask_set:
@@ -288,8 +323,12 @@ mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
 static void
 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
 {
+	int err;
 	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
 
+	err = prune_table_destroy(erp->prune_table);
+	WARN(err, "Failed to destroy prune table\n");
+
 	rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
 			       mlxsw_sp_acl_erp_ht_params);
 	mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
@@ -688,6 +727,7 @@ __mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 				     struct mlxsw_sp_acl_erp_key *key)
 {
 	struct mlxsw_sp_acl_erp *erp;
+	struct prune *prune;
 	int err;
 
 	erp = kzalloc(sizeof(*erp), GFP_KERNEL);
@@ -710,6 +750,15 @@ __mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 	if (err)
 		goto err_rhashtable_insert;
 
+	prune = erp_table->aregion->region->prune;
+	erp->prune_table = prune_table_create(prune, erp->mask_bitmap,
+					      MLXSW_SP_ACL_TCAM_MASK_LEN,
+					      erp);
+	if (IS_ERR(erp->prune_table)) {
+		err = PTR_ERR(erp->prune_table);
+		goto err_prune_table_create;
+	}
+
 	err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
 	if (err)
 		goto err_erp_region_ctcam_enable;
@@ -720,6 +769,9 @@ __mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 	return erp;
 
 err_erp_region_ctcam_enable:
+	if (prune_table_destroy(erp->prune_table))
+		WARN(1, "Failed to destroy prune table err %d\n", err);
+err_prune_table_create:
 	rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
 			       mlxsw_sp_acl_erp_ht_params);
 err_rhashtable_insert:
@@ -765,8 +817,12 @@ static void
 mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
 {
 	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
+	int err;
 
 	mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
+	err = prune_table_destroy(erp->prune_table);
+	WARN(err, "Failed to destroy prune table\n");
+
 	rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
 			       mlxsw_sp_acl_erp_ht_params);
 	mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
@@ -862,7 +918,6 @@ mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 		err = PTR_ERR(erp);
 		goto err_erp_create;
 	}
-
 	err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
 	if (err)
 		goto err_erp_index_get;
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
index e171513..2b392e9 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c
@@ -8,6 +8,7 @@
 #include <linux/list.h>
 #include <linux/rhashtable.h>
 #include <linux/netdevice.h>
+#include <linux/prune.h>
 
 #include "reg.h"
 #include "core.h"
@@ -82,8 +83,8 @@ void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp,
 }
 
 int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
-				   struct mlxsw_sp_acl_rule_info *rulei,
-				   u32 *priority, bool fillup_priority)
+				   u32 rule_priority, u32 *priority,
+				   bool fillup_priority)
 {
 	u64 max_priority;
 
@@ -96,11 +97,11 @@ int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
 		return -EIO;
 
 	max_priority = MLXSW_CORE_RES_GET(mlxsw_sp->core, KVD_SIZE);
-	if (rulei->priority > max_priority)
+	if (rule_priority > max_priority)
 		return -EINVAL;
 
 	/* Unlike in TC, in HW, higher number means higher priority. */
-	*priority = max_priority - rulei->priority;
+	*priority = max_priority - rule_priority;
 	return 0;
 }
 
diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
index 219a4e2..3b67782 100644
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h
@@ -6,6 +6,7 @@
 
 #include <linux/list.h>
 #include <linux/parman.h>
+#include <linux/prune.h>
 
 #include "reg.h"
 #include "spectrum.h"
@@ -27,9 +28,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
 void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp,
 			    struct mlxsw_sp_acl_tcam *tcam);
 int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
-				   struct mlxsw_sp_acl_rule_info *rulei,
-				   u32 *priority, bool fillup_priority);
-
+				   u32 rule_priority, u32 *priority,
+				   bool fillup_priority);
 struct mlxsw_sp_acl_profile_ops {
 	size_t ruleset_priv_size;
 	int (*ruleset_add)(struct mlxsw_sp *mlxsw_sp,
@@ -58,6 +58,7 @@ mlxsw_sp_acl_tcam_profile_ops(struct mlxsw_sp *mlxsw_sp,
 
 #define MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT 16
 #define MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP 16
+#define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
 
 #define MLXSW_SP_ACL_TCAM_CATCHALL_PRIO (~0U)
 
@@ -75,6 +76,7 @@ struct mlxsw_sp_acl_tcam_region {
 	char tcam_region_info[MLXSW_REG_PXXX_TCAM_REGION_INFO_LEN];
 	struct mlxsw_afk_key_info *key_info;
 	struct mlxsw_sp *mlxsw_sp;
+	struct prune *prune;
 	unsigned long priv[0];
 	/* priv has to be always the last item */
 };
@@ -96,7 +98,9 @@ struct mlxsw_sp_acl_ctcam_entry {
 struct mlxsw_sp_acl_ctcam_region_ops {
 	int (*entry_insert)(struct mlxsw_sp_acl_ctcam_region *cregion,
 			    struct mlxsw_sp_acl_ctcam_entry *centry,
-			    const char *mask);
+			    const char *key,
+			    const char *mask,
+			    u32 priority);
 	void (*entry_remove)(struct mlxsw_sp_acl_ctcam_region *cregion,
 			     struct mlxsw_sp_acl_ctcam_entry *centry);
 };
@@ -168,6 +172,11 @@ struct mlxsw_sp_acl_atcam_entry {
 	struct mlxsw_sp_acl_ctcam_entry centry;
 	struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
 	struct mlxsw_sp_acl_erp *erp;
+	struct prune_item *prune_item;
+	DECLARE_BITMAP(key_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
+	DECLARE_BITMAP(prune_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
+	/* Counts the number of ctcam erps that the rule should scan */
+	unsigned int num_ctcam_erps_scan;
 };
 
 static inline struct mlxsw_sp_acl_atcam_region *
@@ -189,7 +198,9 @@ mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
 			       struct mlxsw_sp_acl_atcam *atcam,
 			       struct mlxsw_sp_acl_atcam_region *aregion,
 			       struct mlxsw_sp_acl_tcam_region *region,
-			       const struct mlxsw_sp_acl_ctcam_region_ops *ops);
+			       const struct mlxsw_sp_acl_ctcam_region_ops *ops,
+			       const struct prune_ops
+			       *mlxsw_acl_atcam_prune_ops);
 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion);
 void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion,
 				   struct mlxsw_sp_acl_atcam_chunk *achunk,
@@ -208,11 +219,22 @@ int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
 			    struct mlxsw_sp_acl_atcam *atcam);
 void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
 			     struct mlxsw_sp_acl_atcam *atcam);
-
+int
+mlxsw_sp_acl_atcam_region_entry_update(struct mlxsw_sp *mlxsw_sp,
+				       struct mlxsw_sp_acl_atcam_region *aregion,
+				       struct mlxsw_sp_acl_atcam_entry *aentry,
+				       u32 priority);
 struct mlxsw_sp_acl_erp;
 
 bool mlxsw_sp_acl_erp_is_ctcam_erp(const struct mlxsw_sp_acl_erp *erp);
 u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp);
+u8 mlxsw_sp_acl_erp_index(const struct mlxsw_sp_acl_erp *erp);
+struct prune_table *
+mlxsw_sp_acl_erp_prune_table(const struct mlxsw_sp_acl_erp *erp);
+enum mlxsw_sp_acl_atcam_region_type
+mlxsw_sp_acl_erp_region_type(const struct mlxsw_sp_acl_erp *erp);
+struct mlxsw_sp_acl_atcam_region *
+mlxsw_sp_acl_erp_aregion(const struct mlxsw_sp_acl_erp *erp);
 struct mlxsw_sp_acl_erp *
 mlxsw_sp_acl_erp_get(struct mlxsw_sp_acl_atcam_region *aregion,
 		     const char *mask, bool ctcam);
@@ -225,4 +247,12 @@ int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
 			    struct mlxsw_sp_acl_atcam *atcam);
 
+struct  mlxsw_afa_block;
+
+struct  mlxsw_afa_block *
+mlxsw_sp2_acl_tcam_aentry_act_block(struct mlxsw_sp_acl_atcam_entry *aentry);
+void
+mlxsw_sp2_acl_tcam_prune_vector_bit_set(struct mlxsw_sp_acl_erp *erp,
+					struct mlxsw_sp_acl_atcam_entry *aentry,
+					bool pruned);
 #endif
