diff mbox series

[net-next] cxgb4: add driver support for FW_CLIP2_CMD

Message ID 20241204135416.14041-1-anumula@chelsio.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net-next] cxgb4: add driver support for FW_CLIP2_CMD | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers warning 1 maintainers not CCed: edumazet@google.com
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 343 this patch: 343
netdev/checkpatch warning WARNING: line length of 89 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 18 this patch: 18
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-12-06--18-00 (tests: 764)

Commit Message

Anumula Murali Mohan Reddy Dec. 4, 2024, 1:54 p.m. UTC
Query firmware for FW_CLIP2_CMD support and enable it. FW_CLIP2_CMD
will be used for setting LIP mask for the corresponding entry in the
CLIP table. If no LIP mask is specified, a default value of ~0 is
written for mask.

Signed-off-by: Anumula Murali Mohan Reddy <anumula@chelsio.com>
Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
---
 drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 146 ++++++++++++++----
 drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h |   6 +-
 drivers/net/ethernet/chelsio/cxgb4/cxgb4.h    |   1 +
 .../net/ethernet/chelsio/cxgb4/cxgb4_filter.c |  23 ++-
 .../net/ethernet/chelsio/cxgb4/cxgb4_main.c   |   3 +
 drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h |  12 ++
 6 files changed, 152 insertions(+), 39 deletions(-)

Comments

