diff options
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/en_netdev.c | 143 | ||||
| -rw-r--r-- | drivers/net/ethernet/mellanox/mlx4/mlx4_en.h | 16 |
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) | |||
| 170 | static void mlx4_en_clear_list(struct net_device *dev) | 170 | static 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 | ||
| 179 | static void mlx4_en_cache_mclist(struct net_device *dev) | 181 | static 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 | ||
| 200 | static 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 | ||
| 201 | static void mlx4_en_set_multicast(struct net_device *dev) | 249 | static 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, | ||
