138535d6cSHans Petter Selasky /*-
2f8f5b459SHans Petter Selasky * Copyright (c) 2016-2020 Mellanox Technologies. All rights reserved.
338535d6cSHans Petter Selasky *
438535d6cSHans Petter Selasky * Redistribution and use in source and binary forms, with or without
538535d6cSHans Petter Selasky * modification, are permitted provided that the following conditions
638535d6cSHans Petter Selasky * are met:
738535d6cSHans Petter Selasky * 1. Redistributions of source code must retain the above copyright
838535d6cSHans Petter Selasky * notice, this list of conditions and the following disclaimer.
938535d6cSHans Petter Selasky * 2. Redistributions in binary form must reproduce the above copyright
1038535d6cSHans Petter Selasky * notice, this list of conditions and the following disclaimer in the
1138535d6cSHans Petter Selasky * documentation and/or other materials provided with the distribution.
1238535d6cSHans Petter Selasky *
1338535d6cSHans Petter Selasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
1438535d6cSHans Petter Selasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1538535d6cSHans Petter Selasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1638535d6cSHans Petter Selasky * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
1738535d6cSHans Petter Selasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1838535d6cSHans Petter Selasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1938535d6cSHans Petter Selasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2038535d6cSHans Petter Selasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2138535d6cSHans Petter Selasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2238535d6cSHans Petter Selasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2338535d6cSHans Petter Selasky * SUCH DAMAGE.
2438535d6cSHans Petter Selasky */
2538535d6cSHans Petter Selasky
26b984b956SKonstantin Belousov #include "opt_rss.h"
27b984b956SKonstantin Belousov #include "opt_ratelimit.h"
28b984b956SKonstantin Belousov
2989918a23SKonstantin Belousov #include <dev/mlx5/mlx5_en/en.h>
3038535d6cSHans Petter Selasky
3138535d6cSHans Petter Selasky #ifdef RATELIMIT
3238535d6cSHans Petter Selasky
3338535d6cSHans Petter Selasky static int mlx5e_rl_open_workers(struct mlx5e_priv *);
3438535d6cSHans Petter Selasky static void mlx5e_rl_close_workers(struct mlx5e_priv *);
3538535d6cSHans Petter Selasky static int mlx5e_rl_sysctl_show_rate_table(SYSCTL_HANDLER_ARGS);
3638535d6cSHans Petter Selasky static void mlx5e_rl_sysctl_add_u64_oid(struct mlx5e_rl_priv_data *, unsigned x,
3738535d6cSHans Petter Selasky struct sysctl_oid *, const char *name, const char *desc);
3838535d6cSHans Petter Selasky static void mlx5e_rl_sysctl_add_stats_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
3938535d6cSHans Petter Selasky struct sysctl_oid *node, const char *name, const char *desc);
4038535d6cSHans Petter Selasky static int mlx5e_rl_tx_limit_add(struct mlx5e_rl_priv_data *, uint64_t value);
4138535d6cSHans Petter Selasky static int mlx5e_rl_tx_limit_clr(struct mlx5e_rl_priv_data *, uint64_t value);
42c782ea8bSJohn Baldwin static if_snd_tag_modify_t mlx5e_rl_snd_tag_modify;
43c782ea8bSJohn Baldwin static if_snd_tag_query_t mlx5e_rl_snd_tag_query;
44c782ea8bSJohn Baldwin static if_snd_tag_free_t mlx5e_rl_snd_tag_free;
45c782ea8bSJohn Baldwin
46c782ea8bSJohn Baldwin static const struct if_snd_tag_sw mlx5e_rl_snd_tag_sw = {
47c782ea8bSJohn Baldwin .snd_tag_modify = mlx5e_rl_snd_tag_modify,
48c782ea8bSJohn Baldwin .snd_tag_query = mlx5e_rl_snd_tag_query,
49c782ea8bSJohn Baldwin .snd_tag_free = mlx5e_rl_snd_tag_free,
50c782ea8bSJohn Baldwin .type = IF_SND_TAG_TYPE_RATE_LIMIT
51c782ea8bSJohn Baldwin };
5238535d6cSHans Petter Selasky
5338535d6cSHans Petter Selasky static void
mlx5e_rl_build_sq_param(struct mlx5e_rl_priv_data * rl,struct mlx5e_sq_param * param)5438535d6cSHans Petter Selasky mlx5e_rl_build_sq_param(struct mlx5e_rl_priv_data *rl,
5538535d6cSHans Petter Selasky struct mlx5e_sq_param *param)
5638535d6cSHans Petter Selasky {
5738535d6cSHans Petter Selasky void *sqc = param->sqc;
5838535d6cSHans Petter Selasky void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
5938535d6cSHans Petter Selasky uint8_t log_sq_size = order_base_2(rl->param.tx_queue_size);
6038535d6cSHans Petter Selasky
6138535d6cSHans Petter Selasky MLX5_SET(wq, wq, log_wq_sz, log_sq_size);
6238535d6cSHans Petter Selasky MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
6338535d6cSHans Petter Selasky MLX5_SET(wq, wq, pd, rl->priv->pdn);
6438535d6cSHans Petter Selasky
6538535d6cSHans Petter Selasky param->wq.linear = 1;
6638535d6cSHans Petter Selasky }
6738535d6cSHans Petter Selasky
6838535d6cSHans Petter Selasky static void
mlx5e_rl_build_cq_param(struct mlx5e_rl_priv_data * rl,struct mlx5e_cq_param * param)6938535d6cSHans Petter Selasky mlx5e_rl_build_cq_param(struct mlx5e_rl_priv_data *rl,
7038535d6cSHans Petter Selasky struct mlx5e_cq_param *param)
7138535d6cSHans Petter Selasky {
7238535d6cSHans Petter Selasky void *cqc = param->cqc;
7338535d6cSHans Petter Selasky uint8_t log_sq_size = order_base_2(rl->param.tx_queue_size);
7438535d6cSHans Petter Selasky
7538535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, log_cq_size, log_sq_size);
7638535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, cq_period, rl->param.tx_coalesce_usecs);
7738535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, cq_max_count, rl->param.tx_coalesce_pkts);
78b8051298SHans Petter Selasky MLX5_SET(cqc, cqc, uar_page, rl->priv->mdev->priv.uar->index);
7938535d6cSHans Petter Selasky
8038535d6cSHans Petter Selasky switch (rl->param.tx_coalesce_mode) {
8138535d6cSHans Petter Selasky case 0:
8238535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
8338535d6cSHans Petter Selasky break;
8438535d6cSHans Petter Selasky default:
8538535d6cSHans Petter Selasky if (MLX5_CAP_GEN(rl->priv->mdev, cq_period_start_from_cqe))
8638535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
8738535d6cSHans Petter Selasky else
8838535d6cSHans Petter Selasky MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
8938535d6cSHans Petter Selasky break;
9038535d6cSHans Petter Selasky }
9138535d6cSHans Petter Selasky }
9238535d6cSHans Petter Selasky
9338535d6cSHans Petter Selasky static void
mlx5e_rl_build_channel_param(struct mlx5e_rl_priv_data * rl,struct mlx5e_rl_channel_param * cparam)9438535d6cSHans Petter Selasky mlx5e_rl_build_channel_param(struct mlx5e_rl_priv_data *rl,
9538535d6cSHans Petter Selasky struct mlx5e_rl_channel_param *cparam)
9638535d6cSHans Petter Selasky {
9738535d6cSHans Petter Selasky memset(cparam, 0, sizeof(*cparam));
9838535d6cSHans Petter Selasky
9938535d6cSHans Petter Selasky mlx5e_rl_build_sq_param(rl, &cparam->sq);
10038535d6cSHans Petter Selasky mlx5e_rl_build_cq_param(rl, &cparam->cq);
10138535d6cSHans Petter Selasky }
10238535d6cSHans Petter Selasky
10338535d6cSHans Petter Selasky static int
mlx5e_rl_create_sq(struct mlx5e_priv * priv,struct mlx5e_sq * sq,struct mlx5e_sq_param * param,int ix)10438535d6cSHans Petter Selasky mlx5e_rl_create_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq,
10538535d6cSHans Petter Selasky struct mlx5e_sq_param *param, int ix)
10638535d6cSHans Petter Selasky {
10738535d6cSHans Petter Selasky struct mlx5_core_dev *mdev = priv->mdev;
10838535d6cSHans Petter Selasky void *sqc = param->sqc;
10938535d6cSHans Petter Selasky void *sqc_wq = MLX5_ADDR_OF(sqc, sqc, wq);
11038535d6cSHans Petter Selasky int err;
11138535d6cSHans Petter Selasky
11238535d6cSHans Petter Selasky /* Create DMA descriptor TAG */
11338535d6cSHans Petter Selasky if ((err = -bus_dma_tag_create(
11438535d6cSHans Petter Selasky bus_get_dma_tag(mdev->pdev->dev.bsddev),
11538535d6cSHans Petter Selasky 1, /* any alignment */
11638535d6cSHans Petter Selasky 0, /* no boundary */
11738535d6cSHans Petter Selasky BUS_SPACE_MAXADDR, /* lowaddr */
11838535d6cSHans Petter Selasky BUS_SPACE_MAXADDR, /* highaddr */
11938535d6cSHans Petter Selasky NULL, NULL, /* filter, filterarg */
12038535d6cSHans Petter Selasky MLX5E_MAX_TX_PAYLOAD_SIZE, /* maxsize */
12138535d6cSHans Petter Selasky MLX5E_MAX_TX_MBUF_FRAGS, /* nsegments */
12238535d6cSHans Petter Selasky MLX5E_MAX_TX_MBUF_SIZE, /* maxsegsize */
12338535d6cSHans Petter Selasky 0, /* flags */
12438535d6cSHans Petter Selasky NULL, NULL, /* lockfunc, lockfuncarg */
12538535d6cSHans Petter Selasky &sq->dma_tag)))
12638535d6cSHans Petter Selasky goto done;
12738535d6cSHans Petter Selasky
1287c3eff94SHans Petter Selasky sq->mkey_be = cpu_to_be32(priv->mr.key);
1297c3eff94SHans Petter Selasky sq->ifp = priv->ifp;
1307c3eff94SHans Petter Selasky sq->priv = priv;
1317c3eff94SHans Petter Selasky
13238535d6cSHans Petter Selasky err = mlx5_wq_cyc_create(mdev, ¶m->wq, sqc_wq, &sq->wq,
13338535d6cSHans Petter Selasky &sq->wq_ctrl);
13438535d6cSHans Petter Selasky if (err)
13538535d6cSHans Petter Selasky goto err_free_dma_tag;
13638535d6cSHans Petter Selasky
13738535d6cSHans Petter Selasky sq->wq.db = &sq->wq.db[MLX5_SND_DBR];
13838535d6cSHans Petter Selasky
13938535d6cSHans Petter Selasky err = mlx5e_alloc_sq_db(sq);
14038535d6cSHans Petter Selasky if (err)
14138535d6cSHans Petter Selasky goto err_sq_wq_destroy;
14238535d6cSHans Petter Selasky
1433e581cabSSlava Shwartsman mlx5e_update_sq_inline(sq);
14438535d6cSHans Petter Selasky
14538535d6cSHans Petter Selasky return (0);
14638535d6cSHans Petter Selasky
14738535d6cSHans Petter Selasky err_sq_wq_destroy:
14838535d6cSHans Petter Selasky mlx5_wq_destroy(&sq->wq_ctrl);
14938535d6cSHans Petter Selasky err_free_dma_tag:
15038535d6cSHans Petter Selasky bus_dma_tag_destroy(sq->dma_tag);
15138535d6cSHans Petter Selasky done:
15238535d6cSHans Petter Selasky return (err);
15338535d6cSHans Petter Selasky }
15438535d6cSHans Petter Selasky
15538535d6cSHans Petter Selasky static void
mlx5e_rl_destroy_sq(struct mlx5e_sq * sq)15638535d6cSHans Petter Selasky mlx5e_rl_destroy_sq(struct mlx5e_sq *sq)
15738535d6cSHans Petter Selasky {
15838535d6cSHans Petter Selasky
15938535d6cSHans Petter Selasky mlx5e_free_sq_db(sq);
16038535d6cSHans Petter Selasky mlx5_wq_destroy(&sq->wq_ctrl);
16176a35558SHans Petter Selasky bus_dma_tag_destroy(sq->dma_tag);
16238535d6cSHans Petter Selasky }
16338535d6cSHans Petter Selasky
16438535d6cSHans Petter Selasky static int
mlx5e_rl_query_sq(struct mlx5e_sq * sq)165266c81aaSHans Petter Selasky mlx5e_rl_query_sq(struct mlx5e_sq *sq)
166266c81aaSHans Petter Selasky {
167266c81aaSHans Petter Selasky void *out;
168266c81aaSHans Petter Selasky int inlen;
169266c81aaSHans Petter Selasky int err;
170266c81aaSHans Petter Selasky
171266c81aaSHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(query_sq_out);
172266c81aaSHans Petter Selasky out = mlx5_vzalloc(inlen);
173266c81aaSHans Petter Selasky if (!out)
174266c81aaSHans Petter Selasky return -ENOMEM;
175266c81aaSHans Petter Selasky
176266c81aaSHans Petter Selasky err = mlx5_core_query_sq(sq->priv->mdev, sq->sqn, out);
177266c81aaSHans Petter Selasky if (err)
178266c81aaSHans Petter Selasky goto out;
179266c81aaSHans Petter Selasky
180266c81aaSHans Petter Selasky sq->queue_handle = MLX5_GET(query_sq_out, out, sq_context.queue_handle);
181266c81aaSHans Petter Selasky
182266c81aaSHans Petter Selasky out:
183266c81aaSHans Petter Selasky kvfree(out);
184266c81aaSHans Petter Selasky return err;
185266c81aaSHans Petter Selasky }
186266c81aaSHans Petter Selasky
187266c81aaSHans Petter Selasky static int
mlx5e_rl_open_sq(struct mlx5e_priv * priv,struct mlx5e_sq * sq,struct mlx5e_sq_param * param,int ix)18838535d6cSHans Petter Selasky mlx5e_rl_open_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq,
18938535d6cSHans Petter Selasky struct mlx5e_sq_param *param, int ix)
19038535d6cSHans Petter Selasky {
19138535d6cSHans Petter Selasky int err;
19238535d6cSHans Petter Selasky
19338535d6cSHans Petter Selasky err = mlx5e_rl_create_sq(priv, sq, param, ix);
19438535d6cSHans Petter Selasky if (err)
19538535d6cSHans Petter Selasky return (err);
19638535d6cSHans Petter Selasky
1979dfa2148SHans Petter Selasky err = mlx5e_enable_sq(sq, param, &priv->channel[ix].bfreg, priv->rl.tisn);
19838535d6cSHans Petter Selasky if (err)
19938535d6cSHans Petter Selasky goto err_destroy_sq;
20038535d6cSHans Petter Selasky
20138535d6cSHans Petter Selasky err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
20238535d6cSHans Petter Selasky if (err)
20338535d6cSHans Petter Selasky goto err_disable_sq;
20438535d6cSHans Petter Selasky
205266c81aaSHans Petter Selasky if (MLX5_CAP_QOS(priv->mdev, qos_remap_pp)) {
206266c81aaSHans Petter Selasky err = mlx5e_rl_query_sq(sq);
207266c81aaSHans Petter Selasky if (err) {
208266c81aaSHans Petter Selasky mlx5_en_err(priv->ifp, "Failed retrieving send queue handle for"
209266c81aaSHans Petter Selasky "SQ remap - sqn=%u, err=(%d)\n", sq->sqn, err);
210266c81aaSHans Petter Selasky sq->queue_handle = MLX5_INVALID_QUEUE_HANDLE;
211266c81aaSHans Petter Selasky }
212266c81aaSHans Petter Selasky } else
213266c81aaSHans Petter Selasky sq->queue_handle = MLX5_INVALID_QUEUE_HANDLE;
214266c81aaSHans Petter Selasky
2152647c1e4SHans Petter Selasky WRITE_ONCE(sq->running, 1);
2162647c1e4SHans Petter Selasky
21738535d6cSHans Petter Selasky return (0);
21838535d6cSHans Petter Selasky
21938535d6cSHans Petter Selasky err_disable_sq:
22038535d6cSHans Petter Selasky mlx5e_disable_sq(sq);
22138535d6cSHans Petter Selasky err_destroy_sq:
22238535d6cSHans Petter Selasky mlx5e_rl_destroy_sq(sq);
22338535d6cSHans Petter Selasky
22438535d6cSHans Petter Selasky return (err);
22538535d6cSHans Petter Selasky }
22638535d6cSHans Petter Selasky
22738535d6cSHans Petter Selasky static void
mlx5e_rl_chan_mtx_init(struct mlx5e_priv * priv,struct mlx5e_sq * sq)22838535d6cSHans Petter Selasky mlx5e_rl_chan_mtx_init(struct mlx5e_priv *priv, struct mlx5e_sq *sq)
22938535d6cSHans Petter Selasky {
23038535d6cSHans Petter Selasky mtx_init(&sq->lock, "mlx5tx-rl", NULL, MTX_DEF);
23138535d6cSHans Petter Selasky mtx_init(&sq->comp_lock, "mlx5comp-rl", NULL, MTX_DEF);
23238535d6cSHans Petter Selasky
23338535d6cSHans Petter Selasky callout_init_mtx(&sq->cev_callout, &sq->lock, 0);
23438535d6cSHans Petter Selasky
23538535d6cSHans Petter Selasky sq->cev_factor = priv->rl.param.tx_completion_fact;
23638535d6cSHans Petter Selasky
23738535d6cSHans Petter Selasky /* ensure the TX completion event factor is not zero */
23838535d6cSHans Petter Selasky if (sq->cev_factor == 0)
23938535d6cSHans Petter Selasky sq->cev_factor = 1;
24038535d6cSHans Petter Selasky }
24138535d6cSHans Petter Selasky
24238535d6cSHans Petter Selasky static int
mlx5e_rl_open_channel(struct mlx5e_rl_worker * rlw,int eq_ix,struct mlx5e_rl_channel_param * cparam,struct mlx5e_sq * volatile * ppsq)24338535d6cSHans Petter Selasky mlx5e_rl_open_channel(struct mlx5e_rl_worker *rlw, int eq_ix,
24438535d6cSHans Petter Selasky struct mlx5e_rl_channel_param *cparam,
24538535d6cSHans Petter Selasky struct mlx5e_sq *volatile *ppsq)
24638535d6cSHans Petter Selasky {
24738535d6cSHans Petter Selasky struct mlx5e_priv *priv = rlw->priv;
24838535d6cSHans Petter Selasky struct mlx5e_sq *sq;
24938535d6cSHans Petter Selasky int err;
25038535d6cSHans Petter Selasky
25138535d6cSHans Petter Selasky sq = malloc(sizeof(*sq), M_MLX5EN, M_WAITOK | M_ZERO);
25238535d6cSHans Petter Selasky
25338535d6cSHans Petter Selasky /* init mutexes */
25438535d6cSHans Petter Selasky mlx5e_rl_chan_mtx_init(priv, sq);
25538535d6cSHans Petter Selasky
25638535d6cSHans Petter Selasky /* open TX completion queue */
25738535d6cSHans Petter Selasky err = mlx5e_open_cq(priv, &cparam->cq, &sq->cq,
25838535d6cSHans Petter Selasky &mlx5e_tx_cq_comp, eq_ix);
25938535d6cSHans Petter Selasky if (err)
26038535d6cSHans Petter Selasky goto err_free;
26138535d6cSHans Petter Selasky
26238535d6cSHans Petter Selasky err = mlx5e_rl_open_sq(priv, sq, &cparam->sq, eq_ix);
26338535d6cSHans Petter Selasky if (err)
26438535d6cSHans Petter Selasky goto err_close_tx_cq;
26538535d6cSHans Petter Selasky
26638535d6cSHans Petter Selasky /* store TX channel pointer */
26738535d6cSHans Petter Selasky *ppsq = sq;
26838535d6cSHans Petter Selasky
26938535d6cSHans Petter Selasky /* poll TX queue initially */
270f34f0a65SHans Petter Selasky sq->cq.mcq.comp(&sq->cq.mcq, NULL);
27138535d6cSHans Petter Selasky
27238535d6cSHans Petter Selasky return (0);
27338535d6cSHans Petter Selasky
27438535d6cSHans Petter Selasky err_close_tx_cq:
27538535d6cSHans Petter Selasky mlx5e_close_cq(&sq->cq);
27638535d6cSHans Petter Selasky
27738535d6cSHans Petter Selasky err_free:
27838535d6cSHans Petter Selasky /* destroy mutexes */
27938535d6cSHans Petter Selasky mtx_destroy(&sq->lock);
28038535d6cSHans Petter Selasky mtx_destroy(&sq->comp_lock);
28138535d6cSHans Petter Selasky free(sq, M_MLX5EN);
28238535d6cSHans Petter Selasky atomic_add_64(&priv->rl.stats.tx_allocate_resource_failure, 1ULL);
28338535d6cSHans Petter Selasky return (err);
28438535d6cSHans Petter Selasky }
28538535d6cSHans Petter Selasky
28638535d6cSHans Petter Selasky static void
mlx5e_rl_close_channel(struct mlx5e_sq * volatile * ppsq)28738535d6cSHans Petter Selasky mlx5e_rl_close_channel(struct mlx5e_sq *volatile *ppsq)
28838535d6cSHans Petter Selasky {
28938535d6cSHans Petter Selasky struct mlx5e_sq *sq = *ppsq;
29038535d6cSHans Petter Selasky
29138535d6cSHans Petter Selasky /* check if channel is already closed */
29238535d6cSHans Petter Selasky if (sq == NULL)
29338535d6cSHans Petter Selasky return;
29438535d6cSHans Petter Selasky /* ensure channel pointer is no longer used */
29538535d6cSHans Petter Selasky *ppsq = NULL;
29638535d6cSHans Petter Selasky
29738535d6cSHans Petter Selasky /* teardown and destroy SQ */
29838535d6cSHans Petter Selasky mlx5e_drain_sq(sq);
29938535d6cSHans Petter Selasky mlx5e_disable_sq(sq);
30038535d6cSHans Petter Selasky mlx5e_rl_destroy_sq(sq);
30138535d6cSHans Petter Selasky
30238535d6cSHans Petter Selasky /* close CQ */
30338535d6cSHans Petter Selasky mlx5e_close_cq(&sq->cq);
30438535d6cSHans Petter Selasky
30538535d6cSHans Petter Selasky /* destroy mutexes */
30638535d6cSHans Petter Selasky mtx_destroy(&sq->lock);
30738535d6cSHans Petter Selasky mtx_destroy(&sq->comp_lock);
30838535d6cSHans Petter Selasky
30938535d6cSHans Petter Selasky free(sq, M_MLX5EN);
31038535d6cSHans Petter Selasky }
31138535d6cSHans Petter Selasky
31238535d6cSHans Petter Selasky static void
mlx5e_rl_sync_tx_completion_fact(struct mlx5e_rl_priv_data * rl)31338535d6cSHans Petter Selasky mlx5e_rl_sync_tx_completion_fact(struct mlx5e_rl_priv_data *rl)
31438535d6cSHans Petter Selasky {
31538535d6cSHans Petter Selasky /*
31638535d6cSHans Petter Selasky * Limit the maximum distance between completion events to
31738535d6cSHans Petter Selasky * half of the currently set TX queue size.
31838535d6cSHans Petter Selasky *
31938535d6cSHans Petter Selasky * The maximum number of queue entries a single IP packet can
32038535d6cSHans Petter Selasky * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
32138535d6cSHans Petter Selasky *
32238535d6cSHans Petter Selasky * The worst case max value is then given as below:
32338535d6cSHans Petter Selasky */
32438535d6cSHans Petter Selasky uint64_t max = rl->param.tx_queue_size /
32538535d6cSHans Petter Selasky (2 * MLX5_SEND_WQE_MAX_WQEBBS);
32638535d6cSHans Petter Selasky
32738535d6cSHans Petter Selasky /*
32838535d6cSHans Petter Selasky * Update the maximum completion factor value in case the
32938535d6cSHans Petter Selasky * tx_queue_size field changed. Ensure we don't overflow
33038535d6cSHans Petter Selasky * 16-bits.
33138535d6cSHans Petter Selasky */
33238535d6cSHans Petter Selasky if (max < 1)
33338535d6cSHans Petter Selasky max = 1;
33438535d6cSHans Petter Selasky else if (max > 65535)
33538535d6cSHans Petter Selasky max = 65535;
33638535d6cSHans Petter Selasky rl->param.tx_completion_fact_max = max;
33738535d6cSHans Petter Selasky
33838535d6cSHans Petter Selasky /*
33938535d6cSHans Petter Selasky * Verify that the current TX completion factor is within the
34038535d6cSHans Petter Selasky * given limits:
34138535d6cSHans Petter Selasky */
34238535d6cSHans Petter Selasky if (rl->param.tx_completion_fact < 1)
34338535d6cSHans Petter Selasky rl->param.tx_completion_fact = 1;
34438535d6cSHans Petter Selasky else if (rl->param.tx_completion_fact > max)
34538535d6cSHans Petter Selasky rl->param.tx_completion_fact = max;
34638535d6cSHans Petter Selasky }
34738535d6cSHans Petter Selasky
34838535d6cSHans Petter Selasky static int
mlx5e_rl_modify_sq(struct mlx5e_sq * sq,uint16_t rl_index)34938535d6cSHans Petter Selasky mlx5e_rl_modify_sq(struct mlx5e_sq *sq, uint16_t rl_index)
35038535d6cSHans Petter Selasky {
35138535d6cSHans Petter Selasky struct mlx5e_priv *priv = sq->priv;
35238535d6cSHans Petter Selasky struct mlx5_core_dev *mdev = priv->mdev;
35338535d6cSHans Petter Selasky
35438535d6cSHans Petter Selasky void *in;
35538535d6cSHans Petter Selasky void *sqc;
35638535d6cSHans Petter Selasky int inlen;
35738535d6cSHans Petter Selasky int err;
35838535d6cSHans Petter Selasky
35938535d6cSHans Petter Selasky inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
36038535d6cSHans Petter Selasky in = mlx5_vzalloc(inlen);
36138535d6cSHans Petter Selasky if (in == NULL)
36238535d6cSHans Petter Selasky return (-ENOMEM);
36338535d6cSHans Petter Selasky
36438535d6cSHans Petter Selasky sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
36538535d6cSHans Petter Selasky
36638535d6cSHans Petter Selasky MLX5_SET(modify_sq_in, in, sqn, sq->sqn);
36738535d6cSHans Petter Selasky MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RDY);
36838535d6cSHans Petter Selasky MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
36938535d6cSHans Petter Selasky MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY);
37038535d6cSHans Petter Selasky MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index);
37138535d6cSHans Petter Selasky
37238535d6cSHans Petter Selasky err = mlx5_core_modify_sq(mdev, in, inlen);
37338535d6cSHans Petter Selasky
37438535d6cSHans Petter Selasky kvfree(in);
37538535d6cSHans Petter Selasky
37638535d6cSHans Petter Selasky return (err);
37738535d6cSHans Petter Selasky }
37838535d6cSHans Petter Selasky
37938535d6cSHans Petter Selasky /*
38038535d6cSHans Petter Selasky * This function will search the configured rate limit table for the
38138535d6cSHans Petter Selasky * best match to avoid that a single socket based application can
38238535d6cSHans Petter Selasky * allocate all the available hardware rates. If the user selected
38338535d6cSHans Petter Selasky * rate deviates too much from the closes rate available in the rate
38438535d6cSHans Petter Selasky * limit table, unlimited rate will be selected.
38538535d6cSHans Petter Selasky */
38638535d6cSHans Petter Selasky static uint64_t
mlx5e_rl_find_best_rate_locked(struct mlx5e_rl_priv_data * rl,uint64_t user_rate)38738535d6cSHans Petter Selasky mlx5e_rl_find_best_rate_locked(struct mlx5e_rl_priv_data *rl, uint64_t user_rate)
38838535d6cSHans Petter Selasky {
38938535d6cSHans Petter Selasky uint64_t distance = -1ULL;
39038535d6cSHans Petter Selasky uint64_t diff;
39138535d6cSHans Petter Selasky uint64_t retval = 0; /* unlimited */
39238535d6cSHans Petter Selasky uint64_t x;
39338535d6cSHans Petter Selasky
39438535d6cSHans Petter Selasky /* search for closest rate */
39538535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++) {
39638535d6cSHans Petter Selasky uint64_t rate = rl->rate_limit_table[x];
39738535d6cSHans Petter Selasky if (rate == 0)
39838535d6cSHans Petter Selasky continue;
39938535d6cSHans Petter Selasky
40038535d6cSHans Petter Selasky if (rate > user_rate)
40138535d6cSHans Petter Selasky diff = rate - user_rate;
40238535d6cSHans Petter Selasky else
40338535d6cSHans Petter Selasky diff = user_rate - rate;
40438535d6cSHans Petter Selasky
40538535d6cSHans Petter Selasky /* check if distance is smaller than previous rate */
40638535d6cSHans Petter Selasky if (diff < distance) {
40738535d6cSHans Petter Selasky distance = diff;
40838535d6cSHans Petter Selasky retval = rate;
40938535d6cSHans Petter Selasky }
41038535d6cSHans Petter Selasky }
41138535d6cSHans Petter Selasky
41238535d6cSHans Petter Selasky /* range check for multiplication below */
41338535d6cSHans Petter Selasky if (user_rate > rl->param.tx_limit_max)
41438535d6cSHans Petter Selasky user_rate = rl->param.tx_limit_max;
41538535d6cSHans Petter Selasky
41638535d6cSHans Petter Selasky /* fallback to unlimited, if rate deviates too much */
41738535d6cSHans Petter Selasky if (distance > howmany(user_rate *
41838535d6cSHans Petter Selasky rl->param.tx_allowed_deviation, 1000ULL))
41938535d6cSHans Petter Selasky retval = 0;
42038535d6cSHans Petter Selasky
42138535d6cSHans Petter Selasky return (retval);
42238535d6cSHans Petter Selasky }
42338535d6cSHans Petter Selasky
424266c81aaSHans Petter Selasky static int
mlx5e_rl_post_sq_remap_wqe(struct mlx5e_iq * iq,u32 scq_handle,u32 sq_handle,struct mlx5e_rl_channel * sq_channel)425a8e715d2SHans Petter Selasky mlx5e_rl_post_sq_remap_wqe(struct mlx5e_iq *iq, u32 scq_handle, u32 sq_handle,
426a8e715d2SHans Petter Selasky struct mlx5e_rl_channel *sq_channel)
427266c81aaSHans Petter Selasky {
428266c81aaSHans Petter Selasky const u32 ds_cnt = DIV_ROUND_UP(sizeof(struct mlx5e_tx_qos_remap_wqe),
429266c81aaSHans Petter Selasky MLX5_SEND_WQE_DS);
430266c81aaSHans Petter Selasky struct mlx5e_tx_qos_remap_wqe *wqe;
431266c81aaSHans Petter Selasky int pi;
432266c81aaSHans Petter Selasky
433266c81aaSHans Petter Selasky mtx_lock(&iq->lock);
434266c81aaSHans Petter Selasky pi = mlx5e_iq_get_producer_index(iq);
435266c81aaSHans Petter Selasky if (pi < 0) {
436266c81aaSHans Petter Selasky mtx_unlock(&iq->lock);
437266c81aaSHans Petter Selasky return (-ENOMEM);
438266c81aaSHans Petter Selasky }
439266c81aaSHans Petter Selasky wqe = mlx5_wq_cyc_get_wqe(&iq->wq, pi);
440266c81aaSHans Petter Selasky
441266c81aaSHans Petter Selasky memset(wqe, 0, sizeof(*wqe));
442266c81aaSHans Petter Selasky
443266c81aaSHans Petter Selasky wqe->qos_remap.qos_handle = cpu_to_be32(scq_handle);
444266c81aaSHans Petter Selasky wqe->qos_remap.queue_handle = cpu_to_be32(sq_handle);
445266c81aaSHans Petter Selasky
446266c81aaSHans Petter Selasky wqe->ctrl.opmod_idx_opcode = cpu_to_be32((iq->pc << 8) |
447266c81aaSHans Petter Selasky MLX5_OPCODE_QOS_REMAP);
448266c81aaSHans Petter Selasky wqe->ctrl.qpn_ds = cpu_to_be32((iq->sqn << 8) | ds_cnt);
449266c81aaSHans Petter Selasky wqe->ctrl.imm = cpu_to_be32(iq->priv->tisn[0] << 8);
450266c81aaSHans Petter Selasky wqe->ctrl.fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE | MLX5_FENCE_MODE_INITIATOR_SMALL;
451266c81aaSHans Petter Selasky
452266c81aaSHans Petter Selasky /* copy data for doorbell */
453266c81aaSHans Petter Selasky memcpy(iq->doorbell.d32, &wqe->ctrl, sizeof(iq->doorbell.d32));
454266c81aaSHans Petter Selasky
455266c81aaSHans Petter Selasky iq->data[pi].num_wqebbs = DIV_ROUND_UP(ds_cnt, MLX5_SEND_WQEBB_NUM_DS);
456a8e715d2SHans Petter Selasky iq->data[pi].p_refcount = &sq_channel->refcount;
457a8e715d2SHans Petter Selasky atomic_add_int(iq->data[pi].p_refcount, 1);
458266c81aaSHans Petter Selasky iq->pc += iq->data[pi].num_wqebbs;
459266c81aaSHans Petter Selasky
460266c81aaSHans Petter Selasky mlx5e_iq_notify_hw(iq);
461266c81aaSHans Petter Selasky
462266c81aaSHans Petter Selasky mtx_unlock(&iq->lock);
463266c81aaSHans Petter Selasky
464266c81aaSHans Petter Selasky return (0); /* success */
465266c81aaSHans Petter Selasky }
466266c81aaSHans Petter Selasky
467266c81aaSHans Petter Selasky static int
mlx5e_rl_remap_sq(struct mlx5e_sq * sq,uint16_t index,struct mlx5e_rl_channel * sq_channel)468a8e715d2SHans Petter Selasky mlx5e_rl_remap_sq(struct mlx5e_sq *sq, uint16_t index,
469a8e715d2SHans Petter Selasky struct mlx5e_rl_channel *sq_channel)
470266c81aaSHans Petter Selasky {
471266c81aaSHans Petter Selasky struct mlx5e_channel *iq_channel;
472266c81aaSHans Petter Selasky u32 scq_handle;
473266c81aaSHans Petter Selasky u32 sq_handle;
474266c81aaSHans Petter Selasky int error;
475266c81aaSHans Petter Selasky
476266c81aaSHans Petter Selasky /* Specific SQ remap operations should be handled by same IQ */
477266c81aaSHans Petter Selasky iq_channel = &sq->priv->channel[sq->sqn % sq->priv->params.num_channels];
478266c81aaSHans Petter Selasky
479266c81aaSHans Petter Selasky sq_handle = sq->queue_handle;
480266c81aaSHans Petter Selasky scq_handle = mlx5_rl_get_scq_handle(sq->priv->mdev, index);
481266c81aaSHans Petter Selasky
482a8e715d2SHans Petter Selasky if (sq_handle == MLX5_INVALID_QUEUE_HANDLE ||
483a8e715d2SHans Petter Selasky scq_handle == MLX5_INVALID_QUEUE_HANDLE)
484266c81aaSHans Petter Selasky error = -1;
485266c81aaSHans Petter Selasky else
486a8e715d2SHans Petter Selasky error = mlx5e_rl_post_sq_remap_wqe(&iq_channel->iq, scq_handle,
487a8e715d2SHans Petter Selasky sq_handle, sq_channel);
488266c81aaSHans Petter Selasky
489266c81aaSHans Petter Selasky return (error);
490266c81aaSHans Petter Selasky }
491266c81aaSHans Petter Selasky
49238535d6cSHans Petter Selasky /*
49338535d6cSHans Petter Selasky * This function sets the requested rate for a rate limit channel, in
49438535d6cSHans Petter Selasky * bits per second. The requested rate will be filtered through the
49538535d6cSHans Petter Selasky * find best rate function above.
49638535d6cSHans Petter Selasky */
49738535d6cSHans Petter Selasky static int
mlx5e_rlw_channel_set_rate_locked(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel * channel,uint64_t rate)49838535d6cSHans Petter Selasky mlx5e_rlw_channel_set_rate_locked(struct mlx5e_rl_worker *rlw,
49938535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel, uint64_t rate)
50038535d6cSHans Petter Selasky {
50138535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = &rlw->priv->rl;
50238535d6cSHans Petter Selasky struct mlx5e_sq *sq;
50338535d6cSHans Petter Selasky uint64_t temp;
50438535d6cSHans Petter Selasky uint16_t index;
50538535d6cSHans Petter Selasky uint16_t burst;
50638535d6cSHans Petter Selasky int error;
507266c81aaSHans Petter Selasky bool use_sq_remap;
50838535d6cSHans Petter Selasky
50938535d6cSHans Petter Selasky if (rate != 0) {
51038535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
51138535d6cSHans Petter Selasky
51238535d6cSHans Petter Selasky MLX5E_RL_RLOCK(rl);
51338535d6cSHans Petter Selasky
51438535d6cSHans Petter Selasky /* get current burst size in bytes */
51538535d6cSHans Petter Selasky temp = rl->param.tx_burst_size *
516*5dc00f00SJustin Hibbits MLX5E_SW2HW_MTU(if_getmtu(rlw->priv->ifp));
51738535d6cSHans Petter Selasky
51838535d6cSHans Petter Selasky /* limit burst size to 64K currently */
51938535d6cSHans Petter Selasky if (temp > 65535)
52038535d6cSHans Petter Selasky temp = 65535;
52138535d6cSHans Petter Selasky burst = temp;
52238535d6cSHans Petter Selasky
52338535d6cSHans Petter Selasky /* find best rate */
52438535d6cSHans Petter Selasky rate = mlx5e_rl_find_best_rate_locked(rl, rate);
52538535d6cSHans Petter Selasky
52638535d6cSHans Petter Selasky MLX5E_RL_RUNLOCK(rl);
52738535d6cSHans Petter Selasky
52838535d6cSHans Petter Selasky if (rate == 0) {
52938535d6cSHans Petter Selasky /* rate doesn't exist, fallback to unlimited */
53038535d6cSHans Petter Selasky index = 0;
53138535d6cSHans Petter Selasky rate = 0;
53238535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_modify_rate_failure, 1ULL);
53338535d6cSHans Petter Selasky } else {
53438535d6cSHans Petter Selasky /* get a reference on the new rate */
53538535d6cSHans Petter Selasky error = -mlx5_rl_add_rate(rlw->priv->mdev,
53638535d6cSHans Petter Selasky howmany(rate, 1000), burst, &index);
53738535d6cSHans Petter Selasky
53838535d6cSHans Petter Selasky if (error != 0) {
53938535d6cSHans Petter Selasky /* adding rate failed, fallback to unlimited */
54038535d6cSHans Petter Selasky index = 0;
54138535d6cSHans Petter Selasky rate = 0;
54238535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_add_new_rate_failure, 1ULL);
54338535d6cSHans Petter Selasky }
54438535d6cSHans Petter Selasky }
54538535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
54638535d6cSHans Petter Selasky } else {
54738535d6cSHans Petter Selasky index = 0;
54838535d6cSHans Petter Selasky burst = 0; /* default */
54938535d6cSHans Petter Selasky }
55038535d6cSHans Petter Selasky
551266c81aaSHans Petter Selasky /* paced <--> non-paced transitions must go via FW */
552266c81aaSHans Petter Selasky use_sq_remap = MLX5_CAP_QOS(rlw->priv->mdev, qos_remap_pp) &&
553266c81aaSHans Petter Selasky channel->last_rate != 0 && rate != 0;
554266c81aaSHans Petter Selasky
55538535d6cSHans Petter Selasky /* atomically swap rates */
55638535d6cSHans Petter Selasky temp = channel->last_rate;
55738535d6cSHans Petter Selasky channel->last_rate = rate;
55838535d6cSHans Petter Selasky rate = temp;
55938535d6cSHans Petter Selasky
56038535d6cSHans Petter Selasky /* atomically swap burst size */
56138535d6cSHans Petter Selasky temp = channel->last_burst;
56238535d6cSHans Petter Selasky channel->last_burst = burst;
56338535d6cSHans Petter Selasky burst = temp;
56438535d6cSHans Petter Selasky
56538535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
56638535d6cSHans Petter Selasky /* put reference on the old rate, if any */
56738535d6cSHans Petter Selasky if (rate != 0) {
56838535d6cSHans Petter Selasky mlx5_rl_remove_rate(rlw->priv->mdev,
56938535d6cSHans Petter Selasky howmany(rate, 1000), burst);
57038535d6cSHans Petter Selasky }
57138535d6cSHans Petter Selasky
5723230c29dSSlava Shwartsman /* set new rate, if SQ is running */
57338535d6cSHans Petter Selasky sq = channel->sq;
5743230c29dSSlava Shwartsman if (sq != NULL && READ_ONCE(sq->running) != 0) {
575a8e715d2SHans Petter Selasky if (!use_sq_remap || mlx5e_rl_remap_sq(sq, index, channel)) {
576a8e715d2SHans Petter Selasky while (atomic_load_int(&channel->refcount) != 0 &&
577a8e715d2SHans Petter Selasky rlw->priv->mdev->state != MLX5_DEVICE_STATE_INTERNAL_ERROR &&
578a8e715d2SHans Petter Selasky pci_channel_offline(rlw->priv->mdev->pdev) == 0)
579a8e715d2SHans Petter Selasky pause("W", 1);
58038535d6cSHans Petter Selasky error = mlx5e_rl_modify_sq(sq, index);
58138535d6cSHans Petter Selasky if (error != 0)
58238535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_modify_rate_failure, 1ULL);
583266c81aaSHans Petter Selasky }
58438535d6cSHans Petter Selasky } else
58538535d6cSHans Petter Selasky error = 0;
586266c81aaSHans Petter Selasky
58738535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
58838535d6cSHans Petter Selasky
58938535d6cSHans Petter Selasky return (-error);
59038535d6cSHans Petter Selasky }
59138535d6cSHans Petter Selasky
59238535d6cSHans Petter Selasky static void
mlx5e_rl_worker(void * arg)59338535d6cSHans Petter Selasky mlx5e_rl_worker(void *arg)
59438535d6cSHans Petter Selasky {
59538535d6cSHans Petter Selasky struct thread *td;
59638535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = arg;
59738535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel;
59838535d6cSHans Petter Selasky struct mlx5e_priv *priv;
59938535d6cSHans Petter Selasky unsigned ix;
60038535d6cSHans Petter Selasky uint64_t x;
60138535d6cSHans Petter Selasky int error;
60238535d6cSHans Petter Selasky
60338535d6cSHans Petter Selasky /* set thread priority */
60438535d6cSHans Petter Selasky td = curthread;
60538535d6cSHans Petter Selasky
60638535d6cSHans Petter Selasky thread_lock(td);
60738535d6cSHans Petter Selasky sched_prio(td, PI_SWI(SWI_NET));
60838535d6cSHans Petter Selasky thread_unlock(td);
60938535d6cSHans Petter Selasky
61038535d6cSHans Petter Selasky priv = rlw->priv;
61138535d6cSHans Petter Selasky
61238535d6cSHans Petter Selasky /* compute completion vector */
61338535d6cSHans Petter Selasky ix = (rlw - priv->rl.workers) %
61438535d6cSHans Petter Selasky priv->mdev->priv.eq_table.num_comp_vectors;
61538535d6cSHans Petter Selasky
61638535d6cSHans Petter Selasky /* TODO bind to CPU */
61738535d6cSHans Petter Selasky
61838535d6cSHans Petter Selasky /* open all the SQs */
61938535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
62038535d6cSHans Petter Selasky for (x = 0; x < priv->rl.param.tx_channels_per_worker_def; x++) {
62138535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel = rlw->channels + x;
62238535d6cSHans Petter Selasky
62338535d6cSHans Petter Selasky #if !defined(HAVE_RL_PRE_ALLOCATE_CHANNELS)
62438535d6cSHans Petter Selasky if (channel->state == MLX5E_RL_ST_FREE)
62538535d6cSHans Petter Selasky continue;
62638535d6cSHans Petter Selasky #endif
62738535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
62838535d6cSHans Petter Selasky
62938535d6cSHans Petter Selasky MLX5E_RL_RLOCK(&priv->rl);
63038535d6cSHans Petter Selasky error = mlx5e_rl_open_channel(rlw, ix,
63138535d6cSHans Petter Selasky &priv->rl.chan_param, &channel->sq);
63238535d6cSHans Petter Selasky MLX5E_RL_RUNLOCK(&priv->rl);
63338535d6cSHans Petter Selasky
63438535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
63538535d6cSHans Petter Selasky if (error != 0) {
6366b4040d8SHans Petter Selasky mlx5_en_err(priv->ifp,
63738535d6cSHans Petter Selasky "mlx5e_rl_open_channel failed: %d\n", error);
63838535d6cSHans Petter Selasky break;
63938535d6cSHans Petter Selasky }
64038535d6cSHans Petter Selasky mlx5e_rlw_channel_set_rate_locked(rlw, channel, channel->init_rate);
64138535d6cSHans Petter Selasky }
64238535d6cSHans Petter Selasky while (1) {
64338535d6cSHans Petter Selasky if (STAILQ_FIRST(&rlw->process_head) == NULL) {
64438535d6cSHans Petter Selasky /* check if we are tearing down */
64538535d6cSHans Petter Selasky if (rlw->worker_done != 0)
64638535d6cSHans Petter Selasky break;
64738535d6cSHans Petter Selasky cv_wait(&rlw->cv, &rlw->mtx);
64838535d6cSHans Petter Selasky }
64938535d6cSHans Petter Selasky /* check if we are tearing down */
65038535d6cSHans Petter Selasky if (rlw->worker_done != 0)
65138535d6cSHans Petter Selasky break;
65238535d6cSHans Petter Selasky channel = STAILQ_FIRST(&rlw->process_head);
65338535d6cSHans Petter Selasky if (channel != NULL) {
65438535d6cSHans Petter Selasky STAILQ_REMOVE_HEAD(&rlw->process_head, entry);
65538535d6cSHans Petter Selasky
65638535d6cSHans Petter Selasky switch (channel->state) {
65738535d6cSHans Petter Selasky case MLX5E_RL_ST_MODIFY:
65838535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_USED;
65938535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
66038535d6cSHans Petter Selasky
66138535d6cSHans Petter Selasky /* create channel by demand */
66238535d6cSHans Petter Selasky if (channel->sq == NULL) {
66338535d6cSHans Petter Selasky MLX5E_RL_RLOCK(&priv->rl);
66438535d6cSHans Petter Selasky error = mlx5e_rl_open_channel(rlw, ix,
66538535d6cSHans Petter Selasky &priv->rl.chan_param, &channel->sq);
66638535d6cSHans Petter Selasky MLX5E_RL_RUNLOCK(&priv->rl);
66738535d6cSHans Petter Selasky
66838535d6cSHans Petter Selasky if (error != 0) {
6696b4040d8SHans Petter Selasky mlx5_en_err(priv->ifp,
67038535d6cSHans Petter Selasky "mlx5e_rl_open_channel failed: %d\n", error);
67138535d6cSHans Petter Selasky } else {
67238535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_open_queues, 1ULL);
67338535d6cSHans Petter Selasky }
67438535d6cSHans Petter Selasky } else {
67538535d6cSHans Petter Selasky mlx5e_resume_sq(channel->sq);
67638535d6cSHans Petter Selasky }
67738535d6cSHans Petter Selasky
67838535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
67938535d6cSHans Petter Selasky /* convert from bytes/s to bits/s and set new rate */
68038535d6cSHans Petter Selasky error = mlx5e_rlw_channel_set_rate_locked(rlw, channel,
68138535d6cSHans Petter Selasky channel->new_rate * 8ULL);
68238535d6cSHans Petter Selasky if (error != 0) {
6836b4040d8SHans Petter Selasky mlx5_en_err(priv->ifp,
68438535d6cSHans Petter Selasky "mlx5e_rlw_channel_set_rate_locked failed: %d\n",
68538535d6cSHans Petter Selasky error);
68638535d6cSHans Petter Selasky }
68738535d6cSHans Petter Selasky break;
68838535d6cSHans Petter Selasky
68938535d6cSHans Petter Selasky case MLX5E_RL_ST_DESTROY:
69038535d6cSHans Petter Selasky error = mlx5e_rlw_channel_set_rate_locked(rlw, channel, 0);
69138535d6cSHans Petter Selasky if (error != 0) {
6926b4040d8SHans Petter Selasky mlx5_en_err(priv->ifp,
69338535d6cSHans Petter Selasky "mlx5e_rlw_channel_set_rate_locked failed: %d\n",
69438535d6cSHans Petter Selasky error);
69538535d6cSHans Petter Selasky }
69638535d6cSHans Petter Selasky if (channel->sq != NULL) {
69738535d6cSHans Petter Selasky /*
69838535d6cSHans Petter Selasky * Make sure all packets are
69938535d6cSHans Petter Selasky * transmitted before SQ is
70038535d6cSHans Petter Selasky * returned to free list:
70138535d6cSHans Petter Selasky */
70238535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
70338535d6cSHans Petter Selasky mlx5e_drain_sq(channel->sq);
70438535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
70538535d6cSHans Petter Selasky }
70638535d6cSHans Petter Selasky /* put the channel back into the free list */
70738535d6cSHans Petter Selasky STAILQ_INSERT_HEAD(&rlw->index_list_head, channel, entry);
70838535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_FREE;
70938535d6cSHans Petter Selasky atomic_add_64(&priv->rl.stats.tx_active_connections, -1ULL);
71038535d6cSHans Petter Selasky break;
71138535d6cSHans Petter Selasky default:
71238535d6cSHans Petter Selasky /* NOP */
71338535d6cSHans Petter Selasky break;
71438535d6cSHans Petter Selasky }
71538535d6cSHans Petter Selasky }
71638535d6cSHans Petter Selasky }
71738535d6cSHans Petter Selasky
71838535d6cSHans Petter Selasky /* close all the SQs */
71938535d6cSHans Petter Selasky for (x = 0; x < priv->rl.param.tx_channels_per_worker_def; x++) {
72038535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel = rlw->channels + x;
72138535d6cSHans Petter Selasky
72238535d6cSHans Petter Selasky /* update the initial rate */
72338535d6cSHans Petter Selasky channel->init_rate = channel->last_rate;
72438535d6cSHans Petter Selasky
72538535d6cSHans Petter Selasky /* make sure we free up the rate resource */
72638535d6cSHans Petter Selasky mlx5e_rlw_channel_set_rate_locked(rlw, channel, 0);
72738535d6cSHans Petter Selasky
72838535d6cSHans Petter Selasky if (channel->sq != NULL) {
72938535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
73038535d6cSHans Petter Selasky mlx5e_rl_close_channel(&channel->sq);
73138535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_open_queues, -1ULL);
73238535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
73338535d6cSHans Petter Selasky }
73438535d6cSHans Petter Selasky }
73538535d6cSHans Petter Selasky
73638535d6cSHans Petter Selasky rlw->worker_done = 0;
73738535d6cSHans Petter Selasky cv_broadcast(&rlw->cv);
73838535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
73938535d6cSHans Petter Selasky
74038535d6cSHans Petter Selasky kthread_exit();
74138535d6cSHans Petter Selasky }
74238535d6cSHans Petter Selasky
74338535d6cSHans Petter Selasky static int
mlx5e_rl_open_tis(struct mlx5e_priv * priv)74438535d6cSHans Petter Selasky mlx5e_rl_open_tis(struct mlx5e_priv *priv)
74538535d6cSHans Petter Selasky {
74638535d6cSHans Petter Selasky struct mlx5_core_dev *mdev = priv->mdev;
74738535d6cSHans Petter Selasky u32 in[MLX5_ST_SZ_DW(create_tis_in)];
74838535d6cSHans Petter Selasky void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
74938535d6cSHans Petter Selasky
75038535d6cSHans Petter Selasky memset(in, 0, sizeof(in));
75138535d6cSHans Petter Selasky
75238535d6cSHans Petter Selasky MLX5_SET(tisc, tisc, prio, 0);
75338535d6cSHans Petter Selasky MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
75438535d6cSHans Petter Selasky
75538535d6cSHans Petter Selasky return (mlx5_core_create_tis(mdev, in, sizeof(in), &priv->rl.tisn));
75638535d6cSHans Petter Selasky }
75738535d6cSHans Petter Selasky
75838535d6cSHans Petter Selasky static void
mlx5e_rl_close_tis(struct mlx5e_priv * priv)75938535d6cSHans Petter Selasky mlx5e_rl_close_tis(struct mlx5e_priv *priv)
76038535d6cSHans Petter Selasky {
761b633e08cSHans Petter Selasky mlx5_core_destroy_tis(priv->mdev, priv->rl.tisn, 0);
76238535d6cSHans Petter Selasky }
76338535d6cSHans Petter Selasky
76438535d6cSHans Petter Selasky static void
mlx5e_rl_set_default_params(struct mlx5e_rl_params * param,struct mlx5_core_dev * mdev)76538535d6cSHans Petter Selasky mlx5e_rl_set_default_params(struct mlx5e_rl_params *param,
76638535d6cSHans Petter Selasky struct mlx5_core_dev *mdev)
76738535d6cSHans Petter Selasky {
76838535d6cSHans Petter Selasky /* ratelimit workers */
76938535d6cSHans Petter Selasky param->tx_worker_threads_def = mdev->priv.eq_table.num_comp_vectors;
77038535d6cSHans Petter Selasky param->tx_worker_threads_max = MLX5E_RL_MAX_WORKERS;
77138535d6cSHans Petter Selasky
77238535d6cSHans Petter Selasky /* range check */
77338535d6cSHans Petter Selasky if (param->tx_worker_threads_def == 0 ||
77438535d6cSHans Petter Selasky param->tx_worker_threads_def > param->tx_worker_threads_max)
77538535d6cSHans Petter Selasky param->tx_worker_threads_def = param->tx_worker_threads_max;
77638535d6cSHans Petter Selasky
77738535d6cSHans Petter Selasky /* ratelimit channels */
77838535d6cSHans Petter Selasky param->tx_channels_per_worker_def = MLX5E_RL_MAX_SQS /
77938535d6cSHans Petter Selasky param->tx_worker_threads_def;
78038535d6cSHans Petter Selasky param->tx_channels_per_worker_max = MLX5E_RL_MAX_SQS;
78138535d6cSHans Petter Selasky
78238535d6cSHans Petter Selasky /* range check */
78338535d6cSHans Petter Selasky if (param->tx_channels_per_worker_def > MLX5E_RL_DEF_SQ_PER_WORKER)
78438535d6cSHans Petter Selasky param->tx_channels_per_worker_def = MLX5E_RL_DEF_SQ_PER_WORKER;
78538535d6cSHans Petter Selasky
78638535d6cSHans Petter Selasky /* set default burst size */
78738535d6cSHans Petter Selasky param->tx_burst_size = 4; /* MTUs */
78838535d6cSHans Petter Selasky
78938535d6cSHans Petter Selasky /*
79038535d6cSHans Petter Selasky * Set maximum burst size
79138535d6cSHans Petter Selasky *
79238535d6cSHans Petter Selasky * The burst size is multiplied by the MTU and clamped to the
79338535d6cSHans Petter Selasky * range 0 ... 65535 bytes inclusivly before fed into the
79438535d6cSHans Petter Selasky * firmware.
79538535d6cSHans Petter Selasky *
79638535d6cSHans Petter Selasky * NOTE: If the burst size or MTU is changed only ratelimit
79738535d6cSHans Petter Selasky * connections made after the change will use the new burst
79838535d6cSHans Petter Selasky * size.
79938535d6cSHans Petter Selasky */
80038535d6cSHans Petter Selasky param->tx_burst_size_max = 255;
80138535d6cSHans Petter Selasky
80238535d6cSHans Petter Selasky /* get firmware rate limits in 1000bit/s and convert them to bit/s */
80338535d6cSHans Petter Selasky param->tx_limit_min = mdev->priv.rl_table.min_rate * 1000ULL;
80438535d6cSHans Petter Selasky param->tx_limit_max = mdev->priv.rl_table.max_rate * 1000ULL;
80538535d6cSHans Petter Selasky
80638535d6cSHans Petter Selasky /* ratelimit table size */
80738535d6cSHans Petter Selasky param->tx_rates_max = mdev->priv.rl_table.max_size;
80838535d6cSHans Petter Selasky
80938535d6cSHans Petter Selasky /* range check */
81038535d6cSHans Petter Selasky if (param->tx_rates_max > MLX5E_RL_MAX_TX_RATES)
81138535d6cSHans Petter Selasky param->tx_rates_max = MLX5E_RL_MAX_TX_RATES;
81238535d6cSHans Petter Selasky
81338535d6cSHans Petter Selasky /* set default number of rates */
81438535d6cSHans Petter Selasky param->tx_rates_def = param->tx_rates_max;
81538535d6cSHans Petter Selasky
81638535d6cSHans Petter Selasky /* set maximum allowed rate deviation */
81738535d6cSHans Petter Selasky if (param->tx_limit_max != 0) {
81838535d6cSHans Petter Selasky /*
81938535d6cSHans Petter Selasky * Make sure the deviation multiplication doesn't
82038535d6cSHans Petter Selasky * overflow unsigned 64-bit:
82138535d6cSHans Petter Selasky */
82238535d6cSHans Petter Selasky param->tx_allowed_deviation_max = -1ULL /
82338535d6cSHans Petter Selasky param->tx_limit_max;
82438535d6cSHans Petter Selasky }
82538535d6cSHans Petter Selasky /* set default rate deviation */
82638535d6cSHans Petter Selasky param->tx_allowed_deviation = 50; /* 5.0% */
82738535d6cSHans Petter Selasky
82838535d6cSHans Petter Selasky /* channel parameters */
82938535d6cSHans Petter Selasky param->tx_queue_size = (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
83038535d6cSHans Petter Selasky param->tx_coalesce_usecs = MLX5E_RL_TX_COAL_USEC_DEFAULT;
83138535d6cSHans Petter Selasky param->tx_coalesce_pkts = MLX5E_RL_TX_COAL_PKTS_DEFAULT;
83238535d6cSHans Petter Selasky param->tx_coalesce_mode = MLX5E_RL_TX_COAL_MODE_DEFAULT;
83338535d6cSHans Petter Selasky param->tx_completion_fact = MLX5E_RL_TX_COMP_FACT_DEFAULT;
83438535d6cSHans Petter Selasky }
83538535d6cSHans Petter Selasky
83638535d6cSHans Petter Selasky static const char *mlx5e_rl_params_desc[] = {
83738535d6cSHans Petter Selasky MLX5E_RL_PARAMS(MLX5E_STATS_DESC)
83838535d6cSHans Petter Selasky };
83938535d6cSHans Petter Selasky
84038535d6cSHans Petter Selasky static const char *mlx5e_rl_table_params_desc[] = {
84138535d6cSHans Petter Selasky MLX5E_RL_TABLE_PARAMS(MLX5E_STATS_DESC)
84238535d6cSHans Petter Selasky };
84338535d6cSHans Petter Selasky
84438535d6cSHans Petter Selasky static const char *mlx5e_rl_stats_desc[] = {
84538535d6cSHans Petter Selasky MLX5E_RL_STATS(MLX5E_STATS_DESC)
84638535d6cSHans Petter Selasky };
84738535d6cSHans Petter Selasky
84838535d6cSHans Petter Selasky int
mlx5e_rl_init(struct mlx5e_priv * priv)84938535d6cSHans Petter Selasky mlx5e_rl_init(struct mlx5e_priv *priv)
85038535d6cSHans Petter Selasky {
85138535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = &priv->rl;
85238535d6cSHans Petter Selasky struct sysctl_oid *node;
85338535d6cSHans Petter Selasky struct sysctl_oid *stats;
85438535d6cSHans Petter Selasky char buf[64];
85538535d6cSHans Petter Selasky uint64_t i;
85638535d6cSHans Petter Selasky uint64_t j;
85738535d6cSHans Petter Selasky int error;
85838535d6cSHans Petter Selasky
85938535d6cSHans Petter Selasky /* check if there is support for packet pacing */
86038535d6cSHans Petter Selasky if (!MLX5_CAP_GEN(priv->mdev, qos) || !MLX5_CAP_QOS(priv->mdev, packet_pacing))
86138535d6cSHans Petter Selasky return (0);
86238535d6cSHans Petter Selasky
86338535d6cSHans Petter Selasky rl->priv = priv;
86438535d6cSHans Petter Selasky
86538535d6cSHans Petter Selasky sysctl_ctx_init(&rl->ctx);
86638535d6cSHans Petter Selasky
86738535d6cSHans Petter Selasky sx_init(&rl->rl_sxlock, "ratelimit-sxlock");
86838535d6cSHans Petter Selasky
86938535d6cSHans Petter Selasky /* open own TIS domain for ratelimit SQs */
87038535d6cSHans Petter Selasky error = mlx5e_rl_open_tis(priv);
87138535d6cSHans Petter Selasky if (error)
872f8f5b459SHans Petter Selasky goto done;
87338535d6cSHans Petter Selasky
87438535d6cSHans Petter Selasky /* setup default value for parameters */
87538535d6cSHans Petter Selasky mlx5e_rl_set_default_params(&rl->param, priv->mdev);
87638535d6cSHans Petter Selasky
87738535d6cSHans Petter Selasky /* update the completion factor */
87838535d6cSHans Petter Selasky mlx5e_rl_sync_tx_completion_fact(rl);
87938535d6cSHans Petter Selasky
88038535d6cSHans Petter Selasky /* create root node */
88138535d6cSHans Petter Selasky node = SYSCTL_ADD_NODE(&rl->ctx,
88238535d6cSHans Petter Selasky SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
8837029da5cSPawel Biernacki "rate_limit", CTLFLAG_RW | CTLFLAG_MPSAFE, NULL, "Rate limiting support");
88438535d6cSHans Petter Selasky
88538535d6cSHans Petter Selasky if (node != NULL) {
88638535d6cSHans Petter Selasky /* create SYSCTLs */
88738535d6cSHans Petter Selasky for (i = 0; i != MLX5E_RL_PARAMS_NUM; i++) {
88838535d6cSHans Petter Selasky mlx5e_rl_sysctl_add_u64_oid(rl,
88938535d6cSHans Petter Selasky MLX5E_RL_PARAMS_INDEX(arg[i]),
89038535d6cSHans Petter Selasky node, mlx5e_rl_params_desc[2 * i],
89138535d6cSHans Petter Selasky mlx5e_rl_params_desc[2 * i + 1]);
89238535d6cSHans Petter Selasky }
89338535d6cSHans Petter Selasky
89438535d6cSHans Petter Selasky stats = SYSCTL_ADD_NODE(&rl->ctx, SYSCTL_CHILDREN(node),
8957029da5cSPawel Biernacki OID_AUTO, "stats", CTLFLAG_RD | CTLFLAG_MPSAFE, NULL,
89638535d6cSHans Petter Selasky "Rate limiting statistics");
89738535d6cSHans Petter Selasky if (stats != NULL) {
89838535d6cSHans Petter Selasky /* create SYSCTLs */
89938535d6cSHans Petter Selasky for (i = 0; i != MLX5E_RL_STATS_NUM; i++) {
90038535d6cSHans Petter Selasky mlx5e_rl_sysctl_add_stats_u64_oid(rl, i,
90138535d6cSHans Petter Selasky stats, mlx5e_rl_stats_desc[2 * i],
90238535d6cSHans Petter Selasky mlx5e_rl_stats_desc[2 * i + 1]);
90338535d6cSHans Petter Selasky }
90438535d6cSHans Petter Selasky }
90538535d6cSHans Petter Selasky }
90638535d6cSHans Petter Selasky
90738535d6cSHans Petter Selasky /* allocate workers array */
90838535d6cSHans Petter Selasky rl->workers = malloc(sizeof(rl->workers[0]) *
90938535d6cSHans Petter Selasky rl->param.tx_worker_threads_def, M_MLX5EN, M_WAITOK | M_ZERO);
91038535d6cSHans Petter Selasky
91138535d6cSHans Petter Selasky /* allocate rate limit array */
91238535d6cSHans Petter Selasky rl->rate_limit_table = malloc(sizeof(rl->rate_limit_table[0]) *
91338535d6cSHans Petter Selasky rl->param.tx_rates_def, M_MLX5EN, M_WAITOK | M_ZERO);
91438535d6cSHans Petter Selasky
91538535d6cSHans Petter Selasky if (node != NULL) {
91638535d6cSHans Petter Selasky /* create more SYSCTls */
91738535d6cSHans Petter Selasky SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
91838535d6cSHans Petter Selasky "tx_rate_show", CTLTYPE_STRING | CTLFLAG_RD |
91938535d6cSHans Petter Selasky CTLFLAG_MPSAFE, rl, 0, &mlx5e_rl_sysctl_show_rate_table,
92038535d6cSHans Petter Selasky "A", "Show table of all configured TX rates");
92138535d6cSHans Petter Selasky
92238535d6cSHans Petter Selasky /* try to fetch rate table from kernel environment */
92338535d6cSHans Petter Selasky for (i = 0; i != rl->param.tx_rates_def; i++) {
92438535d6cSHans Petter Selasky /* compute path for tunable */
92538535d6cSHans Petter Selasky snprintf(buf, sizeof(buf), "dev.mce.%d.rate_limit.tx_rate_add_%d",
92638535d6cSHans Petter Selasky device_get_unit(priv->mdev->pdev->dev.bsddev), (int)i);
92738535d6cSHans Petter Selasky if (TUNABLE_QUAD_FETCH(buf, &j))
92838535d6cSHans Petter Selasky mlx5e_rl_tx_limit_add(rl, j);
92938535d6cSHans Petter Selasky }
93038535d6cSHans Petter Selasky
93138535d6cSHans Petter Selasky /* setup rate table sysctls */
93238535d6cSHans Petter Selasky for (i = 0; i != MLX5E_RL_TABLE_PARAMS_NUM; i++) {
93338535d6cSHans Petter Selasky mlx5e_rl_sysctl_add_u64_oid(rl,
93438535d6cSHans Petter Selasky MLX5E_RL_PARAMS_INDEX(table_arg[i]),
93538535d6cSHans Petter Selasky node, mlx5e_rl_table_params_desc[2 * i],
93638535d6cSHans Petter Selasky mlx5e_rl_table_params_desc[2 * i + 1]);
93738535d6cSHans Petter Selasky }
93838535d6cSHans Petter Selasky }
93938535d6cSHans Petter Selasky
94038535d6cSHans Petter Selasky for (j = 0; j < rl->param.tx_worker_threads_def; j++) {
94138535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + j;
94238535d6cSHans Petter Selasky
94338535d6cSHans Petter Selasky rlw->priv = priv;
94438535d6cSHans Petter Selasky
94538535d6cSHans Petter Selasky cv_init(&rlw->cv, "mlx5-worker-cv");
94638535d6cSHans Petter Selasky mtx_init(&rlw->mtx, "mlx5-worker-mtx", NULL, MTX_DEF);
94738535d6cSHans Petter Selasky STAILQ_INIT(&rlw->index_list_head);
94838535d6cSHans Petter Selasky STAILQ_INIT(&rlw->process_head);
94938535d6cSHans Petter Selasky
95038535d6cSHans Petter Selasky rlw->channels = malloc(sizeof(rlw->channels[0]) *
95138535d6cSHans Petter Selasky rl->param.tx_channels_per_worker_def, M_MLX5EN, M_WAITOK | M_ZERO);
95238535d6cSHans Petter Selasky
95338535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
95438535d6cSHans Petter Selasky for (i = 0; i < rl->param.tx_channels_per_worker_def; i++) {
95538535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel = rlw->channels + i;
95638535d6cSHans Petter Selasky channel->worker = rlw;
95738535d6cSHans Petter Selasky STAILQ_INSERT_TAIL(&rlw->index_list_head, channel, entry);
95838535d6cSHans Petter Selasky }
95938535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
96038535d6cSHans Petter Selasky }
96138535d6cSHans Petter Selasky
96238535d6cSHans Petter Selasky PRIV_LOCK(priv);
96338535d6cSHans Petter Selasky error = mlx5e_rl_open_workers(priv);
96438535d6cSHans Petter Selasky PRIV_UNLOCK(priv);
96538535d6cSHans Petter Selasky
96638535d6cSHans Petter Selasky if (error != 0) {
9676b4040d8SHans Petter Selasky mlx5_en_err(priv->ifp,
96838535d6cSHans Petter Selasky "mlx5e_rl_open_workers failed: %d\n", error);
96938535d6cSHans Petter Selasky }
97038535d6cSHans Petter Selasky
97138535d6cSHans Petter Selasky return (0);
97238535d6cSHans Petter Selasky
97338535d6cSHans Petter Selasky done:
97438535d6cSHans Petter Selasky sysctl_ctx_free(&rl->ctx);
97538535d6cSHans Petter Selasky sx_destroy(&rl->rl_sxlock);
97638535d6cSHans Petter Selasky return (error);
97738535d6cSHans Petter Selasky }
97838535d6cSHans Petter Selasky
97938535d6cSHans Petter Selasky static int
mlx5e_rl_open_workers(struct mlx5e_priv * priv)98038535d6cSHans Petter Selasky mlx5e_rl_open_workers(struct mlx5e_priv *priv)
98138535d6cSHans Petter Selasky {
98238535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = &priv->rl;
98338535d6cSHans Petter Selasky struct thread *rl_thread = NULL;
98438535d6cSHans Petter Selasky struct proc *rl_proc = NULL;
98538535d6cSHans Petter Selasky uint64_t j;
98638535d6cSHans Petter Selasky int error;
98738535d6cSHans Petter Selasky
98838535d6cSHans Petter Selasky if (priv->gone || rl->opened)
98938535d6cSHans Petter Selasky return (-EINVAL);
99038535d6cSHans Petter Selasky
99138535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
99238535d6cSHans Petter Selasky /* compute channel parameters once */
99338535d6cSHans Petter Selasky mlx5e_rl_build_channel_param(rl, &rl->chan_param);
99438535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
99538535d6cSHans Petter Selasky
99638535d6cSHans Petter Selasky for (j = 0; j < rl->param.tx_worker_threads_def; j++) {
99738535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + j;
99838535d6cSHans Petter Selasky
99938535d6cSHans Petter Selasky /* start worker thread */
100038535d6cSHans Petter Selasky error = kproc_kthread_add(mlx5e_rl_worker, rlw, &rl_proc, &rl_thread,
100138535d6cSHans Petter Selasky RFHIGHPID, 0, "mlx5-ratelimit", "mlx5-rl-worker-thread-%d", (int)j);
100238535d6cSHans Petter Selasky if (error != 0) {
10036b4040d8SHans Petter Selasky mlx5_en_err(rl->priv->ifp,
100438535d6cSHans Petter Selasky "kproc_kthread_add failed: %d\n", error);
100538535d6cSHans Petter Selasky rlw->worker_done = 1;
100638535d6cSHans Petter Selasky }
100738535d6cSHans Petter Selasky }
100838535d6cSHans Petter Selasky
100938535d6cSHans Petter Selasky rl->opened = 1;
101038535d6cSHans Petter Selasky
101138535d6cSHans Petter Selasky return (0);
101238535d6cSHans Petter Selasky }
101338535d6cSHans Petter Selasky
101438535d6cSHans Petter Selasky static void
mlx5e_rl_close_workers(struct mlx5e_priv * priv)101538535d6cSHans Petter Selasky mlx5e_rl_close_workers(struct mlx5e_priv *priv)
101638535d6cSHans Petter Selasky {
101738535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = &priv->rl;
101838535d6cSHans Petter Selasky uint64_t y;
101938535d6cSHans Petter Selasky
102038535d6cSHans Petter Selasky if (rl->opened == 0)
102138535d6cSHans Petter Selasky return;
102238535d6cSHans Petter Selasky
102338535d6cSHans Petter Selasky /* tear down worker threads simultaneously */
102438535d6cSHans Petter Selasky for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
102538535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + y;
102638535d6cSHans Petter Selasky
102738535d6cSHans Petter Selasky /* tear down worker before freeing SQs */
102838535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
102938535d6cSHans Petter Selasky if (rlw->worker_done == 0) {
103038535d6cSHans Petter Selasky rlw->worker_done = 1;
103138535d6cSHans Petter Selasky cv_broadcast(&rlw->cv);
103238535d6cSHans Petter Selasky } else {
103338535d6cSHans Petter Selasky /* XXX thread not started */
103438535d6cSHans Petter Selasky rlw->worker_done = 0;
103538535d6cSHans Petter Selasky }
103638535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
103738535d6cSHans Petter Selasky }
103838535d6cSHans Petter Selasky
103938535d6cSHans Petter Selasky /* wait for worker threads to exit */
104038535d6cSHans Petter Selasky for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
104138535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + y;
104238535d6cSHans Petter Selasky
104338535d6cSHans Petter Selasky /* tear down worker before freeing SQs */
104438535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
104538535d6cSHans Petter Selasky while (rlw->worker_done != 0)
104638535d6cSHans Petter Selasky cv_wait(&rlw->cv, &rlw->mtx);
104738535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
104838535d6cSHans Petter Selasky }
104938535d6cSHans Petter Selasky
105038535d6cSHans Petter Selasky rl->opened = 0;
105138535d6cSHans Petter Selasky }
105238535d6cSHans Petter Selasky
105338535d6cSHans Petter Selasky static void
mlx5e_rl_reset_rates(struct mlx5e_rl_priv_data * rl)105438535d6cSHans Petter Selasky mlx5e_rl_reset_rates(struct mlx5e_rl_priv_data *rl)
105538535d6cSHans Petter Selasky {
105638535d6cSHans Petter Selasky unsigned x;
105738535d6cSHans Petter Selasky
105838535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
105938535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++)
106038535d6cSHans Petter Selasky rl->rate_limit_table[x] = 0;
106138535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
106238535d6cSHans Petter Selasky }
106338535d6cSHans Petter Selasky
106438535d6cSHans Petter Selasky void
mlx5e_rl_cleanup(struct mlx5e_priv * priv)106538535d6cSHans Petter Selasky mlx5e_rl_cleanup(struct mlx5e_priv *priv)
106638535d6cSHans Petter Selasky {
106738535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = &priv->rl;
106838535d6cSHans Petter Selasky uint64_t y;
106938535d6cSHans Petter Selasky
107038535d6cSHans Petter Selasky /* check if there is support for packet pacing */
107138535d6cSHans Petter Selasky if (!MLX5_CAP_GEN(priv->mdev, qos) || !MLX5_CAP_QOS(priv->mdev, packet_pacing))
107238535d6cSHans Petter Selasky return;
107338535d6cSHans Petter Selasky
107438535d6cSHans Petter Selasky /* TODO check if there is support for packet pacing */
107538535d6cSHans Petter Selasky
107638535d6cSHans Petter Selasky sysctl_ctx_free(&rl->ctx);
107738535d6cSHans Petter Selasky
107838535d6cSHans Petter Selasky PRIV_LOCK(priv);
107938535d6cSHans Petter Selasky mlx5e_rl_close_workers(priv);
108038535d6cSHans Petter Selasky PRIV_UNLOCK(priv);
108138535d6cSHans Petter Selasky
108238535d6cSHans Petter Selasky mlx5e_rl_reset_rates(rl);
108338535d6cSHans Petter Selasky
108438535d6cSHans Petter Selasky /* close TIS domain */
108538535d6cSHans Petter Selasky mlx5e_rl_close_tis(priv);
108638535d6cSHans Petter Selasky
108738535d6cSHans Petter Selasky for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
108838535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + y;
108938535d6cSHans Petter Selasky
109038535d6cSHans Petter Selasky cv_destroy(&rlw->cv);
109138535d6cSHans Petter Selasky mtx_destroy(&rlw->mtx);
109238535d6cSHans Petter Selasky free(rlw->channels, M_MLX5EN);
109338535d6cSHans Petter Selasky }
109438535d6cSHans Petter Selasky free(rl->rate_limit_table, M_MLX5EN);
109538535d6cSHans Petter Selasky free(rl->workers, M_MLX5EN);
109638535d6cSHans Petter Selasky sx_destroy(&rl->rl_sxlock);
109738535d6cSHans Petter Selasky }
109838535d6cSHans Petter Selasky
109938535d6cSHans Petter Selasky static void
mlx5e_rlw_queue_channel_locked(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel * channel)110038535d6cSHans Petter Selasky mlx5e_rlw_queue_channel_locked(struct mlx5e_rl_worker *rlw,
110138535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel)
110238535d6cSHans Petter Selasky {
110338535d6cSHans Petter Selasky STAILQ_INSERT_TAIL(&rlw->process_head, channel, entry);
110438535d6cSHans Petter Selasky cv_broadcast(&rlw->cv);
110538535d6cSHans Petter Selasky }
110638535d6cSHans Petter Selasky
110738535d6cSHans Petter Selasky static void
mlx5e_rl_free(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel * channel)110838535d6cSHans Petter Selasky mlx5e_rl_free(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel)
110938535d6cSHans Petter Selasky {
111038535d6cSHans Petter Selasky if (channel == NULL)
111138535d6cSHans Petter Selasky return;
111238535d6cSHans Petter Selasky
111338535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
111438535d6cSHans Petter Selasky switch (channel->state) {
111538535d6cSHans Petter Selasky case MLX5E_RL_ST_MODIFY:
111638535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_DESTROY;
111738535d6cSHans Petter Selasky break;
111838535d6cSHans Petter Selasky case MLX5E_RL_ST_USED:
111938535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_DESTROY;
112038535d6cSHans Petter Selasky mlx5e_rlw_queue_channel_locked(rlw, channel);
112138535d6cSHans Petter Selasky break;
112238535d6cSHans Petter Selasky default:
112338535d6cSHans Petter Selasky break;
112438535d6cSHans Petter Selasky }
112538535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
112638535d6cSHans Petter Selasky }
112738535d6cSHans Petter Selasky
112838535d6cSHans Petter Selasky static int
mlx5e_rl_modify(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel * channel,uint64_t rate)112938535d6cSHans Petter Selasky mlx5e_rl_modify(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel, uint64_t rate)
113038535d6cSHans Petter Selasky {
113138535d6cSHans Petter Selasky
113238535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
113338535d6cSHans Petter Selasky channel->new_rate = rate;
113438535d6cSHans Petter Selasky switch (channel->state) {
113538535d6cSHans Petter Selasky case MLX5E_RL_ST_USED:
113638535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_MODIFY;
113738535d6cSHans Petter Selasky mlx5e_rlw_queue_channel_locked(rlw, channel);
113838535d6cSHans Petter Selasky break;
113938535d6cSHans Petter Selasky default:
114038535d6cSHans Petter Selasky break;
114138535d6cSHans Petter Selasky }
114238535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
114338535d6cSHans Petter Selasky
114438535d6cSHans Petter Selasky return (0);
114538535d6cSHans Petter Selasky }
114638535d6cSHans Petter Selasky
114738535d6cSHans Petter Selasky static int
mlx5e_rl_query(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel * channel,union if_snd_tag_query_params * params)1148cc971b22SSlava Shwartsman mlx5e_rl_query(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel,
1149cc971b22SSlava Shwartsman union if_snd_tag_query_params *params)
115038535d6cSHans Petter Selasky {
115138535d6cSHans Petter Selasky int retval;
115238535d6cSHans Petter Selasky
115338535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
115438535d6cSHans Petter Selasky switch (channel->state) {
115538535d6cSHans Petter Selasky case MLX5E_RL_ST_USED:
1156cc971b22SSlava Shwartsman params->rate_limit.max_rate = channel->last_rate;
1157cc971b22SSlava Shwartsman params->rate_limit.queue_level = mlx5e_sq_queue_level(channel->sq);
115838535d6cSHans Petter Selasky retval = 0;
115938535d6cSHans Petter Selasky break;
116038535d6cSHans Petter Selasky case MLX5E_RL_ST_MODIFY:
1161cc971b22SSlava Shwartsman params->rate_limit.max_rate = channel->last_rate;
1162cc971b22SSlava Shwartsman params->rate_limit.queue_level = mlx5e_sq_queue_level(channel->sq);
116338535d6cSHans Petter Selasky retval = EBUSY;
116438535d6cSHans Petter Selasky break;
116538535d6cSHans Petter Selasky default:
116638535d6cSHans Petter Selasky retval = EINVAL;
116738535d6cSHans Petter Selasky break;
116838535d6cSHans Petter Selasky }
116938535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
117038535d6cSHans Petter Selasky
117138535d6cSHans Petter Selasky return (retval);
117238535d6cSHans Petter Selasky }
117338535d6cSHans Petter Selasky
117438535d6cSHans Petter Selasky static int
mlx5e_find_available_tx_ring_index(struct mlx5e_rl_worker * rlw,struct mlx5e_rl_channel ** pchannel)117538535d6cSHans Petter Selasky mlx5e_find_available_tx_ring_index(struct mlx5e_rl_worker *rlw,
117638535d6cSHans Petter Selasky struct mlx5e_rl_channel **pchannel)
117738535d6cSHans Petter Selasky {
117838535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel;
117938535d6cSHans Petter Selasky int retval = ENOMEM;
118038535d6cSHans Petter Selasky
118138535d6cSHans Petter Selasky MLX5E_RL_WORKER_LOCK(rlw);
118238535d6cSHans Petter Selasky /* Check for available channel in free list */
118338535d6cSHans Petter Selasky if ((channel = STAILQ_FIRST(&rlw->index_list_head)) != NULL) {
118438535d6cSHans Petter Selasky retval = 0;
118538535d6cSHans Petter Selasky /* Remove head index from available list */
118638535d6cSHans Petter Selasky STAILQ_REMOVE_HEAD(&rlw->index_list_head, entry);
118738535d6cSHans Petter Selasky channel->state = MLX5E_RL_ST_USED;
118838535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_active_connections, 1ULL);
118938535d6cSHans Petter Selasky } else {
119038535d6cSHans Petter Selasky atomic_add_64(&rlw->priv->rl.stats.tx_available_resource_failure, 1ULL);
119138535d6cSHans Petter Selasky }
119238535d6cSHans Petter Selasky MLX5E_RL_WORKER_UNLOCK(rlw);
119338535d6cSHans Petter Selasky
119438535d6cSHans Petter Selasky *pchannel = channel;
119538535d6cSHans Petter Selasky #ifdef RATELIMIT_DEBUG
11966b4040d8SHans Petter Selasky mlx5_en_info(rlw->priv->ifp,
11976b4040d8SHans Petter Selasky "Channel pointer for rate limit connection is %p\n", channel);
119838535d6cSHans Petter Selasky #endif
119938535d6cSHans Petter Selasky return (retval);
120038535d6cSHans Petter Selasky }
120138535d6cSHans Petter Selasky
120238535d6cSHans Petter Selasky int
mlx5e_rl_snd_tag_alloc(if_t ifp,union if_snd_tag_alloc_params * params,struct m_snd_tag ** ppmt)1203*5dc00f00SJustin Hibbits mlx5e_rl_snd_tag_alloc(if_t ifp,
120438535d6cSHans Petter Selasky union if_snd_tag_alloc_params *params,
120538535d6cSHans Petter Selasky struct m_snd_tag **ppmt)
120638535d6cSHans Petter Selasky {
120738535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel;
120838535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw;
120938535d6cSHans Petter Selasky struct mlx5e_priv *priv;
121038535d6cSHans Petter Selasky int error;
121138535d6cSHans Petter Selasky
1212*5dc00f00SJustin Hibbits priv = if_getsoftc(ifp);
121338535d6cSHans Petter Selasky
121438535d6cSHans Petter Selasky /* check if there is support for packet pacing or if device is going away */
121538535d6cSHans Petter Selasky if (!MLX5_CAP_GEN(priv->mdev, qos) ||
121638535d6cSHans Petter Selasky !MLX5_CAP_QOS(priv->mdev, packet_pacing) || priv->gone ||
121738535d6cSHans Petter Selasky params->rate_limit.hdr.type != IF_SND_TAG_TYPE_RATE_LIMIT)
121838535d6cSHans Petter Selasky return (EOPNOTSUPP);
121938535d6cSHans Petter Selasky
122038535d6cSHans Petter Selasky /* compute worker thread this TCP connection belongs to */
122138535d6cSHans Petter Selasky rlw = priv->rl.workers + ((params->rate_limit.hdr.flowid % 128) %
122238535d6cSHans Petter Selasky priv->rl.param.tx_worker_threads_def);
122338535d6cSHans Petter Selasky
122438535d6cSHans Petter Selasky error = mlx5e_find_available_tx_ring_index(rlw, &channel);
122538535d6cSHans Petter Selasky if (error != 0)
122638535d6cSHans Petter Selasky goto done;
122738535d6cSHans Petter Selasky
122838535d6cSHans Petter Selasky error = mlx5e_rl_modify(rlw, channel, params->rate_limit.max_rate);
122938535d6cSHans Petter Selasky if (error != 0) {
123038535d6cSHans Petter Selasky mlx5e_rl_free(rlw, channel);
123138535d6cSHans Petter Selasky goto done;
123238535d6cSHans Petter Selasky }
123338535d6cSHans Petter Selasky
123438535d6cSHans Petter Selasky /* store pointer to mbuf tag */
123556fb710fSJohn Baldwin MPASS(channel->tag.refcount == 0);
1236c782ea8bSJohn Baldwin m_snd_tag_init(&channel->tag, ifp, &mlx5e_rl_snd_tag_sw);
123756fb710fSJohn Baldwin *ppmt = &channel->tag;
123838535d6cSHans Petter Selasky done:
123938535d6cSHans Petter Selasky return (error);
124038535d6cSHans Petter Selasky }
124138535d6cSHans Petter Selasky
124238535d6cSHans Petter Selasky
1243c782ea8bSJohn Baldwin static int
mlx5e_rl_snd_tag_modify(struct m_snd_tag * pmt,union if_snd_tag_modify_params * params)124438535d6cSHans Petter Selasky mlx5e_rl_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_params *params)
124538535d6cSHans Petter Selasky {
124638535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel =
124756fb710fSJohn Baldwin container_of(pmt, struct mlx5e_rl_channel, tag);
124838535d6cSHans Petter Selasky
124938535d6cSHans Petter Selasky return (mlx5e_rl_modify(channel->worker, channel, params->rate_limit.max_rate));
125038535d6cSHans Petter Selasky }
125138535d6cSHans Petter Selasky
1252c782ea8bSJohn Baldwin static int
mlx5e_rl_snd_tag_query(struct m_snd_tag * pmt,union if_snd_tag_query_params * params)125338535d6cSHans Petter Selasky mlx5e_rl_snd_tag_query(struct m_snd_tag *pmt, union if_snd_tag_query_params *params)
125438535d6cSHans Petter Selasky {
125538535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel =
125656fb710fSJohn Baldwin container_of(pmt, struct mlx5e_rl_channel, tag);
125738535d6cSHans Petter Selasky
1258cc971b22SSlava Shwartsman return (mlx5e_rl_query(channel->worker, channel, params));
125938535d6cSHans Petter Selasky }
126038535d6cSHans Petter Selasky
1261c782ea8bSJohn Baldwin static void
mlx5e_rl_snd_tag_free(struct m_snd_tag * pmt)126238535d6cSHans Petter Selasky mlx5e_rl_snd_tag_free(struct m_snd_tag *pmt)
126338535d6cSHans Petter Selasky {
126438535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel =
126556fb710fSJohn Baldwin container_of(pmt, struct mlx5e_rl_channel, tag);
126638535d6cSHans Petter Selasky
126738535d6cSHans Petter Selasky mlx5e_rl_free(channel->worker, channel);
126838535d6cSHans Petter Selasky }
126938535d6cSHans Petter Selasky
127038535d6cSHans Petter Selasky static int
mlx5e_rl_sysctl_show_rate_table(SYSCTL_HANDLER_ARGS)127138535d6cSHans Petter Selasky mlx5e_rl_sysctl_show_rate_table(SYSCTL_HANDLER_ARGS)
127238535d6cSHans Petter Selasky {
127338535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = arg1;
127438535d6cSHans Petter Selasky struct mlx5e_priv *priv = rl->priv;
127538535d6cSHans Petter Selasky struct sbuf sbuf;
127638535d6cSHans Petter Selasky unsigned x;
127738535d6cSHans Petter Selasky int error;
127838535d6cSHans Petter Selasky
127938535d6cSHans Petter Selasky error = sysctl_wire_old_buffer(req, 0);
128038535d6cSHans Petter Selasky if (error != 0)
128138535d6cSHans Petter Selasky return (error);
128238535d6cSHans Petter Selasky
128338535d6cSHans Petter Selasky PRIV_LOCK(priv);
128438535d6cSHans Petter Selasky
128538535d6cSHans Petter Selasky sbuf_new_for_sysctl(&sbuf, NULL, 128 * rl->param.tx_rates_def, req);
128638535d6cSHans Petter Selasky
128738535d6cSHans Petter Selasky sbuf_printf(&sbuf,
128838535d6cSHans Petter Selasky "\n\n" "\t" "ENTRY" "\t" "BURST" "\t" "RATE [bit/s]\n"
128938535d6cSHans Petter Selasky "\t" "--------------------------------------------\n");
129038535d6cSHans Petter Selasky
129138535d6cSHans Petter Selasky MLX5E_RL_RLOCK(rl);
129238535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++) {
129338535d6cSHans Petter Selasky if (rl->rate_limit_table[x] == 0)
129438535d6cSHans Petter Selasky continue;
129538535d6cSHans Petter Selasky
129638535d6cSHans Petter Selasky sbuf_printf(&sbuf, "\t" "%3u" "\t" "%3u" "\t" "%lld\n",
129738535d6cSHans Petter Selasky x, (unsigned)rl->param.tx_burst_size,
129838535d6cSHans Petter Selasky (long long)rl->rate_limit_table[x]);
129938535d6cSHans Petter Selasky }
130038535d6cSHans Petter Selasky MLX5E_RL_RUNLOCK(rl);
130138535d6cSHans Petter Selasky
130238535d6cSHans Petter Selasky error = sbuf_finish(&sbuf);
130338535d6cSHans Petter Selasky sbuf_delete(&sbuf);
130438535d6cSHans Petter Selasky
130538535d6cSHans Petter Selasky PRIV_UNLOCK(priv);
130638535d6cSHans Petter Selasky
130738535d6cSHans Petter Selasky return (error);
130838535d6cSHans Petter Selasky }
130938535d6cSHans Petter Selasky
131038535d6cSHans Petter Selasky static int
mlx5e_rl_refresh_channel_params(struct mlx5e_rl_priv_data * rl)131138535d6cSHans Petter Selasky mlx5e_rl_refresh_channel_params(struct mlx5e_rl_priv_data *rl)
131238535d6cSHans Petter Selasky {
131338535d6cSHans Petter Selasky uint64_t x;
131438535d6cSHans Petter Selasky uint64_t y;
131538535d6cSHans Petter Selasky
131638535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
131738535d6cSHans Petter Selasky /* compute channel parameters once */
131838535d6cSHans Petter Selasky mlx5e_rl_build_channel_param(rl, &rl->chan_param);
131938535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
132038535d6cSHans Petter Selasky
132138535d6cSHans Petter Selasky for (y = 0; y != rl->param.tx_worker_threads_def; y++) {
132238535d6cSHans Petter Selasky struct mlx5e_rl_worker *rlw = rl->workers + y;
132338535d6cSHans Petter Selasky
132438535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_channels_per_worker_def; x++) {
132538535d6cSHans Petter Selasky struct mlx5e_rl_channel *channel;
132638535d6cSHans Petter Selasky struct mlx5e_sq *sq;
132738535d6cSHans Petter Selasky
132838535d6cSHans Petter Selasky channel = rlw->channels + x;
132938535d6cSHans Petter Selasky sq = channel->sq;
133038535d6cSHans Petter Selasky
133138535d6cSHans Petter Selasky if (sq == NULL)
133238535d6cSHans Petter Selasky continue;
133338535d6cSHans Petter Selasky
133438535d6cSHans Petter Selasky if (MLX5_CAP_GEN(rl->priv->mdev, cq_period_mode_modify)) {
133538535d6cSHans Petter Selasky mlx5_core_modify_cq_moderation_mode(rl->priv->mdev, &sq->cq.mcq,
133638535d6cSHans Petter Selasky rl->param.tx_coalesce_usecs,
133738535d6cSHans Petter Selasky rl->param.tx_coalesce_pkts,
133838535d6cSHans Petter Selasky rl->param.tx_coalesce_mode);
133938535d6cSHans Petter Selasky } else {
134038535d6cSHans Petter Selasky mlx5_core_modify_cq_moderation(rl->priv->mdev, &sq->cq.mcq,
134138535d6cSHans Petter Selasky rl->param.tx_coalesce_usecs,
134238535d6cSHans Petter Selasky rl->param.tx_coalesce_pkts);
134338535d6cSHans Petter Selasky }
134438535d6cSHans Petter Selasky }
134538535d6cSHans Petter Selasky }
134638535d6cSHans Petter Selasky return (0);
134738535d6cSHans Petter Selasky }
134838535d6cSHans Petter Selasky
13493e581cabSSlava Shwartsman void
mlx5e_rl_refresh_sq_inline(struct mlx5e_rl_priv_data * rl)13503e581cabSSlava Shwartsman mlx5e_rl_refresh_sq_inline(struct mlx5e_rl_priv_data *rl)
13513e581cabSSlava Shwartsman {
13523e581cabSSlava Shwartsman uint64_t x;
13533e581cabSSlava Shwartsman uint64_t y;
13543e581cabSSlava Shwartsman
13553e581cabSSlava Shwartsman for (y = 0; y != rl->param.tx_worker_threads_def; y++) {
13563e581cabSSlava Shwartsman struct mlx5e_rl_worker *rlw = rl->workers + y;
13573e581cabSSlava Shwartsman
13583e581cabSSlava Shwartsman for (x = 0; x != rl->param.tx_channels_per_worker_def; x++) {
13593e581cabSSlava Shwartsman struct mlx5e_rl_channel *channel;
13603e581cabSSlava Shwartsman struct mlx5e_sq *sq;
13613e581cabSSlava Shwartsman
13623e581cabSSlava Shwartsman channel = rlw->channels + x;
13633e581cabSSlava Shwartsman sq = channel->sq;
13643e581cabSSlava Shwartsman
13653e581cabSSlava Shwartsman if (sq == NULL)
13663e581cabSSlava Shwartsman continue;
13673e581cabSSlava Shwartsman
13683e581cabSSlava Shwartsman mtx_lock(&sq->lock);
13693e581cabSSlava Shwartsman mlx5e_update_sq_inline(sq);
13703e581cabSSlava Shwartsman mtx_unlock(&sq->lock);
13713e581cabSSlava Shwartsman }
13723e581cabSSlava Shwartsman }
13733e581cabSSlava Shwartsman }
13743e581cabSSlava Shwartsman
137538535d6cSHans Petter Selasky static int
mlx5e_rl_tx_limit_add(struct mlx5e_rl_priv_data * rl,uint64_t value)137638535d6cSHans Petter Selasky mlx5e_rl_tx_limit_add(struct mlx5e_rl_priv_data *rl, uint64_t value)
137738535d6cSHans Petter Selasky {
137838535d6cSHans Petter Selasky unsigned x;
137938535d6cSHans Petter Selasky int error;
138038535d6cSHans Petter Selasky
138138535d6cSHans Petter Selasky if (value < 1000 ||
138238535d6cSHans Petter Selasky mlx5_rl_is_in_range(rl->priv->mdev, howmany(value, 1000), 0) == 0)
138338535d6cSHans Petter Selasky return (EINVAL);
138438535d6cSHans Petter Selasky
138538535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
138638535d6cSHans Petter Selasky error = ENOMEM;
138738535d6cSHans Petter Selasky
138838535d6cSHans Petter Selasky /* check if rate already exists */
138938535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++) {
139038535d6cSHans Petter Selasky if (rl->rate_limit_table[x] != value)
139138535d6cSHans Petter Selasky continue;
139238535d6cSHans Petter Selasky error = EEXIST;
139338535d6cSHans Petter Selasky break;
139438535d6cSHans Petter Selasky }
139538535d6cSHans Petter Selasky
139638535d6cSHans Petter Selasky /* check if there is a free rate entry */
139738535d6cSHans Petter Selasky if (x == rl->param.tx_rates_def) {
139838535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++) {
139938535d6cSHans Petter Selasky if (rl->rate_limit_table[x] != 0)
140038535d6cSHans Petter Selasky continue;
140138535d6cSHans Petter Selasky rl->rate_limit_table[x] = value;
140238535d6cSHans Petter Selasky error = 0;
140338535d6cSHans Petter Selasky break;
140438535d6cSHans Petter Selasky }
140538535d6cSHans Petter Selasky }
140638535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
140738535d6cSHans Petter Selasky
140838535d6cSHans Petter Selasky return (error);
140938535d6cSHans Petter Selasky }
141038535d6cSHans Petter Selasky
141138535d6cSHans Petter Selasky static int
mlx5e_rl_tx_limit_clr(struct mlx5e_rl_priv_data * rl,uint64_t value)141238535d6cSHans Petter Selasky mlx5e_rl_tx_limit_clr(struct mlx5e_rl_priv_data *rl, uint64_t value)
141338535d6cSHans Petter Selasky {
141438535d6cSHans Petter Selasky unsigned x;
141538535d6cSHans Petter Selasky int error;
141638535d6cSHans Petter Selasky
141738535d6cSHans Petter Selasky if (value == 0)
141838535d6cSHans Petter Selasky return (EINVAL);
141938535d6cSHans Petter Selasky
142038535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
142138535d6cSHans Petter Selasky
142238535d6cSHans Petter Selasky /* check if rate already exists */
142338535d6cSHans Petter Selasky for (x = 0; x != rl->param.tx_rates_def; x++) {
142438535d6cSHans Petter Selasky if (rl->rate_limit_table[x] != value)
142538535d6cSHans Petter Selasky continue;
142638535d6cSHans Petter Selasky /* free up rate */
142738535d6cSHans Petter Selasky rl->rate_limit_table[x] = 0;
142838535d6cSHans Petter Selasky break;
142938535d6cSHans Petter Selasky }
143038535d6cSHans Petter Selasky
143138535d6cSHans Petter Selasky /* check if there is a free rate entry */
143238535d6cSHans Petter Selasky if (x == rl->param.tx_rates_def)
143338535d6cSHans Petter Selasky error = ENOENT;
143438535d6cSHans Petter Selasky else
143538535d6cSHans Petter Selasky error = 0;
143638535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
143738535d6cSHans Petter Selasky
143838535d6cSHans Petter Selasky return (error);
143938535d6cSHans Petter Selasky }
144038535d6cSHans Petter Selasky
144138535d6cSHans Petter Selasky static int
mlx5e_rl_sysctl_handler(SYSCTL_HANDLER_ARGS)144238535d6cSHans Petter Selasky mlx5e_rl_sysctl_handler(SYSCTL_HANDLER_ARGS)
144338535d6cSHans Petter Selasky {
144438535d6cSHans Petter Selasky struct mlx5e_rl_priv_data *rl = arg1;
144538535d6cSHans Petter Selasky struct mlx5e_priv *priv = rl->priv;
144638535d6cSHans Petter Selasky unsigned mode_modify;
144738535d6cSHans Petter Selasky unsigned was_opened;
144838535d6cSHans Petter Selasky uint64_t value;
144938535d6cSHans Petter Selasky int error;
145038535d6cSHans Petter Selasky
145138535d6cSHans Petter Selasky PRIV_LOCK(priv);
145238535d6cSHans Petter Selasky
145338535d6cSHans Petter Selasky MLX5E_RL_RLOCK(rl);
145438535d6cSHans Petter Selasky value = rl->param.arg[arg2];
145538535d6cSHans Petter Selasky MLX5E_RL_RUNLOCK(rl);
145638535d6cSHans Petter Selasky
145738535d6cSHans Petter Selasky if (req != NULL) {
145838535d6cSHans Petter Selasky error = sysctl_handle_64(oidp, &value, 0, req);
145938535d6cSHans Petter Selasky if (error || req->newptr == NULL ||
146038535d6cSHans Petter Selasky value == rl->param.arg[arg2])
146138535d6cSHans Petter Selasky goto done;
146238535d6cSHans Petter Selasky } else {
146338535d6cSHans Petter Selasky error = 0;
146438535d6cSHans Petter Selasky }
146538535d6cSHans Petter Selasky
146638535d6cSHans Petter Selasky /* check if device is gone */
146738535d6cSHans Petter Selasky if (priv->gone) {
146838535d6cSHans Petter Selasky error = ENXIO;
146938535d6cSHans Petter Selasky goto done;
147038535d6cSHans Petter Selasky }
147138535d6cSHans Petter Selasky was_opened = rl->opened;
147238535d6cSHans Petter Selasky mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
147338535d6cSHans Petter Selasky
147438535d6cSHans Petter Selasky switch (MLX5E_RL_PARAMS_INDEX(arg[arg2])) {
147538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_worker_threads_def):
147638535d6cSHans Petter Selasky if (value > rl->param.tx_worker_threads_max)
147738535d6cSHans Petter Selasky value = rl->param.tx_worker_threads_max;
147838535d6cSHans Petter Selasky else if (value < 1)
147938535d6cSHans Petter Selasky value = 1;
148038535d6cSHans Petter Selasky
148138535d6cSHans Petter Selasky /* store new value */
148238535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
148338535d6cSHans Petter Selasky break;
148438535d6cSHans Petter Selasky
148538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_channels_per_worker_def):
148638535d6cSHans Petter Selasky if (value > rl->param.tx_channels_per_worker_max)
148738535d6cSHans Petter Selasky value = rl->param.tx_channels_per_worker_max;
148838535d6cSHans Petter Selasky else if (value < 1)
148938535d6cSHans Petter Selasky value = 1;
149038535d6cSHans Petter Selasky
149138535d6cSHans Petter Selasky /* store new value */
149238535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
149338535d6cSHans Petter Selasky break;
149438535d6cSHans Petter Selasky
149538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_rates_def):
149638535d6cSHans Petter Selasky if (value > rl->param.tx_rates_max)
149738535d6cSHans Petter Selasky value = rl->param.tx_rates_max;
149838535d6cSHans Petter Selasky else if (value < 1)
149938535d6cSHans Petter Selasky value = 1;
150038535d6cSHans Petter Selasky
150138535d6cSHans Petter Selasky /* store new value */
150238535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
150338535d6cSHans Petter Selasky break;
150438535d6cSHans Petter Selasky
150538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_coalesce_usecs):
150638535d6cSHans Petter Selasky /* range check */
150738535d6cSHans Petter Selasky if (value < 1)
150838535d6cSHans Petter Selasky value = 0;
150938535d6cSHans Petter Selasky else if (value > MLX5E_FLD_MAX(cqc, cq_period))
151038535d6cSHans Petter Selasky value = MLX5E_FLD_MAX(cqc, cq_period);
151138535d6cSHans Petter Selasky
151238535d6cSHans Petter Selasky /* store new value */
151338535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
151438535d6cSHans Petter Selasky
151538535d6cSHans Petter Selasky /* check to avoid down and up the network interface */
151638535d6cSHans Petter Selasky if (was_opened)
151738535d6cSHans Petter Selasky error = mlx5e_rl_refresh_channel_params(rl);
151838535d6cSHans Petter Selasky break;
151938535d6cSHans Petter Selasky
152038535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_coalesce_pkts):
152138535d6cSHans Petter Selasky /* import TX coal pkts */
152238535d6cSHans Petter Selasky if (value < 1)
152338535d6cSHans Petter Selasky value = 0;
152438535d6cSHans Petter Selasky else if (value > MLX5E_FLD_MAX(cqc, cq_max_count))
152538535d6cSHans Petter Selasky value = MLX5E_FLD_MAX(cqc, cq_max_count);
152638535d6cSHans Petter Selasky
152738535d6cSHans Petter Selasky /* store new value */
152838535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
152938535d6cSHans Petter Selasky
153038535d6cSHans Petter Selasky /* check to avoid down and up the network interface */
153138535d6cSHans Petter Selasky if (was_opened)
153238535d6cSHans Petter Selasky error = mlx5e_rl_refresh_channel_params(rl);
153338535d6cSHans Petter Selasky break;
153438535d6cSHans Petter Selasky
153538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_coalesce_mode):
153638535d6cSHans Petter Selasky /* network interface must be down */
153738535d6cSHans Petter Selasky if (was_opened != 0 && mode_modify == 0)
153838535d6cSHans Petter Selasky mlx5e_rl_close_workers(priv);
153938535d6cSHans Petter Selasky
154038535d6cSHans Petter Selasky /* import TX coalesce mode */
154138535d6cSHans Petter Selasky if (value != 0)
154238535d6cSHans Petter Selasky value = 1;
154338535d6cSHans Petter Selasky
154438535d6cSHans Petter Selasky /* store new value */
154538535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
154638535d6cSHans Petter Selasky
154738535d6cSHans Petter Selasky /* restart network interface, if any */
154838535d6cSHans Petter Selasky if (was_opened != 0) {
154938535d6cSHans Petter Selasky if (mode_modify == 0)
155038535d6cSHans Petter Selasky mlx5e_rl_open_workers(priv);
155138535d6cSHans Petter Selasky else
155238535d6cSHans Petter Selasky error = mlx5e_rl_refresh_channel_params(rl);
155338535d6cSHans Petter Selasky }
155438535d6cSHans Petter Selasky break;
155538535d6cSHans Petter Selasky
155638535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_queue_size):
155738535d6cSHans Petter Selasky /* network interface must be down */
155838535d6cSHans Petter Selasky if (was_opened)
155938535d6cSHans Petter Selasky mlx5e_rl_close_workers(priv);
156038535d6cSHans Petter Selasky
156138535d6cSHans Petter Selasky /* import TX queue size */
156238535d6cSHans Petter Selasky if (value < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE))
156338535d6cSHans Petter Selasky value = (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
156438535d6cSHans Petter Selasky else if (value > priv->params_ethtool.tx_queue_size_max)
156538535d6cSHans Petter Selasky value = priv->params_ethtool.tx_queue_size_max;
156638535d6cSHans Petter Selasky
156738535d6cSHans Petter Selasky /* store actual TX queue size */
156838535d6cSHans Petter Selasky value = 1ULL << order_base_2(value);
156938535d6cSHans Petter Selasky
157038535d6cSHans Petter Selasky /* store new value */
157138535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
157238535d6cSHans Petter Selasky
157338535d6cSHans Petter Selasky /* verify TX completion factor */
157438535d6cSHans Petter Selasky mlx5e_rl_sync_tx_completion_fact(rl);
157538535d6cSHans Petter Selasky
157638535d6cSHans Petter Selasky /* restart network interface, if any */
157738535d6cSHans Petter Selasky if (was_opened)
157838535d6cSHans Petter Selasky mlx5e_rl_open_workers(priv);
157938535d6cSHans Petter Selasky break;
158038535d6cSHans Petter Selasky
158138535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_completion_fact):
158238535d6cSHans Petter Selasky /* network interface must be down */
158338535d6cSHans Petter Selasky if (was_opened)
158438535d6cSHans Petter Selasky mlx5e_rl_close_workers(priv);
158538535d6cSHans Petter Selasky
158638535d6cSHans Petter Selasky /* store new value */
158738535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
158838535d6cSHans Petter Selasky
158938535d6cSHans Petter Selasky /* verify parameter */
159038535d6cSHans Petter Selasky mlx5e_rl_sync_tx_completion_fact(rl);
159138535d6cSHans Petter Selasky
159238535d6cSHans Petter Selasky /* restart network interface, if any */
159338535d6cSHans Petter Selasky if (was_opened)
159438535d6cSHans Petter Selasky mlx5e_rl_open_workers(priv);
159538535d6cSHans Petter Selasky break;
159638535d6cSHans Petter Selasky
159738535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_limit_add):
159838535d6cSHans Petter Selasky error = mlx5e_rl_tx_limit_add(rl, value);
159938535d6cSHans Petter Selasky break;
160038535d6cSHans Petter Selasky
160138535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_limit_clr):
160238535d6cSHans Petter Selasky error = mlx5e_rl_tx_limit_clr(rl, value);
160338535d6cSHans Petter Selasky break;
160438535d6cSHans Petter Selasky
160538535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_allowed_deviation):
160638535d6cSHans Petter Selasky /* range check */
160738535d6cSHans Petter Selasky if (value > rl->param.tx_allowed_deviation_max)
160838535d6cSHans Petter Selasky value = rl->param.tx_allowed_deviation_max;
160938535d6cSHans Petter Selasky else if (value < rl->param.tx_allowed_deviation_min)
161038535d6cSHans Petter Selasky value = rl->param.tx_allowed_deviation_min;
161138535d6cSHans Petter Selasky
161238535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
161338535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
161438535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
161538535d6cSHans Petter Selasky break;
161638535d6cSHans Petter Selasky
161738535d6cSHans Petter Selasky case MLX5E_RL_PARAMS_INDEX(tx_burst_size):
161838535d6cSHans Petter Selasky /* range check */
161938535d6cSHans Petter Selasky if (value > rl->param.tx_burst_size_max)
162038535d6cSHans Petter Selasky value = rl->param.tx_burst_size_max;
162138535d6cSHans Petter Selasky else if (value < rl->param.tx_burst_size_min)
162238535d6cSHans Petter Selasky value = rl->param.tx_burst_size_min;
162338535d6cSHans Petter Selasky
162438535d6cSHans Petter Selasky MLX5E_RL_WLOCK(rl);
162538535d6cSHans Petter Selasky rl->param.arg[arg2] = value;
162638535d6cSHans Petter Selasky MLX5E_RL_WUNLOCK(rl);
162738535d6cSHans Petter Selasky break;
162838535d6cSHans Petter Selasky
162938535d6cSHans Petter Selasky default:
163038535d6cSHans Petter Selasky break;
163138535d6cSHans Petter Selasky }
163238535d6cSHans Petter Selasky done:
163338535d6cSHans Petter Selasky PRIV_UNLOCK(priv);
163438535d6cSHans Petter Selasky return (error);
163538535d6cSHans Petter Selasky }
163638535d6cSHans Petter Selasky
163738535d6cSHans Petter Selasky static void
mlx5e_rl_sysctl_add_u64_oid(struct mlx5e_rl_priv_data * rl,unsigned x,struct sysctl_oid * node,const char * name,const char * desc)163838535d6cSHans Petter Selasky mlx5e_rl_sysctl_add_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
163938535d6cSHans Petter Selasky struct sysctl_oid *node, const char *name, const char *desc)
164038535d6cSHans Petter Selasky {
164138535d6cSHans Petter Selasky /*
164238535d6cSHans Petter Selasky * NOTE: In FreeBSD-11 and newer the CTLFLAG_RWTUN flag will
164338535d6cSHans Petter Selasky * take care of loading default sysctl value from the kernel
164438535d6cSHans Petter Selasky * environment, if any:
164538535d6cSHans Petter Selasky */
164638535d6cSHans Petter Selasky if (strstr(name, "_max") != 0 || strstr(name, "_min") != 0) {
164738535d6cSHans Petter Selasky /* read-only SYSCTLs */
164838535d6cSHans Petter Selasky SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
164938535d6cSHans Petter Selasky name, CTLTYPE_U64 | CTLFLAG_RD |
165038535d6cSHans Petter Selasky CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
165138535d6cSHans Petter Selasky } else {
165238535d6cSHans Petter Selasky if (strstr(name, "_def") != 0) {
165338535d6cSHans Petter Selasky #ifdef RATELIMIT_DEBUG
165438535d6cSHans Petter Selasky /* tunable read-only advanced SYSCTLs */
165538535d6cSHans Petter Selasky SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
165638535d6cSHans Petter Selasky name, CTLTYPE_U64 | CTLFLAG_RDTUN |
165738535d6cSHans Petter Selasky CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
165838535d6cSHans Petter Selasky #endif
165938535d6cSHans Petter Selasky } else {
166038535d6cSHans Petter Selasky /* read-write SYSCTLs */
166138535d6cSHans Petter Selasky SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
166238535d6cSHans Petter Selasky name, CTLTYPE_U64 | CTLFLAG_RWTUN |
166338535d6cSHans Petter Selasky CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
166438535d6cSHans Petter Selasky }
166538535d6cSHans Petter Selasky }
166638535d6cSHans Petter Selasky }
166738535d6cSHans Petter Selasky
166838535d6cSHans Petter Selasky static void
mlx5e_rl_sysctl_add_stats_u64_oid(struct mlx5e_rl_priv_data * rl,unsigned x,struct sysctl_oid * node,const char * name,const char * desc)166938535d6cSHans Petter Selasky mlx5e_rl_sysctl_add_stats_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
167038535d6cSHans Petter Selasky struct sysctl_oid *node, const char *name, const char *desc)
167138535d6cSHans Petter Selasky {
167238535d6cSHans Petter Selasky /* read-only SYSCTLs */
167338535d6cSHans Petter Selasky SYSCTL_ADD_U64(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
167438535d6cSHans Petter Selasky CTLFLAG_RD, &rl->stats.arg[x], 0, desc);
167538535d6cSHans Petter Selasky }
167638535d6cSHans Petter Selasky
16777272f9cdSHans Petter Selasky #else
16787272f9cdSHans Petter Selasky
16797272f9cdSHans Petter Selasky int
mlx5e_rl_init(struct mlx5e_priv * priv)16807272f9cdSHans Petter Selasky mlx5e_rl_init(struct mlx5e_priv *priv)
16817272f9cdSHans Petter Selasky {
16827272f9cdSHans Petter Selasky
16837272f9cdSHans Petter Selasky return (0);
16847272f9cdSHans Petter Selasky }
16857272f9cdSHans Petter Selasky
16867272f9cdSHans Petter Selasky void
mlx5e_rl_cleanup(struct mlx5e_priv * priv)16877272f9cdSHans Petter Selasky mlx5e_rl_cleanup(struct mlx5e_priv *priv)
16887272f9cdSHans Petter Selasky {
16897272f9cdSHans Petter Selasky /* NOP */
16907272f9cdSHans Petter Selasky }
16917272f9cdSHans Petter Selasky
16927272f9cdSHans Petter Selasky #endif /* RATELIMIT */
1693