Michal Swiatkowski Dec. 5, 2024, 8:13 a.m. UTC | #1
On Wed, Dec 04, 2024 at 07:24:16PM +0530, Anumula Murali Mohan Reddy wrote:
> Query firmware for FW_CLIP2_CMD support and enable it. FW_CLIP2_CMD
> will be used for setting LIP mask for the corresponding entry in the
> CLIP table. If no LIP mask is specified, a default value of ~0 is
> written for mask.
> 
> Signed-off-by: Anumula Murali Mohan Reddy <anumula@chelsio.com>
> Signed-off-by: Potnuri Bharat Teja <bharat@chelsio.com>
> ---
>  drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c | 146 ++++++++++++++----
>  drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h |   6 +-
>  drivers/net/ethernet/chelsio/cxgb4/cxgb4.h    |   1 +
>  .../net/ethernet/chelsio/cxgb4/cxgb4_filter.c |  23 ++-
>  .../net/ethernet/chelsio/cxgb4/cxgb4_main.c   |   3 +
>  drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h |  12 ++
>  6 files changed, 152 insertions(+), 39 deletions(-)
> 
> diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
> index 5060d3998889..8da9e7fe7f65 100644
> --- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
> +++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
> @@ -18,6 +18,8 @@
>  #include "cxgb4.h"
>  #include "clip_tbl.h"
>  
> +static const u64 clip_ipv6_exact_mask[2] = { ~0, ~0 };
> +
>  static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key)
>  {
>  	unsigned int clipt_size_half = c->clipt_size / 2;
> @@ -42,36 +44,73 @@ static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
>  }
>  
>  static int clip6_get_mbox(const struct net_device *dev,
> -			  const struct in6_addr *lip)
> +			  const struct in6_addr *lip,
> +			  const struct in6_addr *lipm)
>  {
>  	struct adapter *adap = netdev2adap(dev);
> -	struct fw_clip_cmd c;
> +	struct fw_clip2_cmd c;
> +
> +	if (!adap->params.clip2_cmd_support) {
> +		struct fw_clip_cmd old_cmd;
> +
> +		memset(&old_cmd, 0, sizeof(old_cmd));
> +		old_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
> +					    FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
> +		old_cmd.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F |
> +					       FW_LEN16(old_cmd));
> +		*(__be64 *)&old_cmd.ip_hi = *(__be64 *)(lip->s6_addr);
> +		*(__be64 *)&old_cmd.ip_lo = *(__be64 *)(lip->s6_addr + 8);
> +
> +		return t4_wr_mbox_meat(adap, adap->mbox, &old_cmd,
> +				       sizeof(old_cmd), &old_cmd, false);
> +	}
>  
>  	memset(&c, 0, sizeof(c));
> -	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
> +	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP2_CMD) |
>  			      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
>  	c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c));
>  	*(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
>  	*(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
> +	*(__be64 *)&c.ipm_hi = *(__be64 *)(lipm->s6_addr);
> +	*(__be64 *)&c.ipm_lo = *(__be64 *)(lipm->s6_addr + 8);
>  	return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
>  }
>  
>  static int clip6_release_mbox(const struct net_device *dev,
> -			      const struct in6_addr *lip)
> +			      const struct in6_addr *lip,
> +			      const struct in6_addr *lipm)
>  {
>  	struct adapter *adap = netdev2adap(dev);
> -	struct fw_clip_cmd c;
> +	struct fw_clip2_cmd c;
> +
> +	if (!adap->params.clip2_cmd_support) {
> +		struct fw_clip_cmd old_cmd;
> +
> +		memset(&old_cmd, 0, sizeof(old_cmd));
> +		old_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
> +					    FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
> +		old_cmd.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F |
> +					       FW_LEN16(old_cmd));
> +		*(__be64 *)&old_cmd.ip_hi = *(__be64 *)(lip->s6_addr);
> +		*(__be64 *)&old_cmd.ip_lo = *(__be64 *)(lip->s6_addr + 8);
> +
> +		return t4_wr_mbox_meat(adap, adap->mbox, &old_cmd,
> +				       sizeof(old_cmd), &old_cmd, false);
This block is similar to the block for old command in get_mbox, maybe
move to function:
olc_cmd_send(..., cmd_type)
{
	...
	old_cmd.alloc_to_len16 = htonl(cmd_type | FW_LEN16(old_cmd));
	...
}

To be honest the same can be done for whole release/get
clip6_get_mbox(...)
{
	clip6_mbox(..., ALLOC);
}

clip6_release_mbox(...)
{
	clip6_mbox(..., FREE);
}

You will safe some lines.

}
> +	}
>  
>  	memset(&c, 0, sizeof(c));
> -	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
> -			      FW_CMD_REQUEST_F | FW_CMD_READ_F);
> +	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP2_CMD) |
> +			      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
>  	c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c));
>  	*(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
>  	*(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
> +	*(__be64 *)&c.ipm_hi = *(__be64 *)(lipm->s6_addr);
> +	*(__be64 *)&c.ipm_lo = *(__be64 *)(lipm->s6_addr + 8);
> +
>  	return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
>  }
>  
>

[...]

> -- 
> 2.39.3
Jakub Kicinski Dec. 8, 2024, 2:31 a.m. UTC | #2
On Wed,  4 Dec 2024 19:24:16 +0530 Anumula Murali Mohan Reddy wrote:
> Query firmware for FW_CLIP2_CMD support and enable it. FW_CLIP2_CMD
> will be used for setting LIP mask for the corresponding entry in the
> CLIP table. If no LIP mask is specified, a default value of ~0 is
> written for mask.

I don't know what LIP mask or CLIP table are, how they are used, 
and most importantly what the impact of this change is to the user.
Please write a proper commit message.
diff mbox series

Patch

diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
index 5060d3998889..8da9e7fe7f65 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
@@ -18,6 +18,8 @@ 
 #include "cxgb4.h"
 #include "clip_tbl.h"
 
+static const u64 clip_ipv6_exact_mask[2] = { ~0, ~0 };
+
 static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key)
 {
 	unsigned int clipt_size_half = c->clipt_size / 2;
@@ -42,36 +44,73 @@  static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
 }
 
 static int clip6_get_mbox(const struct net_device *dev,
-			  const struct in6_addr *lip)
+			  const struct in6_addr *lip,
+			  const struct in6_addr *lipm)
 {
 	struct adapter *adap = netdev2adap(dev);
-	struct fw_clip_cmd c;
+	struct fw_clip2_cmd c;
+
+	if (!adap->params.clip2_cmd_support) {
+		struct fw_clip_cmd old_cmd;
+
+		memset(&old_cmd, 0, sizeof(old_cmd));
+		old_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+					    FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+		old_cmd.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F |
+					       FW_LEN16(old_cmd));
+		*(__be64 *)&old_cmd.ip_hi = *(__be64 *)(lip->s6_addr);
+		*(__be64 *)&old_cmd.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+
+		return t4_wr_mbox_meat(adap, adap->mbox, &old_cmd,
+				       sizeof(old_cmd), &old_cmd, false);
+	}
 
 	memset(&c, 0, sizeof(c));
