aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c143
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h16
2 files changed, 124 insertions, 35 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 073b85b45fc..bedcbb30d38 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -170,33 +170,81 @@ static void mlx4_en_do_set_mac(struct work_struct *work)
170static void mlx4_en_clear_list(struct net_device *dev) 170static void mlx4_en_clear_list(struct net_device *dev)
171{ 171{
172 struct mlx4_en_priv *priv = netdev_priv(dev); 172 struct mlx4_en_priv *priv = netdev_priv(dev);
173 struct mlx4_en_mc_list *tmp, *mc_to_del;
173 174
174 kfree(priv->mc_addrs); 175 list_for_each_entry_safe(mc_to_del, tmp, &priv->mc_list, list) {
175 priv->mc_addrs = NULL; 176 list_del(&mc_to_del->list);
176 priv->mc_addrs_cnt = 0; 177 kfree(mc_to_del);
178 }
177} 179}
178 180
179static void mlx4_en_cache_mclist(struct net_device *dev) 181static void mlx4_en_cache_mclist(struct net_device *dev)
180{ 182{
181 struct mlx4_en_priv *priv = netdev_priv(dev); 183 struct mlx4_en_priv *priv = netdev_priv(dev);
182 struct netdev_hw_addr *ha; 184 struct netdev_hw_addr *ha;
183 char *mc_addrs; 185 struct mlx4_en_mc_list *tmp;
184 int mc_addrs_cnt = netdev_mc_count(dev);
185 int i;
186 186
187 mc_addrs = kmalloc(mc_addrs_cnt * ETH_ALEN, GFP_ATOMIC);
188 if (!mc_addrs) {
189 en_err(priv, "failed to allocate multicast list\n");
190 return;
191 }
192 i = 0;
193 netdev_for_each_mc_addr(ha, dev)
194 memcpy(mc_addrs + i++ * ETH_ALEN, ha->addr, ETH_ALEN);
195 mlx4_en_clear_list(dev); 187 mlx4_en_clear_list(dev);
196 priv->mc_addrs = mc_addrs; 188 netdev_for_each_mc_addr(ha, dev) {
197 priv->mc_addrs_cnt = mc_addrs_cnt; 189 tmp = kzalloc(sizeof(struct mlx4_en_mc_list), GFP_ATOMIC);
190 if (!tmp) {
191 en_err(priv, "failed to allocate multicast list\n");
192 mlx4_en_clear_list(dev);
193 return;
194 }
195 memcpy(tmp->addr, ha->addr, ETH_ALEN);
196 list_add_tail(&tmp->list, &priv->mc_list);
197 }
198} 198}
199 199
200static void update_mclist_flags(struct mlx4_en_priv *priv,
201 struct list_head *dst,
202 struct list_head *src)
203{
204 struct mlx4_en_mc_list *dst_tmp, *src_tmp, *new_mc;
205 bool found;
206
207 /* Find all the entries that should be removed from dst,
208 * These are the entries that are not found in src
209 */
210 list_for_each_entry(dst_tmp, dst, list) {
211 found = false;
212 list_for_each_entry(src_tmp, src, list) {
213 if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) {
214 found = true;
215 break;
216 }
217 }
218 if (!found)
219 dst_tmp->action = MCLIST_REM;
220 }
221
222 /* Add entries that exist in src but not in dst
223 * mark them as need to add
224 */
225 list_for_each_entry(src_tmp, src, list) {
226 found = false;
227 list_for_each_entry(dst_tmp, dst, list) {
228 if (!memcmp(dst_tmp->addr, src_tmp->addr, ETH_ALEN)) {
229 dst_tmp->action = MCLIST_NONE;
230 found = true;
231 break;
232 }
233 }
234 if (!found) {
235 new_mc = kmalloc(sizeof(struct mlx4_en_mc_list),
236 GFP_KERNEL);
237 if (!new_mc) {
238 en_err(priv, "Failed to allocate current multicast list\n");
239 return;
240 }
241 memcpy(new_mc, src_tmp,
242 sizeof(struct mlx4_en_mc_list));
243 new_mc->action = MCLIST_ADD;
244 list_add_tail(&new_mc->list, dst);
245 }
246 }
247}
200 248
201static void mlx4_en_set_multicast(struct net_device *dev) 249static void mlx4_en_set_multicast(struct net_device *dev)
202{ 250{
@@ -214,6 +262,7 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
214 mcast_task); 262 mcast_task);
215 struct mlx4_en_dev *mdev = priv->mdev; 263 struct mlx4_en_dev *mdev = priv->mdev;
216 struct net_device *dev = priv->dev; 264 struct net_device *dev = priv->dev;
265 struct mlx4_en_mc_list *mclist, *tmp;
217 u64 mcast_addr = 0; 266 u64 mcast_addr = 0;
218 u8 mc_list[16] = {0}; 267 u8 mc_list[16] = {0};
219 int err; 268 int err;
@@ -336,7 +385,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
336 priv->flags |= MLX4_EN_FLAG_MC_PROMISC; 385 priv->flags |= MLX4_EN_FLAG_MC_PROMISC;
337 } 386 }
338 } else { 387 } else {
339 int i;
340 /* Disable Multicast promisc */ 388 /* Disable Multicast promisc */
341 if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) { 389 if (priv->flags & MLX4_EN_FLAG_MC_PROMISC) {
342 err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn, 390 err = mlx4_multicast_promisc_remove(mdev->dev, priv->base_qpn,
@@ -351,13 +399,6 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
351 if (err) 399 if (err)
352 en_err(priv, "Failed disabling multicast filter\n"); 400 en_err(priv, "Failed disabling multicast filter\n");
353 401
354 /* Detach our qp from all the multicast addresses */
355 for (i = 0; i < priv->mc_addrs_cnt; i++) {
356 memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
357 mc_list[5] = priv->port;
358 mlx4_multicast_detach(mdev->dev, &priv->rss_map.indir_qp,
359 mc_list, MLX4_PROT_ETH);
360 }
361 /* Flush mcast filter and init it with broadcast address */ 402 /* Flush mcast filter and init it with broadcast address */
362 mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST, 403 mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, ETH_BCAST,
363 1, MLX4_MCAST_CONFIG); 404 1, MLX4_MCAST_CONFIG);
@@ -367,13 +408,8 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
367 netif_tx_lock_bh(dev); 408 netif_tx_lock_bh(dev);
368 mlx4_en_cache_mclist(dev); 409 mlx4_en_cache_mclist(dev);
369 netif_tx_unlock_bh(dev); 410 netif_tx_unlock_bh(dev);
370 for (i = 0; i < priv->mc_addrs_cnt; i++) { 411 list_for_each_entry(mclist, &priv->mc_list, list) {
371 mcast_addr = 412 mcast_addr = mlx4_en_mac_to_u64(mclist->addr);
372 mlx4_en_mac_to_u64(priv->mc_addrs + i * ETH_ALEN);
373 memcpy(&mc_list[10], priv->mc_addrs + i * ETH_ALEN, ETH_ALEN);
374 mc_list[5] = priv->port;
375 mlx4_multicast_attach(mdev->dev, &priv->rss_map.indir_qp,
376 mc_list, 0, MLX4_PROT_ETH);
377 mlx4_SET_MCAST_FLTR(mdev->dev, priv->port, 413 mlx4_SET_MCAST_FLTR(mdev->dev, priv->port,
378 mcast_addr, 0, MLX4_MCAST_CONFIG); 414 mcast_addr, 0, MLX4_MCAST_CONFIG);
379 } 415 }
@@ -381,6 +417,38 @@ static void mlx4_en_do_set_multicast(struct work_struct *work)
381 0, MLX4_MCAST_ENABLE); 417 0, MLX4_MCAST_ENABLE);
382 if (err) 418 if (err)
383 en_err(priv, "Failed enabling multicast filter\n"); 419 en_err(priv, "Failed enabling multicast filter\n");
420
421 update_mclist_flags(priv, &priv->curr_list, &priv->mc_list);
422 list_for_each_entry_safe(mclist, tmp, &priv->curr_list, list) {
423 if (mclist->action == MCLIST_REM) {
424 /* detach this address and delete from list */
425 memcpy(&mc_list[10], mclist->addr, ETH_ALEN);
426 mc_list[5] = priv->port;
427 err = mlx4_multicast_detach(mdev->dev,
428 &priv->rss_map.indir_qp,
429 mc_list,
430 MLX4_PROT_ETH);
431 if (err)
432 en_err(priv, "Fail to detach multicast address\n");
433
434 /* remove from list */
435 list_del(&mclist->list);
436 kfree(mclist);
437 }
438
439 if (mclist->action == MCLIST_ADD) {
440 /* attach the address */
441 memcpy(&mc_list[10], mclist->addr, ETH_ALEN);
442 mc_list[5] = priv->port;
443 err = mlx4_multicast_attach(mdev->dev,
444 &priv->rss_map.indir_qp,