]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/mlx5/mlx5_en/mlx5_en_rl.c
MFS r353184, r353186, r353188, r353190, r353192, r353194, r353196, r353198,
[FreeBSD/FreeBSD.git] / sys / dev / mlx5 / mlx5_en / mlx5_en_rl.c
1 /*-
2  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  *
25  * $FreeBSD$
26  */
27
28 #include "en.h"
29
30 #ifdef RATELIMIT
31
32 static int mlx5e_rl_open_workers(struct mlx5e_priv *);
33 static void mlx5e_rl_close_workers(struct mlx5e_priv *);
34 static int mlx5e_rl_sysctl_show_rate_table(SYSCTL_HANDLER_ARGS);
35 static void mlx5e_rl_sysctl_add_u64_oid(struct mlx5e_rl_priv_data *, unsigned x,
36     struct sysctl_oid *, const char *name, const char *desc);
37 static void mlx5e_rl_sysctl_add_stats_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
38       struct sysctl_oid *node, const char *name, const char *desc);
39 static int mlx5e_rl_tx_limit_add(struct mlx5e_rl_priv_data *, uint64_t value);
40 static int mlx5e_rl_tx_limit_clr(struct mlx5e_rl_priv_data *, uint64_t value);
41
42 static void
43 mlx5e_rl_build_sq_param(struct mlx5e_rl_priv_data *rl,
44     struct mlx5e_sq_param *param)
45 {
46         void *sqc = param->sqc;
47         void *wq = MLX5_ADDR_OF(sqc, sqc, wq);
48         uint8_t log_sq_size = order_base_2(rl->param.tx_queue_size);
49
50         MLX5_SET(wq, wq, log_wq_sz, log_sq_size);
51         MLX5_SET(wq, wq, log_wq_stride, ilog2(MLX5_SEND_WQE_BB));
52         MLX5_SET(wq, wq, pd, rl->priv->pdn);
53
54         param->wq.buf_numa_node = 0;
55         param->wq.db_numa_node = 0;
56         param->wq.linear = 1;
57 }
58
59 static void
60 mlx5e_rl_build_cq_param(struct mlx5e_rl_priv_data *rl,
61     struct mlx5e_cq_param *param)
62 {
63         void *cqc = param->cqc;
64         uint8_t log_sq_size = order_base_2(rl->param.tx_queue_size);
65
66         MLX5_SET(cqc, cqc, log_cq_size, log_sq_size);
67         MLX5_SET(cqc, cqc, cq_period, rl->param.tx_coalesce_usecs);
68         MLX5_SET(cqc, cqc, cq_max_count, rl->param.tx_coalesce_pkts);
69
70         switch (rl->param.tx_coalesce_mode) {
71         case 0:
72                 MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
73                 break;
74         default:
75                 if (MLX5_CAP_GEN(rl->priv->mdev, cq_period_start_from_cqe))
76                         MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_CQE);
77                 else
78                         MLX5_SET(cqc, cqc, cq_period_mode, MLX5_CQ_PERIOD_MODE_START_FROM_EQE);
79                 break;
80         }
81 }
82
83 static void
84 mlx5e_rl_build_channel_param(struct mlx5e_rl_priv_data *rl,
85     struct mlx5e_rl_channel_param *cparam)
86 {
87         memset(cparam, 0, sizeof(*cparam));
88
89         mlx5e_rl_build_sq_param(rl, &cparam->sq);
90         mlx5e_rl_build_cq_param(rl, &cparam->cq);
91 }
92
93 static int
94 mlx5e_rl_create_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq,
95     struct mlx5e_sq_param *param, int ix)
96 {
97         struct mlx5_core_dev *mdev = priv->mdev;
98         void *sqc = param->sqc;
99         void *sqc_wq = MLX5_ADDR_OF(sqc, sqc, wq);
100         int err;
101
102         /* Create DMA descriptor TAG */
103         if ((err = -bus_dma_tag_create(
104             bus_get_dma_tag(mdev->pdev->dev.bsddev),
105             1,                          /* any alignment */
106             0,                          /* no boundary */
107             BUS_SPACE_MAXADDR,          /* lowaddr */
108             BUS_SPACE_MAXADDR,          /* highaddr */
109             NULL, NULL,                 /* filter, filterarg */
110             MLX5E_MAX_TX_PAYLOAD_SIZE,  /* maxsize */
111             MLX5E_MAX_TX_MBUF_FRAGS,    /* nsegments */
112             MLX5E_MAX_TX_MBUF_SIZE,     /* maxsegsize */
113             0,                          /* flags */
114             NULL, NULL,                 /* lockfunc, lockfuncarg */
115             &sq->dma_tag)))
116                 goto done;
117
118         /* use shared UAR */
119         sq->uar = priv->rl.sq_uar;
120
121         err = mlx5_wq_cyc_create(mdev, &param->wq, sqc_wq, &sq->wq,
122             &sq->wq_ctrl);
123         if (err)
124                 goto err_free_dma_tag;
125
126         sq->wq.db = &sq->wq.db[MLX5_SND_DBR];
127         /*
128          * The sq->bf_buf_size variable is intentionally left zero so
129          * that the doorbell writes will occur at the same memory
130          * location.
131          */
132
133         err = mlx5e_alloc_sq_db(sq);
134         if (err)
135                 goto err_sq_wq_destroy;
136
137         sq->mkey_be = cpu_to_be32(priv->mr.key);
138         sq->ifp = priv->ifp;
139         sq->priv = priv;
140
141         mlx5e_update_sq_inline(sq);
142
143         return (0);
144
145 err_sq_wq_destroy:
146         mlx5_wq_destroy(&sq->wq_ctrl);
147 err_free_dma_tag:
148         bus_dma_tag_destroy(sq->dma_tag);
149 done:
150         return (err);
151 }
152
153 static void
154 mlx5e_rl_destroy_sq(struct mlx5e_sq *sq)
155 {
156
157         mlx5e_free_sq_db(sq);
158         mlx5_wq_destroy(&sq->wq_ctrl);
159         bus_dma_tag_destroy(sq->dma_tag);
160 }
161
162 static int
163 mlx5e_rl_open_sq(struct mlx5e_priv *priv, struct mlx5e_sq *sq,
164     struct mlx5e_sq_param *param, int ix)
165 {
166         int err;
167
168         err = mlx5e_rl_create_sq(priv, sq, param, ix);
169         if (err)
170                 return (err);
171
172         err = mlx5e_enable_sq(sq, param, priv->rl.tisn);
173         if (err)
174                 goto err_destroy_sq;
175
176         err = mlx5e_modify_sq(sq, MLX5_SQC_STATE_RST, MLX5_SQC_STATE_RDY);
177         if (err)
178                 goto err_disable_sq;
179
180         WRITE_ONCE(sq->running, 1);
181
182         return (0);
183
184 err_disable_sq:
185         mlx5e_disable_sq(sq);
186 err_destroy_sq:
187         mlx5e_rl_destroy_sq(sq);
188
189         return (err);
190 }
191
192 static void
193 mlx5e_rl_chan_mtx_init(struct mlx5e_priv *priv, struct mlx5e_sq *sq)
194 {
195         mtx_init(&sq->lock, "mlx5tx-rl", NULL, MTX_DEF);
196         mtx_init(&sq->comp_lock, "mlx5comp-rl", NULL, MTX_DEF);
197
198         callout_init_mtx(&sq->cev_callout, &sq->lock, 0);
199
200         sq->cev_factor = priv->rl.param.tx_completion_fact;
201
202         /* ensure the TX completion event factor is not zero */
203         if (sq->cev_factor == 0)
204                 sq->cev_factor = 1;
205 }
206
207 static int
208 mlx5e_rl_open_channel(struct mlx5e_rl_worker *rlw, int eq_ix,
209     struct mlx5e_rl_channel_param *cparam,
210     struct mlx5e_sq *volatile *ppsq)
211 {
212         struct mlx5e_priv *priv = rlw->priv;
213         struct mlx5e_sq *sq;
214         int err;
215
216         sq = malloc(sizeof(*sq), M_MLX5EN, M_WAITOK | M_ZERO);
217
218         /* init mutexes */
219         mlx5e_rl_chan_mtx_init(priv, sq);
220
221         /* open TX completion queue */
222         err = mlx5e_open_cq(priv, &cparam->cq, &sq->cq,
223             &mlx5e_tx_cq_comp, eq_ix);
224         if (err)
225                 goto err_free;
226
227         err = mlx5e_rl_open_sq(priv, sq, &cparam->sq, eq_ix);
228         if (err)
229                 goto err_close_tx_cq;
230
231         /* store TX channel pointer */
232         *ppsq = sq;
233
234         /* poll TX queue initially */
235         sq->cq.mcq.comp(&sq->cq.mcq);
236
237         return (0);
238
239 err_close_tx_cq:
240         mlx5e_close_cq(&sq->cq);
241
242 err_free:
243         /* destroy mutexes */
244         mtx_destroy(&sq->lock);
245         mtx_destroy(&sq->comp_lock);
246         free(sq, M_MLX5EN);
247         atomic_add_64(&priv->rl.stats.tx_allocate_resource_failure, 1ULL);
248         return (err);
249 }
250
251 static void
252 mlx5e_rl_close_channel(struct mlx5e_sq *volatile *ppsq)
253 {
254         struct mlx5e_sq *sq = *ppsq;
255
256         /* check if channel is already closed */
257         if (sq == NULL)
258                 return;
259         /* ensure channel pointer is no longer used */
260         *ppsq = NULL;
261
262         /* teardown and destroy SQ */
263         mlx5e_drain_sq(sq);
264         mlx5e_disable_sq(sq);
265         mlx5e_rl_destroy_sq(sq);
266
267         /* close CQ */
268         mlx5e_close_cq(&sq->cq);
269
270         /* destroy mutexes */
271         mtx_destroy(&sq->lock);
272         mtx_destroy(&sq->comp_lock);
273
274         free(sq, M_MLX5EN);
275 }
276
277 static void
278 mlx5e_rl_sync_tx_completion_fact(struct mlx5e_rl_priv_data *rl)
279 {
280         /*
281          * Limit the maximum distance between completion events to
282          * half of the currently set TX queue size.
283          *
284          * The maximum number of queue entries a single IP packet can
285          * consume is given by MLX5_SEND_WQE_MAX_WQEBBS.
286          *
287          * The worst case max value is then given as below:
288          */
289         uint64_t max = rl->param.tx_queue_size /
290             (2 * MLX5_SEND_WQE_MAX_WQEBBS);
291
292         /*
293          * Update the maximum completion factor value in case the
294          * tx_queue_size field changed. Ensure we don't overflow
295          * 16-bits.
296          */
297         if (max < 1)
298                 max = 1;
299         else if (max > 65535)
300                 max = 65535;
301         rl->param.tx_completion_fact_max = max;
302
303         /*
304          * Verify that the current TX completion factor is within the
305          * given limits:
306          */
307         if (rl->param.tx_completion_fact < 1)
308                 rl->param.tx_completion_fact = 1;
309         else if (rl->param.tx_completion_fact > max)
310                 rl->param.tx_completion_fact = max;
311 }
312
313 static int
314 mlx5e_rl_modify_sq(struct mlx5e_sq *sq, uint16_t rl_index)
315 {
316         struct mlx5e_priv *priv = sq->priv;
317         struct mlx5_core_dev *mdev = priv->mdev;
318
319         void *in;
320         void *sqc;
321         int inlen;
322         int err;
323
324         inlen = MLX5_ST_SZ_BYTES(modify_sq_in);
325         in = mlx5_vzalloc(inlen);
326         if (in == NULL)
327                 return (-ENOMEM);
328
329         sqc = MLX5_ADDR_OF(modify_sq_in, in, ctx);
330
331         MLX5_SET(modify_sq_in, in, sqn, sq->sqn);
332         MLX5_SET(modify_sq_in, in, sq_state, MLX5_SQC_STATE_RDY);
333         MLX5_SET64(modify_sq_in, in, modify_bitmask, 1);
334         MLX5_SET(sqc, sqc, state, MLX5_SQC_STATE_RDY);
335         MLX5_SET(sqc, sqc, packet_pacing_rate_limit_index, rl_index);
336
337         err = mlx5_core_modify_sq(mdev, in, inlen);
338
339         kvfree(in);
340
341         return (err);
342 }
343
344 /*
345  * This function will search the configured rate limit table for the
346  * best match to avoid that a single socket based application can
347  * allocate all the available hardware rates. If the user selected
348  * rate deviates too much from the closes rate available in the rate
349  * limit table, unlimited rate will be selected.
350  */
351 static uint64_t
352 mlx5e_rl_find_best_rate_locked(struct mlx5e_rl_priv_data *rl, uint64_t user_rate)
353 {
354         uint64_t distance = -1ULL;
355         uint64_t diff;
356         uint64_t retval = 0;            /* unlimited */
357         uint64_t x;
358
359         /* search for closest rate */
360         for (x = 0; x != rl->param.tx_rates_def; x++) {
361                 uint64_t rate = rl->rate_limit_table[x];
362                 if (rate == 0)
363                         continue;
364
365                 if (rate > user_rate)
366                         diff = rate - user_rate;
367                 else
368                         diff = user_rate - rate;
369
370                 /* check if distance is smaller than previous rate */
371                 if (diff < distance) {
372                         distance = diff;
373                         retval = rate;
374                 }
375         }
376
377         /* range check for multiplication below */
378         if (user_rate > rl->param.tx_limit_max)
379                 user_rate = rl->param.tx_limit_max;
380
381         /* fallback to unlimited, if rate deviates too much */
382         if (distance > howmany(user_rate *
383             rl->param.tx_allowed_deviation, 1000ULL))
384                 retval = 0;
385
386         return (retval);
387 }
388
389 /*
390  * This function sets the requested rate for a rate limit channel, in
391  * bits per second. The requested rate will be filtered through the
392  * find best rate function above.
393  */
394 static int
395 mlx5e_rlw_channel_set_rate_locked(struct mlx5e_rl_worker *rlw,
396     struct mlx5e_rl_channel *channel, uint64_t rate)
397 {
398         struct mlx5e_rl_priv_data *rl = &rlw->priv->rl;
399         struct mlx5e_sq *sq;
400         uint64_t temp;
401         uint16_t index;
402         uint16_t burst;
403         int error;
404
405         if (rate != 0) {
406                 MLX5E_RL_WORKER_UNLOCK(rlw);
407
408                 MLX5E_RL_RLOCK(rl);
409
410                 /* get current burst size in bytes */
411                 temp = rl->param.tx_burst_size *
412                     MLX5E_SW2HW_MTU(rlw->priv->ifp->if_mtu);
413
414                 /* limit burst size to 64K currently */
415                 if (temp > 65535)
416                         temp = 65535;
417                 burst = temp;
418
419                 /* find best rate */
420                 rate = mlx5e_rl_find_best_rate_locked(rl, rate);
421
422                 MLX5E_RL_RUNLOCK(rl);
423
424                 if (rate == 0) {
425                         /* rate doesn't exist, fallback to unlimited */
426                         index = 0;
427                         rate = 0;
428                         atomic_add_64(&rlw->priv->rl.stats.tx_modify_rate_failure, 1ULL);
429                 } else {
430                         /* get a reference on the new rate */
431                         error = -mlx5_rl_add_rate(rlw->priv->mdev,
432                             howmany(rate, 1000), burst, &index);
433
434                         if (error != 0) {
435                                 /* adding rate failed, fallback to unlimited */
436                                 index = 0;
437                                 rate = 0;
438                                 atomic_add_64(&rlw->priv->rl.stats.tx_add_new_rate_failure, 1ULL);
439                         }
440                 }
441                 MLX5E_RL_WORKER_LOCK(rlw);
442         } else {
443                 index = 0;
444                 burst = 0;      /* default */
445         }
446
447         /* atomically swap rates */
448         temp = channel->last_rate;
449         channel->last_rate = rate;
450         rate = temp;
451
452         /* atomically swap burst size */
453         temp = channel->last_burst;
454         channel->last_burst = burst;
455         burst = temp;
456
457         MLX5E_RL_WORKER_UNLOCK(rlw);
458         /* put reference on the old rate, if any */
459         if (rate != 0) {
460                 mlx5_rl_remove_rate(rlw->priv->mdev,
461                     howmany(rate, 1000), burst);
462         }
463
464         /* set new rate, if SQ is running */
465         sq = channel->sq;
466         if (sq != NULL && READ_ONCE(sq->running) != 0) {
467                 error = mlx5e_rl_modify_sq(sq, index);
468                 if (error != 0)
469                         atomic_add_64(&rlw->priv->rl.stats.tx_modify_rate_failure, 1ULL);
470         } else
471                 error = 0;
472         MLX5E_RL_WORKER_LOCK(rlw);
473
474         return (-error);
475 }
476
477 static void
478 mlx5e_rl_worker(void *arg)
479 {
480         struct thread *td;
481         struct mlx5e_rl_worker *rlw = arg;
482         struct mlx5e_rl_channel *channel;
483         struct mlx5e_priv *priv;
484         unsigned ix;
485         uint64_t x;
486         int error;
487
488         /* set thread priority */
489         td = curthread;
490
491         thread_lock(td);
492         sched_prio(td, PI_SWI(SWI_NET));
493         thread_unlock(td);
494
495         priv = rlw->priv;
496
497         /* compute completion vector */
498         ix = (rlw - priv->rl.workers) %
499             priv->mdev->priv.eq_table.num_comp_vectors;
500
501         /* TODO bind to CPU */
502
503         /* open all the SQs */
504         MLX5E_RL_WORKER_LOCK(rlw);
505         for (x = 0; x < priv->rl.param.tx_channels_per_worker_def; x++) {
506                 struct mlx5e_rl_channel *channel = rlw->channels + x;
507
508 #if !defined(HAVE_RL_PRE_ALLOCATE_CHANNELS)
509                 if (channel->state == MLX5E_RL_ST_FREE)
510                         continue;
511 #endif
512                 MLX5E_RL_WORKER_UNLOCK(rlw);
513
514                 MLX5E_RL_RLOCK(&priv->rl);
515                 error = mlx5e_rl_open_channel(rlw, ix,
516                     &priv->rl.chan_param, &channel->sq);
517                 MLX5E_RL_RUNLOCK(&priv->rl);
518
519                 MLX5E_RL_WORKER_LOCK(rlw);
520                 if (error != 0) {
521                         mlx5_en_err(priv->ifp,
522                             "mlx5e_rl_open_channel failed: %d\n", error);
523                         break;
524                 }
525                 mlx5e_rlw_channel_set_rate_locked(rlw, channel, channel->init_rate);
526         }
527         while (1) {
528                 if (STAILQ_FIRST(&rlw->process_head) == NULL) {
529                         /* check if we are tearing down */
530                         if (rlw->worker_done != 0)
531                                 break;
532                         cv_wait(&rlw->cv, &rlw->mtx);
533                 }
534                 /* check if we are tearing down */
535                 if (rlw->worker_done != 0)
536                         break;
537                 channel = STAILQ_FIRST(&rlw->process_head);
538                 if (channel != NULL) {
539                         STAILQ_REMOVE_HEAD(&rlw->process_head, entry);
540
541                         switch (channel->state) {
542                         case MLX5E_RL_ST_MODIFY:
543                                 channel->state = MLX5E_RL_ST_USED;
544                                 MLX5E_RL_WORKER_UNLOCK(rlw);
545
546                                 /* create channel by demand */
547                                 if (channel->sq == NULL) {
548                                         MLX5E_RL_RLOCK(&priv->rl);
549                                         error = mlx5e_rl_open_channel(rlw, ix,
550                                             &priv->rl.chan_param, &channel->sq);
551                                         MLX5E_RL_RUNLOCK(&priv->rl);
552
553                                         if (error != 0) {
554                                                 mlx5_en_err(priv->ifp,
555                                                     "mlx5e_rl_open_channel failed: %d\n", error);
556                                         } else {
557                                                 atomic_add_64(&rlw->priv->rl.stats.tx_open_queues, 1ULL);
558                                         }
559                                 } else {
560                                         mlx5e_resume_sq(channel->sq);
561                                 }
562
563                                 MLX5E_RL_WORKER_LOCK(rlw);
564                                 /* convert from bytes/s to bits/s and set new rate */
565                                 error = mlx5e_rlw_channel_set_rate_locked(rlw, channel,
566                                     channel->new_rate * 8ULL);
567                                 if (error != 0) {
568                                         mlx5_en_err(priv->ifp,
569                                             "mlx5e_rlw_channel_set_rate_locked failed: %d\n",
570                                             error);
571                                 }
572                                 break;
573
574                         case MLX5E_RL_ST_DESTROY:
575                                 error = mlx5e_rlw_channel_set_rate_locked(rlw, channel, 0);
576                                 if (error != 0) {
577                                         mlx5_en_err(priv->ifp,
578                                             "mlx5e_rlw_channel_set_rate_locked failed: %d\n",
579                                             error);
580                                 }
581                                 if (channel->sq != NULL) {
582                                         /*
583                                          * Make sure all packets are
584                                          * transmitted before SQ is
585                                          * returned to free list:
586                                          */
587                                         MLX5E_RL_WORKER_UNLOCK(rlw);
588                                         mlx5e_drain_sq(channel->sq);
589                                         MLX5E_RL_WORKER_LOCK(rlw);
590                                 }
591                                 /* put the channel back into the free list */
592                                 STAILQ_INSERT_HEAD(&rlw->index_list_head, channel, entry);
593                                 channel->state = MLX5E_RL_ST_FREE;
594                                 atomic_add_64(&priv->rl.stats.tx_active_connections, -1ULL);
595                                 break;
596                         default:
597                                 /* NOP */
598                                 break;
599                         }
600                 }
601         }
602
603         /* close all the SQs */
604         for (x = 0; x < priv->rl.param.tx_channels_per_worker_def; x++) {
605                 struct mlx5e_rl_channel *channel = rlw->channels + x;
606
607                 /* update the initial rate */
608                 channel->init_rate = channel->last_rate;
609
610                 /* make sure we free up the rate resource */
611                 mlx5e_rlw_channel_set_rate_locked(rlw, channel, 0);
612
613                 if (channel->sq != NULL) {
614                         MLX5E_RL_WORKER_UNLOCK(rlw);
615                         mlx5e_rl_close_channel(&channel->sq);
616                         atomic_add_64(&rlw->priv->rl.stats.tx_open_queues, -1ULL);
617                         MLX5E_RL_WORKER_LOCK(rlw);
618                 }
619         }
620
621         rlw->worker_done = 0;
622         cv_broadcast(&rlw->cv);
623         MLX5E_RL_WORKER_UNLOCK(rlw);
624
625         kthread_exit();
626 }
627
628 static int
629 mlx5e_rl_open_tis(struct mlx5e_priv *priv)
630 {
631         struct mlx5_core_dev *mdev = priv->mdev;
632         u32 in[MLX5_ST_SZ_DW(create_tis_in)];
633         void *tisc = MLX5_ADDR_OF(create_tis_in, in, ctx);
634
635         memset(in, 0, sizeof(in));
636
637         MLX5_SET(tisc, tisc, prio, 0);
638         MLX5_SET(tisc, tisc, transport_domain, priv->tdn);
639
640         return (mlx5_core_create_tis(mdev, in, sizeof(in), &priv->rl.tisn));
641 }
642
643 static void
644 mlx5e_rl_close_tis(struct mlx5e_priv *priv)
645 {
646         mlx5_core_destroy_tis(priv->mdev, priv->rl.tisn);
647 }
648
649 static void
650 mlx5e_rl_set_default_params(struct mlx5e_rl_params *param,
651     struct mlx5_core_dev *mdev)
652 {
653         /* ratelimit workers */
654         param->tx_worker_threads_def = mdev->priv.eq_table.num_comp_vectors;
655         param->tx_worker_threads_max = MLX5E_RL_MAX_WORKERS;
656
657         /* range check */
658         if (param->tx_worker_threads_def == 0 ||
659             param->tx_worker_threads_def > param->tx_worker_threads_max)
660                 param->tx_worker_threads_def = param->tx_worker_threads_max;
661
662         /* ratelimit channels */
663         param->tx_channels_per_worker_def = MLX5E_RL_MAX_SQS /
664             param->tx_worker_threads_def;
665         param->tx_channels_per_worker_max = MLX5E_RL_MAX_SQS;
666
667         /* range check */
668         if (param->tx_channels_per_worker_def > MLX5E_RL_DEF_SQ_PER_WORKER)
669                 param->tx_channels_per_worker_def = MLX5E_RL_DEF_SQ_PER_WORKER;
670
671         /* set default burst size */
672         param->tx_burst_size = 4;       /* MTUs */
673
674         /*
675          * Set maximum burst size
676          *
677          * The burst size is multiplied by the MTU and clamped to the
678          * range 0 ... 65535 bytes inclusivly before fed into the
679          * firmware.
680          *
681          * NOTE: If the burst size or MTU is changed only ratelimit
682          * connections made after the change will use the new burst
683          * size.
684          */
685         param->tx_burst_size_max = 255;
686
687         /* get firmware rate limits in 1000bit/s and convert them to bit/s */
688         param->tx_limit_min = mdev->priv.rl_table.min_rate * 1000ULL;
689         param->tx_limit_max = mdev->priv.rl_table.max_rate * 1000ULL;
690
691         /* ratelimit table size */
692         param->tx_rates_max = mdev->priv.rl_table.max_size;
693
694         /* range check */
695         if (param->tx_rates_max > MLX5E_RL_MAX_TX_RATES)
696                 param->tx_rates_max = MLX5E_RL_MAX_TX_RATES;
697
698         /* set default number of rates */
699         param->tx_rates_def = param->tx_rates_max;
700
701         /* set maximum allowed rate deviation */
702         if (param->tx_limit_max != 0) {
703                 /*
704                  * Make sure the deviation multiplication doesn't
705                  * overflow unsigned 64-bit:
706                  */
707                 param->tx_allowed_deviation_max = -1ULL /
708                     param->tx_limit_max;
709         }
710         /* set default rate deviation */
711         param->tx_allowed_deviation = 50;       /* 5.0% */
712
713         /* channel parameters */
714         param->tx_queue_size = (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
715         param->tx_coalesce_usecs = MLX5E_RL_TX_COAL_USEC_DEFAULT;
716         param->tx_coalesce_pkts = MLX5E_RL_TX_COAL_PKTS_DEFAULT;
717         param->tx_coalesce_mode = MLX5E_RL_TX_COAL_MODE_DEFAULT;
718         param->tx_completion_fact = MLX5E_RL_TX_COMP_FACT_DEFAULT;
719 }
720
721 static const char *mlx5e_rl_params_desc[] = {
722         MLX5E_RL_PARAMS(MLX5E_STATS_DESC)
723 };
724
725 static const char *mlx5e_rl_table_params_desc[] = {
726         MLX5E_RL_TABLE_PARAMS(MLX5E_STATS_DESC)
727 };
728
729 static const char *mlx5e_rl_stats_desc[] = {
730         MLX5E_RL_STATS(MLX5E_STATS_DESC)
731 };
732
733 int
734 mlx5e_rl_init(struct mlx5e_priv *priv)
735 {
736         struct mlx5e_rl_priv_data *rl = &priv->rl;
737         struct sysctl_oid *node;
738         struct sysctl_oid *stats;
739         char buf[64];
740         uint64_t i;
741         uint64_t j;
742         int error;
743
744         /* check if there is support for packet pacing */
745         if (!MLX5_CAP_GEN(priv->mdev, qos) || !MLX5_CAP_QOS(priv->mdev, packet_pacing))
746                 return (0);
747
748         rl->priv = priv;
749
750         sysctl_ctx_init(&rl->ctx);
751
752         sx_init(&rl->rl_sxlock, "ratelimit-sxlock");
753
754         /* allocate shared UAR for SQs */
755         error = mlx5_alloc_map_uar(priv->mdev, &rl->sq_uar);
756         if (error)
757                 goto done;
758
759         /* open own TIS domain for ratelimit SQs */
760         error = mlx5e_rl_open_tis(priv);
761         if (error)
762                 goto err_uar;
763
764         /* setup default value for parameters */
765         mlx5e_rl_set_default_params(&rl->param, priv->mdev);
766
767         /* update the completion factor */
768         mlx5e_rl_sync_tx_completion_fact(rl);
769
770         /* create root node */
771         node = SYSCTL_ADD_NODE(&rl->ctx,
772             SYSCTL_CHILDREN(priv->sysctl_ifnet), OID_AUTO,
773             "rate_limit", CTLFLAG_RW, NULL, "Rate limiting support");
774
775         if (node != NULL) {
776                 /* create SYSCTLs */
777                 for (i = 0; i != MLX5E_RL_PARAMS_NUM; i++) {
778                         mlx5e_rl_sysctl_add_u64_oid(rl,
779                             MLX5E_RL_PARAMS_INDEX(arg[i]),
780                             node, mlx5e_rl_params_desc[2 * i],
781                             mlx5e_rl_params_desc[2 * i + 1]);
782                 }
783
784                 stats = SYSCTL_ADD_NODE(&rl->ctx, SYSCTL_CHILDREN(node),
785                     OID_AUTO, "stats", CTLFLAG_RD, NULL,
786                     "Rate limiting statistics");
787                 if (stats != NULL) {
788                         /* create SYSCTLs */
789                         for (i = 0; i != MLX5E_RL_STATS_NUM; i++) {
790                                 mlx5e_rl_sysctl_add_stats_u64_oid(rl, i,
791                                     stats, mlx5e_rl_stats_desc[2 * i],
792                                     mlx5e_rl_stats_desc[2 * i + 1]);
793                         }
794                 }
795         }
796
797         /* allocate workers array */
798         rl->workers = malloc(sizeof(rl->workers[0]) *
799             rl->param.tx_worker_threads_def, M_MLX5EN, M_WAITOK | M_ZERO);
800
801         /* allocate rate limit array */
802         rl->rate_limit_table = malloc(sizeof(rl->rate_limit_table[0]) *
803             rl->param.tx_rates_def, M_MLX5EN, M_WAITOK | M_ZERO);
804
805         if (node != NULL) {
806                 /* create more SYSCTls */
807                 SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
808                     "tx_rate_show", CTLTYPE_STRING | CTLFLAG_RD |
809                     CTLFLAG_MPSAFE, rl, 0, &mlx5e_rl_sysctl_show_rate_table,
810                     "A", "Show table of all configured TX rates");
811
812                 /* try to fetch rate table from kernel environment */
813                 for (i = 0; i != rl->param.tx_rates_def; i++) {
814                         /* compute path for tunable */
815                         snprintf(buf, sizeof(buf), "dev.mce.%d.rate_limit.tx_rate_add_%d",
816                             device_get_unit(priv->mdev->pdev->dev.bsddev), (int)i);
817                         if (TUNABLE_QUAD_FETCH(buf, &j))
818                                 mlx5e_rl_tx_limit_add(rl, j);
819                 }
820
821                 /* setup rate table sysctls */
822                 for (i = 0; i != MLX5E_RL_TABLE_PARAMS_NUM; i++) {
823                         mlx5e_rl_sysctl_add_u64_oid(rl,
824                             MLX5E_RL_PARAMS_INDEX(table_arg[i]),
825                             node, mlx5e_rl_table_params_desc[2 * i],
826                             mlx5e_rl_table_params_desc[2 * i + 1]);
827                 }
828         }
829
830         for (j = 0; j < rl->param.tx_worker_threads_def; j++) {
831                 struct mlx5e_rl_worker *rlw = rl->workers + j;
832
833                 rlw->priv = priv;
834
835                 cv_init(&rlw->cv, "mlx5-worker-cv");
836                 mtx_init(&rlw->mtx, "mlx5-worker-mtx", NULL, MTX_DEF);
837                 STAILQ_INIT(&rlw->index_list_head);
838                 STAILQ_INIT(&rlw->process_head);
839
840                 rlw->channels = malloc(sizeof(rlw->channels[0]) *
841                     rl->param.tx_channels_per_worker_def, M_MLX5EN, M_WAITOK | M_ZERO);
842
843                 MLX5E_RL_WORKER_LOCK(rlw);
844                 for (i = 0; i < rl->param.tx_channels_per_worker_def; i++) {
845                         struct mlx5e_rl_channel *channel = rlw->channels + i;
846                         channel->worker = rlw;
847                         channel->tag.m_snd_tag.ifp = priv->ifp;
848                         channel->tag.type = IF_SND_TAG_TYPE_RATE_LIMIT;
849                         STAILQ_INSERT_TAIL(&rlw->index_list_head, channel, entry);
850                 }
851                 MLX5E_RL_WORKER_UNLOCK(rlw);
852         }
853
854         PRIV_LOCK(priv);
855         error = mlx5e_rl_open_workers(priv);
856         PRIV_UNLOCK(priv);
857
858         if (error != 0) {
859                 mlx5_en_err(priv->ifp,
860                     "mlx5e_rl_open_workers failed: %d\n", error);
861         }
862
863         return (0);
864
865 err_uar:
866         mlx5_unmap_free_uar(priv->mdev, &rl->sq_uar);
867 done:
868         sysctl_ctx_free(&rl->ctx);
869         sx_destroy(&rl->rl_sxlock);
870         return (error);
871 }
872
873 static int
874 mlx5e_rl_open_workers(struct mlx5e_priv *priv)
875 {
876         struct mlx5e_rl_priv_data *rl = &priv->rl;
877         struct thread *rl_thread = NULL;
878         struct proc *rl_proc = NULL;
879         uint64_t j;
880         int error;
881
882         if (priv->gone || rl->opened)
883                 return (-EINVAL);
884
885         MLX5E_RL_WLOCK(rl);
886         /* compute channel parameters once */
887         mlx5e_rl_build_channel_param(rl, &rl->chan_param);
888         MLX5E_RL_WUNLOCK(rl);
889
890         for (j = 0; j < rl->param.tx_worker_threads_def; j++) {
891                 struct mlx5e_rl_worker *rlw = rl->workers + j;
892
893                 /* start worker thread */
894                 error = kproc_kthread_add(mlx5e_rl_worker, rlw, &rl_proc, &rl_thread,
895                     RFHIGHPID, 0, "mlx5-ratelimit", "mlx5-rl-worker-thread-%d", (int)j);
896                 if (error != 0) {
897                         mlx5_en_err(rl->priv->ifp,
898                             "kproc_kthread_add failed: %d\n", error);
899                         rlw->worker_done = 1;
900                 }
901         }
902
903         rl->opened = 1;
904
905         return (0);
906 }
907
908 static void
909 mlx5e_rl_close_workers(struct mlx5e_priv *priv)
910 {
911         struct mlx5e_rl_priv_data *rl = &priv->rl;
912         uint64_t y;
913
914         if (rl->opened == 0)
915                 return;
916
917         /* tear down worker threads simultaneously */
918         for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
919                 struct mlx5e_rl_worker *rlw = rl->workers + y;
920
921                 /* tear down worker before freeing SQs */
922                 MLX5E_RL_WORKER_LOCK(rlw);
923                 if (rlw->worker_done == 0) {
924                         rlw->worker_done = 1;
925                         cv_broadcast(&rlw->cv);
926                 } else {
927                         /* XXX thread not started */
928                         rlw->worker_done = 0;
929                 }
930                 MLX5E_RL_WORKER_UNLOCK(rlw);
931         }
932
933         /* wait for worker threads to exit */
934         for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
935                 struct mlx5e_rl_worker *rlw = rl->workers + y;
936
937                 /* tear down worker before freeing SQs */
938                 MLX5E_RL_WORKER_LOCK(rlw);
939                 while (rlw->worker_done != 0)
940                         cv_wait(&rlw->cv, &rlw->mtx);
941                 MLX5E_RL_WORKER_UNLOCK(rlw);
942         }
943
944         rl->opened = 0;
945 }
946
947 static void
948 mlx5e_rl_reset_rates(struct mlx5e_rl_priv_data *rl)
949 {
950         unsigned x;
951
952         MLX5E_RL_WLOCK(rl);
953         for (x = 0; x != rl->param.tx_rates_def; x++)
954                 rl->rate_limit_table[x] = 0;
955         MLX5E_RL_WUNLOCK(rl);
956 }
957
958 void
959 mlx5e_rl_cleanup(struct mlx5e_priv *priv)
960 {
961         struct mlx5e_rl_priv_data *rl = &priv->rl;
962         uint64_t y;
963
964         /* check if there is support for packet pacing */
965         if (!MLX5_CAP_GEN(priv->mdev, qos) || !MLX5_CAP_QOS(priv->mdev, packet_pacing))
966                 return;
967
968         /* TODO check if there is support for packet pacing */
969
970         sysctl_ctx_free(&rl->ctx);
971
972         PRIV_LOCK(priv);
973         mlx5e_rl_close_workers(priv);
974         PRIV_UNLOCK(priv);
975
976         mlx5e_rl_reset_rates(rl);
977
978         /* free shared UAR for SQs */
979         mlx5_unmap_free_uar(priv->mdev, &rl->sq_uar);
980
981         /* close TIS domain */
982         mlx5e_rl_close_tis(priv);
983
984         for (y = 0; y < rl->param.tx_worker_threads_def; y++) {
985                 struct mlx5e_rl_worker *rlw = rl->workers + y;
986
987                 cv_destroy(&rlw->cv);
988                 mtx_destroy(&rlw->mtx);
989                 free(rlw->channels, M_MLX5EN);
990         }
991         free(rl->rate_limit_table, M_MLX5EN);
992         free(rl->workers, M_MLX5EN);
993         sx_destroy(&rl->rl_sxlock);
994 }
995
996 static void
997 mlx5e_rlw_queue_channel_locked(struct mlx5e_rl_worker *rlw,
998     struct mlx5e_rl_channel *channel)
999 {
1000         STAILQ_INSERT_TAIL(&rlw->process_head, channel, entry);
1001         cv_broadcast(&rlw->cv);
1002 }
1003
1004 static void
1005 mlx5e_rl_free(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel)
1006 {
1007         if (channel == NULL)
1008                 return;
1009
1010         MLX5E_RL_WORKER_LOCK(rlw);
1011         switch (channel->state) {
1012         case MLX5E_RL_ST_MODIFY:
1013                 channel->state = MLX5E_RL_ST_DESTROY;
1014                 break;
1015         case MLX5E_RL_ST_USED:
1016                 channel->state = MLX5E_RL_ST_DESTROY;
1017                 mlx5e_rlw_queue_channel_locked(rlw, channel);
1018                 break;
1019         default:
1020                 break;
1021         }
1022         MLX5E_RL_WORKER_UNLOCK(rlw);
1023 }
1024
1025 static int
1026 mlx5e_rl_modify(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel, uint64_t rate)
1027 {
1028
1029         MLX5E_RL_WORKER_LOCK(rlw);
1030         channel->new_rate = rate;
1031         switch (channel->state) {
1032         case MLX5E_RL_ST_USED:
1033                 channel->state = MLX5E_RL_ST_MODIFY;
1034                 mlx5e_rlw_queue_channel_locked(rlw, channel);
1035                 break;
1036         default:
1037                 break;
1038         }
1039         MLX5E_RL_WORKER_UNLOCK(rlw);
1040
1041         return (0);
1042 }
1043
1044 static int
1045 mlx5e_rl_query(struct mlx5e_rl_worker *rlw, struct mlx5e_rl_channel *channel,
1046     union if_snd_tag_query_params *params)
1047 {
1048         int retval;
1049
1050         MLX5E_RL_WORKER_LOCK(rlw);
1051         switch (channel->state) {
1052         case MLX5E_RL_ST_USED:
1053                 params->rate_limit.max_rate = channel->last_rate;
1054                 params->rate_limit.queue_level = mlx5e_sq_queue_level(channel->sq);
1055                 retval = 0;
1056                 break;
1057         case MLX5E_RL_ST_MODIFY:
1058                 params->rate_limit.max_rate = channel->last_rate;
1059                 params->rate_limit.queue_level = mlx5e_sq_queue_level(channel->sq);
1060                 retval = EBUSY;
1061                 break;
1062         default:
1063                 retval = EINVAL;
1064                 break;
1065         }
1066         MLX5E_RL_WORKER_UNLOCK(rlw);
1067
1068         return (retval);
1069 }
1070
1071 static int
1072 mlx5e_find_available_tx_ring_index(struct mlx5e_rl_worker *rlw,
1073     struct mlx5e_rl_channel **pchannel)
1074 {
1075         struct mlx5e_rl_channel *channel;
1076         int retval = ENOMEM;
1077
1078         MLX5E_RL_WORKER_LOCK(rlw);
1079         /* Check for available channel in free list */
1080         if ((channel = STAILQ_FIRST(&rlw->index_list_head)) != NULL) {
1081                 retval = 0;
1082                 /* Remove head index from available list */
1083                 STAILQ_REMOVE_HEAD(&rlw->index_list_head, entry);
1084                 channel->state = MLX5E_RL_ST_USED;
1085                 atomic_add_64(&rlw->priv->rl.stats.tx_active_connections, 1ULL);
1086         } else {
1087                 atomic_add_64(&rlw->priv->rl.stats.tx_available_resource_failure, 1ULL);
1088         }
1089         MLX5E_RL_WORKER_UNLOCK(rlw);
1090
1091         *pchannel = channel;
1092 #ifdef RATELIMIT_DEBUG
1093         mlx5_en_info(rlw->priv->ifp,
1094             "Channel pointer for rate limit connection is %p\n", channel);
1095 #endif
1096         return (retval);
1097 }
1098
1099 int
1100 mlx5e_rl_snd_tag_alloc(struct ifnet *ifp,
1101     union if_snd_tag_alloc_params *params,
1102     struct m_snd_tag **ppmt)
1103 {
1104         struct mlx5e_rl_channel *channel;
1105         struct mlx5e_rl_worker *rlw;
1106         struct mlx5e_priv *priv;
1107         int error;
1108
1109         priv = ifp->if_softc;
1110
1111         /* check if there is support for packet pacing or if device is going away */
1112         if (!MLX5_CAP_GEN(priv->mdev, qos) ||
1113             !MLX5_CAP_QOS(priv->mdev, packet_pacing) || priv->gone ||
1114             params->rate_limit.hdr.type != IF_SND_TAG_TYPE_RATE_LIMIT)
1115                 return (EOPNOTSUPP);
1116
1117         /* compute worker thread this TCP connection belongs to */
1118         rlw = priv->rl.workers + ((params->rate_limit.hdr.flowid % 128) %
1119             priv->rl.param.tx_worker_threads_def);
1120
1121         error = mlx5e_find_available_tx_ring_index(rlw, &channel);
1122         if (error != 0)
1123                 goto done;
1124
1125         error = mlx5e_rl_modify(rlw, channel, params->rate_limit.max_rate);
1126         if (error != 0) {
1127                 mlx5e_rl_free(rlw, channel);
1128                 goto done;
1129         }
1130
1131         /* store pointer to mbuf tag */
1132         *ppmt = &channel->tag.m_snd_tag;
1133 done:
1134         return (error);
1135 }
1136
1137
1138 int
1139 mlx5e_rl_snd_tag_modify(struct m_snd_tag *pmt, union if_snd_tag_modify_params *params)
1140 {
1141         struct mlx5e_rl_channel *channel =
1142             container_of(pmt, struct mlx5e_rl_channel, tag.m_snd_tag);
1143
1144         return (mlx5e_rl_modify(channel->worker, channel, params->rate_limit.max_rate));
1145 }
1146
1147 int
1148 mlx5e_rl_snd_tag_query(struct m_snd_tag *pmt, union if_snd_tag_query_params *params)
1149 {
1150         struct mlx5e_rl_channel *channel =
1151             container_of(pmt, struct mlx5e_rl_channel, tag.m_snd_tag);
1152
1153         return (mlx5e_rl_query(channel->worker, channel, params));
1154 }
1155
1156 void
1157 mlx5e_rl_snd_tag_free(struct m_snd_tag *pmt)
1158 {
1159         struct mlx5e_rl_channel *channel =
1160             container_of(pmt, struct mlx5e_rl_channel, tag.m_snd_tag);
1161
1162         mlx5e_rl_free(channel->worker, channel);
1163 }
1164
1165 static int
1166 mlx5e_rl_sysctl_show_rate_table(SYSCTL_HANDLER_ARGS)
1167 {
1168         struct mlx5e_rl_priv_data *rl = arg1;
1169         struct mlx5e_priv *priv = rl->priv;
1170         struct sbuf sbuf;
1171         unsigned x;
1172         int error;
1173
1174         error = sysctl_wire_old_buffer(req, 0);
1175         if (error != 0)
1176                 return (error);
1177
1178         PRIV_LOCK(priv);
1179
1180         sbuf_new_for_sysctl(&sbuf, NULL, 128 * rl->param.tx_rates_def, req);
1181
1182         sbuf_printf(&sbuf,
1183             "\n\n" "\t" "ENTRY" "\t" "BURST" "\t" "RATE [bit/s]\n"
1184             "\t" "--------------------------------------------\n");
1185
1186         MLX5E_RL_RLOCK(rl);
1187         for (x = 0; x != rl->param.tx_rates_def; x++) {
1188                 if (rl->rate_limit_table[x] == 0)
1189                         continue;
1190
1191                 sbuf_printf(&sbuf, "\t" "%3u" "\t" "%3u" "\t" "%lld\n",
1192                     x, (unsigned)rl->param.tx_burst_size,
1193                     (long long)rl->rate_limit_table[x]);
1194         }
1195         MLX5E_RL_RUNLOCK(rl);
1196
1197         error = sbuf_finish(&sbuf);
1198         sbuf_delete(&sbuf);
1199
1200         PRIV_UNLOCK(priv);
1201
1202         return (error);
1203 }
1204
1205 static int
1206 mlx5e_rl_refresh_channel_params(struct mlx5e_rl_priv_data *rl)
1207 {
1208         uint64_t x;
1209         uint64_t y;
1210
1211         MLX5E_RL_WLOCK(rl);
1212         /* compute channel parameters once */
1213         mlx5e_rl_build_channel_param(rl, &rl->chan_param);
1214         MLX5E_RL_WUNLOCK(rl);
1215
1216         for (y = 0; y != rl->param.tx_worker_threads_def; y++) {
1217                 struct mlx5e_rl_worker *rlw = rl->workers + y;
1218
1219                 for (x = 0; x != rl->param.tx_channels_per_worker_def; x++) {
1220                         struct mlx5e_rl_channel *channel;
1221                         struct mlx5e_sq *sq;
1222
1223                         channel = rlw->channels + x;
1224                         sq = channel->sq;
1225
1226                         if (sq == NULL)
1227                                 continue;
1228
1229                         if (MLX5_CAP_GEN(rl->priv->mdev, cq_period_mode_modify)) {
1230                                 mlx5_core_modify_cq_moderation_mode(rl->priv->mdev, &sq->cq.mcq,
1231                                     rl->param.tx_coalesce_usecs,
1232                                     rl->param.tx_coalesce_pkts,
1233                                     rl->param.tx_coalesce_mode);
1234                         } else {
1235                                 mlx5_core_modify_cq_moderation(rl->priv->mdev, &sq->cq.mcq,
1236                                     rl->param.tx_coalesce_usecs,
1237                                     rl->param.tx_coalesce_pkts);
1238                         }
1239                 }
1240         }
1241         return (0);
1242 }
1243
1244 void
1245 mlx5e_rl_refresh_sq_inline(struct mlx5e_rl_priv_data *rl)
1246 {
1247         uint64_t x;
1248         uint64_t y;
1249
1250         for (y = 0; y != rl->param.tx_worker_threads_def; y++) {
1251                 struct mlx5e_rl_worker *rlw = rl->workers + y;
1252
1253                 for (x = 0; x != rl->param.tx_channels_per_worker_def; x++) {
1254                         struct mlx5e_rl_channel *channel;
1255                         struct mlx5e_sq *sq;
1256
1257                         channel = rlw->channels + x;
1258                         sq = channel->sq;
1259
1260                         if (sq == NULL)
1261                                 continue;
1262
1263                         mtx_lock(&sq->lock);
1264                         mlx5e_update_sq_inline(sq);
1265                         mtx_unlock(&sq->lock);
1266                 }
1267         }
1268 }
1269
1270 static int
1271 mlx5e_rl_tx_limit_add(struct mlx5e_rl_priv_data *rl, uint64_t value)
1272 {
1273         unsigned x;
1274         int error;
1275
1276         if (value < 1000 ||
1277             mlx5_rl_is_in_range(rl->priv->mdev, howmany(value, 1000), 0) == 0)
1278                 return (EINVAL);
1279
1280         MLX5E_RL_WLOCK(rl);
1281         error = ENOMEM;
1282
1283         /* check if rate already exists */
1284         for (x = 0; x != rl->param.tx_rates_def; x++) {
1285                 if (rl->rate_limit_table[x] != value)
1286                         continue;
1287                 error = EEXIST;
1288                 break;
1289         }
1290
1291         /* check if there is a free rate entry */
1292         if (x == rl->param.tx_rates_def) {
1293                 for (x = 0; x != rl->param.tx_rates_def; x++) {
1294                         if (rl->rate_limit_table[x] != 0)
1295                                 continue;
1296                         rl->rate_limit_table[x] = value;
1297                         error = 0;
1298                         break;
1299                 }
1300         }
1301         MLX5E_RL_WUNLOCK(rl);
1302
1303         return (error);
1304 }
1305
1306 static int
1307 mlx5e_rl_tx_limit_clr(struct mlx5e_rl_priv_data *rl, uint64_t value)
1308 {
1309         unsigned x;
1310         int error;
1311
1312         if (value == 0)
1313                 return (EINVAL);
1314
1315         MLX5E_RL_WLOCK(rl);
1316
1317         /* check if rate already exists */
1318         for (x = 0; x != rl->param.tx_rates_def; x++) {
1319                 if (rl->rate_limit_table[x] != value)
1320                         continue;
1321                 /* free up rate */
1322                 rl->rate_limit_table[x] = 0;
1323                 break;
1324         }
1325
1326         /* check if there is a free rate entry */
1327         if (x == rl->param.tx_rates_def)
1328                 error = ENOENT;
1329         else
1330                 error = 0;
1331         MLX5E_RL_WUNLOCK(rl);
1332
1333         return (error);
1334 }
1335
1336 static int
1337 mlx5e_rl_sysctl_handler(SYSCTL_HANDLER_ARGS)
1338 {
1339         struct mlx5e_rl_priv_data *rl = arg1;
1340         struct mlx5e_priv *priv = rl->priv;
1341         unsigned mode_modify;
1342         unsigned was_opened;
1343         uint64_t value;
1344         uint64_t old;
1345         int error;
1346
1347         PRIV_LOCK(priv);
1348
1349         MLX5E_RL_RLOCK(rl);
1350         value = rl->param.arg[arg2];
1351         MLX5E_RL_RUNLOCK(rl);
1352
1353         if (req != NULL) {
1354                 old = value;
1355                 error = sysctl_handle_64(oidp, &value, 0, req);
1356                 if (error || req->newptr == NULL ||
1357                     value == rl->param.arg[arg2])
1358                         goto done;
1359         } else {
1360                 old = 0;
1361                 error = 0;
1362         }
1363
1364         /* check if device is gone */
1365         if (priv->gone) {
1366                 error = ENXIO;
1367                 goto done;
1368         }
1369         was_opened = rl->opened;
1370         mode_modify = MLX5_CAP_GEN(priv->mdev, cq_period_mode_modify);
1371
1372         switch (MLX5E_RL_PARAMS_INDEX(arg[arg2])) {
1373         case MLX5E_RL_PARAMS_INDEX(tx_worker_threads_def):
1374                 if (value > rl->param.tx_worker_threads_max)
1375                         value = rl->param.tx_worker_threads_max;
1376                 else if (value < 1)
1377                         value = 1;
1378
1379                 /* store new value */
1380                 rl->param.arg[arg2] = value;
1381                 break;
1382
1383         case MLX5E_RL_PARAMS_INDEX(tx_channels_per_worker_def):
1384                 if (value > rl->param.tx_channels_per_worker_max)
1385                         value = rl->param.tx_channels_per_worker_max;
1386                 else if (value < 1)
1387                         value = 1;
1388
1389                 /* store new value */
1390                 rl->param.arg[arg2] = value;
1391                 break;
1392
1393         case MLX5E_RL_PARAMS_INDEX(tx_rates_def):
1394                 if (value > rl->param.tx_rates_max)
1395                         value = rl->param.tx_rates_max;
1396                 else if (value < 1)
1397                         value = 1;
1398
1399                 /* store new value */
1400                 rl->param.arg[arg2] = value;
1401                 break;
1402
1403         case MLX5E_RL_PARAMS_INDEX(tx_coalesce_usecs):
1404                 /* range check */
1405                 if (value < 1)
1406                         value = 0;
1407                 else if (value > MLX5E_FLD_MAX(cqc, cq_period))
1408                         value = MLX5E_FLD_MAX(cqc, cq_period);
1409
1410                 /* store new value */
1411                 rl->param.arg[arg2] = value;
1412
1413                 /* check to avoid down and up the network interface */
1414                 if (was_opened)
1415                         error = mlx5e_rl_refresh_channel_params(rl);
1416                 break;
1417
1418         case MLX5E_RL_PARAMS_INDEX(tx_coalesce_pkts):
1419                 /* import TX coal pkts */
1420                 if (value < 1)
1421                         value = 0;
1422                 else if (value > MLX5E_FLD_MAX(cqc, cq_max_count))
1423                         value = MLX5E_FLD_MAX(cqc, cq_max_count);
1424
1425                 /* store new value */
1426                 rl->param.arg[arg2] = value;
1427
1428                 /* check to avoid down and up the network interface */
1429                 if (was_opened)
1430                         error = mlx5e_rl_refresh_channel_params(rl);
1431                 break;
1432
1433         case MLX5E_RL_PARAMS_INDEX(tx_coalesce_mode):
1434                 /* network interface must be down */
1435                 if (was_opened != 0 && mode_modify == 0)
1436                         mlx5e_rl_close_workers(priv);
1437
1438                 /* import TX coalesce mode */
1439                 if (value != 0)
1440                         value = 1;
1441
1442                 /* store new value */
1443                 rl->param.arg[arg2] = value;
1444
1445                 /* restart network interface, if any */
1446                 if (was_opened != 0) {
1447                         if (mode_modify == 0)
1448                                 mlx5e_rl_open_workers(priv);
1449                         else
1450                                 error = mlx5e_rl_refresh_channel_params(rl);
1451                 }
1452                 break;
1453
1454         case MLX5E_RL_PARAMS_INDEX(tx_queue_size):
1455                 /* network interface must be down */
1456                 if (was_opened)
1457                         mlx5e_rl_close_workers(priv);
1458
1459                 /* import TX queue size */
1460                 if (value < (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE))
1461                         value = (1 << MLX5E_PARAMS_MINIMUM_LOG_SQ_SIZE);
1462                 else if (value > priv->params_ethtool.tx_queue_size_max)
1463                         value = priv->params_ethtool.tx_queue_size_max;
1464
1465                 /* store actual TX queue size */
1466                 value = 1ULL << order_base_2(value);
1467
1468                 /* store new value */
1469                 rl->param.arg[arg2] = value;
1470
1471                 /* verify TX completion factor */
1472                 mlx5e_rl_sync_tx_completion_fact(rl);
1473
1474                 /* restart network interface, if any */
1475                 if (was_opened)
1476                         mlx5e_rl_open_workers(priv);
1477                 break;
1478
1479         case MLX5E_RL_PARAMS_INDEX(tx_completion_fact):
1480                 /* network interface must be down */
1481                 if (was_opened)
1482                         mlx5e_rl_close_workers(priv);
1483
1484                 /* store new value */
1485                 rl->param.arg[arg2] = value;
1486
1487                 /* verify parameter */
1488                 mlx5e_rl_sync_tx_completion_fact(rl);
1489
1490                 /* restart network interface, if any */
1491                 if (was_opened)
1492                         mlx5e_rl_open_workers(priv);
1493                 break;
1494
1495         case MLX5E_RL_PARAMS_INDEX(tx_limit_add):
1496                 error = mlx5e_rl_tx_limit_add(rl, value);
1497                 break;
1498
1499         case MLX5E_RL_PARAMS_INDEX(tx_limit_clr):
1500                 error = mlx5e_rl_tx_limit_clr(rl, value);
1501                 break;
1502
1503         case MLX5E_RL_PARAMS_INDEX(tx_allowed_deviation):
1504                 /* range check */
1505                 if (value > rl->param.tx_allowed_deviation_max)
1506                         value = rl->param.tx_allowed_deviation_max;
1507                 else if (value < rl->param.tx_allowed_deviation_min)
1508                         value = rl->param.tx_allowed_deviation_min;
1509
1510                 MLX5E_RL_WLOCK(rl);
1511                 rl->param.arg[arg2] = value;
1512                 MLX5E_RL_WUNLOCK(rl);
1513                 break;
1514
1515         case MLX5E_RL_PARAMS_INDEX(tx_burst_size):
1516                 /* range check */
1517                 if (value > rl->param.tx_burst_size_max)
1518                         value = rl->param.tx_burst_size_max;
1519                 else if (value < rl->param.tx_burst_size_min)
1520                         value = rl->param.tx_burst_size_min;
1521
1522                 MLX5E_RL_WLOCK(rl);
1523                 rl->param.arg[arg2] = value;
1524                 MLX5E_RL_WUNLOCK(rl);
1525                 break;
1526
1527         default:
1528                 break;
1529         }
1530 done:
1531         PRIV_UNLOCK(priv);
1532         return (error);
1533 }
1534
1535 static void
1536 mlx5e_rl_sysctl_add_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
1537     struct sysctl_oid *node, const char *name, const char *desc)
1538 {
1539         /*
1540          * NOTE: In FreeBSD-11 and newer the CTLFLAG_RWTUN flag will
1541          * take care of loading default sysctl value from the kernel
1542          * environment, if any:
1543          */
1544         if (strstr(name, "_max") != 0 || strstr(name, "_min") != 0) {
1545                 /* read-only SYSCTLs */
1546                 SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1547                     name, CTLTYPE_U64 | CTLFLAG_RD |
1548                     CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
1549         } else {
1550                 if (strstr(name, "_def") != 0) {
1551 #ifdef RATELIMIT_DEBUG
1552                         /* tunable read-only advanced SYSCTLs */
1553                         SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1554                             name, CTLTYPE_U64 | CTLFLAG_RDTUN |
1555                             CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
1556 #endif
1557                 } else {
1558                         /* read-write SYSCTLs */
1559                         SYSCTL_ADD_PROC(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO,
1560                             name, CTLTYPE_U64 | CTLFLAG_RWTUN |
1561                             CTLFLAG_MPSAFE, rl, x, &mlx5e_rl_sysctl_handler, "QU", desc);
1562                 }
1563         }
1564 }
1565
1566 static void
1567 mlx5e_rl_sysctl_add_stats_u64_oid(struct mlx5e_rl_priv_data *rl, unsigned x,
1568     struct sysctl_oid *node, const char *name, const char *desc)
1569 {
1570         /* read-only SYSCTLs */
1571         SYSCTL_ADD_U64(&rl->ctx, SYSCTL_CHILDREN(node), OID_AUTO, name,
1572             CTLFLAG_RD, &rl->stats.arg[x], 0, desc);
1573 }
1574
1575 #endif