Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b37b07f authored by Achiad Shochat's avatar Achiad Shochat Committed by David S. Miller
Browse files

net/mlx5e: Take advantage of the light-weight netdev open/stop



Now that TIRs, TISs and flow tables are kept alive while the netdev is
stopped (after executing ndo_stop()) we can do the following
improvements:

- Obsolete the active_vlans SW shadow.
- Do not delete/add flow table rules upon ndo_stop/open.
  In addition to simplifying the flow, this change also fastens
  the ndo_open/close operations.
- Obsolete synchronization of threads accessing the flow tables
  with the netdev stop/open threads.

Signed-off-by: default avatarAchiad Shochat <achiad@mellanox.com>
Signed-off-by: default avatarAmir Vadai <amirv@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1cefa326
Loading
Loading
Loading
Loading
+1 −4
Original line number Original line Diff line number Diff line
@@ -374,10 +374,10 @@ struct mlx5e_eth_addr_db {
enum {
enum {
	MLX5E_STATE_ASYNC_EVENTS_ENABLE,
	MLX5E_STATE_ASYNC_EVENTS_ENABLE,
	MLX5E_STATE_OPENED,
	MLX5E_STATE_OPENED,
	MLX5E_STATE_DESTROYING,
};
};


struct mlx5e_vlan_db {
struct mlx5e_vlan_db {
	unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
	u32           active_vlans_ft_ix[VLAN_N_VID];
	u32           active_vlans_ft_ix[VLAN_N_VID];
	u32           untagged_rule_ft_ix;
	u32           untagged_rule_ft_ix;
	u32           any_vlan_rule_ft_ix;
	u32           any_vlan_rule_ft_ix;
@@ -485,7 +485,6 @@ void mlx5e_update_stats(struct mlx5e_priv *priv);
int mlx5e_create_flow_tables(struct mlx5e_priv *priv);
int mlx5e_create_flow_tables(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv);
void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv);
void mlx5e_init_eth_addr(struct mlx5e_priv *priv);
void mlx5e_init_eth_addr(struct mlx5e_priv *priv);
void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv);
void mlx5e_set_rx_mode_work(struct work_struct *work);
void mlx5e_set_rx_mode_work(struct work_struct *work);


int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
@@ -494,8 +493,6 @@ int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
			   u16 vid);
			   u16 vid);
void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv);
void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv);
int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv);
void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv);


int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_open_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
int mlx5e_close_locked(struct net_device *netdev);
+24 −85
Original line number Original line Diff line number Diff line
@@ -594,44 +594,28 @@ static void mlx5e_del_vlan_rule(struct mlx5e_priv *priv,


void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv)
void mlx5e_enable_vlan_filter(struct mlx5e_priv *priv)
{
{
	WARN_ON(!mutex_is_locked(&priv->state_lock));
	if (!priv->vlan.filter_disabled)
		return;


	if (priv->vlan.filter_disabled) {
	priv->vlan.filter_disabled = false;
	priv->vlan.filter_disabled = false;
		if (test_bit(MLX5E_STATE_OPENED, &priv->state))
	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);
			mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
					    0);
	}
}
}


void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv)
void mlx5e_disable_vlan_filter(struct mlx5e_priv *priv)
{
{
	WARN_ON(!mutex_is_locked(&priv->state_lock));
	if (priv->vlan.filter_disabled)
		return;


	if (!priv->vlan.filter_disabled) {
	priv->vlan.filter_disabled = true;
	priv->vlan.filter_disabled = true;
		if (test_bit(MLX5E_STATE_OPENED, &priv->state))
	mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);
			mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
					    0);
	}
}
}


int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
int mlx5e_vlan_rx_add_vid(struct net_device *dev, __always_unused __be16 proto,
			  u16 vid)
			  u16 vid)
{
{
	struct mlx5e_priv *priv = netdev_priv(dev);
	struct mlx5e_priv *priv = netdev_priv(dev);
	int err = 0;


	mutex_lock(&priv->state_lock);
	return mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);

	set_bit(vid, priv->vlan.active_vlans);
	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
		err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
					  vid);

	mutex_unlock(&priv->state_lock);

	return err;
}
}


