diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h index 7bfe7cdc5770..1ceebab4ce08 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/en/tc_priv.h @@ -97,18 +97,14 @@ struct mlx5e_tc_flow { struct encap_flow_item encaps[MLX5_MAX_FLOW_FWD_VPORTS]; struct mlx5e_hairpin_entry *hpe; /* attached hairpin instance */ struct list_head hairpin; /* flows sharing the same hairpin */ - struct list_head peer[MLX5_MAX_PORTS]; /* flows with peer flow */ - DECLARE_BITMAP(peer_used, MLX5_MAX_PORTS); /* tracks populated peer - * slots - */ + struct list_head peer; /* dup: node in origin esw's peer_flows */ struct list_head unready; /* flows not ready to be offloaded (e.g * due to missing route) */ - struct list_head peer_flows; /* flows on peer */ - int peer_index; /* peer-flow index pinned at add time, used at del - * time so removal is independent of LAG state - * changes between add and del. - */ + + /* origin: its dups; dup: node on that list */ + struct list_head peer_flows; + struct mlx5e_tc_flow *peer_orig; /* dup: back-ref to origin flow */ struct net_device *orig_dev; /* netdev adding flow first */ int tmp_entry_index; struct list_head tmp_list; /* temporary flow list used by neigh update */ diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c index 4c6060d54fbe..f90b5a34e097 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_main.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_main.c @@ -5430,8 +5430,7 @@ static void mlx5e_set_netdev_dev_addr(struct net_device *netdev) u8 addr[ETH_ALEN]; mlx5_query_mac_address(priv->mdev, addr); - if (is_zero_ether_addr(addr) && - !MLX5_CAP_GEN(priv->mdev, vport_group_manager)) { + if (is_zero_ether_addr(addr)) { eth_hw_addr_random(netdev); mlx5_core_info(priv->mdev, "Assigned random MAC address %pM\n", netdev->dev_addr); return; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c index b290beb4369a..c99e824b4c6d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/en_tc.c @@ -2116,43 +2116,35 @@ void mlx5e_put_flow_list(struct mlx5e_priv *priv, struct list_head *flow_list) mlx5e_flow_put(priv, flow); } -static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *flow, - int peer_index) +static void mlx5e_tc_del_fdb_peer_flow(struct mlx5e_tc_flow *peer_flow) { - struct mlx5_eswitch *esw = flow->priv->mdev->priv.eswitch; - struct mlx5e_tc_flow *peer_flow; - struct mlx5e_tc_flow *tmp; - - if (!flow_flag_test(flow, ESWITCH) || - !flow_flag_test(flow, DUP)) - return; + struct mlx5e_tc_flow *flow = peer_flow->peer_orig; + struct mlx5_eswitch *esw; + esw = flow->priv->mdev->priv.eswitch; mutex_lock(&esw->offloads.peer_mutex); - list_del(&flow->peer[peer_index]); - clear_bit(peer_index, flow->peer_used); + list_del(&peer_flow->peer); mutex_unlock(&esw->offloads.peer_mutex); - list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) { - if (peer_index != peer_flow->peer_index) - continue; - - list_del(&peer_flow->peer_flows); - if (refcount_dec_and_test(&peer_flow->refcnt)) { - mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow); - kfree(peer_flow); - } - } - + list_del(&peer_flow->peer_flows); if (list_empty(&flow->peer_flows)) flow_flag_clear(flow, DUP); + + if (refcount_dec_and_test(&peer_flow->refcnt)) { + mlx5e_tc_del_fdb_flow(peer_flow->priv, peer_flow); + kfree(peer_flow); + } } static void mlx5e_tc_del_fdb_peers_flow(struct mlx5e_tc_flow *flow) { - int i; + struct mlx5e_tc_flow *peer_flow, *tmp; - for_each_set_bit(i, flow->peer_used, MLX5_MAX_PORTS) - mlx5e_tc_del_fdb_peer_flow(flow, i); + if (!flow_flag_test(flow, ESWITCH) || !flow_flag_test(flow, DUP)) + return; + + list_for_each_entry_safe(peer_flow, tmp, &flow->peer_flows, peer_flows) + mlx5e_tc_del_fdb_peer_flow(peer_flow); } static void mlx5e_tc_del_flow(struct mlx5e_priv *priv, @@ -4604,12 +4596,13 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, unsigned long flow_flags, struct mlx5_eswitch *peer_esw) { + u16 peer_vhca_id = MLX5_CAP_GEN(peer_esw->dev, vhca_id); struct mlx5e_priv *priv = flow->priv, *peer_priv; struct mlx5_eswitch *esw = priv->mdev->priv.eswitch; struct mlx5_esw_flow_attr *attr = flow->attr->esw_attr; struct mlx5e_tc_flow_parse_attr *parse_attr; - int i = mlx5_lag_get_dev_seq(peer_esw->dev); struct mlx5e_rep_priv *peer_urpriv; + struct list_head *dup_peer_flows; struct mlx5e_tc_flow *peer_flow; struct mlx5_core_dev *in_mdev; int err = 0; @@ -4639,12 +4632,14 @@ static int mlx5e_tc_add_fdb_peer_flow(struct flow_cls_offload *f, goto out; } - peer_flow->peer_index = i; + peer_flow->peer_orig = flow; list_add_tail(&peer_flow->peer_flows, &flow->peer_flows); flow_flag_set(flow, DUP); + dup_peer_flows = xa_load(&esw->offloads.peer_flows, peer_vhca_id); + if (!dup_peer_flows) + return -ENODEV; mutex_lock(&esw->offloads.peer_mutex); - list_add_tail(&flow->peer[i], &esw->offloads.peer_flows[i]); - set_bit(i, flow->peer_used); + list_add_tail(&peer_flow->peer, dup_peer_flows); mutex_unlock(&esw->offloads.peer_mutex); out: @@ -5539,22 +5534,14 @@ int mlx5e_tc_num_filters(struct mlx5e_priv *priv, unsigned long flags) void mlx5e_tc_clean_fdb_peer_flows(struct mlx5_eswitch *esw) { - struct mlx5_devcom_comp_dev *devcom; - struct mlx5_devcom_comp_dev *pos; - struct mlx5e_tc_flow *flow, *tmp; - struct mlx5_eswitch *peer_esw; - int i; + struct mlx5e_tc_flow *peer_flow, *tmp_peer_flow; + struct list_head *dup_peer_flows; + unsigned long index; - devcom = esw->devcom; - - mlx5_devcom_for_each_peer_entry(devcom, peer_esw, pos) { - i = mlx5_lag_get_dev_seq(peer_esw->dev); - if (i < 0) - continue; - - list_for_each_entry_safe(flow, tmp, &esw->offloads.peer_flows[i], peer[i]) - mlx5e_tc_del_fdb_peers_flow(flow); - } + xa_for_each(&esw->offloads.peer_flows, index, dup_peer_flows) + list_for_each_entry_safe(peer_flow, tmp_peer_flow, + dup_peer_flows, peer) + mlx5e_tc_del_fdb_peer_flow(peer_flow); } void mlx5e_tc_reoffload_flows_work(struct work_struct *work) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c index fc197d1dc9df..2d289fb1353b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.c @@ -1241,6 +1241,11 @@ static int mlx5_esw_host_functions_enabled_query(struct mlx5_eswitch *esw) struct mlx5_esw_pf_info host_pf_info; const u32 *query_host_out; + if (!mlx5_core_is_pf(esw->dev)) { + esw->esw_funcs.host_funcs_disabled = true; + return 0; + } + if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) return 0; @@ -2460,13 +2465,20 @@ static int mlx5_esw_vports_init(struct mlx5_eswitch *esw) } } - if (mlx5_ecpf_vport_exists(dev) || - mlx5_core_is_ecpf_esw_manager(dev)) { + if (mlx5_ecpf_vport_exists(dev)) { err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_ECPF); if (err) goto err; idx++; } + + if (!xa_load(&esw->vports, esw->manager_vport)) { + err = mlx5_esw_vport_alloc(esw, idx, esw->manager_vport); + if (err) + goto err; + idx++; + } + err = mlx5_esw_vport_alloc(esw, idx, MLX5_VPORT_UPLINK); if (err) goto err; @@ -2951,7 +2963,7 @@ bool mlx5_esw_hold(struct mlx5_core_dev *mdev) { struct mlx5_eswitch *esw = mdev->priv.eswitch; - /* e.g. VF doesn't have eswitch so nothing to do */ + /* Not an eswitch manager, so there is no mode lock to take */ if (!mlx5_esw_allowed(esw)) return true; @@ -3099,7 +3111,7 @@ void mlx5_eswitch_unblock_ipsec(struct mlx5_core_dev *dev) struct mlx5_eswitch *esw = dev->priv.eswitch; if (!mlx5_esw_allowed(esw)) - /* Failure means no eswitch => core dev is not a PF */ + /* Not an eswitch manager, so nothing was blocked */ return; mutex_lock(&esw->state_lock); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h index 8b1f93b13ea9..e9cbcd73b23f 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch.h @@ -319,7 +319,7 @@ struct mlx5_esw_offload { struct mlx5_flow_handle *vport_rx_drop_rule; struct mlx5_flow_table *ft_ipsec_tx_pol; struct xarray vport_reps; - struct list_head peer_flows[MLX5_MAX_PORTS]; + struct xarray peer_flows; struct mutex peer_mutex; struct mutex encap_tbl_lock; /* protects encap_tbl */ DECLARE_HASHTABLE(encap_tbl, 8); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c index eb74b6260168..c712848b202d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads.c @@ -3383,10 +3383,15 @@ static void mlx5_esw_offloads_rep_event_unpair(struct mlx5_eswitch *esw, static void mlx5_esw_offloads_unpair(struct mlx5_eswitch *esw, struct mlx5_eswitch *peer_esw) { + struct list_head *dup_peer_flows; + #if IS_ENABLED(CONFIG_MLX5_CLS_ACT) mlx5e_tc_clean_fdb_peer_flows(esw); #endif mlx5_esw_offloads_rep_event_unpair(esw, peer_esw); + dup_peer_flows = xa_erase(&esw->offloads.peer_flows, + MLX5_CAP_GEN(peer_esw->dev, vhca_id)); + kfree(dup_peer_flows); esw_del_fdb_peer_miss_rules(esw, peer_esw->dev); } @@ -3394,6 +3399,7 @@ static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw, struct mlx5_eswitch *peer_esw) { const struct mlx5_eswitch_rep_ops *ops; + struct list_head *dup_peer_flows; struct mlx5_eswitch_rep *rep; unsigned long i; u8 rep_type; @@ -3403,6 +3409,20 @@ static int mlx5_esw_offloads_pair(struct mlx5_eswitch *esw, if (err) return err; + dup_peer_flows = kzalloc_obj(*dup_peer_flows); + if (!dup_peer_flows) { + err = -ENOMEM; + goto err_out; + } + INIT_LIST_HEAD(dup_peer_flows); + err = xa_err(xa_store(&esw->offloads.peer_flows, + MLX5_CAP_GEN(peer_esw->dev, vhca_id), + dup_peer_flows, GFP_KERNEL)); + if (err) { + kfree(dup_peer_flows); + goto err_out; + } + mlx5_esw_for_each_rep(esw, i, rep) { for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) { ops = esw->offloads.rep_ops[rep_type]; @@ -3548,10 +3568,9 @@ static int mlx5_esw_offloads_devcom_event(int event, void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw, const struct mlx5_devcom_match_attr *attr) { - int i; + int err; - for (i = 0; i < MLX5_MAX_PORTS; i++) - INIT_LIST_HEAD(&esw->offloads.peer_flows[i]); + xa_init(&esw->offloads.peer_flows); mutex_init(&esw->offloads.peer_mutex); if (!MLX5_CAP_ESW(esw->dev, merged_eswitch)) @@ -3572,10 +3591,12 @@ void mlx5_esw_offloads_devcom_init(struct mlx5_eswitch *esw, if (!esw->devcom) return; - mlx5_devcom_send_event(esw->devcom, - ESW_OFFLOADS_DEVCOM_PAIR, - ESW_OFFLOADS_DEVCOM_UNPAIR, - esw); + err = mlx5_devcom_send_event(esw->devcom, + ESW_OFFLOADS_DEVCOM_PAIR, + ESW_OFFLOADS_DEVCOM_UNPAIR, + esw); + if (err) + mlx5_esw_offloads_devcom_cleanup(esw); } void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) @@ -3592,6 +3613,8 @@ void mlx5_esw_offloads_devcom_cleanup(struct mlx5_eswitch *esw) xa_destroy(&esw->paired); xa_destroy(&esw->fdb_table.offloads.peer_miss_rules); esw->devcom = NULL; + WARN_ON_ONCE(!xa_empty(&esw->offloads.peer_flows)); + xa_destroy(&esw->offloads.peer_flows); } bool mlx5_esw_offloads_devcom_is_ready(struct mlx5_eswitch *esw) diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c index e9b8d79d2d21..b6125c7bd91b 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/debugfs.c @@ -101,16 +101,21 @@ static int flags_show(struct seq_file *file, void *priv) static int mapping_show(struct seq_file *file, void *priv) { struct mlx5_core_dev *dev = file->private; - u8 ports[MLX5_MAX_PORTS] = {}; struct mlx5_lag *ldev; bool hash = false; bool lag_active; int i, idx = 0; int num_ports; + u8 *ports; ldev = mlx5_lag_dev(dev); + ports = kcalloc(ldev->ports, sizeof(*ports), GFP_KERNEL); + if (!ports) + return -ENOMEM; + mutex_lock(&ldev->lock); - lag_active = __mlx5_lag_is_active(ldev); + lag_active = __mlx5_lag_is_active(ldev) && + ldev->mode != MLX5_LAG_MODE_MPESW; if (lag_active) { if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &ldev->mode_flags)) { mlx5_infer_tx_enabled(&ldev->tracker, ldev, ports, @@ -123,8 +128,10 @@ static int mapping_show(struct seq_file *file, void *priv) } } mutex_unlock(&ldev->lock); - if (!lag_active) + if (!lag_active) { + kfree(ports); return -EINVAL; + } for (i = 0; i < num_ports; i++) { if (hash) @@ -133,6 +140,7 @@ static int mapping_show(struct seq_file *file, void *priv) seq_printf(file, "%d:%d\n", i + 1, ports[i]); } + kfree(ports); return 0; } diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c index dd14cdc378de..78505e59bf9d 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.c @@ -63,19 +63,25 @@ static int get_port_sel_mode(enum mlx5_lag_mode mode, unsigned long flags) return MLX5_LAG_PORT_SELECT_MODE_QUEUE_AFFINITY; } -static u8 lag_active_port_bits(struct mlx5_lag *ldev, - struct lag_tracker *tracker) +static int lag_active_port_bits(struct mlx5_lag *ldev, + struct lag_tracker *tracker) { - u8 enabled_ports[MLX5_MAX_PORTS] = {}; u8 active_port = 0; + u8 *enabled_ports; int num_enabled; int idx; + enabled_ports = kcalloc(ldev->ports, sizeof(*enabled_ports), + GFP_KERNEL); + if (!enabled_ports) + return -ENOMEM; + mlx5_infer_tx_enabled(tracker, ldev, enabled_ports, &num_enabled); for (idx = 0; idx < num_enabled; idx++) active_port |= BIT_MASK(enabled_ports[idx]); + kfree(enabled_ports); return active_port; } @@ -105,13 +111,21 @@ static int mlx5_cmd_create_lag(struct mlx5_core_dev *dev, struct mlx5_lag *ldev, MLX5_SET(lagc, lag_ctx, tx_remap_affinity_1, ports[idx0]); MLX5_SET(lagc, lag_ctx, tx_remap_affinity_2, ports[idx1]); break; - case MLX5_LAG_PORT_SELECT_MODE_PORT_SELECT_FT: + case MLX5_LAG_PORT_SELECT_MODE_PORT_SELECT_FT: { + u8 active_port; + int ret; + if (!MLX5_CAP_PORT_SELECTION(dev, port_select_flow_table_bypass)) break; - MLX5_SET(lagc, lag_ctx, active_port, - lag_active_port_bits(ldev, tracker)); + ret = lag_active_port_bits(ldev, tracker); + if (ret < 0) + return ret; + + active_port = ret; + MLX5_SET(lagc, lag_ctx, active_port, active_port); break; + } default: break; } @@ -240,22 +254,31 @@ static void mlx5_lag_print_mapping(struct mlx5_core_dev *dev, struct lag_tracker *tracker, unsigned long flags) { - char buf[MLX5_MAX_PORTS * 10 + 1] = {}; - u8 enabled_ports[MLX5_MAX_PORTS] = {}; + u8 *enabled_ports = NULL; int written = 0; int num_enabled; + char *buf; int idx; int err; int i; int j; + buf = kcalloc(ldev->ports * 10 + 1, sizeof(*buf), GFP_KERNEL); + if (!buf) + return; + if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &flags)) { + enabled_ports = kcalloc(ldev->ports, sizeof(*enabled_ports), + GFP_KERNEL); + if (!enabled_ports) + goto free_buf; + mlx5_infer_tx_enabled(tracker, ldev, enabled_ports, &num_enabled); for (i = 0; i < num_enabled; i++) { err = scnprintf(buf + written, 4, "%d, ", enabled_ports[i] + 1); if (err != 3) - return; + goto free_enabled; written += err; } buf[written - 2] = 0; @@ -267,12 +290,17 @@ static void mlx5_lag_print_mapping(struct mlx5_core_dev *dev, err = scnprintf(buf + written, 10, " port %d:%d", i + 1, ldev->v2p_map[idx]); if (err != 9) - return; + goto free_enabled; written += err; } } mlx5_core_info(dev, "lag map:%s\n", buf); } + +free_enabled: + kfree(enabled_ports); +free_buf: + kfree(buf); } static int mlx5_lag_netdev_event(struct notifier_block *this, @@ -308,6 +336,7 @@ static void mlx5_ldev_free(struct kref *ref) cancel_work_sync(&ldev->speed_update_work); destroy_workqueue(ldev->wq); mutex_destroy(&ldev->lock); + kfree(ldev->v2p_map); kfree(ldev); } @@ -330,11 +359,16 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev) if (!ldev) return NULL; + ldev->ports = MLX5_CAP_GEN(dev, num_lag_ports); + ldev->buckets = 1; + ldev->v2p_map = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS, + sizeof(*ldev->v2p_map), GFP_KERNEL); + if (!ldev->v2p_map) + goto err_v2p_map; + ldev->wq = create_singlethread_workqueue("mlx5_lag"); - if (!ldev->wq) { - kfree(ldev); - return NULL; - } + if (!ldev->wq) + goto err_wq; kref_init(&ldev->ref); mutex_init(&ldev->lock); @@ -358,10 +392,13 @@ static struct mlx5_lag *mlx5_lag_dev_alloc(struct mlx5_core_dev *dev) mlx5_core_err(dev, "Failed to init multipath lag err=%d\n", err); - ldev->ports = MLX5_CAP_GEN(dev, num_lag_ports); - ldev->buckets = 1; - return ldev; + +err_wq: + kfree(ldev->v2p_map); +err_v2p_map: + kfree(ldev); + return NULL; } int mlx5_lag_dev_get_netdev_idx(struct mlx5_lag *ldev, @@ -659,20 +696,28 @@ static bool __mlx5_lag_is_sd_active(struct mlx5_lag *ldev, * If there are ports that are disabled fill the relevant slots * with mapping that points to active ports. */ -static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, - struct mlx5_lag *ldev, - u8 buckets, - u8 *ports) +static int mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, + struct mlx5_lag *ldev, + u8 buckets, + u8 *ports) { - int disabled[MLX5_MAX_PORTS] = {}; - int enabled[MLX5_MAX_PORTS] = {}; int disabled_ports_num = 0; int enabled_ports_num = 0; + int *disabled; + int *enabled; + int err = 0; int idx; u32 rand; int i; int j; + enabled = kcalloc(ldev->ports, sizeof(*enabled), GFP_KERNEL); + disabled = kcalloc(ldev->ports, sizeof(*disabled), GFP_KERNEL); + if (!enabled || !disabled) { + err = -ENOMEM; + goto out; + } + mlx5_ldev_for_each(i, 0, ldev) { if (tracker->netdev_state[i].tx_enabled && tracker->netdev_state[i].link_up) @@ -695,7 +740,7 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, /* If all ports are disabled/enabled keep native mapping */ if (enabled_ports_num == ldev->ports || disabled_ports_num == ldev->ports) - return; + goto out; /* Go over the disabled ports and for each assign a random active port */ for (i = 0; i < disabled_ports_num; i++) { @@ -708,6 +753,11 @@ static void mlx5_infer_tx_affinity_mapping(struct lag_tracker *tracker, mlx5_lag_xa_to_dev_idx(ldev, rand_xa_idx) + 1; } } + +out: + kfree(enabled); + kfree(disabled); + return err; } static bool mlx5_lag_has_drop_rule(struct mlx5_lag *ldev) @@ -742,11 +792,8 @@ static void mlx5_lag_drop_rule_cleanup(struct mlx5_lag *ldev) static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev, struct lag_tracker *tracker) { - u8 disabled_ports[MLX5_MAX_PORTS] = {}; struct mlx5_core_dev *dev; struct lag_func *pf; - int disabled_index; - int num_disabled; int err; int i; @@ -758,11 +805,11 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev, if (!ldev->tracker.has_inactive) return; - mlx5_infer_tx_disabled(tracker, ldev, disabled_ports, &num_disabled); - - for (i = 0; i < num_disabled; i++) { - disabled_index = disabled_ports[i]; - pf = mlx5_lag_pf(ldev, disabled_index); + mlx5_ldev_for_each(i, 0, ldev) { + if (tracker->netdev_state[i].tx_enabled && + tracker->netdev_state[i].link_up) + continue; + pf = mlx5_lag_pf(ldev, i); dev = pf->dev; err = mlx5_esw_acl_ingress_vport_drop_rule_create(dev->priv.eswitch, MLX5_VPORT_UPLINK); @@ -770,7 +817,8 @@ static void mlx5_lag_drop_rule_setup(struct mlx5_lag *ldev, pf->has_drop = true; else mlx5_core_err(dev, - "Failed to create lag drop rule, error: %d", err); + "Failed to create lag drop rule, error: %d", + err); } } @@ -807,7 +855,10 @@ static int _mlx5_modify_lag(struct mlx5_lag *ldev, !MLX5_CAP_PORT_SELECTION(dev0, port_select_flow_table_bypass)) return ret; - active_ports = lag_active_port_bits(ldev, tracker); + ret = lag_active_port_bits(ldev, tracker); + if (ret < 0) + return ret; + active_ports = ret; return mlx5_cmd_modify_active_port(dev0, active_ports); } @@ -853,8 +904,8 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, struct lag_tracker *tracker) { int first_idx = mlx5_lag_get_dev_index_by_seq(ldev, MLX5_LAG_P1); - u8 ports[MLX5_MAX_PORTS * MLX5_LAG_MAX_HASH_BUCKETS] = {}; struct mlx5_core_dev *dev0; + u8 *ports; int idx; int err; int i; @@ -864,7 +915,20 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, return; dev0 = mlx5_lag_pf(ldev, first_idx)->dev; - mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, ports); + + ports = kcalloc(ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS, + sizeof(*ports), GFP_KERNEL); + if (!ports) + return; + + err = mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, + ports); + if (err) { + mlx5_core_err(dev0, + "mlx5_infer_tx_affinity_mapping failed, err = %d\n", + err); + goto out; + } mlx5_ldev_for_each(i, 0, ldev) { for (j = 0; j < ldev->buckets; j++) { @@ -876,9 +940,10 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, mlx5_core_err(dev0, "Failed to modify LAG (%d)\n", err); - return; + goto out; } - memcpy(ldev->v2p_map, ports, sizeof(ports)); + memcpy(ldev->v2p_map, ports, + ldev->ports * MLX5_LAG_MAX_HASH_BUCKETS); mlx5_lag_print_mapping(dev0, ldev, tracker, ldev->mode_flags); @@ -899,6 +964,8 @@ void mlx5_modify_lag(struct mlx5_lag *ldev, ndev); dev_put(ndev); } +out: + kfree(ports); } static int mlx5_lag_set_port_sel_mode(struct mlx5_lag *ldev, @@ -1027,7 +1094,16 @@ int mlx5_activate_lag(struct mlx5_lag *ldev, return err; if (mode != MLX5_LAG_MODE_MPESW) { - mlx5_infer_tx_affinity_mapping(tracker, ldev, ldev->buckets, ldev->v2p_map); + err = mlx5_infer_tx_affinity_mapping(tracker, ldev, + ldev->buckets, + ldev->v2p_map); + if (err) { + mlx5_core_err(dev0, + "mlx5_infer_tx_affinity_mapping failed, err = %d\n", + err); + return err; + } + if (test_bit(MLX5_LAG_MODE_FLAG_HASH_BASED, &flags)) { err = mlx5_lag_port_sel_create(ldev, tracker->hash_type, ldev->v2p_map); diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h index e9f0ef83ce1d..8552792b9035 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/lag.h @@ -85,7 +85,7 @@ struct mlx5_lag { u8 ports; u8 buckets; int mode_changes_in_progress; - u8 v2p_map[MLX5_MAX_PORTS * MLX5_LAG_MAX_HASH_BUCKETS]; + u8 *v2p_map; struct kref ref; struct xarray pfs; struct lag_tracker tracker; diff --git a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c index 424040918fa3..7c7e6c832a93 100644 --- a/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c +++ b/drivers/net/ethernet/mellanox/mlx5/core/lag/shared_fdb.c @@ -35,8 +35,7 @@ bool mlx5_lag_shared_fdb_supported_filter(struct mlx5_lag *ldev, u32 filter) if (is_mdev_switchdev_mode(dev0) && mlx5_eswitch_vport_match_metadata_enabled(dev0->priv.eswitch) && - mlx5_esw_offloads_devcom_is_ready(dev0->priv.eswitch) && - MLX5_CAP_ESW(dev0, esw_shared_ingress_acl)) + mlx5_esw_offloads_devcom_is_ready(dev0->priv.eswitch)) ret = true; return ret; diff --git a/include/linux/mlx5/eswitch.h b/include/linux/mlx5/eswitch.h index a0dd162baa78..03d3620141c8 100644 --- a/include/linux/mlx5/eswitch.h +++ b/include/linux/mlx5/eswitch.h @@ -222,6 +222,9 @@ static inline bool is_mdev_switchdev_mode(struct mlx5_core_dev *dev) /* The returned number is valid only when the dev is eswitch manager. */ static inline u16 mlx5_eswitch_manager_vport(struct mlx5_core_dev *dev) { + if (MLX5_CAP_ESW(dev, esw_manager_vport_number_valid)) + return MLX5_CAP_ESW(dev, esw_manager_vport_number); + return mlx5_core_is_ecpf_esw_manager(dev) ? MLX5_VPORT_ECPF : MLX5_VPORT_HOST_PF; }