2 * Copyright (c) 2017 Chelsio Communications, Inc.
4 * Written by: Navdeep Parhar <np@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
32 #include "opt_inet6.h"
33 #include "opt_ratelimit.h"
35 #include <sys/types.h>
36 #include <sys/malloc.h>
37 #include <sys/queue.h>
39 #include <sys/taskqueue.h>
40 #include <sys/sysctl.h>
42 #include "common/common.h"
43 #include "common/t4_regs.h"
44 #include "common/t4_regs_values.h"
45 #include "common/t4_msg.h"
49 in_range(int val, int lo, int hi)
52 return (val < 0 || (val <= hi && val >= lo));
56 set_sched_class_config(struct adapter *sc, int minmax)
63 rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
66 rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
67 end_synchronized_op(sc, 0);
73 set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
76 int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
78 struct tx_cl_rl_params *tc;
79 bool check_pktsize = false;
81 if (p->level == SCHED_CLASS_LEVEL_CL_RL)
82 fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
83 else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
84 fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
85 else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
86 fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
90 if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
91 if (p->mode == SCHED_CLASS_MODE_CLASS)
92 fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
93 else if (p->mode == SCHED_CLASS_MODE_FLOW) {
95 fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
101 /* Valid channel must always be provided. */
104 if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
107 pi = sc->port[sc->chan_map[p->channel]];
110 MPASS(pi->tx_chan == p->channel);
111 top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
113 if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
114 p->level == SCHED_CLASS_LEVEL_CH_RL) {
116 * Valid rate (mode, unit and values) must be provided.
124 if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS) {
125 fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
126 /* ratemode could be relative (%) or absolute. */
127 if (p->ratemode == SCHED_CLASS_RATEMODE_REL) {
128 fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
129 /* maxrate is % of port bandwidth. */
130 if (!in_range(p->minrate, 0, 100) ||
131 !in_range(p->maxrate, 0, 100)) {
134 } else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS) {
135 fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
136 /* maxrate is absolute value in kbps. */
137 if (!in_range(p->minrate, 0, top_speed) ||
138 !in_range(p->maxrate, 0, top_speed)) {
143 } else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS) {
144 /* maxrate is the absolute value in pps. */
145 check_pktsize = true;
146 fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
150 MPASS(p->level == SCHED_CLASS_LEVEL_CL_WRR);
153 * Valid weight must be provided.
157 if (!in_range(p->weight, 1, 99))
164 if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
165 p->level == SCHED_CLASS_LEVEL_CL_WRR) {
167 * Valid scheduling class must be provided.
171 if (!in_range(p->cl, 0, sc->chip_params->nsched_cls - 1))
178 if (!in_range(p->pktsize, 64, pi->vi[0].ifp->if_mtu))
182 rc = begin_synchronized_op(sc, NULL,
183 sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
186 if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
187 tc = &pi->sched_params->cl_rl[p->cl];
188 if (tc->refcount > 0) {
192 tc->ratemode = fw_ratemode;
193 tc->rateunit = fw_rateunit;
195 tc->maxrate = p->maxrate;
196 tc->pktsize = p->pktsize;
199 rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode,
200 fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate,
201 p->weight, p->pktsize, sleep_ok);
202 if (p->level == SCHED_CLASS_LEVEL_CL_RL && rc != 0) {
204 * Unknown state at this point, see parameters in tc for what
207 tc->flags |= TX_CLRL_ERROR;
210 end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
216 update_tx_sched(void *context, int pending)
218 int i, j, mode, rateunit, ratemode, maxrate, pktsize, rc;
219 struct port_info *pi;
220 struct tx_cl_rl_params *tc;
221 struct adapter *sc = context;
222 const int n = sc->chip_params->nsched_cls;
224 mtx_lock(&sc->tc_lock);
225 for_each_port(sc, i) {
227 tc = &pi->sched_params->cl_rl[0];
228 for (j = 0; j < n; j++, tc++) {
229 MPASS(mtx_owned(&sc->tc_lock));
230 if ((tc->flags & TX_CLRL_REFRESH) == 0)
234 rateunit = tc->rateunit;
235 ratemode = tc->ratemode;
236 maxrate = tc->maxrate;
237 pktsize = tc->pktsize;
238 mtx_unlock(&sc->tc_lock);
240 if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
242 mtx_lock(&sc->tc_lock);
245 rc = t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED,
246 FW_SCHED_PARAMS_LEVEL_CL_RL, mode, rateunit,
247 ratemode, pi->tx_chan, j, 0, maxrate, 0, pktsize,
249 end_synchronized_op(sc, 0);
251 mtx_lock(&sc->tc_lock);
253 tc->flags |= TX_CLRL_ERROR;
254 } else if (tc->mode == mode &&
255 tc->rateunit == rateunit &&
256 tc->maxrate == maxrate &&
257 tc->pktsize == tc->pktsize) {
258 tc->flags &= ~(TX_CLRL_REFRESH | TX_CLRL_ERROR);
262 mtx_unlock(&sc->tc_lock);
266 t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
269 if (p->type != SCHED_CLASS_TYPE_PACKET)
272 if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
273 return (set_sched_class_config(sc, p->u.config.minmax));
275 if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
276 return (set_sched_class_params(sc, &p->u.params, 1));
282 t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
284 struct port_info *pi = NULL;
287 uint32_t fw_mnem, fw_queue, fw_class;
290 rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq");
294 if (p->port >= sc->params.nports) {
299 /* XXX: Only supported for the main VI. */
300 pi = sc->port[p->port];
302 if (!(vi->flags & VI_INIT_DONE)) {
303 /* tx queues not set up yet */
308 if (!in_range(p->queue, 0, vi->ntxq - 1) ||
309 !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) {
315 * Create a template for the FW_PARAMS_CMD mnemonic and value (TX
316 * Scheduling Class in this case).
318 fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
319 V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH));
320 fw_class = p->cl < 0 ? 0xffffffff : p->cl;
323 * If op.queue is non-negative, then we're only changing the scheduling
324 * on a single specified TX queue.
327 txq = &sc->sge.txq[vi->first_txq + p->queue];
328 fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
329 rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
335 * Change the scheduling on all the TX queues for the
338 for_each_txq(vi, i, txq) {
339 fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
340 rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue,
348 end_synchronized_op(sc, 0);
353 t4_init_tx_sched(struct adapter *sc)
356 const int n = sc->chip_params->nsched_cls;
357 struct port_info *pi;
358 struct tx_cl_rl_params *tc;
360 mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF);
361 TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc);
362 for_each_port(sc, i) {
364 pi->sched_params = malloc(sizeof(*pi->sched_params) +
365 n * sizeof(*tc), M_CXGBE, M_ZERO | M_WAITOK);
366 tc = &pi->sched_params->cl_rl[0];
367 for (j = 0; j < n; j++, tc++) {
369 tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
370 tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
371 tc->mode = FW_SCHED_PARAMS_MODE_CLASS;
372 tc->maxrate = 1000 * 1000; /* 1 Gbps. Arbitrary */
374 if (t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j,
375 tc->mode, tc->maxrate, tc->pktsize, 1) == 0)
378 tc->flags = TX_CLRL_ERROR;
386 t4_free_tx_sched(struct adapter *sc)
390 taskqueue_drain(taskqueue_thread, &sc->tc_task);
392 for_each_port(sc, i) {
393 if (sc->port[i] != NULL)
394 free(sc->port[i]->sched_params, M_CXGBE);
397 if (mtx_initialized(&sc->tc_lock))
398 mtx_destroy(&sc->tc_lock);
404 t4_update_tx_sched(struct adapter *sc)
407 taskqueue_enqueue(taskqueue_thread, &sc->tc_task);
411 t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate,
414 int rc = 0, fa = -1, i;
415 struct tx_cl_rl_params *tc;
417 MPASS(port_id >= 0 && port_id < sc->params.nports);
419 tc = &sc->port[port_id]->sched_params->cl_rl[0];
420 mtx_lock(&sc->tc_lock);
421 for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) {
422 if (fa < 0 && tc->refcount == 0)
425 if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS &&
426 tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE &&
427 tc->mode == FW_SCHED_PARAMS_MODE_FLOW &&
428 tc->maxrate == maxrate) {
435 MPASS(i == sc->chip_params->nsched_cls);
437 tc = &sc->port[port_id]->sched_params->cl_rl[fa];
438 tc->flags = TX_CLRL_REFRESH;
440 tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
441 tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
442 tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
443 tc->maxrate = maxrate;
444 tc->pktsize = ETHERMTU; /* XXX */
446 t4_update_tx_sched(sc);
452 mtx_unlock(&sc->tc_lock);
457 t4_release_cl_rl_kbps(struct adapter *sc, int port_id, int tc_idx)
459 struct tx_cl_rl_params *tc;
461 MPASS(port_id >= 0 && port_id < sc->params.nports);
462 MPASS(tc_idx >= 0 && tc_idx < sc->chip_params->nsched_cls);
464 mtx_lock(&sc->tc_lock);
465 tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx];
466 MPASS(tc->refcount > 0);
467 MPASS(tc->ratemode == FW_SCHED_PARAMS_RATE_ABS);
468 MPASS(tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE);
469 MPASS(tc->mode == FW_SCHED_PARAMS_MODE_FLOW);
471 mtx_unlock(&sc->tc_lock);
476 t4_init_etid_table(struct adapter *sc)
481 if (!is_ethoffload(sc))
485 MPASS(t->netids > 0);
487 mtx_init(&t->etid_lock, "etid lock", NULL, MTX_DEF);
488 t->etid_tab = malloc(sizeof(*t->etid_tab) * t->netids, M_CXGBE,
490 t->efree = t->etid_tab;
492 for (i = 1; i < t->netids; i++)
493 t->etid_tab[i - 1].next = &t->etid_tab[i];
494 t->etid_tab[t->netids - 1].next = NULL;
498 t4_free_etid_table(struct adapter *sc)
502 if (!is_ethoffload(sc))
506 MPASS(t->netids > 0);
508 free(t->etid_tab, M_CXGBE);
511 if (mtx_initialized(&t->etid_lock))
512 mtx_destroy(&t->etid_lock);
516 static int alloc_etid(struct adapter *, struct cxgbe_snd_tag *);
517 static void free_etid(struct adapter *, int);
520 alloc_etid(struct adapter *sc, struct cxgbe_snd_tag *cst)
522 struct tid_info *t = &sc->tids;
525 mtx_lock(&t->etid_lock);
527 union etid_entry *p = t->efree;
529 etid = p - t->etid_tab + t->etid_base;
534 mtx_unlock(&t->etid_lock);
538 struct cxgbe_snd_tag *
539 lookup_etid(struct adapter *sc, int etid)
541 struct tid_info *t = &sc->tids;
543 return (t->etid_tab[etid - t->etid_base].cst);
547 free_etid(struct adapter *sc, int etid)
549 struct tid_info *t = &sc->tids;
550 union etid_entry *p = &t->etid_tab[etid - t->etid_base];
552 mtx_lock(&t->etid_lock);
556 mtx_unlock(&t->etid_lock);
560 cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params,
561 struct m_snd_tag **pt)
564 struct vi_info *vi = ifp->if_softc;
565 struct port_info *pi = vi->pi;
566 struct adapter *sc = pi->adapter;
567 struct cxgbe_snd_tag *cst;
569 if (params->hdr.type != IF_SND_TAG_TYPE_RATE_LIMIT)
572 rc = t4_reserve_cl_rl_kbps(sc, pi->port_id,
573 (params->rate_limit.max_rate * 8ULL / 1000), &schedcl);
576 MPASS(schedcl >= 0 && schedcl < sc->chip_params->nsched_cls);
578 cst = malloc(sizeof(*cst), M_CXGBE, M_ZERO | M_NOWAIT);
581 t4_release_cl_rl_kbps(sc, pi->port_id, schedcl);
585 cst->etid = alloc_etid(sc, cst);
591 mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF);
592 mbufq_init(&cst->pending_tx, INT_MAX);
593 mbufq_init(&cst->pending_fwack, INT_MAX);
595 cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF;
597 cst->port_id = pi->port_id;
598 cst->schedcl = schedcl;
599 cst->max_rate = params->rate_limit.max_rate;
600 cst->tx_credits = sc->params.eo_wr_cred;
601 cst->tx_total = cst->tx_credits;
603 cst->ctrl0 = htobe32(V_TXPKT_OPCODE(CPL_TX_PKT) |
604 V_TXPKT_INTF(pi->tx_chan) | V_TXPKT_PF(G_FW_VIID_PFN(vi->viid)) |
605 V_TXPKT_VF(G_FW_VIID_VIN(vi->viid)) |
606 V_TXPKT_VF_VLD(G_FW_VIID_VIVLD(vi->viid)));
609 * Queues will be selected later when the connection flowid is available.
617 * Change in parameters, no change in ifp.
620 cxgbe_snd_tag_modify(struct m_snd_tag *mst,
621 union if_snd_tag_modify_params *params)
624 struct cxgbe_snd_tag *cst = mst_to_cst(mst);
625 struct adapter *sc = cst->adapter;
627 /* XXX: is schedcl -1 ok here? */
628 MPASS(cst->schedcl >= 0 && cst->schedcl < sc->chip_params->nsched_cls);
630 mtx_lock(&cst->lock);
631 MPASS(cst->flags & EO_SND_TAG_REF);
632 rc = t4_reserve_cl_rl_kbps(sc, cst->port_id,
633 (params->rate_limit.max_rate * 8ULL / 1000), &schedcl);
636 MPASS(schedcl >= 0 && schedcl < sc->chip_params->nsched_cls);
637 t4_release_cl_rl_kbps(sc, cst->port_id, cst->schedcl);
638 cst->schedcl = schedcl;
639 cst->max_rate = params->rate_limit.max_rate;
640 mtx_unlock(&cst->lock);
646 cxgbe_snd_tag_query(struct m_snd_tag *mst,
647 union if_snd_tag_query_params *params)
649 struct cxgbe_snd_tag *cst = mst_to_cst(mst);
651 params->rate_limit.max_rate = cst->max_rate;
653 #define CST_TO_MST_QLEVEL_SCALE (IF_SND_QUEUE_LEVEL_MAX / cst->tx_total)
654 params->rate_limit.queue_level =
655 (cst->tx_total - cst->tx_credits) * CST_TO_MST_QLEVEL_SCALE;
661 * Unlocks cst and frees it.
664 cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *cst)
666 struct adapter *sc = cst->adapter;
668 mtx_assert(&cst->lock, MA_OWNED);
669 MPASS((cst->flags & EO_SND_TAG_REF) == 0);
670 MPASS(cst->tx_credits == cst->tx_total);
671 MPASS(cst->plen == 0);
672 MPASS(mbufq_first(&cst->pending_tx) == NULL);
673 MPASS(mbufq_first(&cst->pending_fwack) == NULL);
676 free_etid(sc, cst->etid);
677 if (cst->schedcl != -1)
678 t4_release_cl_rl_kbps(sc, cst->port_id, cst->schedcl);
679 mtx_unlock(&cst->lock);
680 mtx_destroy(&cst->lock);
685 cxgbe_snd_tag_free(struct m_snd_tag *mst)
687 struct cxgbe_snd_tag *cst = mst_to_cst(mst);
689 mtx_lock(&cst->lock);
691 /* The kernel is done with the snd_tag. Remove its reference. */
692 MPASS(cst->flags & EO_SND_TAG_REF);
693 cst->flags &= ~EO_SND_TAG_REF;
695 if (cst->ncompl == 0) {
697 * No fw4_ack in flight. Free the tag right away if there are
698 * no outstanding credits. Request the firmware to return all
699 * credits for the etid otherwise.
701 if (cst->tx_credits == cst->tx_total) {
702 cxgbe_snd_tag_free_locked(cst);
703 return; /* cst is gone. */
705 send_etid_flush_wr(cst);
707 mtx_unlock(&cst->lock);