mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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:
commit
df2d695617
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user