xref: /freebsd/sys/dev/mlx5/mlx5_en/mlx5_en_rl.c (revision 95ee2897e98f5d444f26ed2334cc7c439f9c16c6)
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, &param->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