Merge branch 'net-mlx5-qos-refactor-esw-qos-to-support-new-features'

Tariq Toukan says:

====================
net/mlx5: qos: Refactor esw qos to support new features

This patch series by Cosmin and Carolina prepares the mlx5 qos infra for
the upcoming feature of cross E-Switch scheduling.

Noop cleanups:
net/mlx5: qos: Flesh out element_attributes in mlx5_ifc.h
net/mlx5: qos: Rename vport 'tsar' into 'sched_elem'.
net/mlx5: qos: Consistently name vport vars as 'vport'
net/mlx5: qos: Refactor and document bw_share calculation
net/mlx5: qos: Rename rate group 'list' as 'parent_entry'

Refactor the code with the goal of moving groups out of E-Switches:
net/mlx5: qos: Maintain rate group vport members in a list
net/mlx5: qos: Always create group0
net/mlx5: qos: Drop 'esw' param from vport qos functions
net/mlx5: qos: Store the eswitch in a mlx5_esw_rate_group

Move groups from an E-Switch into an mlx5_qos_domain:
net/mlx5: qos: Store rate groups in a qos domain

Refactor locking to use a new mutex in the qos domain:
net/mlx5: qos: Refactor locking to a qos domain mutex

In follow-up patchsets, we'll allow qos domains to be shared
between E-Switches of the same NIC.

The two top patches are simple enhancements.
====================

