diff options
author | Gal Pressman <galp@mellanox.com> | 2018-01-10 10:11:11 -0500 |
---|---|---|
committer | Saeed Mahameed <saeedm@mellanox.com> | 2018-01-11 19:01:49 -0500 |
commit | 75b81ce719b79565eb0b39aa9954b6e11a5e73bf (patch) | |
tree | 90bb66dcc4e5990e7afebc5c11573ccf62e9a381 | |
parent | 4b7d4363f14a0398eca48c7e96e46120c5eb6a96 (diff) |
net/mlx5e: Don't override netdev features field unless in error flow
Set features function sets dev->features in order to keep track of which
features were successfully changed and which weren't (in case the user
asks for more than one change in a single command).
This breaks the logic in __netdev_update_features which assumes that
dev->features is not changed on success and checks for diffs between
features and dev->features (diffs that might not exist at this point
because of the driver override).
The solution is to keep track of successful/failed feature changes and
assign them to dev->features in case of failure only.
Fixes: 0e405443e803 ("net/mlx5e: Improve set features ndo resiliency")
Signed-off-by: Gal Pressman <galp@mellanox.com>
Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
-rw-r--r-- | drivers/net/ethernet/mellanox/mlx5/core/en_main.c | 43 |
1 files changed, 25 insertions, 18 deletions
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index d9d8227f195f..311d5ec8407c 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c | |||
@@ -3219,12 +3219,12 @@ static int mlx5e_set_mac(struct net_device *netdev, void *addr) | |||
3219 | return 0; | 3219 | return 0; |
3220 | } | 3220 | } |
3221 | 3221 | ||
3222 | #define MLX5E_SET_FEATURE(netdev, feature, enable) \ | 3222 | #define MLX5E_SET_FEATURE(features, feature, enable) \ |
3223 | do { \ | 3223 | do { \ |
3224 | if (enable) \ | 3224 | if (enable) \ |
3225 | netdev->features |= feature; \ | 3225 | *features |= feature; \ |
3226 | else \ | 3226 | else \ |
3227 | netdev->features &= ~feature; \ | 3227 | *features &= ~feature; \ |
3228 | } while (0) | 3228 | } while (0) |
3229 | 3229 | ||
3230 | typedef int (*mlx5e_feature_handler)(struct net_device *netdev, bool enable); | 3230 | typedef int (*mlx5e_feature_handler)(struct net_device *netdev, bool enable); |
@@ -3347,6 +3347,7 @@ static int set_feature_arfs(struct net_device *netdev, bool enable) | |||
3347 | #endif | 3347 | #endif |
3348 | 3348 | ||
3349 | static int mlx5e_handle_feature(struct net_device *netdev, | 3349 | static int mlx5e_handle_feature(struct net_device *netdev, |
3350 | netdev_features_t *features, | ||
3350 | netdev_features_t wanted_features, | 3351 | netdev_features_t wanted_features, |
3351 | netdev_features_t feature, | 3352 | netdev_features_t feature, |
3352 | mlx5e_feature_handler feature_handler) | 3353 | mlx5e_feature_handler feature_handler) |
@@ -3365,34 +3366,40 @@ static int mlx5e_handle_feature(struct net_device *netdev, | |||
3365 | return err; | 3366 | return err; |
3366 | } | 3367 | } |
3367 | 3368 | ||
3368 | MLX5E_SET_FEATURE(netdev, feature, enable); | 3369 | MLX5E_SET_FEATURE(features, feature, enable); |
3369 | return 0; | 3370 | return 0; |
3370 | } | 3371 | } |
3371 | 3372 | ||
3372 | static int mlx5e_set_features(struct net_device *netdev, | 3373 | static int mlx5e_set_features(struct net_device *netdev, |
3373 | netdev_features_t features) | 3374 | netdev_features_t features) |
3374 | { | 3375 | { |
3376 | netdev_features_t oper_features = netdev->features; | ||
3375 | int err; | 3377 | int err; |
3376 | 3378 | ||
3377 | err = mlx5e_handle_feature(netdev, features, NETIF_F_LRO, | 3379 | err = mlx5e_handle_feature(netdev, &oper_features, features, |
3378 | set_feature_lro); | 3380 | NETIF_F_LRO, set_feature_lro); |
3379 | err |= mlx5e_handle_feature(netdev, features, | 3381 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3380 | NETIF_F_HW_VLAN_CTAG_FILTER, | 3382 | NETIF_F_HW_VLAN_CTAG_FILTER, |
3381 | set_feature_cvlan_filter); | 3383 | set_feature_cvlan_filter); |
3382 | err |= mlx5e_handle_feature(netdev, features, NETIF_F_HW_TC, | 3384 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3383 | set_feature_tc_num_filters); | 3385 | NETIF_F_HW_TC, set_feature_tc_num_filters); |
3384 | err |= mlx5e_handle_feature(netdev, features, NETIF_F_RXALL, | 3386 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3385 | set_feature_rx_all); | 3387 | NETIF_F_RXALL, set_feature_rx_all); |
3386 | err |= mlx5e_handle_feature(netdev, features, NETIF_F_RXFCS, | 3388 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3387 | set_feature_rx_fcs); | 3389 | NETIF_F_RXFCS, set_feature_rx_fcs); |
3388 | err |= mlx5e_handle_feature(netdev, features, NETIF_F_HW_VLAN_CTAG_RX, | 3390 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3389 | set_feature_rx_vlan); | 3391 | NETIF_F_HW_VLAN_CTAG_RX, set_feature_rx_vlan); |
3390 | #ifdef CONFIG_RFS_ACCEL | 3392 | #ifdef CONFIG_RFS_ACCEL |
3391 | err |= mlx5e_handle_feature(netdev, features, NETIF_F_NTUPLE, | 3393 | err |= mlx5e_handle_feature(netdev, &oper_features, features, |
3392 | set_feature_arfs); | 3394 | NETIF_F_NTUPLE, set_feature_arfs); |
3393 | #endif | 3395 | #endif |
3394 | 3396 | ||
3395 | return err ? -EINVAL : 0; | 3397 | if (err) { |
3398 | netdev->features = oper_features; | ||
3399 | return -EINVAL; | ||
3400 | } | ||
3401 | |||
3402 | return 0; | ||
3396 | } | 3403 | } |
3397 | 3404 | ||
3398 | static netdev_features_t mlx5e_fix_features(struct net_device *netdev, | 3405 | static netdev_features_t mlx5e_fix_features(struct net_device *netdev, |