1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB 2 /* Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved. */ 3 4 #include <linux/netdevice.h> 5 #include <net/nexthop.h> 6 #include "lag/lag.h" 7 #include "eswitch.h" 8 #include "esw/acl/ofld.h" 9 #include "lib/events.h" 10 11 static void mlx5_mpesw_metadata_cleanup(struct mlx5_lag *ldev) 12 { 13 struct mlx5_core_dev *dev; 14 struct mlx5_eswitch *esw; 15 u32 pf_metadata; 16 int i; 17 18 mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { 19 dev = mlx5_lag_pf(ldev, i)->dev; 20 esw = dev->priv.eswitch; 21 pf_metadata = ldev->lag_mpesw.pf_metadata[i]; 22 if (!pf_metadata) 23 continue; 24 mlx5_esw_acl_ingress_vport_metadata_update(esw, MLX5_VPORT_UPLINK, 0); 25 mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_MULTIPORT_ESW, 26 (void *)0); 27 mlx5_esw_match_metadata_free(esw, pf_metadata); 28 ldev->lag_mpesw.pf_metadata[i] = 0; 29 } 30 } 31 32 static int mlx5_mpesw_metadata_set(struct mlx5_lag *ldev) 33 { 34 struct mlx5_core_dev *dev; 35 struct mlx5_eswitch *esw; 36 u32 pf_metadata; 37 int i, err; 38 39 mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { 40 dev = mlx5_lag_pf(ldev, i)->dev; 41 esw = dev->priv.eswitch; 42 pf_metadata = mlx5_esw_match_metadata_alloc(esw); 43 if (!pf_metadata) { 44 err = -ENOSPC; 45 goto err_metadata; 46 } 47 48 ldev->lag_mpesw.pf_metadata[i] = pf_metadata; 49 err = mlx5_esw_acl_ingress_vport_metadata_update(esw, MLX5_VPORT_UPLINK, 50 pf_metadata); 51 if (err) 52 goto err_metadata; 53 } 54 55 mlx5_lag_for_each(i, 0, ldev, MLX5_LAG_FILTER_ALL) { 56 dev = mlx5_lag_pf(ldev, i)->dev; 57 mlx5_notifier_call_chain(dev->priv.events, MLX5_DEV_EVENT_MULTIPORT_ESW, 58 (void *)0); 59 } 60 61 return 0; 62 63 err_metadata: 64 mlx5_mpesw_metadata_cleanup(ldev); 65 return err; 66 } 67 68 static void mlx5_mpesw_restore_sd_fdb(struct mlx5_lag *ldev) 69 { 70 struct lag_func *pf; 71 int err, i; 72 73 mlx5_ldev_for_each(i, 0, ldev) { 74 pf = mlx5_lag_pf(ldev, i); 75 err = mlx5_lag_shared_fdb_create(ldev, NULL, 0, pf->group_id); 76 if (err) 77 mlx5_core_warn(pf->dev, 78 "Failed to restore SD shared FDB (%d)\n", 79 err); 80 } 81 } 82 83 static int mlx5_mpesw_teardown_sd_fdb(struct mlx5_lag *ldev) 84 { 85 struct lag_func *pf; 86 int i; 87 88 mlx5_ldev_for_each(i, 0, ldev) { 89 pf = mlx5_lag_pf(ldev, i); 90 if (!pf->sd_fdb_active) 91 continue; 92 mlx5_lag_shared_fdb_destroy(ldev, pf->group_id); 93 } 94 return 0; 95 } 96 97 static bool mlx5_lag_has_sd_group(struct mlx5_lag *ldev) 98 { 99 struct lag_func *pf; 100 int i; 101 102 mlx5_ldev_for_each(i, 0, ldev) { 103 pf = mlx5_lag_pf(ldev, i); 104 if (pf->group_id) 105 return true; 106 } 107 return false; 108 } 109 110 static int mlx5_lag_enable_mpesw(struct mlx5_lag *ldev) 111 { 112 int idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); 113 struct mlx5_core_dev *dev0; 114 int err; 115 116 if (ldev->mode == MLX5_LAG_MODE_MPESW) 117 return 0; 118 119 if (ldev->mode != MLX5_LAG_MODE_NONE) 120 return -EINVAL; 121 122 if (idx < 0) 123 return -EINVAL; 124 125 dev0 = mlx5_lag_pf(ldev, idx)->dev; 126 if (mlx5_eswitch_mode(dev0) != MLX5_ESWITCH_OFFLOADS || 127 !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table) || 128 !MLX5_CAP_GEN(dev0, create_lag_when_not_master_up) || 129 !mlx5_lag_check_prereq(ldev) || 130 !mlx5_lag_shared_fdb_supported_filter(ldev, MLX5_LAG_FILTER_ALL)) 131 return -EOPNOTSUPP; 132 133 err = mlx5_mpesw_metadata_set(ldev); 134 if (err) 135 return err; 136 137 if (mlx5_lag_has_sd_group(ldev)) 138 mlx5_mpesw_teardown_sd_fdb(ldev); 139 140 err = mlx5_lag_shared_fdb_create(ldev, NULL, MLX5_LAG_MODE_MPESW, 141 MLX5_LAG_FILTER_ALL); 142 if (err) { 143 mlx5_core_warn(dev0, 144 "Failed to create LAG in MPESW mode (%d)\n", 145 err); 146 if (mlx5_lag_has_sd_group(ldev)) 147 mlx5_mpesw_restore_sd_fdb(ldev); 148 mlx5_mpesw_metadata_cleanup(ldev); 149 return err; 150 } 151 152 return 0; 153 } 154 155 void mlx5_lag_disable_mpesw(struct mlx5_lag *ldev) 156 { 157 if (ldev->mode != MLX5_LAG_MODE_MPESW) 158 return; 159 160 mlx5_mpesw_metadata_cleanup(ldev); 161 mlx5_lag_shared_fdb_destroy(ldev, MLX5_LAG_FILTER_ALL); 162 if (mlx5_lag_has_sd_group(ldev)) 163 mlx5_mpesw_restore_sd_fdb(ldev); 164 } 165 166 void mlx5_mpesw_sd_devcoms_lock(struct mlx5_lag *ldev) 167 { 168 struct mlx5_devcom_comp_dev *sd_devcom; 169 int i; 170 171 mlx5_ldev_for_each(i, 0, ldev) { 172 sd_devcom = mlx5_sd_get_devcom(mlx5_lag_pf(ldev, i)->dev); 173 if (sd_devcom) 174 mlx5_devcom_comp_lock(sd_devcom); 175 } 176 } 177 178 void mlx5_mpesw_sd_devcoms_unlock(struct mlx5_lag *ldev) 179 { 180 struct mlx5_devcom_comp_dev *sd_devcom; 181 int i; 182 183 mlx5_ldev_for_each_reverse(i, MLX5_MAX_PORTS, 0, ldev) { 184 sd_devcom = mlx5_sd_get_devcom(mlx5_lag_pf(ldev, i)->dev); 185 if (sd_devcom) 186 mlx5_devcom_comp_unlock(sd_devcom); 187 } 188 } 189 190 static void mlx5_mpesw_work(struct work_struct *work) 191 { 192 struct mlx5_mpesw_work_st *mpesww = container_of(work, struct mlx5_mpesw_work_st, work); 193 struct mlx5_devcom_comp_dev *devcom; 194 struct mlx5_lag *ldev = mpesww->lag; 195 196 devcom = mlx5_lag_get_devcom_comp(ldev); 197 if (!devcom) 198 return; 199 200 mlx5_devcom_comp_lock(devcom); 201 mlx5_mpesw_sd_devcoms_lock(ldev); 202 mutex_lock(&ldev->lock); 203 if (ldev->mode_changes_in_progress) { 204 mpesww->result = -EAGAIN; 205 goto unlock; 206 } 207 208 if (mpesww->op == MLX5_MPESW_OP_ENABLE) 209 mpesww->result = mlx5_lag_enable_mpesw(ldev); 210 else if (mpesww->op == MLX5_MPESW_OP_DISABLE) 211 mlx5_lag_disable_mpesw(ldev); 212 unlock: 213 mutex_unlock(&ldev->lock); 214 mlx5_mpesw_sd_devcoms_unlock(ldev); 215 mlx5_devcom_comp_unlock(devcom); 216 complete(&mpesww->comp); 217 } 218 219 static int mlx5_lag_mpesw_queue_work(struct mlx5_core_dev *dev, 220 enum mpesw_op op) 221 { 222 struct mlx5_lag *ldev = mlx5_lag_dev(dev); 223 struct mlx5_mpesw_work_st *work; 224 int err = 0; 225 226 if (!ldev) 227 return 0; 228 229 work = kzalloc_obj(*work); 230 if (!work) 231 return -ENOMEM; 232 233 INIT_WORK(&work->work, mlx5_mpesw_work); 234 init_completion(&work->comp); 235 work->op = op; 236 work->lag = ldev; 237 238 if (!queue_work(ldev->wq, &work->work)) { 239 mlx5_core_warn(dev, "failed to queue mpesw work\n"); 240 err = -EINVAL; 241 goto out; 242 } 243 wait_for_completion(&work->comp); 244 err = work->result; 245 out: 246 kfree(work); 247 return err; 248 } 249 250 void mlx5_lag_mpesw_disable(struct mlx5_core_dev *dev) 251 { 252 mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_DISABLE); 253 } 254 255 int mlx5_lag_mpesw_enable(struct mlx5_core_dev *dev) 256 { 257 return mlx5_lag_mpesw_queue_work(dev, MLX5_MPESW_OP_ENABLE); 258 } 259 260 int mlx5_lag_mpesw_do_mirred(struct mlx5_core_dev *mdev, 261 struct net_device *out_dev, 262 struct netlink_ext_ack *extack) 263 { 264 struct mlx5_lag *ldev = mlx5_lag_dev(mdev); 265 266 if (!netif_is_bond_master(out_dev) || !ldev) 267 return 0; 268 269 if (ldev->mode != MLX5_LAG_MODE_MPESW) 270 return 0; 271 272 NL_SET_ERR_MSG_MOD(extack, "can't forward to bond in mpesw mode"); 273 return -EOPNOTSUPP; 274 } 275 276 bool mlx5_lag_is_mpesw(struct mlx5_core_dev *dev) 277 { 278 struct mlx5_lag *ldev = mlx5_lag_dev(dev); 279 280 return ldev && ldev->mode == MLX5_LAG_MODE_MPESW && 281 __mlx5_lag_dev_is_port(ldev, dev); 282 } 283 EXPORT_SYMBOL(mlx5_lag_is_mpesw); 284 285 void mlx5_mpesw_speed_update_work(struct work_struct *work) 286 { 287 struct mlx5_lag *ldev = container_of(work, struct mlx5_lag, 288 speed_update_work); 289 290 mutex_lock(&ldev->lock); 291 if (ldev->mode == MLX5_LAG_MODE_MPESW) { 292 if (ldev->mode_changes_in_progress) 293 queue_work(ldev->wq, &ldev->speed_update_work); 294 else 295 mlx5_lag_set_vports_agg_speed(ldev); 296 } 297 298 mutex_unlock(&ldev->lock); 299 } 300 301 int mlx5_lag_mpesw_port_change_event(struct notifier_block *nb, 302 unsigned long event, void *data) 303 { 304 struct mlx5_nb *mlx5_nb = container_of(nb, struct mlx5_nb, nb); 305 struct lag_func *lag_func = container_of(mlx5_nb, 306 struct lag_func, 307 port_change_nb); 308 struct mlx5_core_dev *dev = lag_func->dev; 309 struct mlx5_lag *ldev = dev->priv.lag; 310 struct mlx5_eqe *eqe = data; 311 312 if (!ldev) 313 return NOTIFY_DONE; 314 315 if (eqe->sub_type == MLX5_PORT_CHANGE_SUBTYPE_DOWN || 316 eqe->sub_type == MLX5_PORT_CHANGE_SUBTYPE_ACTIVE) 317 queue_work(ldev->wq, &ldev->speed_update_work); 318 319 return NOTIFY_OK; 320 } 321