@@ -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));
}
}
@@ -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);
@@ -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
@@ -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;
}
@@ -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.
@@ -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,
};