-	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP2_CMD) |
 			      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
 	c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c));
 	*(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
 	*(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+	*(__be64 *)&c.ipm_hi = *(__be64 *)(lipm->s6_addr);
+	*(__be64 *)&c.ipm_lo = *(__be64 *)(lipm->s6_addr + 8);
 	return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
 }
 
 static int clip6_release_mbox(const struct net_device *dev,
-			      const struct in6_addr *lip)
+			      const struct in6_addr *lip,
+			      const struct in6_addr *lipm)
 {
 	struct adapter *adap = netdev2adap(dev);
-	struct fw_clip_cmd c;
+	struct fw_clip2_cmd c;
+
+	if (!adap->params.clip2_cmd_support) {
+		struct fw_clip_cmd old_cmd;
+
+		memset(&old_cmd, 0, sizeof(old_cmd));
+		old_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+					    FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+		old_cmd.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F |
+					       FW_LEN16(old_cmd));
+		*(__be64 *)&old_cmd.ip_hi = *(__be64 *)(lip->s6_addr);
+		*(__be64 *)&old_cmd.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+
+		return t4_wr_mbox_meat(adap, adap->mbox, &old_cmd,
+				       sizeof(old_cmd), &old_cmd, false);
+	}
 
 	memset(&c, 0, sizeof(c));
