Commit 5ec6df77 authored by David S. Miller's avatar David S. Miller

Merge branch 'mlx4-fixes'

Tariq Toukan says:

====================
Safe flow for mlx4_en configuration change

This patchset improves the mlx4_en driver resiliency, especially on
systems with low memory.  Upon a configuration change that requires
the allocation of new resources, we first try to allocate, prior to
destroying the current ones.  Once it is successfully done,
we release the old resources and attach the new ones.  Otherwise, we
stay with a functioning interface having the same old configuration.

This improvement became of greater significance after removing the use
of vmap.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c74bfbdb ec25bc04
...@@ -1042,6 +1042,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev, ...@@ -1042,6 +1042,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_port_profile new_prof;
struct mlx4_en_priv *tmp;
u32 rx_size, tx_size; u32 rx_size, tx_size;
int port_up = 0; int port_up = 0;
int err = 0; int err = 0;
...@@ -1061,22 +1063,25 @@ static int mlx4_en_set_ringparam(struct net_device *dev, ...@@ -1061,22 +1063,25 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
tx_size == priv->tx_ring[0]->size) tx_size == priv->tx_ring[0]->size)
return 0; return 0;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
mutex_lock(&mdev->state_lock); mutex_lock(&mdev->state_lock);
memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile));
new_prof.tx_ring_size = tx_size;
new_prof.rx_ring_size = rx_size;
err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof);
if (err)
goto out;
if (priv->port_up) { if (priv->port_up) {
port_up = 1; port_up = 1;
mlx4_en_stop_port(dev, 1); mlx4_en_stop_port(dev, 1);
} }
mlx4_en_free_resources(priv); mlx4_en_safe_replace_resources(priv, tmp);
priv->prof->tx_ring_size = tx_size;
priv->prof->rx_ring_size = rx_size;
err = mlx4_en_alloc_resources(priv);
if (err) {
en_err(priv, "Failed reallocating port resources\n");
goto out;
}
if (port_up) { if (port_up) {
err = mlx4_en_start_port(dev); err = mlx4_en_start_port(dev);
if (err) if (err)
...@@ -1084,8 +1089,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev, ...@@ -1084,8 +1089,8 @@ static int mlx4_en_set_ringparam(struct net_device *dev,
} }
err = mlx4_en_moderation_update(priv); err = mlx4_en_moderation_update(priv);
out: out:
kfree(tmp);
mutex_unlock(&mdev->state_lock); mutex_unlock(&mdev->state_lock);
return err; return err;
} }
...@@ -1714,6 +1719,8 @@ static int mlx4_en_set_channels(struct net_device *dev, ...@@ -1714,6 +1719,8 @@ static int mlx4_en_set_channels(struct net_device *dev,
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_port_profile new_prof;
struct mlx4_en_priv *tmp;
int port_up = 0; int port_up = 0;
int err = 0; int err = 0;
...@@ -1723,23 +1730,26 @@ static int mlx4_en_set_channels(struct net_device *dev, ...@@ -1723,23 +1730,26 @@ static int mlx4_en_set_channels(struct net_device *dev,
!channel->tx_count || !channel->rx_count) !channel->tx_count || !channel->rx_count)
return -EINVAL; return -EINVAL;
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
mutex_lock(&mdev->state_lock); mutex_lock(&mdev->state_lock);
memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile));
new_prof.num_tx_rings_p_up = channel->tx_count;
new_prof.tx_ring_num = channel->tx_count * MLX4_EN_NUM_UP;
new_prof.rx_ring_num = channel->rx_count;
err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof);
if (err)
goto out;
if (priv->port_up) { if (priv->port_up) {
port_up = 1; port_up = 1;
mlx4_en_stop_port(dev, 1); mlx4_en_stop_port(dev, 1);
} }
mlx4_en_free_resources(priv); mlx4_en_safe_replace_resources(priv, tmp);
priv->num_tx_rings_p_up = channel->tx_count;
priv->tx_ring_num = channel->tx_count * MLX4_EN_NUM_UP;
priv->rx_ring_num = channel->rx_count;
err = mlx4_en_alloc_resources(priv);
if (err) {
en_err(priv, "Failed reallocating port resources\n");
goto out;
}
netif_set_real_num_tx_queues(dev, priv->tx_ring_num); netif_set_real_num_tx_queues(dev, priv->tx_ring_num);
netif_set_real_num_rx_queues(dev, priv->rx_ring_num); netif_set_real_num_rx_queues(dev, priv->rx_ring_num);
...@@ -1757,8 +1767,8 @@ static int mlx4_en_set_channels(struct net_device *dev, ...@@ -1757,8 +1767,8 @@ static int mlx4_en_set_channels(struct net_device *dev,
} }
err = mlx4_en_moderation_update(priv); err = mlx4_en_moderation_update(priv);
out: out:
kfree(tmp);
mutex_unlock(&mdev->state_lock); mutex_unlock(&mdev->state_lock);
return err; return err;
} }
......
...@@ -1954,7 +1954,7 @@ static int mlx4_en_close(struct net_device *dev) ...@@ -1954,7 +1954,7 @@ static int mlx4_en_close(struct net_device *dev)
return 0; return 0;
} }
void mlx4_en_free_resources(struct mlx4_en_priv *priv) static void mlx4_en_free_resources(struct mlx4_en_priv *priv)
{ {
int i; int i;
...@@ -1979,7 +1979,7 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv) ...@@ -1979,7 +1979,7 @@ void mlx4_en_free_resources(struct mlx4_en_priv *priv)
} }
int mlx4_en_alloc_resources(struct mlx4_en_priv *priv) static int mlx4_en_alloc_resources(struct mlx4_en_priv *priv)
{ {
struct mlx4_en_port_profile *prof = priv->prof; struct mlx4_en_port_profile *prof = priv->prof;
int i; int i;
...@@ -2044,6 +2044,77 @@ static void mlx4_en_shutdown(struct net_device *dev) ...@@ -2044,6 +2044,77 @@ static void mlx4_en_shutdown(struct net_device *dev)
rtnl_unlock(); rtnl_unlock();
} }
static int mlx4_en_copy_priv(struct mlx4_en_priv *dst,
struct mlx4_en_priv *src,
struct mlx4_en_port_profile *prof)
{
memcpy(&dst->hwtstamp_config, &prof->hwtstamp_config,
sizeof(dst->hwtstamp_config));
dst->num_tx_rings_p_up = src->mdev->profile.num_tx_rings_p_up;
dst->tx_ring_num = prof->tx_ring_num;
dst->rx_ring_num = prof->rx_ring_num;
dst->flags = prof->flags;
dst->mdev = src->mdev;
dst->port = src->port;
dst->dev = src->dev;
dst->prof = prof;
dst->stride = roundup_pow_of_two(sizeof(struct mlx4_en_rx_desc) +
DS_SIZE * MLX4_EN_MAX_RX_FRAGS);
dst->tx_ring = kzalloc(sizeof(struct mlx4_en_tx_ring *) * MAX_TX_RINGS,
GFP_KERNEL);
if (!dst->tx_ring)
return -ENOMEM;
dst->tx_cq = kzalloc(sizeof(struct mlx4_en_cq *) * MAX_TX_RINGS,
GFP_KERNEL);
if (!dst->tx_cq) {
kfree(dst->tx_ring);
return -ENOMEM;
}
return 0;
}
static void mlx4_en_update_priv(struct mlx4_en_priv *dst,
struct mlx4_en_priv *src)
{
memcpy(dst->rx_ring, src->rx_ring,
sizeof(struct mlx4_en_rx_ring *) * src->rx_ring_num);
memcpy(dst->rx_cq, src->rx_cq,
sizeof(struct mlx4_en_cq *) * src->rx_ring_num);
memcpy(&dst->hwtstamp_config, &src->hwtstamp_config,
sizeof(dst->hwtstamp_config));
dst->tx_ring_num = src->tx_ring_num;
dst->rx_ring_num = src->rx_ring_num;
dst->tx_ring = src->tx_ring;
dst->tx_cq = src->tx_cq;
memcpy(dst->prof, src->prof, sizeof(struct mlx4_en_port_profile));
}
int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv,
struct mlx4_en_priv *tmp,
struct mlx4_en_port_profile *prof)
{
mlx4_en_copy_priv(tmp, priv, prof);
if (mlx4_en_alloc_resources(tmp)) {
en_warn(priv,
"%s: Resource allocation failed, using previous configuration\n",
__func__);
kfree(tmp->tx_ring);
kfree(tmp->tx_cq);
return -ENOMEM;
}
return 0;
}
void mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv,
struct mlx4_en_priv *tmp)
{
mlx4_en_free_resources(priv);
mlx4_en_update_priv(priv, tmp);
}
void mlx4_en_destroy_netdev(struct net_device *dev) void mlx4_en_destroy_netdev(struct net_device *dev)
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
...@@ -2080,6 +2151,10 @@ void mlx4_en_destroy_netdev(struct net_device *dev) ...@@ -2080,6 +2151,10 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
mdev->upper[priv->port] = NULL; mdev->upper[priv->port] = NULL;
mutex_unlock(&mdev->state_lock); mutex_unlock(&mdev->state_lock);
#ifdef CONFIG_RFS_ACCEL
mlx4_en_cleanup_filters(priv);
#endif
mlx4_en_free_resources(priv); mlx4_en_free_resources(priv);
kfree(priv->tx_ring); kfree(priv->tx_ring);
...@@ -3124,6 +3199,8 @@ int mlx4_en_reset_config(struct net_device *dev, ...@@ -3124,6 +3199,8 @@ int mlx4_en_reset_config(struct net_device *dev,
{ {
struct mlx4_en_priv *priv = netdev_priv(dev); struct mlx4_en_priv *priv = netdev_priv(dev);
struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_dev *mdev = priv->mdev;
struct mlx4_en_port_profile new_prof;
struct mlx4_en_priv *tmp;
int port_up = 0; int port_up = 0;
int err = 0; int err = 0;
...@@ -3140,19 +3217,29 @@ int mlx4_en_reset_config(struct net_device *dev, ...@@ -3140,19 +3217,29 @@ int mlx4_en_reset_config(struct net_device *dev,
return -EINVAL; return -EINVAL;
} }
tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
if (!tmp)
return -ENOMEM;
mutex_lock(&mdev->state_lock); mutex_lock(&mdev->state_lock);
memcpy(&new_prof, priv->prof, sizeof(struct mlx4_en_port_profile));
memcpy(&new_prof.hwtstamp_config, &ts_config, sizeof(ts_config));
err = mlx4_en_try_alloc_resources(priv, tmp, &new_prof);
if (err)
goto out;
if (priv->port_up) { if (priv->port_up) {
port_up = 1; port_up = 1;
mlx4_en_stop_port(dev, 1); mlx4_en_stop_port(dev, 1);
} }
mlx4_en_free_resources(priv);
en_warn(priv, "Changing device configuration rx filter(%x) rx vlan(%x)\n", en_warn(priv, "Changing device configuration rx filter(%x) rx vlan(%x)\n",
ts_config.rx_filter, !!(features & NETIF_F_HW_VLAN_CTAG_RX)); ts_config.rx_filter,
!!(features & NETIF_F_HW_VLAN_CTAG_RX));
priv->hwtstamp_config.tx_type = ts_config.tx_type; mlx4_en_safe_replace_resources(priv, tmp);
priv->hwtstamp_config.rx_filter = ts_config.rx_filter;
if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) { if (DEV_FEATURE_CHANGED(dev, features, NETIF_F_HW_VLAN_CTAG_RX)) {
if (features & NETIF_F_HW_VLAN_CTAG_RX) if (features & NETIF_F_HW_VLAN_CTAG_RX)
...@@ -3186,11 +3273,6 @@ int mlx4_en_reset_config(struct net_device *dev, ...@@ -3186,11 +3273,6 @@ int mlx4_en_reset_config(struct net_device *dev,
dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX; dev->features &= ~NETIF_F_HW_VLAN_CTAG_RX;
} }
err = mlx4_en_alloc_resources(priv);
if (err) {
en_err(priv, "Failed reallocating port resources\n");
goto out;
}
if (port_up) { if (port_up) {
err = mlx4_en_start_port(dev); err = mlx4_en_start_port(dev);
if (err) if (err)
...@@ -3199,6 +3281,8 @@ int mlx4_en_reset_config(struct net_device *dev, ...@@ -3199,6 +3281,8 @@ int mlx4_en_reset_config(struct net_device *dev,
out: out:
mutex_unlock(&mdev->state_lock); mutex_unlock(&mdev->state_lock);
netdev_features_change(dev); kfree(tmp);
if (!err)
netdev_features_change(dev);
return err; return err;
} }
...@@ -514,9 +514,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv, ...@@ -514,9 +514,6 @@ void mlx4_en_destroy_rx_ring(struct mlx4_en_priv *priv,
ring->rx_info = NULL; ring->rx_info = NULL;
kfree(ring); kfree(ring);
*pring = NULL; *pring = NULL;
#ifdef CONFIG_RFS_ACCEL
mlx4_en_cleanup_filters(priv);
#endif
} }
void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv, void mlx4_en_deactivate_rx_ring(struct mlx4_en_priv *priv,
......
...@@ -353,12 +353,14 @@ struct mlx4_en_port_profile { ...@@ -353,12 +353,14 @@ struct mlx4_en_port_profile {
u32 rx_ring_num; u32 rx_ring_num;
u32 tx_ring_size; u32 tx_ring_size;
u32 rx_ring_size; u32 rx_ring_size;
u8 num_tx_rings_p_up;
u8 rx_pause; u8 rx_pause;
u8 rx_ppp; u8 rx_ppp;
u8 tx_pause; u8 tx_pause;
u8 tx_ppp; u8 tx_ppp;
int rss_rings; int rss_rings;
int inline_thold; int inline_thold;
struct hwtstamp_config hwtstamp_config;
}; };
struct mlx4_en_profile { struct mlx4_en_profile {
...@@ -623,8 +625,11 @@ void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev, ...@@ -623,8 +625,11 @@ void mlx4_en_set_stats_bitmap(struct mlx4_dev *dev,
u8 rx_ppp, u8 rx_pause, u8 rx_ppp, u8 rx_pause,
u8 tx_ppp, u8 tx_pause); u8 tx_ppp, u8 tx_pause);
void mlx4_en_free_resources(struct mlx4_en_priv *priv); int mlx4_en_try_alloc_resources(struct mlx4_en_priv *priv,
int mlx4_en_alloc_resources(struct mlx4_en_priv *priv); struct mlx4_en_priv *tmp,
struct mlx4_en_port_profile *prof);
void mlx4_en_safe_replace_resources(struct mlx4_en_priv *priv,
struct mlx4_en_priv *tmp);
int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq, int mlx4_en_create_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq **pcq,
int entries, int ring, enum cq_type mode, int node); int entries, int ring, enum cq_type mode, int node);
......
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