Merge branch 'net-mlx5-preparations-for-nested-e-switch'

Tariq Toukan says:

====================
net/mlx5: Preparations for nested E-switch

This series by Shay has two intertwined goals. The first is to remove
the compile-time MLX5_MAX_PORTS sizing from the LAG and eswitch/TC
datapaths so that structures scale with the actual number of ports/peers
rather than a fixed maximum. The second is a set of small,
self-contained fixes that prepare the eswitch and LAG code for a VF/SF
acting as a nested e-switch manager - a mode new FW will allow, where a
VF/SF has its own eswitch and the VFs/SFs can be grouped by MPESW.

No functional change is intended for existing configurations.
====================

Link: https://patch.msgid.link/20260923103830.1183-1-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2026-09-28 17:17:50 -07:00
commit df2d695617
11 changed files with 215 additions and 112 deletions

View File

@ -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 */

View File

@ -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;

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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)

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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;

View File

@ -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;
}