Link: https://patch.msgid.link/20241008183222.137702-1-tariqt@nvidia.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
Paolo Abeni
2024-10-10 13:12:03 +02:00
12 changed files with 549 additions and 378 deletions
@@ -187,7 +187,7 @@ rate_err:
return err;
}
void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport)
void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
{
struct mlx5_devlink_port *dl_port;
@@ -195,7 +195,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct
return;
dl_port = vport->dl_port;
mlx5_esw_qos_vport_update_group(esw, vport, NULL, NULL);
mlx5_esw_qos_vport_update_group(vport, NULL, NULL);
devl_rate_leaf_destroy(&dl_port->dl_port);
devl_port_unregister(&dl_port->dl_port);
@@ -11,52 +11,55 @@
#include "eswitch.h"
TRACE_EVENT(mlx5_esw_vport_qos_destroy,
TP_PROTO(const struct mlx5_vport *vport),
TP_ARGS(vport),
TP_STRUCT__entry(__string(devname, dev_name(vport->dev->device))
TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport),
TP_ARGS(dev, vport),
TP_STRUCT__entry(__string(devname, dev_name(dev->device))
__field(unsigned short, vport_id)
__field(unsigned int, tsar_ix)
__field(unsigned int, sched_elem_ix)
),
TP_fast_assign(__assign_str(devname);
__entry->vport_id = vport->vport;
__entry->tsar_ix = vport->qos.esw_tsar_ix;
__entry->sched_elem_ix = vport->qos.esw_sched_elem_ix;
),
TP_printk("(%s) vport=%hu tsar_ix=%u\n",
__get_str(devname), __entry->vport_id, __entry->tsar_ix
TP_printk("(%s) vport=%hu sched_elem_ix=%u\n",
__get_str(devname), __entry->vport_id, __entry->sched_elem_ix
)
);
DECLARE_EVENT_CLASS(mlx5_esw_vport_qos_template,
TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate),
TP_ARGS(vport, bw_share, max_rate),
TP_STRUCT__entry(__string(devname, dev_name(vport->dev->device))
TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport,
u32 bw_share, u32 max_rate),
TP_ARGS(dev, vport, bw_share, max_rate),
TP_STRUCT__entry(__string(devname, dev_name(dev->device))
__field(unsigned short, vport_id)
__field(unsigned int, tsar_ix)
__field(unsigned int, sched_elem_ix)
__field(unsigned int, bw_share)
__field(unsigned int, max_rate)
__field(void *, group)
),
TP_fast_assign(__assign_str(devname);
__entry->vport_id = vport->vport;
__entry->tsar_ix = vport->qos.esw_tsar_ix;
__entry->sched_elem_ix = vport->qos.esw_sched_elem_ix;
__entry->bw_share = bw_share;
__entry->max_rate = max_rate;
__entry->group = vport->qos.group;
),
TP_printk("(%s) vport=%hu tsar_ix=%u bw_share=%u, max_rate=%u group=%p\n",
__get_str(devname), __entry->vport_id, __entry->tsar_ix,
TP_printk("(%s) vport=%hu sched_elem_ix=%u bw_share=%u, max_rate=%u group=%p\n",
__get_str(devname), __entry->vport_id, __entry->sched_elem_ix,
__entry->bw_share, __entry->max_rate, __entry->group
)
);
DEFINE_EVENT(mlx5_esw_vport_qos_template, mlx5_esw_vport_qos_create,
TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate),
TP_ARGS(vport, bw_share, max_rate)
TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport,
u32 bw_share, u32 max_rate),
TP_ARGS(dev, vport, bw_share, max_rate)
);
DEFINE_EVENT(mlx5_esw_vport_qos_template, mlx5_esw_vport_qos_config,
TP_PROTO(const struct mlx5_vport *vport, u32 bw_share, u32 max_rate),
TP_ARGS(vport, bw_share, max_rate)
TP_PROTO(const struct mlx5_core_dev *dev, const struct mlx5_vport *vport,
u32 bw_share, u32 max_rate),
TP_ARGS(dev, vport, bw_share, max_rate)
);
DECLARE_EVENT_CLASS(mlx5_esw_group_qos_template,
@@ -513,15 +513,11 @@ int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport,
u32 max_rate, u32 min_rate)
{
struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
int err;
if (!mlx5_esw_allowed(esw))
return -EPERM;
if (IS_ERR(evport))
return PTR_ERR(evport);
mutex_lock(&esw->state_lock);
err = mlx5_esw_qos_set_vport_rate(esw, evport, max_rate, min_rate);
mutex_unlock(&esw->state_lock);
return err;
return mlx5_esw_qos_set_vport_rate(evport, max_rate, min_rate);
}
File diff suppressed because it is too large Load Diff
@@ -6,9 +6,12 @@
#ifdef CONFIG_MLX5_ESWITCH
int mlx5_esw_qos_set_vport_rate(struct mlx5_eswitch *esw, struct mlx5_vport *evport,
u32 max_rate, u32 min_rate);
void mlx5_esw_qos_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
int mlx5_esw_qos_init(struct mlx5_eswitch *esw);
void mlx5_esw_qos_cleanup(struct mlx5_eswitch *esw);
int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *evport, u32 max_rate, u32 min_rate);
bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *min_rate);
void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport);
int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void *priv,
u64 tx_share, struct netlink_ext_ack *extack);
@@ -894,7 +894,7 @@ static void esw_vport_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport
vport_num, 1,
MLX5_VPORT_ADMIN_STATE_DOWN);
mlx5_esw_qos_vport_disable(esw, vport);
mlx5_esw_qos_vport_disable(vport);
esw_vport_cleanup_acl(esw, vport);
}
@@ -1481,6 +1481,10 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
mlx5_eq_notifier_register(esw->dev, &esw->nb);
err = mlx5_esw_qos_init(esw);
if (err)
goto err_qos_init;
if (esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_legacy_enable(esw);
} else {
@@ -1489,7 +1493,7 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
}
if (err)
goto abort;
goto err_esw_enable;
esw->fdb_table.flags |= MLX5_ESW_FDB_CREATED;
@@ -1503,7 +1507,10 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
return 0;
abort:
err_esw_enable:
mlx5_esw_qos_cleanup(esw);
err_qos_init:
mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
mlx5_esw_acls_ns_cleanup(esw);
return err;
}
@@ -1631,6 +1638,7 @@ void mlx5_eswitch_disable_locked(struct mlx5_eswitch *esw)
if (esw->mode == MLX5_ESWITCH_OFFLOADS)
devl_rate_nodes_destroy(devlink);
mlx5_esw_qos_cleanup(esw);
}
void mlx5_eswitch_disable(struct mlx5_eswitch *esw)
@@ -2060,6 +2068,7 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
u16 vport, struct ifla_vf_info *ivi)
{
struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
u32 max_rate, min_rate;
if (IS_ERR(evport))
return PTR_ERR(evport);
@@ -2074,9 +2083,10 @@ int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
ivi->qos = evport->info.qos;
ivi->spoofchk = evport->info.spoofchk;
ivi->trusted = evport->info.trusted;
if (evport->qos.enabled) {
ivi->min_tx_rate = evport->qos.min_rate;
ivi->max_tx_rate = evport->qos.max_rate;
if (mlx5_esw_qos_get_vport_rate(evport, &max_rate, &min_rate)) {
ivi->max_tx_rate = max_rate;
ivi->min_tx_rate = min_rate;
}
mutex_unlock(&esw->state_lock);
@@ -212,13 +212,17 @@ struct mlx5_vport {
struct mlx5_vport_info info;
/* Protected with the E-Switch qos domain lock. */
struct {
bool enabled;
u32 esw_tsar_ix;
u32 bw_share;
/* Initially false, set to true whenever any QoS features are used. */
bool enabled;
u32 esw_sched_elem_ix;
u32 min_rate;
u32 max_rate;
/* A computed value indicating relative min_rate between vports in a group. */
u32 bw_share;
struct mlx5_esw_rate_group *group;
struct list_head group_entry;
} qos;
u16 vport;
@@ -333,6 +337,7 @@ enum {
};
struct dentry;
struct mlx5_qos_domain;
struct mlx5_eswitch {
struct mlx5_core_dev *dev;
@@ -359,15 +364,17 @@ struct mlx5_eswitch {
struct rw_semaphore mode_lock;
atomic64_t user_count;
/* Protected with the E-Switch qos domain lock. */
struct {
u32 root_tsar_ix;
struct mlx5_esw_rate_group *group0;
struct list_head groups; /* Protected by esw->state_lock */
/* Protected by esw->state_lock.
* Initially 0, meaning no QoS users and QoS is disabled.
*/
/* Initially 0, meaning no QoS users and QoS is disabled. */
refcount_t refcnt;
u32 root_tsar_ix;
struct mlx5_qos_domain *domain;
/* Contains all vports with QoS enabled but no explicit group.
* Cannot be NULL if QoS is enabled, but may be a fake group
* referencing the root TSAR if the esw doesn't support groups.
*/
struct mlx5_esw_rate_group *group0;
} qos;
struct mlx5_esw_bridge_offloads *br_offloads;
@@ -427,8 +434,7 @@ int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
u16 vport_num, bool setting);
int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport,
u32 max_rate, u32 min_rate);
int mlx5_esw_qos_vport_update_group(struct mlx5_eswitch *esw,
struct mlx5_vport *vport,
int mlx5_esw_qos_vport_update_group(struct mlx5_vport *vport,
struct mlx5_esw_rate_group *group,
struct netlink_ext_ack *extack);
int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting);
@@ -806,7 +812,7 @@ int mlx5_esw_offloads_sf_devlink_port_init(struct mlx5_eswitch *esw, struct mlx5
void mlx5_esw_offloads_sf_devlink_port_cleanup(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
int mlx5_esw_offloads_devlink_port_register(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_eswitch *esw, struct mlx5_vport *vport);
void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport);
struct devlink_port *mlx5_esw_offloads_devlink_port(struct mlx5_eswitch *esw, u16 vport_num);
int mlx5_esw_sf_max_hpf_functions(struct mlx5_core_dev *dev, u16 *max_sfs, u16 *sf_base_id);
@@ -2617,7 +2617,7 @@ int mlx5_esw_offloads_load_rep(struct mlx5_eswitch *esw, struct mlx5_vport *vpor
return err;
load_err:
mlx5_esw_offloads_devlink_port_unregister(esw, vport);
mlx5_esw_offloads_devlink_port_unregister(vport);
return err;
}
@@ -2628,7 +2628,7 @@ void mlx5_esw_offloads_unload_rep(struct mlx5_eswitch *esw, struct mlx5_vport *v
mlx5_esw_offloads_rep_unload(esw, vport->vport);
mlx5_esw_offloads_devlink_port_unregister(esw, vport);
mlx5_esw_offloads_devlink_port_unregister(vport);
}
static int esw_set_slave_root_fdb(struct mlx5_core_dev *master,
@@ -224,6 +224,8 @@ void mlx5_sriov_disable(struct pci_dev *pdev, bool num_vf_change);
int mlx5_core_sriov_set_msix_vec_count(struct pci_dev *vf, int msix_vec_count);
int mlx5_core_enable_hca(struct mlx5_core_dev *dev, u16 func_id);
int mlx5_core_disable_hca(struct mlx5_core_dev *dev, u16 func_id);
bool mlx5_qos_element_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy);
bool mlx5_qos_tsar_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy);
int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
void *context, u32 *element_id);
int mlx5_modify_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
@@ -28,7 +28,9 @@ int mlx5_qos_create_leaf_node(struct mlx5_core_dev *mdev, u32 parent_id,
{
u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
if (!(MLX5_CAP_QOS(mdev, nic_element_type) & ELEMENT_TYPE_CAP_MASK_QUEUE_GROUP))
if (!mlx5_qos_element_type_supported(mdev,
SCHEDULING_CONTEXT_ELEMENT_TYPE_QUEUE_GROUP,
SCHEDULING_HIERARCHY_NIC))
return -EOPNOTSUPP;
MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id);
@@ -47,8 +49,12 @@ int mlx5_qos_create_inner_node(struct mlx5_core_dev *mdev, u32 parent_id,
u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
void *attr;
if (!(MLX5_CAP_QOS(mdev, nic_element_type) & ELEMENT_TYPE_CAP_MASK_TSAR) ||
!(MLX5_CAP_QOS(mdev, nic_tsar_type) & TSAR_TYPE_CAP_MASK_DWRR))
if (!mlx5_qos_element_type_supported(mdev,
SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR,
SCHEDULING_HIERARCHY_NIC) ||
!mlx5_qos_tsar_type_supported(mdev,
TSAR_ELEMENT_TSAR_TYPE_DWRR,
SCHEDULING_HIERARCHY_NIC))
return -EOPNOTSUPP;
MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent_id);
@@ -34,6 +34,64 @@
#include <linux/mlx5/driver.h>
#include "mlx5_core.h"
bool mlx5_qos_tsar_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy)
{
int cap;
switch (hierarchy) {
case SCHEDULING_HIERARCHY_E_SWITCH:
cap = MLX5_CAP_QOS(dev, esw_tsar_type);
break;
case SCHEDULING_HIERARCHY_NIC:
cap = MLX5_CAP_QOS(dev, nic_tsar_type);
break;
default:
return false;
}
switch (type) {
case TSAR_ELEMENT_TSAR_TYPE_DWRR:
return cap & TSAR_TYPE_CAP_MASK_DWRR;
case TSAR_ELEMENT_TSAR_TYPE_ROUND_ROBIN:
return cap & TSAR_TYPE_CAP_MASK_ROUND_ROBIN;
case TSAR_ELEMENT_TSAR_TYPE_ETS:
return cap & TSAR_TYPE_CAP_MASK_ETS;
}
return false;
}
bool mlx5_qos_element_type_supported(struct mlx5_core_dev *dev, int type, u8 hierarchy)
{
int cap;
switch (hierarchy) {
case SCHEDULING_HIERARCHY_E_SWITCH:
cap = MLX5_CAP_QOS(dev, esw_element_type);
break;
case SCHEDULING_HIERARCHY_NIC:
cap = MLX5_CAP_QOS(dev, nic_element_type);
break;
default:
return false;
}
switch (type) {
case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
return cap & ELEMENT_TYPE_CAP_MASK_TSAR;
case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
return cap & ELEMENT_TYPE_CAP_MASK_VPORT;
case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
return cap & ELEMENT_TYPE_CAP_MASK_VPORT_TC;
case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
return cap & ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
case SCHEDULING_CONTEXT_ELEMENT_TYPE_QUEUE_GROUP:
return cap & ELEMENT_TYPE_CAP_MASK_QUEUE_GROUP;
}
return false;
}
/* Scheduling element fw management */
int mlx5_create_scheduling_element_cmd(struct mlx5_core_dev *dev, u8 hierarchy,
void *ctx, u32 *element_id)
+37 -30
View File
@@ -4105,11 +4105,47 @@ enum {
ELEMENT_TYPE_CAP_MASK_QUEUE_GROUP = 1 << 4,
};
enum {
TSAR_ELEMENT_TSAR_TYPE_DWRR = 0x0,
TSAR_ELEMENT_TSAR_TYPE_ROUND_ROBIN = 0x1,
TSAR_ELEMENT_TSAR_TYPE_ETS = 0x2,
};
enum {
TSAR_TYPE_CAP_MASK_DWRR = 1 << 0,
TSAR_TYPE_CAP_MASK_ROUND_ROBIN = 1 << 1,
TSAR_TYPE_CAP_MASK_ETS = 1 << 2,
};
struct mlx5_ifc_tsar_element_bits {
u8 reserved_at_0[0x8];
u8 tsar_type[0x8];
u8 reserved_at_10[0x10];
};
struct mlx5_ifc_vport_element_bits {
u8 reserved_at_0[0x10];
u8 vport_number[0x10];
};
struct mlx5_ifc_vport_tc_element_bits {
u8 traffic_class[0x4];
u8 reserved_at_4[0xc];
u8 vport_number[0x10];
};
union mlx5_ifc_element_attributes_bits {
struct mlx5_ifc_tsar_element_bits tsar;
struct mlx5_ifc_vport_element_bits vport;
struct mlx5_ifc_vport_tc_element_bits vport_tc;
u8 reserved_at_0[0x20];
};
struct mlx5_ifc_scheduling_context_bits {
u8 element_type[0x8];
u8 reserved_at_8[0x18];
u8 element_attributes[0x20];
union mlx5_ifc_element_attributes_bits element_attributes;
u8 parent_element_id[0x20];
@@ -4798,35 +4834,6 @@ struct mlx5_ifc_register_loopback_control_bits {
u8 reserved_at_20[0x60];
};
struct mlx5_ifc_vport_tc_element_bits {
u8 traffic_class[0x4];
u8 reserved_at_4[0xc];
u8 vport_number[0x10];
};
struct mlx5_ifc_vport_element_bits {
u8 reserved_at_0[0x10];
u8 vport_number[0x10];
};
enum {
TSAR_ELEMENT_TSAR_TYPE_DWRR = 0x0,
TSAR_ELEMENT_TSAR_TYPE_ROUND_ROBIN = 0x1,
TSAR_ELEMENT_TSAR_TYPE_ETS = 0x2,
};
enum {
TSAR_TYPE_CAP_MASK_DWRR = 1 << 0,
TSAR_TYPE_CAP_MASK_ROUND_ROBIN = 1 << 1,
TSAR_TYPE_CAP_MASK_ETS = 1 << 2,
};
struct mlx5_ifc_tsar_element_bits {
u8 reserved_at_0[0x8];
u8 tsar_type[0x8];
u8 reserved_at_10[0x10];
};
enum {
MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_SUCCESS = 0x0,
MLX5_TEARDOWN_HCA_OUT_FORCE_STATE_FAIL = 0x1,