aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ethernet/mellanox/mlx4
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/mellanox/mlx4')
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c129
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h3
2 files changed, 130 insertions, 2 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index 8eb24ee598e2..2c19dabccb9a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -1016,6 +1016,126 @@ static void mlx4_en_do_multicast(struct mlx4_en_priv *priv,
1016 } 1016 }
1017} 1017}
1018 1018
1019static void mlx4_en_do_uc_filter(struct mlx4_en_priv *priv,
1020 struct net_device *dev,
1021 struct mlx4_en_dev *mdev)
1022{
1023 struct netdev_hw_addr *ha;
1024 struct mlx4_mac_entry *entry;
1025 struct hlist_node *n, *tmp;
1026 bool found;
1027 u64 mac;
1028 int err = 0;
1029 struct hlist_head *bucket;
1030 unsigned int i;
1031 int removed = 0;
1032 u32 prev_flags;
1033
1034 /* Note that we do not need to protect our mac_hash traversal with rcu,
1035 * since all modification code is protected by mdev->state_lock
1036 */
1037
1038 /* find what to remove */
1039 for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i) {
1040 bucket = &priv->mac_hash[i];
1041 hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
1042 found = false;
1043 netdev_for_each_uc_addr(ha, dev) {
1044 if (ether_addr_equal_64bits(entry->mac,
1045 ha->addr)) {
1046 found = true;
1047 break;
1048 }
1049 }
1050
1051 /* MAC address of the port is not in uc list */
1052 if (ether_addr_equal_64bits(entry->mac, dev->dev_addr))
1053 found = true;
1054
1055 if (!found) {
1056 mac = mlx4_en_mac_to_u64(entry->mac);
1057 mlx4_en_uc_steer_release(priv, entry->mac,
1058 priv->base_qpn,
1059 entry->reg_id);
1060 mlx4_unregister_mac(mdev->dev, priv->port, mac);
1061
1062 hlist_del_rcu(&entry->hlist);
1063 kfree_rcu(entry, rcu);
1064 en_dbg(DRV, priv, "Removed MAC %pM on port:%d\n",
1065 entry->mac, priv->port);
1066 ++removed;
1067 }
1068 }
1069 }
1070
1071 /* if we didn't remove anything, there is no use in trying to add
1072 * again once we are in a forced promisc mode state
1073 */
1074 if ((priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) && 0 == removed)
1075 return;
1076
1077 prev_flags = priv->flags;
1078 priv->flags &= ~MLX4_EN_FLAG_FORCE_PROMISC;
1079
1080 /* find what to add */
1081 netdev_for_each_uc_addr(ha, dev) {
1082 found = false;
1083 bucket = &priv->mac_hash[ha->addr[MLX4_EN_MAC_HASH_IDX]];
1084 hlist_for_each_entry(entry, n, bucket, hlist) {
1085 if (ether_addr_equal_64bits(entry->mac, ha->addr)) {
1086 found = true;
1087 break;
1088 }
1089 }
1090
1091 if (!found) {
1092 entry = kmalloc(sizeof(*entry), GFP_KERNEL);
1093 if (!entry) {
1094 en_err(priv, "Failed adding MAC %pM on port:%d (out of memory)\n",
1095 ha->addr, priv->port);
1096 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1097 break;
1098 }
1099 mac = mlx4_en_mac_to_u64(ha->addr);
1100 memcpy(entry->mac, ha->addr, ETH_ALEN);
1101 err = mlx4_register_mac(mdev->dev, priv->port, mac);
1102 if (err < 0) {
1103 en_err(priv, "Failed registering MAC %pM on port %d: %d\n",
1104 ha->addr, priv->port, err);
1105 kfree(entry);
1106 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1107 break;
1108 }
1109 err = mlx4_en_uc_steer_add(priv, ha->addr,
1110 &priv->base_qpn,
1111 &entry->reg_id);
1112 if (err) {
1113 en_err(priv, "Failed adding MAC %pM on port %d: %d\n",
1114 ha->addr, priv->port, err);
1115 mlx4_unregister_mac(mdev->dev, priv->port, mac);
1116 kfree(entry);
1117 priv->flags |= MLX4_EN_FLAG_FORCE_PROMISC;
1118 break;
1119 } else {
1120 unsigned int mac_hash;
1121 en_dbg(DRV, priv, "Added MAC %pM on port:%d\n",
1122 ha->addr, priv->port);
1123 mac_hash = ha->addr[MLX4_EN_MAC_HASH_IDX];
1124 bucket = &priv->mac_hash[mac_hash];
1125 hlist_add_head_rcu(&entry->hlist, bucket);
1126 }
1127 }
1128 }
1129
1130 if (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC) {
1131 en_warn(priv, "Forcing promiscuous mode on port:%d\n",
1132 priv->port);
1133 } else if (prev_flags & MLX4_EN_FLAG_FORCE_PROMISC) {
1134 en_warn(priv, "Stop forcing promiscuous mode on port:%d\n",
1135 priv->port);
1136 }
1137}
1138
1019static void mlx4_en_do_set_rx_mode(struct work_struct *work) 1139static void mlx4_en_do_set_rx_mode(struct work_struct *work)
1020{ 1140{
1021 struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv, 1141 struct mlx4_en_priv *priv = container_of(work, struct mlx4_en_priv,
@@ -1043,8 +1163,12 @@ static void mlx4_en_do_set_rx_mode(struct work_struct *work)
1043 } 1163 }
1044 } 1164 }
1045 1165
1166 if (dev->priv_flags & IFF_UNICAST_FLT)
1167 mlx4_en_do_uc_filter(priv, dev, mdev);
1168
1046 /* Promsicuous mode: disable all filters */ 1169 /* Promsicuous mode: disable all filters */
1047 if (dev->flags & IFF_PROMISC) { 1170 if ((dev->flags & IFF_PROMISC) ||
1171 (priv->flags & MLX4_EN_FLAG_FORCE_PROMISC)) {
1048 mlx4_en_set_promisc_mode(priv, mdev); 1172 mlx4_en_set_promisc_mode(priv, mdev);
1049 goto out; 1173 goto out;
1050 } 1174 }
@@ -1961,6 +2085,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
1961 MLX4_STEERING_MODE_DEVICE_MANAGED) 2085 MLX4_STEERING_MODE_DEVICE_MANAGED)
1962 dev->hw_features |= NETIF_F_NTUPLE; 2086 dev->hw_features |= NETIF_F_NTUPLE;
1963 2087
2088 if (mdev->dev->caps.steering_mode != MLX4_STEERING_MODE_A0)
2089 dev->priv_flags |= IFF_UNICAST_FLT;
2090
1964 mdev->pndev[port] = dev; 2091 mdev->pndev[port] = dev;
1965 2092
1966 netif_carrier_off(dev); 2093 netif_carrier_off(dev);
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 0ff99e0b2ea3..c313d7e943a9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -439,7 +439,8 @@ enum {
439 */ 439 */
440 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2), 440 MLX4_EN_FLAG_ENABLE_HW_LOOPBACK = (1 << 2),
441 /* whether we need to drop packets that hardware loopback-ed */ 441 /* whether we need to drop packets that hardware loopback-ed */
442 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3) 442 MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3),
443 MLX4_EN_FLAG_FORCE_PROMISC = (1 << 4)
443}; 444};
444 445
445#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE) 446#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)