|
@@ -545,13 +545,10 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv)
|
|
|
memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
|
|
|
entry->reg_id = reg_id;
|
|
|
|
|
|
- err = radix_tree_insert(&priv->mac_tree, *qpn, entry);
|
|
|
- if (err)
|
|
|
- goto insert_err;
|
|
|
- return 0;
|
|
|
+ hlist_add_head_rcu(&entry->hlist,
|
|
|
+ &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]);
|
|
|
|
|
|
-insert_err:
|
|
|
- kfree(entry);
|
|
|
+ return 0;
|
|
|
|
|
|
alloc_err:
|
|
|
mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id);
|
|
@@ -568,7 +565,6 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
|
|
|
{
|
|
|
struct mlx4_en_dev *mdev = priv->mdev;
|
|
|
struct mlx4_dev *dev = mdev->dev;
|
|
|
- struct mlx4_mac_entry *entry;
|
|
|
int qpn = priv->base_qpn;
|
|
|
u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr);
|
|
|
|
|
@@ -577,15 +573,26 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
|
|
|
mlx4_unregister_mac(dev, priv->port, mac);
|
|
|
|
|
|
if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
|
|
|
- entry = radix_tree_lookup(&priv->mac_tree, qpn);
|
|
|
- if (entry) {
|
|
|
- en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
|
|
|
- priv->port, entry->mac, qpn);
|
|
|
- mlx4_en_uc_steer_release(priv, entry->mac,
|
|
|
- qpn, entry->reg_id);
|
|
|
- mlx4_qp_release_range(dev, qpn, 1);
|
|
|
- radix_tree_delete(&priv->mac_tree, qpn);
|
|
|
- kfree(entry);
|
|
|
+ struct mlx4_mac_entry *entry;
|
|
|
+ struct hlist_node *n, *tmp;
|
|
|
+ struct hlist_head *bucket;
|
|
|
+ unsigned int mac_hash;
|
|
|
+
|
|
|
+ mac_hash = priv->dev->dev_addr[MLX4_EN_MAC_HASH_IDX];
|
|
|
+ bucket = &priv->mac_hash[mac_hash];
|
|
|
+ hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
|
|
|
+ if (ether_addr_equal_64bits(entry->mac,
|
|
|
+ priv->dev->dev_addr)) {
|
|
|
+ en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
|
|
|
+ priv->port, priv->dev->dev_addr, qpn);
|
|
|
+ mlx4_en_uc_steer_release(priv, entry->mac,
|
|
|
+ qpn, entry->reg_id);
|
|
|
+ mlx4_qp_release_range(dev, qpn, 1);
|
|
|
+
|
|
|
+ hlist_del_rcu(&entry->hlist);
|
|
|
+ kfree_rcu(entry, rcu);
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -595,26 +602,38 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
|
|
|
{
|
|
|
struct mlx4_en_dev *mdev = priv->mdev;
|
|
|
struct mlx4_dev *dev = mdev->dev;
|
|
|
- struct mlx4_mac_entry *entry;
|
|
|
int err = 0;
|
|
|
u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
|
|
|
|
|
|
if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
|
|
|
- u64 prev_mac_u64;
|
|
|
-
|
|
|
- entry = radix_tree_lookup(&priv->mac_tree, qpn);
|
|
|
- if (!entry)
|
|
|
- return -EINVAL;
|
|
|
- prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac);
|
|
|
- mlx4_en_uc_steer_release(priv, entry->mac,
|
|
|
- qpn, entry->reg_id);
|
|
|
- mlx4_unregister_mac(dev, priv->port, prev_mac_u64);
|
|
|
- memcpy(entry->mac, new_mac, ETH_ALEN);
|
|
|
- entry->reg_id = 0;
|
|
|
- mlx4_register_mac(dev, priv->port, new_mac_u64);
|
|
|
- err = mlx4_en_uc_steer_add(priv, new_mac,
|
|
|
- &qpn, &entry->reg_id);
|
|
|
- return err;
|
|
|
+ struct hlist_head *bucket;
|
|
|
+ unsigned int mac_hash;
|
|
|
+ struct mlx4_mac_entry *entry;
|
|
|
+ struct hlist_node *n, *tmp;
|
|
|
+ u64 prev_mac_u64 = mlx4_en_mac_to_u64(prev_mac);
|
|
|
+
|
|
|
+ bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
|
|
|
+ hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
|
|
|
+ if (ether_addr_equal_64bits(entry->mac, prev_mac)) {
|
|
|
+ mlx4_en_uc_steer_release(priv, entry->mac,
|
|
|
+ qpn, entry->reg_id);
|
|
|
+ mlx4_unregister_mac(dev, priv->port,
|
|
|
+ prev_mac_u64);
|
|
|
+ hlist_del_rcu(&entry->hlist);
|
|
|
+ synchronize_rcu();
|
|
|
+ memcpy(entry->mac, new_mac, ETH_ALEN);
|
|
|
+ entry->reg_id = 0;
|
|
|
+ mac_hash = new_mac[MLX4_EN_MAC_HASH_IDX];
|
|
|
+ hlist_add_head_rcu(&entry->hlist,
|
|
|
+ &priv->mac_hash[mac_hash]);
|
|
|
+ mlx4_register_mac(dev, priv->port, new_mac_u64);
|
|
|
+ err = mlx4_en_uc_steer_add(priv, new_mac,
|
|
|
+ &qpn,
|
|
|
+ &entry->reg_id);
|
|
|
+ return err;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return -EINVAL;
|
|
|
}
|
|
|
|
|
|
return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64);
|
|
@@ -1816,6 +1835,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
|
|
|
{
|
|
|
struct net_device *dev;
|
|
|
struct mlx4_en_priv *priv;
|
|
|
+ int i;
|
|
|
int err;
|
|
|
|
|
|
dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv),
|
|
@@ -1874,7 +1894,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
|
|
|
dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
|
|
|
#endif
|
|
|
|
|
|
- INIT_RADIX_TREE(&priv->mac_tree, GFP_KERNEL);
|
|
|
+ for (i = 0; i < MLX4_EN_MAC_HASH_SIZE; ++i)
|
|
|
+ INIT_HLIST_HEAD(&priv->mac_hash[i]);
|
|
|
|
|
|
/* Query for default mac and max mtu */
|
|
|
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
|