Commit 992d8a4e authored by Gal Pressman's avatar Gal Pressman Committed by Saeed Mahameed

net/mlx5e: Fix wrong features assignment in case of error

In case of an error in mlx5e_set_features(), 'netdev->features' must be
updated with the correct state of the device to indicate which features
were updated successfully.
To do that we maintain a copy of 'netdev->features' and update it after
successful feature changes, so we can assign it to back to
'netdev->features' if needed.

However, since not all netdev features are handled by the driver (e.g.
GRO/TSO/etc), some features may not be updated correctly in case of an
error updating another feature.

For example, while requesting to disable TSO (feature which is not
handled by the driver) and enable HW-GRO, if an error occurs during
HW-GRO enable, 'oper_features' will be assigned with 'netdev->features'
and HW-GRO turned off. TSO will remain enabled in such case, which is a
bug.

To solve that, instead of using 'netdev->features' as the baseline of
'oper_features' and changing it on set feature success, use 'features'
instead and update it in case of errors.

Fixes: 75b81ce7 ("net/mlx5e: Don't override netdev features field unless in error flow")
Signed-off-by: default avatarGal Pressman <gal@nvidia.com>
Signed-off-by: default avatarSaeed Mahameed <saeedm@nvidia.com>
parent 077cdda7
...@@ -3741,12 +3741,11 @@ static int set_feature_arfs(struct net_device *netdev, bool enable) ...@@ -3741,12 +3741,11 @@ static int set_feature_arfs(struct net_device *netdev, bool enable)
static int mlx5e_handle_feature(struct net_device *netdev, static int mlx5e_handle_feature(struct net_device *netdev,
netdev_features_t *features, netdev_features_t *features,
netdev_features_t wanted_features,
netdev_features_t feature, netdev_features_t feature,
mlx5e_feature_handler feature_handler) mlx5e_feature_handler feature_handler)
{ {
netdev_features_t changes = wanted_features ^ netdev->features; netdev_features_t changes = *features ^ netdev->features;
bool enable = !!(wanted_features & feature); bool enable = !!(*features & feature);
int err; int err;
if (!(changes & feature)) if (!(changes & feature))
...@@ -3754,22 +3753,22 @@ static int mlx5e_handle_feature(struct net_device *netdev, ...@@ -3754,22 +3753,22 @@ static int mlx5e_handle_feature(struct net_device *netdev,
err = feature_handler(netdev, enable); err = feature_handler(netdev, enable);
if (err) { if (err) {
MLX5E_SET_FEATURE(features, feature, !enable);
netdev_err(netdev, "%s feature %pNF failed, err %d\n", netdev_err(netdev, "%s feature %pNF failed, err %d\n",
enable ? "Enable" : "Disable", &feature, err); enable ? "Enable" : "Disable", &feature, err);
return err; return err;
} }
MLX5E_SET_FEATURE(features, feature, enable);
return 0; return 0;
} }
int mlx5e_set_features(struct net_device *netdev, netdev_features_t features) int mlx5e_set_features(struct net_device *netdev, netdev_features_t features)
{ {
netdev_features_t oper_features = netdev->features; netdev_features_t oper_features = features;
int err = 0; int err = 0;
#define MLX5E_HANDLE_FEATURE(feature, handler) \ #define MLX5E_HANDLE_FEATURE(feature, handler) \
mlx5e_handle_feature(netdev, &oper_features, features, feature, handler) mlx5e_handle_feature(netdev, &oper_features, feature, handler)
err |= MLX5E_HANDLE_FEATURE(NETIF_F_LRO, set_feature_lro); err |= MLX5E_HANDLE_FEATURE(NETIF_F_LRO, set_feature_lro);
err |= MLX5E_HANDLE_FEATURE(NETIF_F_GRO_HW, set_feature_hw_gro); err |= MLX5E_HANDLE_FEATURE(NETIF_F_GRO_HW, set_feature_hw_gro);
......
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