int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
@@ -639,56 +623,11 @@ int mlx5e_vlan_rx_kill_vid(struct net_device *dev, __always_unused __be16 proto,
{
{
	struct mlx5e_priv *priv = netdev_priv(dev);
	struct mlx5e_priv *priv = netdev_priv(dev);


	mutex_lock(&priv->state_lock);

	clear_bit(vid, priv->vlan.active_vlans);
	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);


	mutex_unlock(&priv->state_lock);

	return 0;
	return 0;
}
}


int mlx5e_add_all_vlan_rules(struct mlx5e_priv *priv)
{
	u16 vid;
	int err;

	for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) {
		err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
					  vid);
		if (err)
			return err;
	}

	err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
	if (err)
		return err;

	if (priv->vlan.filter_disabled) {
		err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
					  0);
		if (err)
			return err;
	}

	return 0;
}

void mlx5e_del_all_vlan_rules(struct mlx5e_priv *priv)
{
	u16 vid;

	if (priv->vlan.filter_disabled)
		mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);

	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);

	for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID)
		mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
}

#define mlx5e_for_each_hash_node(hn, tmp, hash, i) \
#define mlx5e_for_each_hash_node(hn, tmp, hash, i) \
	for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \
	for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \
		hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist)
		hlist_for_each_entry_safe(hn, tmp, &hash[i], hlist)
@@ -752,18 +691,21 @@ static void mlx5e_handle_netdev_addr(struct mlx5e_priv *priv)
	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i)
	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.netdev_mc, i)
		hn->action = MLX5E_ACTION_DEL;
		hn->action = MLX5E_ACTION_DEL;


	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
	if (!test_bit(MLX5E_STATE_DESTROYING, &priv->state))
		mlx5e_sync_netdev_addr(priv);
		mlx5e_sync_netdev_addr(priv);


	mlx5e_apply_netdev_addr(priv);
	mlx5e_apply_netdev_addr(priv);
}
}


void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv)
void mlx5e_set_rx_mode_work(struct work_struct *work)
{
{
	struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
					       set_rx_mode_work);

	struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
	struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
	struct net_device *ndev = priv->netdev;
	struct net_device *ndev = priv->netdev;


	bool rx_mode_enable   = test_bit(MLX5E_STATE_OPENED, &priv->state);
	bool rx_mode_enable   = !test_bit(MLX5E_STATE_DESTROYING, &priv->state);
	bool promisc_enabled   = rx_mode_enable && (ndev->flags & IFF_PROMISC);
	bool promisc_enabled   = rx_mode_enable && (ndev->flags & IFF_PROMISC);
	bool allmulti_enabled  = rx_mode_enable && (ndev->flags & IFF_ALLMULTI);
	bool allmulti_enabled  = rx_mode_enable && (ndev->flags & IFF_ALLMULTI);
	bool broadcast_enabled = rx_mode_enable;
	bool broadcast_enabled = rx_mode_enable;
@@ -796,17 +738,6 @@ void mlx5e_set_rx_mode_core(struct mlx5e_priv *priv)
	ea->broadcast_enabled = broadcast_enabled;
	ea->broadcast_enabled = broadcast_enabled;
}
}


void mlx5e_set_rx_mode_work(struct work_struct *work)
{
	struct mlx5e_priv *priv = container_of(work, struct mlx5e_priv,
					       set_rx_mode_work);

	mutex_lock(&priv->state_lock);
	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
		mlx5e_set_rx_mode_core(priv);
	mutex_unlock(&priv->state_lock);
}

