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: Yan Burman <yanb@mellanox.com> Signed-off-by: Amir Vadai <amirv@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
90bbb74af6
Коммит
c07cb4b0ab
|
@ -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;
|
||||
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);
|
||||
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;
|
||||
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];
|
||||
|
|
|
@ -615,10 +615,25 @@ 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) +
|
||||
frags[0].offset);
|
||||
|
||||
/* Drop the packet, since HW loopback-ed it */
|
||||
if (ether_addr_equal_64bits(dev->dev_addr,
|
||||
ethh->h_source))
|
||||
goto next;
|
||||
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 */
|
||||
mac_hash = ethh->h_source[MLX4_EN_MAC_HASH_IDX];
|
||||
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;
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -442,6 +442,9 @@ enum {
|
|||
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_dev *mdev;
|
||||
struct mlx4_en_port_profile *prof;
|
||||
|
@ -521,7 +524,7 @@ struct mlx4_en_priv {
|
|||
bool wol;
|
||||
struct device *ddev;
|
||||
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
|
||||
struct ieee_ets ets;
|
||||
|
@ -542,8 +545,10 @@ enum mlx4_en_wol {
|
|||
};
|
||||
|
||||
struct mlx4_mac_entry {
|
||||
struct hlist_node hlist;
|
||||
unsigned char mac[ETH_ALEN + 2];
|
||||
u64 reg_id;
|
||||
struct rcu_head rcu;
|
||||
};
|
||||
|
||||
#define MLX4_EN_WOL_DO_MODIFY (1ULL << 63)
|
||||
|
|
Загрузка…
Ссылка в новой задаче