Commit 42eb59d3 authored by Casey Leedom's avatar Casey Leedom Committed by David S. Miller

cxgb4vf: fix setting unicast/multicast addresses ...

We were truncating the number of unicast and multicast MAC addresses
supported.  Additionally, we were incorrectly computing the MAC Address
hash (a "1 << N" where we needed a "1ULL << N").
Signed-off-by: default avatarCasey Leedom <leedom@chelsio.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent bcc70bb3
...@@ -816,17 +816,21 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev) ...@@ -816,17 +816,21 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
} }
/* /*
* Collect up to maxaddrs worth of a netdevice's unicast addresses into an * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
* array of addrss pointers and return the number collected. * at a specified offset within the list, into an array of addrss pointers and
* return the number collected.
*/ */
static inline int collect_netdev_uc_list_addrs(const struct net_device *dev, static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
const u8 **addr, const u8 **addr,
unsigned int offset,
unsigned int maxaddrs) unsigned int maxaddrs)
{ {
unsigned int index = 0;
unsigned int naddr = 0; unsigned int naddr = 0;
const struct netdev_hw_addr *ha; const struct netdev_hw_addr *ha;
for_each_dev_addr(dev, ha) { for_each_dev_addr(dev, ha)
if (index++ >= offset) {
addr[naddr++] = ha->addr; addr[naddr++] = ha->addr;
if (naddr >= maxaddrs) if (naddr >= maxaddrs)
break; break;
...@@ -835,17 +839,21 @@ static inline int collect_netdev_uc_list_addrs(const struct net_device *dev, ...@@ -835,17 +839,21 @@ static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
} }
/* /*
* Collect up to maxaddrs worth of a netdevice's multicast addresses into an * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
* array of addrss pointers and return the number collected. * at a specified offset within the list, into an array of addrss pointers and
* return the number collected.
*/ */
static inline int collect_netdev_mc_list_addrs(const struct net_device *dev, static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
const u8 **addr, const u8 **addr,
unsigned int offset,
unsigned int maxaddrs) unsigned int maxaddrs)
{ {
unsigned int index = 0;
unsigned int naddr = 0; unsigned int naddr = 0;
const struct netdev_hw_addr *ha; const struct netdev_hw_addr *ha;
netdev_for_each_mc_addr(ha, dev) { netdev_for_each_mc_addr(ha, dev)
if (index++ >= offset) {
addr[naddr++] = ha->addr; addr[naddr++] = ha->addr;
if (naddr >= maxaddrs) if (naddr >= maxaddrs)
break; break;
...@@ -862,16 +870,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) ...@@ -862,16 +870,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
u64 mhash = 0; u64 mhash = 0;
u64 uhash = 0; u64 uhash = 0;
bool free = true; bool free = true;
u16 filt_idx[7]; unsigned int offset, naddr;
const u8 *addr[7]; const u8 *addr[7];
int ret, naddr = 0; int ret;
const struct port_info *pi = netdev_priv(dev); const struct port_info *pi = netdev_priv(dev);
/* first do the secondary unicast addresses */ /* first do the secondary unicast addresses */
naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr)); for (offset = 0; ; offset += naddr) {
if (naddr > 0) { naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
ARRAY_SIZE(addr));
if (naddr == 0)
break;
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
naddr, addr, filt_idx, &uhash, sleep); naddr, addr, NULL, &uhash, sleep);
if (ret < 0) if (ret < 0)
return ret; return ret;
...@@ -879,12 +891,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep) ...@@ -879,12 +891,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
} }
/* next set up the multicast addresses */ /* next set up the multicast addresses */
naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr)); for (offset = 0; ; offset += naddr) {
if (naddr > 0) { naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
ARRAY_SIZE(addr));
if (naddr == 0)
break;
ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free, ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
naddr, addr, filt_idx, &mhash, sleep); naddr, addr, NULL, &mhash, sleep);
if (ret < 0) if (ret < 0)
return ret; return ret;
free = false;
} }
return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0, return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
......
...@@ -1014,15 +1014,22 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, ...@@ -1014,15 +1014,22 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
unsigned int naddr, const u8 **addr, u16 *idx, unsigned int naddr, const u8 **addr, u16 *idx,
u64 *hash, bool sleep_ok) u64 *hash, bool sleep_ok)
{ {
int i, ret; int offset, ret = 0;
unsigned nfilters = 0;
unsigned int rem = naddr;
struct fw_vi_mac_cmd cmd, rpl; struct fw_vi_mac_cmd cmd, rpl;
struct fw_vi_mac_exact *p;
size_t len16;
if (naddr > ARRAY_SIZE(cmd.u.exact)) if (naddr > FW_CLS_TCAM_NUM_ENTRIES)
return -EINVAL; return -EINVAL;
len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[naddr]), 16); for (offset = 0; offset < naddr; /**/) {
unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact)
? rem
: ARRAY_SIZE(cmd.u.exact));
size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
u.exact[fw_naddr]), 16);
struct fw_vi_mac_exact *p;
int i;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) | cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
...@@ -1030,32 +1037,49 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free, ...@@ -1030,32 +1037,49 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
FW_CMD_WRITE | FW_CMD_WRITE |
(free ? FW_CMD_EXEC : 0) | (free ? FW_CMD_EXEC : 0) |
FW_VI_MAC_CMD_VIID(viid)); FW_VI_MAC_CMD_VIID(viid));
cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) | cmd.freemacs_to_len16 =
cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
FW_CMD_LEN16(len16)); FW_CMD_LEN16(len16));
for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) { for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
p->valid_to_idx = p->valid_to_idx = cpu_to_be16(
cpu_to_be16(FW_VI_MAC_CMD_VALID | FW_VI_MAC_CMD_VALID |
FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC)); FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
memcpy(p->macaddr, addr[i], sizeof(p->macaddr)); memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
} }
ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
if (ret)
return ret;
for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) { ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl,
u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx)); sleep_ok);
if (ret && ret != -ENOMEM)
break;
for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) {
u16 index = FW_VI_MAC_CMD_IDX_GET(
be16_to_cpu(p->valid_to_idx));
if (idx) if (idx)
idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES idx[offset+i] =
(index >= FW_CLS_TCAM_NUM_ENTRIES
? 0xffff ? 0xffff
: index); : index);
if (index < FW_CLS_TCAM_NUM_ENTRIES) if (index < FW_CLS_TCAM_NUM_ENTRIES)
ret++; nfilters++;
else if (hash) else if (hash)
*hash |= (1 << hash_mac_addr(addr[i])); *hash |= (1ULL << hash_mac_addr(addr[offset+i]));
}
free = false;
offset += fw_naddr;
rem -= fw_naddr;
} }
/*
* If there were no errors or we merely ran out of room in our MAC
* address arena, return the number of filters actually written.
*/
if (ret == 0 || ret == -ENOMEM)
ret = nfilters;
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment