Merge branch 'mlx5-esw-qos-refactor-and-shampo-cleanup'

Tariq Toukan says:

====================
mlx5 esw qos refactor and SHAMPO cleanup

This patchset for the mlx5 core and Eth drivers consists of 3 parts.

First patch by Patrisious improves the E-switch mode change operation.

The following 6 patches by Carolina introduce further refactoring for
the QoS handling, to set the foundation for future extensions.

In the following 5 patches by Dragos, we enhance the SHAMPO datapath
flow by simplifying some logic, and cleaning up the implementation.
====================

Link: https://patch.msgid.link/20241107194357.683732-1-tariqt@nvidia.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski 2024-11-11 19:28:20 -08:00
commit 544070db6c
9 changed files with 305 additions and 441 deletions

View File

@ -83,6 +83,7 @@ struct page_pool;
#define MLX5E_SHAMPO_LOG_HEADER_ENTRY_SIZE (8)
#define MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE (9)
#define MLX5E_SHAMPO_WQ_HEADER_PER_PAGE (PAGE_SIZE >> MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE)
#define MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE (PAGE_SHIFT - MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE)
#define MLX5E_SHAMPO_WQ_BASE_HEAD_ENTRY_SIZE (64)
#define MLX5E_SHAMPO_WQ_RESRV_SIZE (64 * 1024)
#define MLX5E_SHAMPO_WQ_BASE_RESRV_SIZE (4096)
@ -624,16 +625,14 @@ struct mlx5e_dma_info {
struct mlx5e_shampo_hd {
u32 mkey;
struct mlx5e_dma_info *info;
struct mlx5e_frag_page *pages;
u16 curr_page_index;
u32 hd_per_wq;
u16 hd_per_wqe;
u16 pages_per_wq;
unsigned long *bitmap;
u16 pi;
u16 ci;
__be32 key;
u64 last_addr;
};
struct mlx5e_hw_gro_data {

View File

@ -350,19 +350,15 @@ static int mlx5e_rq_shampo_hd_info_alloc(struct mlx5e_rq *rq, int node)
shampo->bitmap = bitmap_zalloc_node(shampo->hd_per_wq, GFP_KERNEL,
node);
shampo->info = kvzalloc_node(array_size(shampo->hd_per_wq,
sizeof(*shampo->info)),
GFP_KERNEL, node);
shampo->pages = kvzalloc_node(array_size(shampo->hd_per_wq,
sizeof(*shampo->pages)),
GFP_KERNEL, node);
if (!shampo->bitmap || !shampo->info || !shampo->pages)
if (!shampo->bitmap || !shampo->pages)
goto err_nomem;
return 0;
err_nomem:
kvfree(shampo->info);
kvfree(shampo->bitmap);
kvfree(shampo->pages);
@ -372,7 +368,6 @@ err_nomem:
static void mlx5e_rq_shampo_hd_info_free(struct mlx5e_rq *rq)
{
kvfree(rq->mpwqe.shampo->bitmap);
kvfree(rq->mpwqe.shampo->info);
kvfree(rq->mpwqe.shampo->pages);
}
@ -767,8 +762,6 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
u32 *pool_size,
int node)
{
void *wqc = MLX5_ADDR_OF(rqc, rqp->rqc, wq);
int wq_size;
int err;
if (!test_bit(MLX5E_RQ_STATE_SHAMPO, &rq->state))
@ -793,9 +786,9 @@ static int mlx5_rq_shampo_alloc(struct mlx5_core_dev *mdev,
cpu_to_be32(rq->mpwqe.shampo->mkey);
rq->mpwqe.shampo->hd_per_wqe =
mlx5e_shampo_hd_per_wqe(mdev, params, rqp);
wq_size = BIT(MLX5_GET(wq, wqc, log_wq_sz));
*pool_size += (rq->mpwqe.shampo->hd_per_wqe * wq_size) /
MLX5E_SHAMPO_WQ_HEADER_PER_PAGE;
rq->mpwqe.shampo->pages_per_wq =
rq->mpwqe.shampo->hd_per_wq / MLX5E_SHAMPO_WQ_HEADER_PER_PAGE;
*pool_size += rq->mpwqe.shampo->pages_per_wq;
return 0;
err_hw_gro_data:

View File

@ -643,83 +643,82 @@ static void build_ksm_umr(struct mlx5e_icosq *sq, struct mlx5e_umr_wqe *umr_wqe,
umr_wqe->uctrl.mkey_mask = cpu_to_be64(MLX5_MKEY_MASK_FREE);
}
static struct mlx5e_frag_page *mlx5e_shampo_hd_to_frag_page(struct mlx5e_rq *rq, int header_index)
{
BUILD_BUG_ON(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE > PAGE_SHIFT);
return &rq->mpwqe.shampo->pages[header_index >> MLX5E_SHAMPO_LOG_WQ_HEADER_PER_PAGE];
}
static u64 mlx5e_shampo_hd_offset(int header_index)
{
return (header_index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) <<
MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE;
}
static void mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index);
static int mlx5e_build_shampo_hd_umr(struct mlx5e_rq *rq,
struct mlx5e_icosq *sq,
u16 ksm_entries, u16 index)
{
struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
u16 entries, pi, header_offset, err, wqe_bbs, new_entries;
u16 pi, header_offset, err, wqe_bbs;
u32 lkey = rq->mdev->mlx5e_res.hw_objs.mkey;
u16 page_index = shampo->curr_page_index;
struct mlx5e_frag_page *frag_page;
u64 addr = shampo->last_addr;
struct mlx5e_dma_info *dma_info;
struct mlx5e_umr_wqe *umr_wqe;
int headroom, i;
int headroom, i = 0;
headroom = rq->buff.headroom;
new_entries = ksm_entries - (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1));
entries = ALIGN(ksm_entries, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT);
wqe_bbs = MLX5E_KSM_UMR_WQEBBS(entries);
wqe_bbs = MLX5E_KSM_UMR_WQEBBS(ksm_entries);
pi = mlx5e_icosq_get_next_pi(sq, wqe_bbs);
umr_wqe = mlx5_wq_cyc_get_wqe(&sq->wq, pi);
build_ksm_umr(sq, umr_wqe, shampo->key, index, entries);
build_ksm_umr(sq, umr_wqe, shampo->key, index, ksm_entries);
frag_page = &shampo->pages[page_index];
WARN_ON_ONCE(ksm_entries & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1));
while (i < ksm_entries) {
struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index);
u64 addr;
for (i = 0; i < entries; i++, index++) {
dma_info = &shampo->info[index];
if (i >= ksm_entries || (index < shampo->pi && shampo->pi - index <
MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT))
goto update_ksm;
header_offset = (index & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) <<
MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE;
if (!(header_offset & (PAGE_SIZE - 1))) {
page_index = (page_index + 1) & (shampo->hd_per_wq - 1);
frag_page = &shampo->pages[page_index];
err = mlx5e_page_alloc_fragmented(rq, frag_page);
if (unlikely(err))
goto err_unmap;
err = mlx5e_page_alloc_fragmented(rq, frag_page);
if (unlikely(err))
goto err_unmap;
addr = page_pool_get_dma_addr(frag_page->page);
addr = page_pool_get_dma_addr(frag_page->page);
dma_info->addr = addr;
dma_info->frag_page = frag_page;
} else {
dma_info->addr = addr + header_offset;
dma_info->frag_page = frag_page;
for (int j = 0; j < MLX5E_SHAMPO_WQ_HEADER_PER_PAGE; j++) {
header_offset = mlx5e_shampo_hd_offset(index++);
umr_wqe->inline_ksms[i++] = (struct mlx5_ksm) {
.key = cpu_to_be32(lkey),
.va = cpu_to_be64(addr + header_offset + headroom),
};
}
update_ksm:
umr_wqe->inline_ksms[i] = (struct mlx5_ksm) {
.key = cpu_to_be32(lkey),
.va = cpu_to_be64(dma_info->addr + headroom),
};
}
sq->db.wqe_info[pi] = (struct mlx5e_icosq_wqe_info) {
.wqe_type = MLX5E_ICOSQ_WQE_SHAMPO_HD_UMR,
.num_wqebbs = wqe_bbs,
.shampo.len = new_entries,
.shampo.len = ksm_entries,
};
shampo->pi = (shampo->pi + new_entries) & (shampo->hd_per_wq - 1);
shampo->curr_page_index = page_index;
shampo->last_addr = addr;
shampo->pi = (shampo->pi + ksm_entries) & (shampo->hd_per_wq - 1);
sq->pc += wqe_bbs;
sq->doorbell_cseg = &umr_wqe->ctrl;
return 0;
err_unmap:
while (--i >= 0) {
dma_info = &shampo->info[--index];
if (!(i & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1))) {
dma_info->addr = ALIGN_DOWN(dma_info->addr, PAGE_SIZE);
mlx5e_page_release_fragmented(rq, dma_info->frag_page);
while (--i) {
--index;
header_offset = mlx5e_shampo_hd_offset(index);
if (!header_offset) {
struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, index);
mlx5e_page_release_fragmented(rq, frag_page);
}
}
rq->stats->buff_alloc_err++;
return err;
}
@ -731,7 +730,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq)
struct mlx5e_icosq *sq = rq->icosq;
int i, err, max_ksm_entries, len;
max_ksm_entries = MLX5E_MAX_KSM_PER_WQE(rq->mdev);
max_ksm_entries = ALIGN_DOWN(MLX5E_MAX_KSM_PER_WQE(rq->mdev),
MLX5E_SHAMPO_WQ_HEADER_PER_PAGE);
ksm_entries = bitmap_find_window(shampo->bitmap,
shampo->hd_per_wqe,
shampo->hd_per_wq, shampo->pi);
@ -739,8 +739,8 @@ static int mlx5e_alloc_rx_hd_mpwqe(struct mlx5e_rq *rq)
if (!ksm_entries)
return 0;
ksm_entries += (shampo->pi & (MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT - 1));
index = ALIGN_DOWN(shampo->pi, MLX5_UMR_KSM_NUM_ENTRIES_ALIGNMENT);
/* pi is aligned to MLX5E_SHAMPO_WQ_HEADER_PER_PAGE */
index = shampo->pi;
entries_before = shampo->hd_per_wq - index;
if (unlikely(entries_before < ksm_entries))
@ -851,13 +851,11 @@ static void
mlx5e_free_rx_shampo_hd_entry(struct mlx5e_rq *rq, u16 header_index)
{
struct mlx5e_shampo_hd *shampo = rq->mpwqe.shampo;
u64 addr = shampo->info[header_index].addr;
if (((header_index + 1) & (MLX5E_SHAMPO_WQ_HEADER_PER_PAGE - 1)) == 0) {
struct mlx5e_dma_info *dma_info = &shampo->info[header_index];
struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
dma_info->addr = ALIGN_DOWN(addr, PAGE_SIZE);
mlx5e_page_release_fragmented(rq, dma_info->frag_page);
mlx5e_page_release_fragmented(rq, frag_page);
}
clear_bit(header_index, shampo->bitmap);
}
@ -1211,10 +1209,10 @@ static void mlx5e_lro_update_hdr(struct sk_buff *skb, struct mlx5_cqe64 *cqe,
static void *mlx5e_shampo_get_packet_hd(struct mlx5e_rq *rq, u16 header_index)
{
struct mlx5e_dma_info *last_head = &rq->mpwqe.shampo->info[header_index];
u16 head_offset = (last_head->addr & (PAGE_SIZE - 1)) + rq->buff.headroom;
struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
u16 head_offset = mlx5e_shampo_hd_offset(header_index) + rq->buff.headroom;
return page_address(last_head->frag_page->page) + head_offset;
return page_address(frag_page->page) + head_offset;
}
static void mlx5e_shampo_update_ipv4_udp_hdr(struct mlx5e_rq *rq, struct iphdr *ipv4)
@ -2185,29 +2183,30 @@ static struct sk_buff *
mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
struct mlx5_cqe64 *cqe, u16 header_index)
{
struct mlx5e_dma_info *head = &rq->mpwqe.shampo->info[header_index];
u16 head_offset = head->addr & (PAGE_SIZE - 1);
struct mlx5e_frag_page *frag_page = mlx5e_shampo_hd_to_frag_page(rq, header_index);
dma_addr_t page_dma_addr = page_pool_get_dma_addr(frag_page->page);
u16 head_offset = mlx5e_shampo_hd_offset(header_index);
dma_addr_t dma_addr = page_dma_addr + head_offset;
u16 head_size = cqe->shampo.header_size;
u16 rx_headroom = rq->buff.headroom;
struct sk_buff *skb = NULL;
void *hdr, *data;
u32 frag_size;
hdr = page_address(head->frag_page->page) + head_offset;
hdr = page_address(frag_page->page) + head_offset;
data = hdr + rx_headroom;
frag_size = MLX5_SKB_FRAG_SZ(rx_headroom + head_size);
if (likely(frag_size <= BIT(MLX5E_SHAMPO_LOG_MAX_HEADER_ENTRY_SIZE))) {
/* build SKB around header */
dma_sync_single_range_for_cpu(rq->pdev, head->addr, 0, frag_size, rq->buff.map_dir);
dma_sync_single_range_for_cpu(rq->pdev, dma_addr, 0, frag_size, rq->buff.map_dir);
net_prefetchw(hdr);
net_prefetch(data);
skb = mlx5e_build_linear_skb(rq, hdr, frag_size, rx_headroom, head_size, 0);
if (unlikely(!skb))
return NULL;
head->frag_page->frags++;
frag_page->frags++;
} else {
/* allocate SKB and copy header for large header */
rq->stats->gro_large_hds++;
@ -2219,7 +2218,7 @@ mlx5e_skb_from_cqe_shampo(struct mlx5e_rq *rq, struct mlx5e_mpw_info *wi,
}
net_prefetchw(skb->data);
mlx5e_copy_skb_header(rq, skb, head->frag_page->page, head->addr,
mlx5e_copy_skb_header(rq, skb, frag_page->page, dma_addr,
head_offset + rx_headroom,
rx_headroom, head_size);
/* skb linear part was allocated with headlen and aligned to long */

View File

@ -195,7 +195,7 @@ void mlx5_esw_offloads_devlink_port_unregister(struct mlx5_vport *vport)
return;
dl_port = vport->dl_port;
mlx5_esw_qos_vport_update_node(vport, NULL, NULL);
mlx5_esw_qos_vport_update_parent(vport, NULL, NULL);
devl_rate_leaf_destroy(&dl_port->dl_port);
devl_port_unregister(&dl_port->dl_port);

View File

@ -101,6 +101,12 @@ esw_qos_node_set_parent(struct mlx5_esw_sched_node *node, struct mlx5_esw_sched_
node->esw = parent->esw;
}
void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport)
{
kfree(vport->qos.sched_node);
memset(&vport->qos, 0, sizeof(vport->qos));
}
u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport)
{
if (!vport->qos.sched_node)
@ -118,18 +124,49 @@ mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport)
return vport->qos.sched_node->parent;
}
static void esw_qos_sched_elem_config_warn(struct mlx5_esw_sched_node *node, int err)
static void esw_qos_sched_elem_warn(struct mlx5_esw_sched_node *node, int err, const char *op)
{
if (node->vport) {
esw_warn(node->esw->dev,
"E-Switch modify %s scheduling element failed (vport=%d,err=%d)\n",
sched_node_type_str[node->type], node->vport->vport, err);
"E-Switch %s %s scheduling element failed (vport=%d,err=%d)\n",
op, sched_node_type_str[node->type], node->vport->vport, err);
return;
}
esw_warn(node->esw->dev,
"E-Switch modify %s scheduling element failed (err=%d)\n",
sched_node_type_str[node->type], err);
"E-Switch %s %s scheduling element failed (err=%d)\n",
op, sched_node_type_str[node->type], err);
}
static int esw_qos_node_create_sched_element(struct mlx5_esw_sched_node *node, void *ctx,
struct netlink_ext_ack *extack)
{
int err;
err = mlx5_create_scheduling_element_cmd(node->esw->dev, SCHEDULING_HIERARCHY_E_SWITCH, ctx,
&node->ix);
if (err) {
esw_qos_sched_elem_warn(node, err, "create");
NL_SET_ERR_MSG_MOD(extack, "E-Switch create scheduling element failed");
}
return err;
}
static int esw_qos_node_destroy_sched_element(struct mlx5_esw_sched_node *node,
struct netlink_ext_ack *extack)
{
int err;
err = mlx5_destroy_scheduling_element_cmd(node->esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH,
node->ix);
if (err) {
esw_qos_sched_elem_warn(node, err, "destroy");
NL_SET_ERR_MSG_MOD(extack, "E-Switch destroying scheduling element failed.");
}
return err;
}
static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_rate, u32 bw_share,
@ -143,10 +180,21 @@ static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_r
if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
return -EOPNOTSUPP;
MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
if (bw_share && (!MLX5_CAP_QOS(dev, esw_bw_share) ||
MLX5_CAP_QOS(dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE))
return -EOPNOTSUPP;
if (node->max_rate == max_rate && node->bw_share == bw_share)
return 0;
if (node->max_rate != max_rate) {
MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
}
if (node->bw_share != bw_share) {
MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
}
err = mlx5_modify_scheduling_element_cmd(dev,
SCHEDULING_HIERARCHY_E_SWITCH,
@ -154,12 +202,14 @@ static int esw_qos_sched_elem_config(struct mlx5_esw_sched_node *node, u32 max_r
node->ix,
bitmask);
if (err) {
esw_qos_sched_elem_config_warn(node, err);
esw_qos_sched_elem_warn(node, err, "modify");
NL_SET_ERR_MSG_MOD(extack, "E-Switch modify scheduling element failed");
return err;
}
node->max_rate = max_rate;
node->bw_share = bw_share;
if (node->type == SCHED_NODE_TYPE_VPORTS_TSAR)
trace_mlx5_esw_node_qos_config(dev, node, node->ix, bw_share, max_rate);
else if (node->type == SCHED_NODE_TYPE_VPORT)
@ -208,166 +258,51 @@ static u32 esw_qos_calc_bw_share(u32 min_rate, u32 divider, u32 fw_max)
return min_t(u32, max_t(u32, DIV_ROUND_UP(min_rate, divider), MLX5_MIN_BW_SHARE), fw_max);
}
static int esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node,
u32 divider,
struct netlink_ext_ack *extack)
static void esw_qos_update_sched_node_bw_share(struct mlx5_esw_sched_node *node,
u32 divider,
struct netlink_ext_ack *extack)
{
u32 fw_max_bw_share = MLX5_CAP_QOS(node->esw->dev, max_tsar_bw_share);
u32 bw_share;
int err;
bw_share = esw_qos_calc_bw_share(node->min_rate, divider, fw_max_bw_share);
if (bw_share == node->bw_share)
return 0;
err = esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack);
if (err)
return err;
node->bw_share = bw_share;
return err;
esw_qos_sched_elem_config(node, node->max_rate, bw_share, extack);
}
static int esw_qos_normalize_min_rate(struct mlx5_eswitch *esw,
struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
static void esw_qos_normalize_min_rate(struct mlx5_eswitch *esw,
struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
{
struct list_head *nodes = parent ? &parent->children : &esw->qos.domain->nodes;
u32 divider = esw_qos_calculate_min_rate_divider(esw, parent);
struct mlx5_esw_sched_node *node;
list_for_each_entry(node, nodes, entry) {
int err;
if (node->esw != esw || node->ix == esw->qos.root_tsar_ix)
continue;
err = esw_qos_update_sched_node_bw_share(node, divider, extack);
if (err)
return err;
esw_qos_update_sched_node_bw_share(node, divider, extack);
if (list_empty(&node->children))
continue;
err = esw_qos_normalize_min_rate(node->esw, node, extack);
if (err)
return err;
esw_qos_normalize_min_rate(node->esw, node, extack);
}
return 0;
}
static int esw_qos_set_vport_min_rate(struct mlx5_vport *vport,
u32 min_rate, struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
u32 fw_max_bw_share, previous_min_rate;
bool min_rate_supported;
int err;
esw_assert_qos_lock_held(vport_node->esw);
fw_max_bw_share = MLX5_CAP_QOS(vport->dev, max_tsar_bw_share);
min_rate_supported = MLX5_CAP_QOS(vport->dev, esw_bw_share) &&
fw_max_bw_share >= MLX5_MIN_BW_SHARE;
if (min_rate && !min_rate_supported)
return -EOPNOTSUPP;
if (min_rate == vport_node->min_rate)
return 0;
previous_min_rate = vport_node->min_rate;
vport_node->min_rate = min_rate;
err = esw_qos_normalize_min_rate(vport_node->parent->esw, vport_node->parent, extack);
if (err)
vport_node->min_rate = previous_min_rate;
return err;
}
static int esw_qos_set_vport_max_rate(struct mlx5_vport *vport,
u32 max_rate, struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
u32 act_max_rate = max_rate;
bool max_rate_supported;
int err;
esw_assert_qos_lock_held(vport_node->esw);
max_rate_supported = MLX5_CAP_QOS(vport->dev, esw_rate_limit);
if (max_rate && !max_rate_supported)
return -EOPNOTSUPP;
if (max_rate == vport_node->max_rate)
return 0;
/* Use parent node limit if new max rate is 0. */
if (!max_rate)
act_max_rate = vport_node->parent->max_rate;
err = esw_qos_sched_elem_config(vport_node, act_max_rate, vport_node->bw_share, extack);
if (!err)
vport_node->max_rate = max_rate;
return err;
}
static int esw_qos_set_node_min_rate(struct mlx5_esw_sched_node *node,
u32 min_rate, struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = node->esw;
u32 previous_min_rate;
int err;
if (!MLX5_CAP_QOS(esw->dev, esw_bw_share) ||
MLX5_CAP_QOS(esw->dev, max_tsar_bw_share) < MLX5_MIN_BW_SHARE)
return -EOPNOTSUPP;
if (min_rate == node->min_rate)
return 0;
previous_min_rate = node->min_rate;
node->min_rate = min_rate;
err = esw_qos_normalize_min_rate(esw, NULL, extack);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "E-Switch node min rate setting failed");
esw_qos_normalize_min_rate(esw, node->parent, extack);
/* Attempt restoring previous configuration */
node->min_rate = previous_min_rate;
if (esw_qos_normalize_min_rate(esw, NULL, extack))
NL_SET_ERR_MSG_MOD(extack, "E-Switch BW share restore failed");
}
return err;
}
static int esw_qos_set_node_max_rate(struct mlx5_esw_sched_node *node,
u32 max_rate, struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node;
int err;
if (node->max_rate == max_rate)
return 0;
err = esw_qos_sched_elem_config(node, max_rate, node->bw_share, extack);
if (err)
return err;
node->max_rate = max_rate;
/* Any unlimited vports in the node should be set with the value of the node. */
list_for_each_entry(vport_node, &node->children, entry) {
if (vport_node->max_rate)
continue;
err = esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share, extack);
if (err)
NL_SET_ERR_MSG_MOD(extack,
"E-Switch vport implicit rate limit setting failed");
}
return err;
return 0;
}
static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_element_id,
@ -397,14 +332,12 @@ static int esw_qos_create_node_sched_elem(struct mlx5_core_dev *dev, u32 parent_
tsar_ix);
}
static int
esw_qos_vport_create_sched_element(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
u32 max_rate, u32 bw_share, u32 *sched_elem_ix)
static int esw_qos_vport_create_sched_element(struct mlx5_esw_sched_node *vport_node,
struct netlink_ext_ack *extack)
{
u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
struct mlx5_core_dev *dev = parent->esw->dev;
struct mlx5_core_dev *dev = vport_node->esw->dev;
void *attr;
int err;
if (!mlx5_qos_element_type_supported(dev,
SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT,
@ -414,93 +347,11 @@ esw_qos_vport_create_sched_element(struct mlx5_vport *vport, struct mlx5_esw_sch
MLX5_SET(scheduling_context, sched_ctx, element_type,
SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
attr = MLX5_ADDR_OF(scheduling_context, sched_ctx, element_attributes);
MLX5_SET(vport_element, attr, vport_number, vport->vport);
MLX5_SET(scheduling_context, sched_ctx, parent_element_id, parent->ix);
MLX5_SET(scheduling_context, sched_ctx, max_average_bw, max_rate);
MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
MLX5_SET(vport_element, attr, vport_number, vport_node->vport->vport);
MLX5_SET(scheduling_context, sched_ctx, parent_element_id, vport_node->parent->ix);
MLX5_SET(scheduling_context, sched_ctx, max_average_bw, vport_node->max_rate);
err = mlx5_create_scheduling_element_cmd(dev,
SCHEDULING_HIERARCHY_E_SWITCH,
sched_ctx,
sched_elem_ix);
if (err) {
esw_warn(dev,
"E-Switch create vport scheduling element failed (vport=%d,err=%d)\n",
vport->vport, err);
return err;
}
return 0;
}
static int esw_qos_update_node_scheduling_element(struct mlx5_vport *vport,
struct mlx5_esw_sched_node *curr_node,
struct mlx5_esw_sched_node *new_node,
struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
u32 max_rate;
int err;
err = mlx5_destroy_scheduling_element_cmd(curr_node->esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH,
vport_node->ix);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy vport scheduling element failed");
return err;
}
/* Use new node max rate if vport max rate is unlimited. */
max_rate = vport_node->max_rate ? vport_node->max_rate : new_node->max_rate;
err = esw_qos_vport_create_sched_element(vport, new_node, max_rate,
vport_node->bw_share,
&vport_node->ix);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "E-Switch vport node set failed.");
goto err_sched;
}
esw_qos_node_set_parent(vport->qos.sched_node, new_node);
return 0;
err_sched:
max_rate = vport_node->max_rate ? vport_node->max_rate : curr_node->max_rate;
if (esw_qos_vport_create_sched_element(vport, curr_node, max_rate,
vport_node->bw_share,
&vport_node->ix))
esw_warn(curr_node->esw->dev, "E-Switch vport node restore failed (vport=%d)\n",
vport->vport);
return err;
}
static int esw_qos_vport_update_node(struct mlx5_vport *vport,
struct mlx5_esw_sched_node *node,
struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
struct mlx5_esw_sched_node *new_node, *curr_node;
int err;
esw_assert_qos_lock_held(esw);
curr_node = vport_node->parent;
new_node = node ?: esw->qos.node0;
if (curr_node == new_node)
return 0;
err = esw_qos_update_node_scheduling_element(vport, curr_node, new_node, extack);
if (err)
return err;
/* Recalculate bw share weights of old and new nodes */
if (vport_node->bw_share || new_node->bw_share) {
esw_qos_normalize_min_rate(curr_node->esw, curr_node, extack);
esw_qos_normalize_min_rate(new_node->esw, new_node, extack);
}
return 0;
return esw_qos_node_create_sched_element(vport_node, sched_ctx, extack);
}
static struct mlx5_esw_sched_node *
@ -531,6 +382,12 @@ static void __esw_qos_free_node(struct mlx5_esw_sched_node *node)
kfree(node);
}
static void esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
{
esw_qos_node_destroy_sched_element(node, extack);
__esw_qos_free_node(node);
}
static struct mlx5_esw_sched_node *
__esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
@ -552,17 +409,11 @@ __esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct mlx5_esw_sch
goto err_alloc_node;
}
err = esw_qos_normalize_min_rate(esw, NULL, extack);
if (err) {
NL_SET_ERR_MSG_MOD(extack, "E-Switch nodes normalization failed");
goto err_min_rate;
}
esw_qos_normalize_min_rate(esw, NULL, extack);
trace_mlx5_esw_node_qos_create(esw->dev, node, node->ix);
return node;
err_min_rate:
__esw_qos_free_node(node);
err_alloc_node:
if (mlx5_destroy_scheduling_element_cmd(esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH,
@ -595,26 +446,13 @@ esw_qos_create_vports_sched_node(struct mlx5_eswitch *esw, struct netlink_ext_ac
return node;
}
static int __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
static void __esw_qos_destroy_node(struct mlx5_esw_sched_node *node, struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = node->esw;
int err;
trace_mlx5_esw_node_qos_destroy(esw->dev, node, node->ix);
err = mlx5_destroy_scheduling_element_cmd(esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH,
node->ix);
if (err)
NL_SET_ERR_MSG_MOD(extack, "E-Switch destroy TSAR_ID failed");
__esw_qos_free_node(node);
err = esw_qos_normalize_min_rate(esw, NULL, extack);
if (err)
NL_SET_ERR_MSG_MOD(extack, "E-Switch nodes normalization failed");
return err;
esw_qos_destroy_node(node, extack);
esw_qos_normalize_min_rate(esw, NULL, extack);
}
static int esw_qos_create(struct mlx5_eswitch *esw, struct netlink_ext_ack *extack)
@ -699,45 +537,62 @@ static void esw_qos_put(struct mlx5_eswitch *esw)
esw_qos_destroy(esw);
}
static int esw_qos_vport_enable(struct mlx5_vport *vport,
u32 max_rate, u32 bw_share, struct netlink_ext_ack *extack)
static void esw_qos_vport_disable(struct mlx5_vport *vport, struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
struct mlx5_esw_sched_node *parent = vport_node->parent;
esw_qos_node_destroy_sched_element(vport_node, extack);
vport_node->bw_share = 0;
list_del_init(&vport_node->entry);
esw_qos_normalize_min_rate(parent->esw, parent, extack);
trace_mlx5_esw_vport_qos_destroy(vport_node->esw->dev, vport);
}
static int esw_qos_vport_enable(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
{
int err;
esw_assert_qos_lock_held(vport->dev->priv.eswitch);
esw_qos_node_set_parent(vport->qos.sched_node, parent);
err = esw_qos_vport_create_sched_element(vport->qos.sched_node, extack);
if (err)
return err;
esw_qos_normalize_min_rate(parent->esw, parent, extack);
return 0;
}
static int mlx5_esw_qos_vport_enable(struct mlx5_vport *vport, enum sched_node_type type,
struct mlx5_esw_sched_node *parent, u32 max_rate,
u32 min_rate, struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
u32 sched_elem_ix;
struct mlx5_esw_sched_node *sched_node;
int err;
esw_assert_qos_lock_held(esw);
if (vport->qos.sched_node)
return 0;
err = esw_qos_get(esw, extack);
if (err)
return err;
err = esw_qos_vport_create_sched_element(vport, esw->qos.node0, max_rate, bw_share,
&sched_elem_ix);
parent = parent ?: esw->qos.node0;
sched_node = __esw_qos_alloc_node(parent->esw, 0, type, parent);
if (!sched_node)
return -ENOMEM;
sched_node->max_rate = max_rate;
sched_node->min_rate = min_rate;
sched_node->vport = vport;
vport->qos.sched_node = sched_node;
err = esw_qos_vport_enable(vport, parent, extack);
if (err)
goto err_out;
vport->qos.sched_node = __esw_qos_alloc_node(esw, sched_elem_ix, SCHED_NODE_TYPE_VPORT,
esw->qos.node0);
if (!vport->qos.sched_node) {
err = -ENOMEM;
goto err_alloc;
}
vport->qos.sched_node->vport = vport;
trace_mlx5_esw_vport_qos_create(vport->dev, vport, bw_share, max_rate);
return 0;
err_alloc:
if (mlx5_destroy_scheduling_element_cmd(esw->dev,
SCHEDULING_HIERARCHY_E_SWITCH, sched_elem_ix))
esw_warn(esw->dev, "E-Switch destroy vport scheduling element failed.\n");
err_out:
esw_qos_put(esw);
esw_qos_put(esw);
return err;
}
@ -745,51 +600,61 @@ err_out:
void mlx5_esw_qos_vport_disable(struct mlx5_vport *vport)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
struct mlx5_esw_sched_node *vport_node;
struct mlx5_core_dev *dev;
int err;
struct mlx5_esw_sched_node *parent;
lockdep_assert_held(&esw->state_lock);
esw_qos_lock(esw);
vport_node = vport->qos.sched_node;
if (!vport_node)
if (!vport->qos.sched_node)
goto unlock;
WARN(vport_node->parent != esw->qos.node0,
"Disabling QoS on port before detaching it from node");
dev = vport_node->esw->dev;
trace_mlx5_esw_vport_qos_destroy(dev, vport);
err = mlx5_destroy_scheduling_element_cmd(dev,
SCHEDULING_HIERARCHY_E_SWITCH,
vport_node->ix);
if (err)
esw_warn(dev,
"E-Switch destroy vport scheduling element failed (vport=%d,err=%d)\n",
vport->vport, err);
__esw_qos_free_node(vport_node);
memset(&vport->qos, 0, sizeof(vport->qos));
parent = vport->qos.sched_node->parent;
WARN(parent != esw->qos.node0, "Disabling QoS on port before detaching it from node");
esw_qos_vport_disable(vport, NULL);
mlx5_esw_qos_vport_qos_free(vport);
esw_qos_put(esw);
unlock:
esw_qos_unlock(esw);
}
static int mlx5_esw_qos_set_vport_max_rate(struct mlx5_vport *vport, u32 max_rate,
struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
esw_assert_qos_lock_held(vport->dev->priv.eswitch);
if (!vport_node)
return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, max_rate, 0,
extack);
else
return esw_qos_sched_elem_config(vport_node, max_rate, vport_node->bw_share,
extack);
}
static int mlx5_esw_qos_set_vport_min_rate(struct mlx5_vport *vport, u32 min_rate,
struct netlink_ext_ack *extack)
{
struct mlx5_esw_sched_node *vport_node = vport->qos.sched_node;
esw_assert_qos_lock_held(vport->dev->priv.eswitch);
if (!vport_node)
return mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, NULL, 0, min_rate,
extack);
else
return esw_qos_set_node_min_rate(vport_node, min_rate, extack);
}
int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *vport, u32 max_rate, u32 min_rate)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err;
esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, NULL);
if (err)
goto unlock;
err = esw_qos_set_vport_min_rate(vport, min_rate, NULL);
err = mlx5_esw_qos_set_vport_min_rate(vport, min_rate, NULL);
if (!err)
err = esw_qos_set_vport_max_rate(vport, max_rate, NULL);
unlock:
err = mlx5_esw_qos_set_vport_max_rate(vport, max_rate, NULL);
esw_qos_unlock(esw);
return err;
}
@ -809,6 +674,31 @@ bool mlx5_esw_qos_get_vport_rate(struct mlx5_vport *vport, u32 *max_rate, u32 *m
return enabled;
}
static int esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
struct mlx5_esw_sched_node *curr_parent;
int err;
esw_assert_qos_lock_held(esw);
curr_parent = vport->qos.sched_node->parent;
parent = parent ?: esw->qos.node0;
if (curr_parent == parent)
return 0;
esw_qos_vport_disable(vport, extack);
err = esw_qos_vport_enable(vport, parent, extack);
if (err) {
if (esw_qos_vport_enable(vport, curr_parent, NULL))
esw_warn(parent->esw->dev, "vport restore QoS failed (vport=%d)\n",
vport->vport);
}
return err;
}
static u32 mlx5_esw_qos_lag_link_speed_get_locked(struct mlx5_core_dev *mdev)
{
struct ethtool_link_ksettings lksettings;
@ -875,10 +765,8 @@ static int mlx5_esw_qos_link_speed_verify(struct mlx5_core_dev *mdev,
int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32 rate_mbps)
{
u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
struct mlx5_vport *vport;
u32 link_speed_max;
u32 bitmask;
int err;
vport = mlx5_eswitch_get_vport(esw, vport_num);
@ -897,20 +785,7 @@ int mlx5_esw_qos_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num, u32
}
esw_qos_lock(esw);
if (!vport->qos.sched_node) {
/* Eswitch QoS wasn't enabled yet. Enable it and vport QoS. */
err = esw_qos_vport_enable(vport, rate_mbps, 0, NULL);
} else {
struct mlx5_core_dev *dev = vport->qos.sched_node->parent->esw->dev;
MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
bitmask = MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
err = mlx5_modify_scheduling_element_cmd(dev,
SCHEDULING_HIERARCHY_E_SWITCH,
ctx,
vport->qos.sched_node->ix,
bitmask);
}
err = mlx5_esw_qos_set_vport_max_rate(vport, rate_mbps, NULL);
esw_qos_unlock(esw);
return err;
@ -981,12 +856,7 @@ int mlx5_esw_devlink_rate_leaf_tx_share_set(struct devlink_rate *rate_leaf, void
return err;
esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, extack);
if (err)
goto unlock;
err = esw_qos_set_vport_min_rate(vport, tx_share, extack);
unlock:
err = mlx5_esw_qos_set_vport_min_rate(vport, tx_share, extack);
esw_qos_unlock(esw);
return err;
}
@ -1007,12 +877,7 @@ int mlx5_esw_devlink_rate_leaf_tx_max_set(struct devlink_rate *rate_leaf, void *
return err;
esw_qos_lock(esw);
err = esw_qos_vport_enable(vport, 0, 0, extack);
if (err)
goto unlock;
err = esw_qos_set_vport_max_rate(vport, tx_max, extack);
unlock:
err = mlx5_esw_qos_set_vport_max_rate(vport, tx_max, extack);
esw_qos_unlock(esw);
return err;
}
@ -1046,7 +911,7 @@ int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *
return err;
esw_qos_lock(esw);
err = esw_qos_set_node_max_rate(node, tx_max, extack);
err = esw_qos_sched_elem_config(node, tx_max, node->bw_share, extack);
esw_qos_unlock(esw);
return err;
}
@ -1087,35 +952,30 @@ int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
{
struct mlx5_esw_sched_node *node = priv;
struct mlx5_eswitch *esw = node->esw;
int err;
esw_qos_lock(esw);
err = __esw_qos_destroy_node(node, extack);
__esw_qos_destroy_node(node, extack);
esw_qos_put(esw);
esw_qos_unlock(esw);
return err;
return 0;
}
int mlx5_esw_qos_vport_update_node(struct mlx5_vport *vport,
struct mlx5_esw_sched_node *node,
struct netlink_ext_ack *extack)
int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *parent,
struct netlink_ext_ack *extack)
{
struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
int err = 0;
if (node && node->esw != esw) {
if (parent && parent->esw != esw) {
NL_SET_ERR_MSG_MOD(extack, "Cross E-Switch scheduling is not supported");
return -EOPNOTSUPP;
}
esw_qos_lock(esw);
if (!vport->qos.sched_node && !node)
goto unlock;
err = esw_qos_vport_enable(vport, 0, 0, extack);
if (!err)
err = esw_qos_vport_update_node(vport, node, extack);
unlock:
if (!vport->qos.sched_node && parent)
err = mlx5_esw_qos_vport_enable(vport, SCHED_NODE_TYPE_VPORT, parent, 0, 0, extack);
else if (vport->qos.sched_node)
err = esw_qos_vport_update_parent(vport, parent, extack);
esw_qos_unlock(esw);
return err;
}
@ -1129,8 +989,8 @@ int mlx5_esw_devlink_rate_parent_set(struct devlink_rate *devlink_rate,
struct mlx5_vport *vport = priv;
if (!parent)
return mlx5_esw_qos_vport_update_node(vport, NULL, extack);
return mlx5_esw_qos_vport_update_parent(vport, NULL, extack);
node = parent_priv;
return mlx5_esw_qos_vport_update_node(vport, node, extack);
return mlx5_esw_qos_vport_update_parent(vport, node, extack);
}

View File

@ -13,6 +13,7 @@ int mlx5_esw_qos_set_vport_rate(struct mlx5_vport *evport, u32 max_rate, u32 min
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);
void mlx5_esw_qos_vport_qos_free(struct mlx5_vport *vport);
u32 mlx5_esw_qos_vport_get_sched_elem_ix(const struct mlx5_vport *vport);
struct mlx5_esw_sched_node *mlx5_esw_qos_vport_get_parent(const struct mlx5_vport *vport);

View File

@ -1061,8 +1061,7 @@ static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
unsigned long i;
mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
kfree(vport->qos.sched_node);
memset(&vport->qos, 0, sizeof(vport->qos));
mlx5_esw_qos_vport_qos_free(vport);
memset(&vport->info, 0, sizeof(vport->info));
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
}
@ -1074,8 +1073,7 @@ static void mlx5_eswitch_clear_ec_vf_vports_info(struct mlx5_eswitch *esw)
unsigned long i;
mlx5_esw_for_each_ec_vf_vport(esw, i, vport, esw->esw_funcs.num_ec_vfs) {
kfree(vport->qos.sched_node);
memset(&vport->qos, 0, sizeof(vport->qos));
mlx5_esw_qos_vport_qos_free(vport);
memset(&vport->info, 0, sizeof(vport->info));
vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
}
@ -1490,7 +1488,6 @@ int mlx5_eswitch_enable_locked(struct mlx5_eswitch *esw, int num_vfs)
if (esw->mode == MLX5_ESWITCH_LEGACY) {
err = esw_legacy_enable(esw);
} else {
mlx5_rescan_drivers(esw->dev);
err = esw_offloads_enable(esw);
}

