Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 315025
b: refs/heads/master
c: 6d19993
h: refs/heads/master
i:
  315023: 141273a
v: v3
  • Loading branch information
Yevgeny Petrilin authored and David S. Miller committed Jul 7, 2012
1 parent aa0c8ff commit a29d2b7
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: aa1ec3dde1d818dcc94e307e25df98242aff5538
refs/heads/master: 6d19993788e080edb557178cc6aba2d963edce4e
143 changes: 110 additions & 33 deletions trunk/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,33 +170,81 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
static void mlx4_en_clear_list(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_mc_list *tmp, *mc_to_del;

kfree(priv->mc_addrs);
priv->mc_addrs = NULL;
priv->mc_addrs_cnt = 0;
list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) {
list_del(&mc_to_del->list);
kfree(mc_to_del);
}
}

static void mlx4_en_cache_mclist(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct netdev_hw_addr *ha;
char *mc_addrs;
int mc_addrs_cnt = netdev_mc_count(dev);
int i;
struct mlx4_en_mc_list *tmp;

mc_addrs = kmalloc(mc_addrs_cnt * ETH_ALEN, GFP_ATOMIC);
if (!mc_addrs) {
en_err(priv, "failed to allocate multicast list\n");
return;
}
i = 0;
netdev_for_each_mc_addr(ha, dev)
memcpy(mc_addrs + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
mlx4_en_clear_list(dev);
priv->mc_addrs = mc_addrs;
priv->mc_addrs_cnt = mc_addrs_cnt;
netdev_for_each_mc_addr(ha, dev) {
tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC);
if (!tmp) {
en_err(priv, "failed to allocate multicast list\n");
mlx4_en_clear_list(dev);
return;
}
memcpy(tmp->addr, ha->addr, ETH_ALEN);
list_add_tail(&tmp->list, &priv->mc_list);
}
}

static void update_mclist_flags(struct mlx4_en_priv *priv,
struct list_head *dst,
struct list_head *src)
{
struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc;
bool found;

/* Find all the entries that should be removed from dst,
* These are the entries that are not found in src
*/
list_for_each_entry(dst_tmp, dst, list) {
found = false;
list_for_each_entry(src_tmp, src, list) {
if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) {
found = true;
break;
}
}
if (!found)
dst_tmp->action = MCLIST_REM;
}

/* Add entries that exist in src but not in dst
* mark them as need to add
*/
list_for_each_entry(src_tmp, src, list) {
found = false;
list_for_each_entry(dst_tmp, dst, list) {
if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) {
dst_tmp->action = MCLIST_NONE;
found = true;
break;
}
}
if (!found) {
new_mc = kmalloc(sizeof(struct mlx4_en_mc_list),
GFP_KERNEL);
if (!new_mc) {
en_err(priv, "Failed to allocate current multicast list\n");
return;
}
memcpy(new_mc, src_tmp,
sizeof(struct mlx4_en_mc_list));
new_mc->action = MCLIST_ADD;
list_add_tail(&new_mc->list, dst);
}
}
}

static void mlx4_en_set_multicast(struct net_device *dev)
{
Expand All @@ -214,6 +262,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
mcast_task);
struct mlx4_en_dev *mdev = priv->mdev;
struct net_device *dev = priv->dev;
struct mlx4_en_mc_list *mclist, *tmp;
u64 mcast_addr = 0;
u8 mc_list[16] = {0};
int err;
Expand Down Expand Up @@ -336,7 +385,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
}
} else {
int i;
/* Disable Multicast promisc */
if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
Expand All @@ -351,13 +399,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
if (err)
en_err(priv, "Failed disabling multicast filter\n");

/* Detach our qp from all the multicast addresses */
for (i = 0; i < priv->mc_addrs_cnt; i++) {
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
mc_list, MLX4_PROT_ETH);
}
/* Flush mcast filter and init it with broadcast address */
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
1, MLX4_MCAST_CONFIG);
Expand All @@ -367,20 +408,47 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
netif_tx_lock_bh(dev);
mlx4_en_cache_mclist(dev);
netif_tx_unlock_bh(dev);
for (i = 0; i < priv->mc_addrs_cnt; i++) {
mcast_addr =
mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN);
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp,
mc_list, 0, MLX4_PROT_ETH);
list_for_each_entry(mclist, &priv->mc_list, list) {
mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
mcast_addr, 0, MLX4_MCAST_CONFIG);
}
err = mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0,
0, MLX4_MCAST_ENABLE);
if (err)
en_err(priv, "Failed enabling multicast filter\n");