void mlx5e_init_eth_addr(struct mlx5e_priv *priv)
void mlx5e_init_eth_addr(struct mlx5e_priv *priv)
{
{
	ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast);
	ether_addr_copy(priv->eth_addr.broadcast.addr, priv->netdev->broadcast);
@@ -941,8 +872,15 @@ int mlx5e_create_flow_tables(struct mlx5e_priv *priv)
	if (err)
	if (err)
		goto err_destroy_main_flow_table;
		goto err_destroy_main_flow_table;


	err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
	if (err)
		goto err_destroy_vlan_flow_table;

	return 0;
	return 0;


err_destroy_vlan_flow_table:
	mlx5e_destroy_vlan_flow_table(priv);

err_destroy_main_flow_table:
err_destroy_main_flow_table:
	mlx5e_destroy_main_flow_table(priv);
	mlx5e_destroy_main_flow_table(priv);


@@ -951,6 +889,7 @@ int mlx5e_create_flow_tables(struct mlx5e_priv *priv)


void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv)
void mlx5e_destroy_flow_tables(struct mlx5e_priv *priv)
{
{
	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
	mlx5e_destroy_vlan_flow_table(priv);
	mlx5e_destroy_vlan_flow_table(priv);
	mlx5e_destroy_main_flow_table(priv);
	mlx5e_destroy_main_flow_table(priv);
}
}
+7 −17
Original line number Original line Diff line number Diff line
@@ -1332,24 +1332,12 @@ int mlx5e_open_locked(struct net_device *netdev)
		return err;
		return err;
	}
	}


	err = mlx5e_add_all_vlan_rules(priv);
	if (err) {
		netdev_err(netdev, "%s: mlx5e_add_all_vlan_rules failed, %d\n",
			   __func__, err);
		goto err_close_channels;
	}

	mlx5e_update_carrier(priv);
	mlx5e_update_carrier(priv);
	mlx5e_redirect_rqts(priv);
	mlx5e_redirect_rqts(priv);
	mlx5e_set_rx_mode_core(priv);


	schedule_delayed_work(&priv->update_stats_work, 0);
	schedule_delayed_work(&priv->update_stats_work, 0);
	return 0;

err_close_channels:
	mlx5e_close_channels(priv);


	return err;
	return 0;
}
}


static int mlx5e_open(struct net_device *netdev)
static int mlx5e_open(struct net_device *netdev)
@@ -1371,8 +1359,6 @@ int mlx5e_close_locked(struct net_device *netdev)
	clear_bit(MLX5E_STATE_OPENED, &priv->state);
	clear_bit(MLX5E_STATE_OPENED, &priv->state);


	mlx5e_redirect_rqts(priv);
	mlx5e_redirect_rqts(priv);
	mlx5e_set_rx_mode_core(priv);
	mlx5e_del_all_vlan_rules(priv);
	netif_carrier_off(priv->netdev);
	netif_carrier_off(priv->netdev);
	mlx5e_close_channels(priv);
	mlx5e_close_channels(priv);


@@ -1794,6 +1780,8 @@ static int mlx5e_set_features(struct net_device *netdev,
			err = mlx5e_open_locked(priv->netdev);
			err = mlx5e_open_locked(priv->netdev);
	}
	}


	mutex_unlock(&priv->state_lock);

	if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) {
	if (changes & NETIF_F_HW_VLAN_CTAG_FILTER) {
		if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
		if (features & NETIF_F_HW_VLAN_CTAG_FILTER)
			mlx5e_enable_vlan_filter(priv);
			mlx5e_enable_vlan_filter(priv);
@@ -1801,8 +1789,6 @@ static int mlx5e_set_features(struct net_device *netdev,
			mlx5e_disable_vlan_filter(priv);
			mlx5e_disable_vlan_filter(priv);
	}
	}


	mutex_unlock(&priv->state_lock);

	return 0;
	return 0;
}
}


@@ -2094,6 +2080,7 @@ static void *mlx5e_create_netdev(struct mlx5_core_dev *mdev)
	}
	}


	mlx5e_enable_async_events(priv);
	mlx5e_enable_async_events(priv);
	schedule_work(&priv->set_rx_mode_work);


	return priv;
	return priv;


@@ -2138,6 +2125,9 @@ static void mlx5e_destroy_netdev(struct mlx5_core_dev *mdev, void *vpriv)
	struct mlx5e_priv *priv = vpriv;
	struct mlx5e_priv *priv = vpriv;
	struct net_device *netdev = priv->netdev;
	struct net_device *netdev = priv->netdev;


	set_bit(MLX5E_STATE_DESTROYING, &priv->state);

	schedule_work(&priv->set_rx_mode_work);
	mlx5e_disable_async_events(priv);
	mlx5e_disable_async_events(priv);
	flush_scheduled_work();
	flush_scheduled_work();
	unregister_netdev(netdev);
	unregister_netdev(netdev);