View File

@ -427,9 +427,8 @@ 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_node(struct mlx5_vport *vport,
struct mlx5_esw_sched_node *node,
struct netlink_ext_ack *extack);
int mlx5_esw_qos_vport_update_parent(struct mlx5_vport *vport, struct mlx5_esw_sched_node *node,
struct netlink_ext_ack *extack);
int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting);
int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting);
int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,

View File

@ -2332,18 +2332,35 @@ out_free:
return err;
}
static void esw_mode_change(struct mlx5_eswitch *esw, u16 mode)
{
mlx5_devcom_comp_lock(esw->dev->priv.hca_devcom_comp);
if (esw->dev->priv.flags & MLX5_PRIV_FLAGS_DISABLE_IB_ADEV) {
esw->mode = mode;
mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp);
return;
}
esw->dev->priv.flags |= MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
mlx5_rescan_drivers_locked(esw->dev);
esw->mode = mode;
esw->dev->priv.flags &= ~MLX5_PRIV_FLAGS_DISABLE_IB_ADEV;
mlx5_rescan_drivers_locked(esw->dev);
mlx5_devcom_comp_unlock(esw->dev->priv.hca_devcom_comp);
}
static int esw_offloads_start(struct mlx5_eswitch *esw,
struct netlink_ext_ack *extack)
{
int err;
esw->mode = MLX5_ESWITCH_OFFLOADS;
esw_mode_change(esw, MLX5_ESWITCH_OFFLOADS);
err = mlx5_eswitch_enable_locked(esw, esw->dev->priv.sriov.num_vfs);
if (err) {
NL_SET_ERR_MSG_MOD(extack,
"Failed setting eswitch to offloads");
esw->mode = MLX5_ESWITCH_LEGACY;
mlx5_rescan_drivers(esw->dev);
esw_mode_change(esw, MLX5_ESWITCH_LEGACY);
return err;
}
if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
@ -3584,7 +3601,7 @@ static int esw_offloads_stop(struct mlx5_eswitch *esw,
{
int err;
esw->mode = MLX5_ESWITCH_LEGACY;
esw_mode_change(esw, MLX5_ESWITCH_LEGACY);
/* If changing from switchdev to legacy mode without sriov enabled,
* no need to create legacy fdb.
@ -3770,7 +3787,6 @@ int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode,
err = esw_offloads_start(esw, extack);
} else if (mode == DEVLINK_ESWITCH_MODE_LEGACY) {
err = esw_offloads_stop(esw, extack);
mlx5_rescan_drivers(esw->dev);
} else {
err = -EINVAL;
}