update_mclist_flags(priv, &priv->curr_list, &priv->mc_list);
list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
if (mclist->action == MCLIST_REM) {
/* detach this address and delete from list */
memcpy(&mc_list[10], mclist->addr, ETH_ALEN);
mc_list[5] = priv->port;
err = mlx4_multicast_detach(mdev->dev,
&priv->rss_map.indir_qp,
mc_list,
MLX4_PROT_ETH);
if (err)
en_err(priv, "Fail to detach multicast address\n");

/* remove from list */
list_del(&mclist->list);
kfree(mclist);
}

if (mclist->action == MCLIST_ADD) {
/* attach the address */
memcpy(&mc_list[10], mclist->addr, ETH_ALEN);
mc_list[5] = priv->port;
err = mlx4_multicast_attach(mdev->dev,
&priv->rss_map.indir_qp,
mc_list, 0,
MLX4_PROT_ETH);
if (err)
en_err(priv, "Fail to attach multicast address\n");

}
}
}
out:
mutex_unlock(&mdev->state_lock);
Expand Down Expand Up @@ -605,6 +673,9 @@ int mlx4_en_start_port(struct net_device *dev)
return 0;
}

INIT_LIST_HEAD(&priv->mc_list);
INIT_LIST_HEAD(&priv->curr_list);

/* Calculate Rx buf size */
dev->mtu = min(dev->mtu, priv->max_mtu);
mlx4_en_calc_rx_buf(dev);
Expand Down Expand Up @@ -760,6 +831,7 @@ void mlx4_en_stop_port(struct net_device *dev)
{
struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_mc_list *mclist, *tmp;
int i;
u8 mc_list[16] = {0};

Expand All @@ -781,13 +853,18 @@ void mlx4_en_stop_port(struct net_device *dev)
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp, mc_list,
MLX4_PROT_ETH);
for (i = 0; i < priv->mc_addrs_cnt; i++) {
memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
list_for_each_entry(mclist, &priv->curr_list, list) {
memcpy(&mc_list[10], mclist->addr, ETH_ALEN);
mc_list[5] = priv->port;
mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
mc_list, MLX4_PROT_ETH);
}
mlx4_en_clear_list(dev);
list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
list_del(&mclist->list);
kfree(mclist);
}

/* Flush multicast filter */
mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 0, 1, MLX4_MCAST_CONFIG);

Expand Down
16 changes: 14 additions & 2 deletions trunk/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,18 @@ struct mlx4_en_perf_stats {
#define NUM_PERF_COUNTERS 6
};

enum mlx4_en_mclist_act {
MCLIST_NONE,
MCLIST_REM,
MCLIST_ADD,
};

struct mlx4_en_mc_list {
struct list_head list;
enum mlx4_en_mclist_act action;
u8 addr[ETH_ALEN];
};

struct mlx4_en_frag_info {
u16 frag_size;
u16 frag_prefix_size;
Expand Down Expand Up @@ -489,8 +501,8 @@ struct mlx4_en_priv {
struct mlx4_en_pkt_stats pkstats;
struct mlx4_en_port_stats port_stats;
u64 stats_bitmap;
char *mc_addrs;
int mc_addrs_cnt;
struct list_head mc_list;
struct list_head curr_list;
struct mlx4_en_stat_out_mbox hw_stats;
int vids[128];
bool wol;
Expand Down

0 comments on commit a29d2b7

Please sign in to comment.