-	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
-			      FW_CMD_REQUEST_F | FW_CMD_READ_F);
+	c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP2_CMD) |
+			      FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
 	c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c));
 	*(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
 	*(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+	*(__be64 *)&c.ipm_hi = *(__be64 *)(lipm->s6_addr);
+	*(__be64 *)&c.ipm_lo = *(__be64 *)(lipm->s6_addr + 8);
+
 	return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
 }
 
-int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
+static int clip_get(const struct net_device *dev, const u32 *lip, const u32 *lipm, u8 v6)
 {
 	struct adapter *adap = netdev2adap(dev);
 	struct clip_tbl *ctbl = adap->clipt;
@@ -82,17 +121,23 @@  int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
 
 	if (!ctbl)
 		return 0;
+	if (!lipm)
+		lipm = (const u32 *)clip_ipv6_exact_mask;
 
 	hash = clip_addr_hash(ctbl, addr, v6);
 
 	read_lock_bh(&ctbl->lock);
 	list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-		if (cte->addr6.sin6_family == AF_INET6 && v6)
-			ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
-				     sizeof(struct in6_addr));
-		else if (cte->addr.sin_family == AF_INET && !v6)
-			ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
-				     sizeof(struct in_addr));
+		if (cte->val.addr6.sin6_family == AF_INET6 && v6)
+			ret = (memcmp(lip, &cte->val.addr6.sin6_addr.s6_addr,
+				      sizeof(struct in6_addr)) ||
+			       memcmp(lipm, &cte->mask.addr6.sin6_addr.s6_addr,
+				      sizeof(struct in6_addr)));
+		else if (cte->val.addr.sin_family == AF_INET && !v6)
+			ret = (memcmp(lip, (char *)(&cte->val.addr.sin_addr),
+				      sizeof(struct in_addr)) ||
+			       memcmp(lipm, (char *)(&cte->mask.addr.sin_addr),
+				      sizeof(struct in_addr)));
 		if (!ret) {
 			ce = cte;
 			read_unlock_bh(&ctbl->lock);
@@ -112,22 +157,29 @@  int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
 		atomic_dec(&ctbl->nfree);
 		list_add_tail(&ce->list, &ctbl->hash_list[hash]);
 		if (v6) {
-			ce->addr6.sin6_family = AF_INET6;
-			memcpy(ce->addr6.sin6_addr.s6_addr,
+			ce->val.addr6.sin6_family = AF_INET6;
+			ce->mask.addr6.sin6_family = AF_INET6;
+			memcpy(ce->val.addr6.sin6_addr.s6_addr,
 			       lip, sizeof(struct in6_addr));
-			ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
+			memcpy(ce->mask.addr6.sin6_addr.s6_addr,
+			       lipm, sizeof(struct in6_addr));
+			ret = clip6_get_mbox(dev, (const struct in6_addr *)lip,
+					     (const struct in6_addr *)lipm);
 			if (ret) {
 				write_unlock_bh(&ctbl->lock);
 				dev_err(adap->pdev_dev,
 					"CLIP FW cmd failed with error %d, "
 					"Connections using %pI6c won't be "
 					"offloaded",
-					ret, ce->addr6.sin6_addr.s6_addr);
+					ret, ce->val.addr6.sin6_addr.s6_addr);
 				return ret;
 			}
 		} else {
-			ce->addr.sin_family = AF_INET;
-			memcpy((char *)(&ce->addr.sin_addr), lip,
+			ce->val.addr.sin_family = AF_INET;
+			ce->mask.addr.sin_family = AF_INET;
+			memcpy((char *)(&ce->val.addr.sin_addr), lip,
+			       sizeof(struct in_addr));
+			memcpy((char *)(&ce->mask.addr.sin_addr), lipm,
 			       sizeof(struct in_addr));
 		}
 	} else {
@@ -141,9 +193,20 @@  int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
 	refcount_set(&ce->refcnt, 1);
 	return 0;
 }
+
+int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
+{
+	return clip_get(dev, lip, NULL, v6);
+}
 EXPORT_SYMBOL(cxgb4_clip_get);
 
-void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
+int cxgb4_clip_get_filter(const struct net_device *dev, const u32 *lip,
+			  const u32 *lipm, u8 v6)
+{
+	return clip_get(dev, lip, lipm, v6);
+}
+
+static void clip_release(const struct net_device *dev, const u32 *lip, const u32 *lipm, u8 v6)
 {
 	struct adapter *adap = netdev2adap(dev);
 	struct clip_tbl *ctbl = adap->clipt;
@@ -154,17 +217,23 @@  void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
 
 	if (!ctbl)
 		return;
+	if (!lipm)
+		lipm = (const u32 *)clip_ipv6_exact_mask;
 
 	hash = clip_addr_hash(ctbl, addr, v6);
 
 	read_lock_bh(&ctbl->lock);
 	list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
-		if (cte->addr6.sin6_family == AF_INET6 && v6)
-			ret = memcmp(lip, cte->addr6.sin6_addr.s6_addr,
-				     sizeof(struct in6_addr));
-		else if (cte->addr.sin_family == AF_INET && !v6)
-			ret = memcmp(lip, (char *)(&cte->addr.sin_addr),
-				     sizeof(struct in_addr));
+		if (cte->val.addr6.sin6_family == AF_INET6 && v6)
+			ret = (memcmp(lip, &cte->val.addr6.sin6_addr.s6_addr,
+				      sizeof(struct in6_addr)) ||
+			       memcmp(lipm, &cte->mask.addr6.sin6_addr.s6_addr,
+				      sizeof(struct in6_addr)));
+		else if (cte->val.addr.sin_family == AF_INET && !v6)
+			ret = (memcmp(lip, (char *)(&cte->val.addr.sin_addr),
+				      sizeof(struct in_addr)) ||
+			       memcmp(lipm, (char *)(&cte->mask.addr.sin_addr),
+				      sizeof(struct in_addr)));
 		if (!ret) {
 			ce = cte;
 			read_unlock_bh(&ctbl->lock);
@@ -182,13 +251,25 @@  void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
 		list_add_tail(&ce->list, &ctbl->ce_free_head);
 		atomic_inc(&ctbl->nfree);
 		if (v6)
-			clip6_release_mbox(dev, (const struct in6_addr *)lip);
+			clip6_release_mbox(dev, (const struct in6_addr *)lip,
+					   (const struct in6_addr *)lipm);
 	}
 	spin_unlock_bh(&ce->lock);
 	write_unlock_bh(&ctbl->lock);
 }
+
+void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
+{
+	return clip_release(dev, lip, NULL, v6);
+}
 EXPORT_SYMBOL(cxgb4_clip_release);
 
+void cxgb4_clip_release_filter(const struct net_device *dev, const u32 *lip,
+			       const u32 *lipm, u8 v6)
+{
+	return clip_release(dev, lip, lipm, v6);
+}
+
 /* Retrieves IPv6 addresses from a root device (bond, vlan) associated with
  * a physical device.
  * The physical device reference is needed to send the actul CLIP command.
@@ -252,17 +333,18 @@  int clip_tbl_show(struct seq_file *seq, void *v)
 	struct adapter *adapter = seq->private;
 	struct clip_tbl *ctbl = adapter->clipt;
 	struct clip_entry *ce;
-	char ip[60];
+	char ip[96];
 	int i;
 
 	read_lock_bh(&ctbl->lock);
 
-	seq_puts(seq, "IP Address                  Users\n");
+	seq_printf(seq, "%-83s   %s\n", "IP Address / IP Mask", "Users");
 	for (i = 0 ; i < ctbl->clipt_size;  ++i) {
 		list_for_each_entry(ce, &ctbl->hash_list[i], list) {
 			ip[0] = '\0';
-			sprintf(ip, "%pISc", &ce->addr);
-			seq_printf(seq, "%-25s   %u\n", ip,
+			sprintf(ip, "%pISc / %pISc", &ce->val.addr,
+				&ce->mask.addr);
+			seq_printf(seq, "%-83s   %d\n", ip,
 				   refcount_read(&ce->refcnt));
 		}
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
index 847c7fc2bbd9..dea64bf828b5 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
@@ -19,7 +19,7 @@  struct clip_entry {
 	union {
 		struct sockaddr_in addr;
 		struct sockaddr_in6 addr6;
-	};
+	} val, mask;
 };
 
 struct clip_tbl {
@@ -43,3 +43,7 @@  void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6);
 int clip_tbl_show(struct seq_file *seq, void *v);
 int cxgb4_update_root_dev_clip(struct net_device *dev);
 void t4_cleanup_clip_tbl(struct adapter *adap);
+int cxgb4_clip_get_filter(const struct net_device *dev, const u32 *lip,
+			  const u32 *lipm, u8 v6);
+void cxgb4_clip_release_filter(const struct net_device *dev, const u32 *lip,
+			       const u32 *lipm, u8 v6);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 75bd69ff61a8..86f46d79e6bc 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -487,6 +487,7 @@  struct adapter_params {
 	u8 mps_bg_map[MAX_NPORTS];	/* MPS Buffer Group Map */
 	bool write_w_imm_support;       /* FW supports WRITE_WITH_IMMEDIATE */
 	bool write_cmpl_support;        /* FW supports WRITE_CMPL */
+	bool clip2_cmd_support;
 };
 
 /* State needed to monitor the forward progress of SGE Ingress DMA activities
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
index dd9e68465e69..4e456f34acbb 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_filter.c
@@ -993,9 +993,10 @@  void clear_filter(struct adapter *adap, struct filter_entry *f)
 		t4_free_encap_mac_filt(adap, pi->viid,
 				       f->fs.val.ovlan & 0x1ff, 0);
 
-	if ((f->fs.hash || is_t6(adap->params.chip)) && f->fs.type)
-		cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1);
-
+	if ((f->fs.hash || is_t6(adap->params.chip)) && f->fs.type) {
+		cxgb4_clip_release_filter(f->dev, (const u32 *)&f->fs.val.lip,
+					  (const u32 *)&f->fs.mask.lip, 1);
+	}
 	/* The zeroing of the filter rule below clears the filter valid,
 	 * pending, locked flags, l2t pointer, etc. so it's all we need for
 	 * this operation.
@@ -1463,7 +1464,13 @@  static int cxgb4_set_hash_filter(struct net_device *dev,
 
 	size = sizeof(struct cpl_t6_act_open_req);
 	if (f->fs.type) {
-		ret = cxgb4_clip_get(f->dev, (const u32 *)&f->fs.val.lip, 1);
+		struct ch_filter_specification *fs = &f->fs;
+
+		ret = cxgb4_clip_get_filter(f->dev,
+					    (const u32 *)&fs->val.lip,
+					    (const u32 *)&fs->mask.lip,
+					    1);
+
 		if (ret)
 			goto free_mps;
 
@@ -1494,7 +1501,8 @@  static int cxgb4_set_hash_filter(struct net_device *dev,
 	return 0;
 
 free_clip:
-	cxgb4_clip_release(f->dev, (const u32 *)&f->fs.val.lip, 1);
+	cxgb4_clip_release_filter(f->dev, (const u32 *)&f->fs.val.lip,
+				  (const u32 *)&f->fs.mask.lip, 1);
 
 free_mps:
 	if (f->fs.val.encap_vld && f->fs.val.ovlan_vld)
@@ -1666,7 +1674,10 @@  int __cxgb4_set_filter(struct net_device *dev, int ftid,
 	if (is_t6(adapter->params.chip) && fs->type &&
 	    ipv6_addr_type((const struct in6_addr *)fs->val.lip) !=
 	    IPV6_ADDR_ANY) {
-		ret = cxgb4_clip_get(dev, (const u32 *)&fs->val.lip, 1);
+		ret = cxgb4_clip_get_filter(dev,
+					    (const u32 *)&fs->val.lip,
+					    (const u32 *)&fs->mask.lip,
+					    1);
 		if (ret)
 			goto free_tid;
 	}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index 97a261d5357e..b0ef1d6a5d79 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -5137,6 +5137,9 @@  static int adap_init0(struct adapter *adap, int vpd_skip)
 			      1, params, val);
 	adap->params.viid_smt_extn_support = (ret == 0 && val[0] != 0);
 
+	params[0] = FW_PARAM_DEV(CLIP2_CMD);
+	ret = t4_query_params(adap, adap->mbox, adap->pf, 0, 1, params, val);
+	adap->params.clip2_cmd_support = (!ret && val[0]);
 	/*
 	 * Get device capabilities so we can determine what resources we need
 	 * to manage.
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 2419459a0b85..c93072994f83 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -847,6 +847,7 @@  enum fw_cmd_opcodes {
 	FW_SCHED_CMD                   = 0x24,
 	FW_DEVLOG_CMD                  = 0x25,
 	FW_CLIP_CMD                    = 0x28,
+	FW_CLIP2_CMD                   = 0x29,
 	FW_PTP_CMD                     = 0x3e,
 	FW_HMA_CMD                     = 0x3f,
 	FW_LASTC2E_CMD                 = 0x40,
@@ -1226,6 +1227,16 @@  enum fw_memtype_cf {
 	FW_MEMTYPE_CF_HMA		= 0x7,
 };
 
+struct fw_clip2_cmd {
+	__be32 op_to_write;
+	__be32 alloc_to_len16;
+	__be64 ip_hi;
+	__be64 ip_lo;
+	__be64 ipm_hi;
+	__be64 ipm_lo;
+	__be32 r4[2];
+};
+
 struct fw_caps_config_cmd {
 	__be32 op_to_write;
 	__be32 cfvalid_to_len16;
@@ -1331,6 +1342,7 @@  enum fw_params_param_dev {
 	FW_PARAMS_PARAM_DEV_DBQ_TIMERTICK = 0x2A,
 	FW_PARAMS_PARAM_DEV_NUM_TM_CLASS = 0x2B,
 	FW_PARAMS_PARAM_DEV_FILTER = 0x2E,
+	FW_PARAMS_PARAM_DEV_CLIP2_CMD = 0x2F,
 	FW_PARAMS_PARAM_DEV_KTLS_HW = 0x31,
 };