Commit c07cb4b0 authored by Yan Burman's avatar Yan Burman Committed by David S. Miller

net/mlx4_en: Manage hash of MAC addresses per port

As a preparation step for supporting multiple unicast addresses, store MAC addresses in hash table.
Remove the radix tree for MAC addresses per QP, as it's not in use.
Signed-off-by: default avatarYan Burman <yanb@mellanox.com>
Signed-off-by: default avatarAmir Vadai <amirv@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 90bbb74a
...@@ -545,13 +545,10 @@ static int mlx4_en_get_qp(struct mlx4_en_priv *priv) ...@@ -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)); memcpy(entry->mac, priv->dev->dev_addr, sizeof(entry->mac));
entry->reg_id = reg_id; entry->reg_id = reg_id;
err = radix_tree_insert(&priv->mac_tree, *qpn, entry); hlist_add_head_rcu(&entry->hlist,
if (err) &priv->mac_hash[entry->mac[MLX4_EN_MAC_HASH_IDX]]);
goto insert_err;
return 0;
insert_err: return 0;
kfree(entry);
alloc_err: alloc_err:
mlx4_en_uc_steer_release(priv, priv->dev->dev_addr, *qpn, reg_id); 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) ...@@ -568,7 +565,6 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
{ {
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_dev *dev = mdev->dev; struct mlx4_dev *dev = mdev->dev;
struct mlx4_mac_entry *entry;
int qpn = priv->base_qpn; int qpn = priv->base_qpn;
u64 mac = mlx4_en_mac_to_u64(priv->dev->dev_addr); 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) ...@@ -577,15 +573,26 @@ static void mlx4_en_put_qp(struct mlx4_en_priv *priv)
mlx4_unregister_mac(dev, priv->port, mac); mlx4_unregister_mac(dev, priv->port, mac);
if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
entry = radix_tree_lookup(&priv->mac_tree, qpn); struct mlx4_mac_entry *entry;
if (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", en_dbg(DRV, priv, "Releasing qp: port %d, MAC %pM, qpn %d\n",
priv->port, entry->mac, qpn); priv->port, priv->dev->dev_addr, qpn);
mlx4_en_uc_steer_release(priv, entry->mac, mlx4_en_uc_steer_release(priv, entry->mac,
qpn, entry->reg_id); qpn, entry->reg_id);
mlx4_qp_release_range(dev, qpn, 1); mlx4_qp_release_range(dev, qpn, 1);
radix_tree_delete(&priv->mac_tree, qpn);
kfree(entry); hlist_del_rcu(&entry->hlist);
kfree_rcu(entry, rcu);
break;
}
} }
} }
} }
...@@ -595,27 +602,39 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn, ...@@ -595,27 +602,39 @@ static int mlx4_en_replace_mac(struct mlx4_en_priv *priv, int qpn,
{ {
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_dev *dev = mdev->dev; struct mlx4_dev *dev = mdev->dev;
struct mlx4_mac_entry *entry;
int err = 0; int err = 0;
u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac); u64 new_mac_u64 = mlx4_en_mac_to_u64(new_mac);
if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) { if (dev->caps.steering_mode != MLX4_STEERING_MODE_A0) {
u64 prev_mac_u64; 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);
entry = radix_tree_lookup(&priv->mac_tree, qpn); bucket = &priv->mac_hash[prev_mac[MLX4_EN_MAC_HASH_IDX]];
if (!entry) hlist_for_each_entry_safe(entry, n, tmp, bucket, hlist) {
return -EINVAL; if (ether_addr_equal_64bits(entry->mac, prev_mac)) {
prev_mac_u64 = mlx4_en_mac_to_u64(entry->mac);
mlx4_en_uc_steer_release(priv, entry->mac, mlx4_en_uc_steer_release(priv, entry->mac,
qpn, entry->reg_id); qpn, entry->reg_id);
mlx4_unregister_mac(dev, priv->port, prev_mac_u64); mlx4_unregister_mac(dev, priv->port,
prev_mac_u64);
hlist_del_rcu(&entry->hlist);
synchronize_rcu();
memcpy(entry->mac, new_mac, ETH_ALEN); memcpy(entry->mac, new_mac, ETH_ALEN);
entry->reg_id = 0; 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); mlx4_register_mac(dev, priv->port, new_mac_u64);
err = mlx4_en_uc_steer_add(priv, new_mac, err = mlx4_en_uc_steer_add(priv, new_mac,
&qpn, &entry->reg_id); &qpn,
&entry->reg_id);
return err; return err;
} }
}
return -EINVAL;
}
return __mlx4_replace_mac(dev, priv->port, qpn, new_mac_u64); 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, ...@@ -1816,6 +1835,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
{ {
struct net_device *dev; struct net_device *dev;
struct mlx4_en_priv *priv; struct mlx4_en_priv *priv;
int i;
int err; int err;
dev = alloc_etherdev_mqs(sizeof(struct mlx4_en_priv), 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, ...@@ -1874,7 +1894,8 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
dev->dcbnl_ops = &mlx4_en_dcbnl_ops; dev->dcbnl_ops = &mlx4_en_dcbnl_ops;
#endif #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 */ /* Query for default mac and max mtu */
priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port]; priv->max_mtu = mdev->dev->caps.eth_mtu_cap[priv->port];
......
...@@ -615,11 +615,26 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud ...@@ -615,11 +615,26 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
ethh = (struct ethhdr *)(page_address(frags[0].page) + ethh = (struct ethhdr *)(page_address(frags[0].page) +
frags[0].offset); frags[0].offset);
if (is_multicast_ether_addr(ethh->h_dest)) {
struct mlx4_mac_entry *entry;
struct hlist_node *n;
struct hlist_head *bucket;
unsigned int mac_hash;
/* Drop the packet, since HW loopback-ed it */ /* Drop the packet, since HW loopback-ed it */
if (ether_addr_equal_64bits(dev->dev_addr, mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
ethh->h_source)) bucket = &priv->mac_hash[mac_hash];
rcu_read_lock();
hlist_for_each_entry_rcu(entry, n, bucket, hlist) {
if (ether_addr_equal_64bits(entry->mac,
ethh->h_source)) {
rcu_read_unlock();
goto next; goto next;
} }
}
rcu_read_unlock();
}
}
/* /*
* Packet is OK - process it. * Packet is OK - process it.
......
...@@ -442,6 +442,9 @@ enum { ...@@ -442,6 +442,9 @@ enum {
MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3) MLX4_EN_FLAG_RX_FILTER_NEEDED = (1 << 3)
}; };
#define MLX4_EN_MAC_HASH_SIZE (1 << BITS_PER_BYTE)
#define MLX4_EN_MAC_HASH_IDX 5
struct mlx4_en_priv { struct mlx4_en_priv {
struct mlx4_en_dev *mdev; struct mlx4_en_dev *mdev;
struct mlx4_en_port_profile *prof; struct mlx4_en_port_profile *prof;
...@@ -521,7 +524,7 @@ struct mlx4_en_priv { ...@@ -521,7 +524,7 @@ struct mlx4_en_priv {
bool wol; bool wol;
struct device *ddev; struct device *ddev;
int base_tx_qpn; int base_tx_qpn;
struct radix_tree_root mac_tree; struct hlist_head mac_hash[MLX4_EN_MAC_HASH_SIZE];
#ifdef CONFIG_MLX4_EN_DCB #ifdef CONFIG_MLX4_EN_DCB
struct ieee_ets ets; struct ieee_ets ets;
...@@ -542,8 +545,10 @@ enum mlx4_en_wol { ...@@ -542,8 +545,10 @@ enum mlx4_en_wol {
}; };
struct mlx4_mac_entry { struct mlx4_mac_entry {
struct hlist_node hlist;
unsigned char mac[ETH_ALEN + 2]; unsigned char mac[ETH_ALEN + 2];
u64 reg_id; u64 reg_id;
struct rcu_head rcu;
}; };
#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63) #define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment