Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

net/mlx5: Handle port and vport speed change events in MPESW

Add port change event handling logic for MPESW LAG mode, ensuring
VFs are updated when the speed of LAG physical ports changes.
This triggers a speed update workflow when relevant port state changes
occur, enabling consistent and accurate reporting of VF bandwidth.

Signed-off-by: Or Har-Toov <ohartoov@nvidia.com>
Reviewed-by: Maher Sanalla <msanalla@nvidia.com>
Reviewed-by: Mark Bloch <mbloch@nvidia.com>
Signed-off-by: Edward Srouji <edwards@nvidia.com>
Signed-off-by: Leon Romanovsky <leon@kernel.org>

authored by

Or Har-Toov and committed by
Leon Romanovsky
28ea6036 50f1d188

+121 -4
+34 -4
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c
··· 233 233 { 234 234 struct mlx5_lag *ldev = container_of(ref, struct mlx5_lag, ref); 235 235 struct net *net; 236 + int i; 236 237 237 238 if (ldev->nb.notifier_call) { 238 239 net = read_pnet(&ldev->net); 239 240 unregister_netdevice_notifier_net(net, &ldev->nb); 240 241 } 241 242 243 + mlx5_ldev_for_each(i, 0, ldev) { 244 + if (ldev->pf[i].dev && 245 + ldev->pf[i].port_change_nb.nb.notifier_call) { 246 + struct mlx5_nb *nb = &ldev->pf[i].port_change_nb; 247 + 248 + mlx5_eq_notifier_unregister(ldev->pf[i].dev, nb); 249 + } 250 + } 251 + 242 252 mlx5_lag_mp_cleanup(ldev); 243 253 cancel_delayed_work_sync(&ldev->bond_work); 254 + cancel_work_sync(&ldev->speed_update_work); 244 255 destroy_workqueue(ldev->wq); 245 256 mutex_destroy(&ldev->lock); 246 257 kfree(ldev); ··· 285 274 kref_init(&ldev->ref); 286 275 mutex_init(&ldev->lock); 287 276 INIT_DELAYED_WORK(&ldev->bond_work, mlx5_do_bond_work); 277 + INIT_WORK(&ldev->speed_update_work, mlx5_mpesw_speed_update_work); 288 278 289 279 ldev->nb.notifier_call = mlx5_lag_netdev_event; 290 280 write_pnet(&ldev->net, mlx5_core_net(dev)); ··· 1045 1033 mlx5_port_max_linkspeed); 1046 1034 } 1047 1035 1036 + static int mlx5_lag_sum_devices_oper_speed(struct mlx5_lag *ldev, 1037 + u32 *oper_speed) 1038 + { 1039 + return mlx5_lag_sum_devices_speed(ldev, oper_speed, 1040 + mlx5_port_oper_linkspeed); 1041 + } 1042 + 1048 1043 static void mlx5_lag_modify_device_vports_speed(struct mlx5_core_dev *mdev, 1049 1044 u32 speed) 1050 1045 { ··· 1089 1070 u32 speed; 1090 1071 int pf_idx; 1091 1072 1092 - speed = ldev->tracker.bond_speed_mbps; 1093 - 1094 - if (speed == SPEED_UNKNOWN) 1095 - return; 1073 + if (ldev->mode == MLX5_LAG_MODE_MPESW) { 1074 + if (mlx5_lag_sum_devices_oper_speed(ldev, &speed)) 1075 + return; 1076 + } else { 1077 + speed = ldev->tracker.bond_speed_mbps; 1078 + if (speed == SPEED_UNKNOWN) 1079 + return; 1080 + } 1096 1081 1097 1082 /* If speed is not set, use the sum of max speeds of all PFs */ 1098 1083 if (!speed && mlx5_lag_sum_devices_max_speed(ldev, &speed)) ··· 1543 1520 1544 1521 ldev->pf[fn].dev = dev; 1545 1522 dev->priv.lag = ldev; 1523 + 1524 + MLX5_NB_INIT(&ldev->pf[fn].port_change_nb, 1525 + mlx5_lag_mpesw_port_change_event, PORT_CHANGE); 1526 + mlx5_eq_notifier_register(dev, &ldev->pf[fn].port_change_nb); 1546 1527 } 1547 1528 1548 1529 static void mlx5_ldev_remove_mdev(struct mlx5_lag *ldev, ··· 1557 1530 fn = mlx5_get_dev_index(dev); 1558 1531 if (ldev->pf[fn].dev != dev) 1559 1532 return; 1533 + 1534 + if (ldev->pf[fn].port_change_nb.nb.notifier_call) 1535 + mlx5_eq_notifier_unregister(dev, &ldev->pf[fn].port_change_nb); 1560 1536 1561 1537 ldev->pf[fn].dev = NULL; 1562 1538 dev->priv.lag = NULL;
+2
drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h
··· 39 39 struct mlx5_core_dev *dev; 40 40 struct net_device *netdev; 41 41 bool has_drop; 42 + struct mlx5_nb port_change_nb; 42 43 }; 43 44 44 45 /* Used for collection of netdev event info. */ ··· 68 67 struct lag_tracker tracker; 69 68 struct workqueue_struct *wq; 70 69 struct delayed_work bond_work; 70 + struct work_struct speed_update_work; 71 71 struct notifier_block nb; 72 72 possible_net_t net; 73 73 struct lag_mp lag_mp;
+39
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.c
··· 110 110 goto err_rescan_drivers; 111 111 } 112 112 113 + mlx5_lag_set_vports_agg_speed(ldev); 114 + 113 115 return 0; 114 116 115 117 err_rescan_drivers: ··· 225 223 return ldev && ldev->mode == MLX5_LAG_MODE_MPESW; 226 224 } 227 225 EXPORT_SYMBOL(mlx5_lag_is_mpesw); 226 + 227 + void mlx5_mpesw_speed_update_work(struct work_struct *work) 228 + { 229 + struct mlx5_lag *ldev = container_of(work, struct mlx5_lag, 230 + speed_update_work); 231 + 232 + mutex_lock(&ldev->lock); 233 + if (ldev->mode == MLX5_LAG_MODE_MPESW) { 234 + if (ldev->mode_changes_in_progress) 235 + queue_work(ldev->wq, &ldev->speed_update_work); 236 + else 237 + mlx5_lag_set_vports_agg_speed(ldev); 238 + } 239 + 240 + mutex_unlock(&ldev->lock); 241 + } 242 + 243 + int mlx5_lag_mpesw_port_change_event(struct notifier_block *nb, 244 + unsigned long event, void *data) 245 + { 246 + struct mlx5_nb *mlx5_nb = container_of(nb, struct mlx5_nb, nb); 247 + struct lag_func *lag_func = container_of(mlx5_nb, 248 + struct lag_func, 249 + port_change_nb); 250 + struct mlx5_core_dev *dev = lag_func->dev; 251 + struct mlx5_lag *ldev = dev->priv.lag; 252 + struct mlx5_eqe *eqe = data; 253 + 254 + if (!ldev) 255 + return NOTIFY_DONE; 256 + 257 + if (eqe->sub_type == MLX5_PORT_CHANGE_SUBTYPE_DOWN || 258 + eqe->sub_type == MLX5_PORT_CHANGE_SUBTYPE_ACTIVE) 259 + queue_work(ldev->wq, &ldev->speed_update_work); 260 + 261 + return NOTIFY_OK; 262 + }
+14
drivers/net/ethernet/mellanox/mlx5/core/lag/mpesw.h
··· 32 32 void mlx5_lag_mpesw_disable(struct mlx5_core_dev *dev); 33 33 int mlx5_lag_mpesw_enable(struct mlx5_core_dev *dev); 34 34 35 + #ifdef CONFIG_MLX5_ESWITCH 36 + void mlx5_mpesw_speed_update_work(struct work_struct *work); 37 + int mlx5_lag_mpesw_port_change_event(struct notifier_block *nb, 38 + unsigned long event, void *data); 39 + #else 40 + static inline void mlx5_mpesw_speed_update_work(struct work_struct *work) {} 41 + static inline int mlx5_lag_mpesw_port_change_event(struct notifier_block *nb, 42 + unsigned long event, 43 + void *data) 44 + { 45 + return NOTIFY_DONE; 46 + } 47 + #endif /* CONFIG_MLX5_ESWITCH */ 48 + 35 49 #endif /* __MLX5_LAG_MPESW_H__ */
+29
drivers/net/ethernet/mellanox/mlx5/core/vport.c
··· 122 122 return mlx5_cmd_exec_in(mdev, modify_vport_state, in); 123 123 } 124 124 125 + int mlx5_query_vport_max_tx_speed(struct mlx5_core_dev *mdev, u8 op_mod, 126 + u16 vport, u8 other_vport, u32 *max_tx_speed) 127 + { 128 + u32 out[MLX5_ST_SZ_DW(query_vport_state_out)] = {}; 129 + u32 in[MLX5_ST_SZ_DW(query_vport_state_in)] = {}; 130 + u32 state; 131 + int err; 132 + 133 + MLX5_SET(query_vport_state_in, in, opcode, 134 + MLX5_CMD_OP_QUERY_VPORT_STATE); 135 + MLX5_SET(query_vport_state_in, in, op_mod, op_mod); 136 + MLX5_SET(query_vport_state_in, in, vport_number, vport); 137 + MLX5_SET(query_vport_state_in, in, other_vport, other_vport); 138 + 139 + err = mlx5_cmd_exec_inout(mdev, query_vport_state, in, out); 140 + if (err) 141 + return err; 142 + 143 + state = MLX5_GET(query_vport_state_out, out, state); 144 + if (state == VPORT_STATE_DOWN) { 145 + *max_tx_speed = 0; 146 + return 0; 147 + } 148 + 149 + *max_tx_speed = MLX5_GET(query_vport_state_out, out, max_tx_speed); 150 + return 0; 151 + } 152 + EXPORT_SYMBOL_GPL(mlx5_query_vport_max_tx_speed); 153 + 125 154 static int mlx5_query_nic_vport_context(struct mlx5_core_dev *mdev, u16 vport, 126 155 bool other_vport, u32 *out) 127 156 {
+1
include/linux/mlx5/driver.h
··· 1149 1149 bool mlx5_lag_is_roce(struct mlx5_core_dev *dev); 1150 1150 bool mlx5_lag_is_sriov(struct mlx5_core_dev *dev); 1151 1151 bool mlx5_lag_is_active(struct mlx5_core_dev *dev); 1152 + int mlx5_lag_query_bond_speed(struct net_device *bond_dev, u32 *speed); 1152 1153 bool mlx5_lag_mode_is_hash(struct mlx5_core_dev *dev); 1153 1154 bool mlx5_lag_is_master(struct mlx5_core_dev *dev); 1154 1155 bool mlx5_lag_is_shared_fdb(struct mlx5_core_dev *dev);
+2
include/linux/mlx5/vport.h
··· 60 60 u8 mlx5_query_vport_state(struct mlx5_core_dev *mdev, u8 opmod, u16 vport); 61 61 int mlx5_modify_vport_admin_state(struct mlx5_core_dev *mdev, u8 opmod, 62 62 u16 vport, u8 other_vport, u8 state); 63 + int mlx5_query_vport_max_tx_speed(struct mlx5_core_dev *mdev, u8 op_mod, 64 + u16 vport, u8 other_vport, u32 *max_tx_speed); 63 65 int mlx5_modify_vport_max_tx_speed(struct mlx5_core_dev *mdev, u8 opmod, 64 66 u16 vport, u8 other_vport, u16 max_tx_speed); 65 67 int mlx5_query_nic_vport_mac_address(struct mlx5_core_dev *mdev,