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: Casey Leedom <leedom@chelsio.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
bcc70bb3ae
commit
42eb59d3a8
@ -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,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* 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,
|
|||||||
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,
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user