12204b427SNavdeep Parhar /*-
22204b427SNavdeep Parhar * Copyright (c) 2017 Chelsio Communications, Inc.
32204b427SNavdeep Parhar * All rights reserved.
42204b427SNavdeep Parhar * Written by: Navdeep Parhar <np@FreeBSD.org>
52204b427SNavdeep Parhar *
62204b427SNavdeep Parhar * Redistribution and use in source and binary forms, with or without
72204b427SNavdeep Parhar * modification, are permitted provided that the following conditions
82204b427SNavdeep Parhar * are met:
92204b427SNavdeep Parhar * 1. Redistributions of source code must retain the above copyright
102204b427SNavdeep Parhar * notice, this list of conditions and the following disclaimer.
112204b427SNavdeep Parhar * 2. Redistributions in binary form must reproduce the above copyright
122204b427SNavdeep Parhar * notice, this list of conditions and the following disclaimer in the
132204b427SNavdeep Parhar * documentation and/or other materials provided with the distribution.
142204b427SNavdeep Parhar *
152204b427SNavdeep Parhar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
162204b427SNavdeep Parhar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
172204b427SNavdeep Parhar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
182204b427SNavdeep Parhar * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
192204b427SNavdeep Parhar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
202204b427SNavdeep Parhar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
212204b427SNavdeep Parhar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
222204b427SNavdeep Parhar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
232204b427SNavdeep Parhar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242204b427SNavdeep Parhar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252204b427SNavdeep Parhar * SUCH DAMAGE.
262204b427SNavdeep Parhar */
272204b427SNavdeep Parhar
282204b427SNavdeep Parhar #include <sys/cdefs.h>
292204b427SNavdeep Parhar #include "opt_inet.h"
302204b427SNavdeep Parhar #include "opt_inet6.h"
3167e07112SNavdeep Parhar #include "opt_ratelimit.h"
322204b427SNavdeep Parhar
332204b427SNavdeep Parhar #include <sys/types.h>
342204b427SNavdeep Parhar #include <sys/malloc.h>
352204b427SNavdeep Parhar #include <sys/queue.h>
362204b427SNavdeep Parhar #include <sys/sbuf.h>
372204b427SNavdeep Parhar #include <sys/taskqueue.h>
382204b427SNavdeep Parhar #include <sys/sysctl.h>
392204b427SNavdeep Parhar
402204b427SNavdeep Parhar #include "common/common.h"
412204b427SNavdeep Parhar #include "common/t4_regs.h"
422204b427SNavdeep Parhar #include "common/t4_regs_values.h"
432204b427SNavdeep Parhar #include "common/t4_msg.h"
442204b427SNavdeep Parhar
452204b427SNavdeep Parhar static int
in_range(int val,int lo,int hi)462204b427SNavdeep Parhar in_range(int val, int lo, int hi)
472204b427SNavdeep Parhar {
482204b427SNavdeep Parhar
492204b427SNavdeep Parhar return (val < 0 || (val <= hi && val >= lo));
502204b427SNavdeep Parhar }
512204b427SNavdeep Parhar
522204b427SNavdeep Parhar static int
set_sched_class_config(struct adapter * sc,int minmax)532204b427SNavdeep Parhar set_sched_class_config(struct adapter *sc, int minmax)
542204b427SNavdeep Parhar {
552204b427SNavdeep Parhar int rc;
562204b427SNavdeep Parhar
572204b427SNavdeep Parhar if (minmax < 0)
582204b427SNavdeep Parhar return (EINVAL);
592204b427SNavdeep Parhar
602204b427SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
612204b427SNavdeep Parhar if (rc)
622204b427SNavdeep Parhar return (rc);
6383b5cda1SNavdeep Parhar if (hw_off_limits(sc))
6483b5cda1SNavdeep Parhar rc = ENXIO;
6583b5cda1SNavdeep Parhar else
662204b427SNavdeep Parhar rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
672204b427SNavdeep Parhar end_synchronized_op(sc, 0);
682204b427SNavdeep Parhar
692204b427SNavdeep Parhar return (rc);
702204b427SNavdeep Parhar }
712204b427SNavdeep Parhar
722204b427SNavdeep Parhar static int
set_sched_class_params(struct adapter * sc,struct t4_sched_class_params * p,int sleep_ok)732204b427SNavdeep Parhar set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
742204b427SNavdeep Parhar int sleep_ok)
752204b427SNavdeep Parhar {
762204b427SNavdeep Parhar int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
772204b427SNavdeep Parhar struct port_info *pi;
781979b511SNavdeep Parhar struct tx_cl_rl_params *tc, old;
799c3b8b3cSNavdeep Parhar bool check_pktsize = false;
802204b427SNavdeep Parhar
812204b427SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL)
822204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
832204b427SNavdeep Parhar else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
842204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
852204b427SNavdeep Parhar else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
862204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
872204b427SNavdeep Parhar else
882204b427SNavdeep Parhar return (EINVAL);
892204b427SNavdeep Parhar
909c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
912204b427SNavdeep Parhar if (p->mode == SCHED_CLASS_MODE_CLASS)
922204b427SNavdeep Parhar fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
939c3b8b3cSNavdeep Parhar else if (p->mode == SCHED_CLASS_MODE_FLOW) {
949c3b8b3cSNavdeep Parhar check_pktsize = true;
952204b427SNavdeep Parhar fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
969c3b8b3cSNavdeep Parhar } else
972204b427SNavdeep Parhar return (EINVAL);
989c3b8b3cSNavdeep Parhar } else
999c3b8b3cSNavdeep Parhar fw_mode = 0;
1002204b427SNavdeep Parhar
1019c3b8b3cSNavdeep Parhar /* Valid channel must always be provided. */
1029c3b8b3cSNavdeep Parhar if (p->channel < 0)
1032204b427SNavdeep Parhar return (EINVAL);
1042204b427SNavdeep Parhar if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
1052204b427SNavdeep Parhar return (ERANGE);
1062204b427SNavdeep Parhar
1072204b427SNavdeep Parhar pi = sc->port[sc->chan_map[p->channel]];
1082204b427SNavdeep Parhar if (pi == NULL)
1092204b427SNavdeep Parhar return (ENXIO);
1102204b427SNavdeep Parhar MPASS(pi->tx_chan == p->channel);
1112204b427SNavdeep Parhar top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
1122204b427SNavdeep Parhar
1139c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
1149c3b8b3cSNavdeep Parhar p->level == SCHED_CLASS_LEVEL_CH_RL) {
1152204b427SNavdeep Parhar /*
1169c3b8b3cSNavdeep Parhar * Valid rate (mode, unit and values) must be provided.
1172204b427SNavdeep Parhar */
1182204b427SNavdeep Parhar
1192204b427SNavdeep Parhar if (p->minrate < 0)
1202204b427SNavdeep Parhar p->minrate = 0;
1219c3b8b3cSNavdeep Parhar if (p->maxrate < 0)
1222204b427SNavdeep Parhar return (EINVAL);
1239c3b8b3cSNavdeep Parhar
1249c3b8b3cSNavdeep Parhar if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS) {
1259c3b8b3cSNavdeep Parhar fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
1269c3b8b3cSNavdeep Parhar /* ratemode could be relative (%) or absolute. */
1279c3b8b3cSNavdeep Parhar if (p->ratemode == SCHED_CLASS_RATEMODE_REL) {
1289c3b8b3cSNavdeep Parhar fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
1299c3b8b3cSNavdeep Parhar /* maxrate is % of port bandwidth. */
1309c3b8b3cSNavdeep Parhar if (!in_range(p->minrate, 0, 100) ||
1319c3b8b3cSNavdeep Parhar !in_range(p->maxrate, 0, 100)) {
1329c3b8b3cSNavdeep Parhar return (ERANGE);
1332204b427SNavdeep Parhar }
1349c3b8b3cSNavdeep Parhar } else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS) {
1359c3b8b3cSNavdeep Parhar fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
1369c3b8b3cSNavdeep Parhar /* maxrate is absolute value in kbps. */
1379c3b8b3cSNavdeep Parhar if (!in_range(p->minrate, 0, top_speed) ||
1389c3b8b3cSNavdeep Parhar !in_range(p->maxrate, 0, top_speed)) {
1399c3b8b3cSNavdeep Parhar return (ERANGE);
1402204b427SNavdeep Parhar }
1419c3b8b3cSNavdeep Parhar } else
1422204b427SNavdeep Parhar return (EINVAL);
1439c3b8b3cSNavdeep Parhar } else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS) {
1449c3b8b3cSNavdeep Parhar /* maxrate is the absolute value in pps. */
1459c3b8b3cSNavdeep Parhar check_pktsize = true;
1469c3b8b3cSNavdeep Parhar fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
1479c3b8b3cSNavdeep Parhar } else
1489c3b8b3cSNavdeep Parhar return (EINVAL);
1499c3b8b3cSNavdeep Parhar } else {
1509c3b8b3cSNavdeep Parhar MPASS(p->level == SCHED_CLASS_LEVEL_CL_WRR);
1519c3b8b3cSNavdeep Parhar
1529c3b8b3cSNavdeep Parhar /*
1539c3b8b3cSNavdeep Parhar * Valid weight must be provided.
1549c3b8b3cSNavdeep Parhar */
1559c3b8b3cSNavdeep Parhar if (p->weight < 0)
1569c3b8b3cSNavdeep Parhar return (EINVAL);
1579c3b8b3cSNavdeep Parhar if (!in_range(p->weight, 1, 99))
1589c3b8b3cSNavdeep Parhar return (ERANGE);
1599c3b8b3cSNavdeep Parhar
1609c3b8b3cSNavdeep Parhar fw_rateunit = 0;
1619c3b8b3cSNavdeep Parhar fw_ratemode = 0;
1629c3b8b3cSNavdeep Parhar }
1639c3b8b3cSNavdeep Parhar
1649c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
1659c3b8b3cSNavdeep Parhar p->level == SCHED_CLASS_LEVEL_CL_WRR) {
1669c3b8b3cSNavdeep Parhar /*
1679c3b8b3cSNavdeep Parhar * Valid scheduling class must be provided.
1689c3b8b3cSNavdeep Parhar */
1699c3b8b3cSNavdeep Parhar if (p->cl < 0)
1709c3b8b3cSNavdeep Parhar return (EINVAL);
1716beb67c7SNavdeep Parhar if (!in_range(p->cl, 0, sc->params.nsched_cls - 1))
1729c3b8b3cSNavdeep Parhar return (ERANGE);
1739c3b8b3cSNavdeep Parhar }
1749c3b8b3cSNavdeep Parhar
1759c3b8b3cSNavdeep Parhar if (check_pktsize) {
1769c3b8b3cSNavdeep Parhar if (p->pktsize < 0)
1779c3b8b3cSNavdeep Parhar return (EINVAL);
178954712e8SJustin Hibbits if (!in_range(p->pktsize, 64, if_getmtu(pi->vi[0].ifp)))
1799c3b8b3cSNavdeep Parhar return (ERANGE);
1802204b427SNavdeep Parhar }
1812204b427SNavdeep Parhar
1822204b427SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
1832204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[p->cl];
1841979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
185ec8004ddSNavdeep Parhar if (tc->refcount > 0 || tc->state == CS_HW_UPDATE_IN_PROGRESS)
1862204b427SNavdeep Parhar rc = EBUSY;
1871979b511SNavdeep Parhar else {
188ec8004ddSNavdeep Parhar old = *tc;
189ec8004ddSNavdeep Parhar
190ec8004ddSNavdeep Parhar tc->flags |= CF_USER;
191ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_IN_PROGRESS;
1922204b427SNavdeep Parhar tc->ratemode = fw_ratemode;
1932204b427SNavdeep Parhar tc->rateunit = fw_rateunit;
1942204b427SNavdeep Parhar tc->mode = fw_mode;
1952204b427SNavdeep Parhar tc->maxrate = p->maxrate;
1962204b427SNavdeep Parhar tc->pktsize = p->pktsize;
1971979b511SNavdeep Parhar rc = 0;
1982204b427SNavdeep Parhar }
1991979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
2001979b511SNavdeep Parhar if (rc != 0)
2011979b511SNavdeep Parhar return (rc);
2021979b511SNavdeep Parhar }
2031979b511SNavdeep Parhar
2041979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL,
2051979b511SNavdeep Parhar sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
2061979b511SNavdeep Parhar if (rc != 0) {
2071979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
2081979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
209ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0);
210ec8004ddSNavdeep Parhar MPASS(tc->flags & CF_USER);
211ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_IN_PROGRESS);
2121979b511SNavdeep Parhar *tc = old;
2131979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
2141979b511SNavdeep Parhar }
2151979b511SNavdeep Parhar return (rc);
2162204b427SNavdeep Parhar }
21783b5cda1SNavdeep Parhar if (!hw_off_limits(sc)) {
21883b5cda1SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level,
21983b5cda1SNavdeep Parhar fw_mode, fw_rateunit, fw_ratemode, p->channel, p->cl,
22083b5cda1SNavdeep Parhar p->minrate, p->maxrate, p->weight, p->pktsize, 0, sleep_ok);
22183b5cda1SNavdeep Parhar }
2222204b427SNavdeep Parhar end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
2232204b427SNavdeep Parhar
2241979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
2251979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
2261979b511SNavdeep Parhar MPASS(tc->refcount == 0);
227ec8004ddSNavdeep Parhar MPASS(tc->flags & CF_USER);
228ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_IN_PROGRESS);
2291979b511SNavdeep Parhar
2301979b511SNavdeep Parhar if (rc == 0)
231ec8004ddSNavdeep Parhar tc->state = CS_HW_CONFIGURED;
232ec8004ddSNavdeep Parhar else {
233ec8004ddSNavdeep Parhar /* parameters failed so we don't park at params_set */
234ec8004ddSNavdeep Parhar tc->state = CS_UNINITIALIZED;
235ec8004ddSNavdeep Parhar tc->flags &= ~CF_USER;
236ec8004ddSNavdeep Parhar CH_ERR(pi, "failed to configure traffic class %d: %d. "
237ec8004ddSNavdeep Parhar "params: mode %d, rateunit %d, ratemode %d, "
238ec8004ddSNavdeep Parhar "channel %d, minrate %d, maxrate %d, pktsize %d, "
239ec8004ddSNavdeep Parhar "burstsize %d\n", p->cl, rc, fw_mode, fw_rateunit,
240ec8004ddSNavdeep Parhar fw_ratemode, p->channel, p->minrate, p->maxrate,
241ec8004ddSNavdeep Parhar p->pktsize, 0);
242ec8004ddSNavdeep Parhar }
2431979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
2441979b511SNavdeep Parhar }
2451979b511SNavdeep Parhar
2462204b427SNavdeep Parhar return (rc);
2472204b427SNavdeep Parhar }
2482204b427SNavdeep Parhar
2492204b427SNavdeep Parhar static void
update_tx_sched(void * context,int pending)2502204b427SNavdeep Parhar update_tx_sched(void *context, int pending)
2512204b427SNavdeep Parhar {
2521979b511SNavdeep Parhar int i, j, rc;
2532204b427SNavdeep Parhar struct port_info *pi;
2542204b427SNavdeep Parhar struct tx_cl_rl_params *tc;
2552204b427SNavdeep Parhar struct adapter *sc = context;
2566beb67c7SNavdeep Parhar const int n = sc->params.nsched_cls;
2572204b427SNavdeep Parhar
2582204b427SNavdeep Parhar mtx_lock(&sc->tc_lock);
2592204b427SNavdeep Parhar for_each_port(sc, i) {
2602204b427SNavdeep Parhar pi = sc->port[i];
2612204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[0];
2622204b427SNavdeep Parhar for (j = 0; j < n; j++, tc++) {
2632204b427SNavdeep Parhar MPASS(mtx_owned(&sc->tc_lock));
264ec8004ddSNavdeep Parhar if (tc->state != CS_HW_UPDATE_REQUESTED)
2652204b427SNavdeep Parhar continue;
2662204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock);
2672204b427SNavdeep Parhar
2682204b427SNavdeep Parhar if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
2692204b427SNavdeep Parhar "t4utxs") != 0) {
2702204b427SNavdeep Parhar mtx_lock(&sc->tc_lock);
2712204b427SNavdeep Parhar continue;
2722204b427SNavdeep Parhar }
2731979b511SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED,
2741979b511SNavdeep Parhar FW_SCHED_PARAMS_LEVEL_CL_RL, tc->mode, tc->rateunit,
2751979b511SNavdeep Parhar tc->ratemode, pi->tx_chan, j, 0, tc->maxrate, 0,
27609a7189fSNavdeep Parhar tc->pktsize, tc->burstsize, 1);
2772204b427SNavdeep Parhar end_synchronized_op(sc, 0);
2782204b427SNavdeep Parhar
2792204b427SNavdeep Parhar mtx_lock(&sc->tc_lock);
280ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_REQUESTED);
281ec8004ddSNavdeep Parhar if (rc == 0) {
282ec8004ddSNavdeep Parhar tc->state = CS_HW_CONFIGURED;
283ec8004ddSNavdeep Parhar continue;
284ec8004ddSNavdeep Parhar }
285ec8004ddSNavdeep Parhar /* parameters failed so we try to avoid params_set */
286ec8004ddSNavdeep Parhar if (tc->refcount > 0)
287ec8004ddSNavdeep Parhar tc->state = CS_PARAMS_SET;
2881979b511SNavdeep Parhar else
289ec8004ddSNavdeep Parhar tc->state = CS_UNINITIALIZED;
290ec8004ddSNavdeep Parhar CH_ERR(pi, "failed to configure traffic class %d: %d. "
291ec8004ddSNavdeep Parhar "params: mode %d, rateunit %d, ratemode %d, "
292ec8004ddSNavdeep Parhar "channel %d, minrate %d, maxrate %d, pktsize %d, "
293ec8004ddSNavdeep Parhar "burstsize %d\n", j, rc, tc->mode, tc->rateunit,
294ec8004ddSNavdeep Parhar tc->ratemode, pi->tx_chan, 0, tc->maxrate,
295ec8004ddSNavdeep Parhar tc->pktsize, tc->burstsize);
2962204b427SNavdeep Parhar }
2972204b427SNavdeep Parhar }
2982204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock);
2992204b427SNavdeep Parhar }
3002204b427SNavdeep Parhar
3012204b427SNavdeep Parhar int
t4_set_sched_class(struct adapter * sc,struct t4_sched_params * p)3022204b427SNavdeep Parhar t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
3032204b427SNavdeep Parhar {
3042204b427SNavdeep Parhar
3052204b427SNavdeep Parhar if (p->type != SCHED_CLASS_TYPE_PACKET)
3062204b427SNavdeep Parhar return (EINVAL);
3072204b427SNavdeep Parhar
3082204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
3092204b427SNavdeep Parhar return (set_sched_class_config(sc, p->u.config.minmax));
3102204b427SNavdeep Parhar
3112204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
3122204b427SNavdeep Parhar return (set_sched_class_params(sc, &p->u.params, 1));
3132204b427SNavdeep Parhar
3142204b427SNavdeep Parhar return (EINVAL);
3152204b427SNavdeep Parhar }
3162204b427SNavdeep Parhar
3171979b511SNavdeep Parhar static int
bind_txq_to_traffic_class(struct adapter * sc,struct sge_txq * txq,int idx)3181979b511SNavdeep Parhar bind_txq_to_traffic_class(struct adapter *sc, struct sge_txq *txq, int idx)
3191979b511SNavdeep Parhar {
3201979b511SNavdeep Parhar struct tx_cl_rl_params *tc0, *tc;
3211979b511SNavdeep Parhar int rc, old_idx;
3221979b511SNavdeep Parhar uint32_t fw_mnem, fw_class;
3231979b511SNavdeep Parhar
32443bbae19SNavdeep Parhar if (!(txq->eq.flags & EQ_HW_ALLOCATED))
32543bbae19SNavdeep Parhar return (ENXIO);
3261979b511SNavdeep Parhar
3271979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
3281979b511SNavdeep Parhar if (txq->tc_idx == -2) {
3291979b511SNavdeep Parhar rc = EBUSY; /* Another bind/unbind in progress already. */
3301979b511SNavdeep Parhar goto done;
3311979b511SNavdeep Parhar }
3321979b511SNavdeep Parhar if (idx == txq->tc_idx) {
3331979b511SNavdeep Parhar rc = 0; /* No change, nothing to do. */
3341979b511SNavdeep Parhar goto done;
3351979b511SNavdeep Parhar }
3361979b511SNavdeep Parhar
337*cca3506dSNavdeep Parhar tc0 = &sc->port[txq->eq.port_id]->sched_params->cl_rl[0];
3381979b511SNavdeep Parhar if (idx != -1) {
3391979b511SNavdeep Parhar /*
3401979b511SNavdeep Parhar * Bind to a different class at index idx.
3411979b511SNavdeep Parhar */
3421979b511SNavdeep Parhar tc = &tc0[idx];
343ec8004ddSNavdeep Parhar if (tc->state != CS_HW_CONFIGURED) {
3441979b511SNavdeep Parhar rc = ENXIO;
3451979b511SNavdeep Parhar goto done;
3461979b511SNavdeep Parhar } else {
3471979b511SNavdeep Parhar /*
3481979b511SNavdeep Parhar * Ok to proceed. Place a reference on the new class
3491979b511SNavdeep Parhar * while still holding on to the reference on the
3501979b511SNavdeep Parhar * previous class, if any.
3511979b511SNavdeep Parhar */
3521979b511SNavdeep Parhar tc->refcount++;
3531979b511SNavdeep Parhar }
3541979b511SNavdeep Parhar }
3551979b511SNavdeep Parhar /* Mark as busy before letting go of the lock. */
3561979b511SNavdeep Parhar old_idx = txq->tc_idx;
3571979b511SNavdeep Parhar txq->tc_idx = -2;
3581979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
3591979b511SNavdeep Parhar
3601979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4btxq");
361ec8004ddSNavdeep Parhar if (rc == 0) {
3621979b511SNavdeep Parhar fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) |
3631979b511SNavdeep Parhar V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH) |
3641979b511SNavdeep Parhar V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id));
3651979b511SNavdeep Parhar fw_class = idx < 0 ? 0xffffffff : idx;
366ec8004ddSNavdeep Parhar rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_mnem,
367ec8004ddSNavdeep Parhar &fw_class);
3681979b511SNavdeep Parhar end_synchronized_op(sc, 0);
369ec8004ddSNavdeep Parhar }
3701979b511SNavdeep Parhar
3711979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
3721979b511SNavdeep Parhar MPASS(txq->tc_idx == -2);
3731979b511SNavdeep Parhar if (rc == 0) {
3741979b511SNavdeep Parhar /*
3751979b511SNavdeep Parhar * Unbind, bind, or bind to a different class succeeded. Remove
3761979b511SNavdeep Parhar * the reference on the old traffic class, if any.
3771979b511SNavdeep Parhar */
3781979b511SNavdeep Parhar if (old_idx != -1) {
3791979b511SNavdeep Parhar tc = &tc0[old_idx];
3801979b511SNavdeep Parhar MPASS(tc->refcount > 0);
3811979b511SNavdeep Parhar tc->refcount--;
3821979b511SNavdeep Parhar }
3831979b511SNavdeep Parhar txq->tc_idx = idx;
3841979b511SNavdeep Parhar } else {
3851979b511SNavdeep Parhar /*
3861979b511SNavdeep Parhar * Unbind, bind, or bind to a different class failed. Remove
3871979b511SNavdeep Parhar * the anticipatory reference on the new traffic class, if any.
3881979b511SNavdeep Parhar */
3891979b511SNavdeep Parhar if (idx != -1) {
3901979b511SNavdeep Parhar tc = &tc0[idx];
3911979b511SNavdeep Parhar MPASS(tc->refcount > 0);
3921979b511SNavdeep Parhar tc->refcount--;
3931979b511SNavdeep Parhar }
3941979b511SNavdeep Parhar txq->tc_idx = old_idx;
3951979b511SNavdeep Parhar }
3961979b511SNavdeep Parhar done:
3976beb67c7SNavdeep Parhar MPASS(txq->tc_idx >= -1 && txq->tc_idx < sc->params.nsched_cls);
3981979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
3991979b511SNavdeep Parhar return (rc);
4001979b511SNavdeep Parhar }
4011979b511SNavdeep Parhar
4022204b427SNavdeep Parhar int
t4_set_sched_queue(struct adapter * sc,struct t4_sched_queue * p)4032204b427SNavdeep Parhar t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
4042204b427SNavdeep Parhar {
4052204b427SNavdeep Parhar struct port_info *pi = NULL;
4062204b427SNavdeep Parhar struct vi_info *vi;
4072204b427SNavdeep Parhar struct sge_txq *txq;
4082204b427SNavdeep Parhar int i, rc;
4092204b427SNavdeep Parhar
4101979b511SNavdeep Parhar if (p->port >= sc->params.nports)
4111979b511SNavdeep Parhar return (EINVAL);
4122204b427SNavdeep Parhar
4131979b511SNavdeep Parhar /*
4141979b511SNavdeep Parhar * XXX: cxgbetool allows the user to specify the physical port only. So
4151979b511SNavdeep Parhar * we always operate on the main VI.
4161979b511SNavdeep Parhar */
4172204b427SNavdeep Parhar pi = sc->port[p->port];
4182204b427SNavdeep Parhar vi = &pi->vi[0];
4191979b511SNavdeep Parhar
4201979b511SNavdeep Parhar /* Checking VI_INIT_DONE outside a synch-op is a harmless race here. */
4211979b511SNavdeep Parhar if (!(vi->flags & VI_INIT_DONE))
4221979b511SNavdeep Parhar return (EAGAIN);
423eb6f5d6eSNavdeep Parhar MPASS(vi->ntxq > 0);
4242204b427SNavdeep Parhar
4252204b427SNavdeep Parhar if (!in_range(p->queue, 0, vi->ntxq - 1) ||
4266beb67c7SNavdeep Parhar !in_range(p->cl, 0, sc->params.nsched_cls - 1))
4271979b511SNavdeep Parhar return (EINVAL);
4282204b427SNavdeep Parhar
4291979b511SNavdeep Parhar if (p->queue < 0) {
4302204b427SNavdeep Parhar /*
4312204b427SNavdeep Parhar * Change the scheduling on all the TX queues for the
4322204b427SNavdeep Parhar * interface.
4332204b427SNavdeep Parhar */
4342204b427SNavdeep Parhar for_each_txq(vi, i, txq) {
4351979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl);
4361979b511SNavdeep Parhar if (rc != 0)
4371979b511SNavdeep Parhar break;
4381979b511SNavdeep Parhar }
4391979b511SNavdeep Parhar } else {
4401979b511SNavdeep Parhar /*
4411979b511SNavdeep Parhar * If op.queue is non-negative, then we're only changing the
4421979b511SNavdeep Parhar * scheduling on a single specified TX queue.
4431979b511SNavdeep Parhar */
4441979b511SNavdeep Parhar txq = &sc->sge.txq[vi->first_txq + p->queue];
4451979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl);
4462204b427SNavdeep Parhar }
4472204b427SNavdeep Parhar
4482204b427SNavdeep Parhar return (rc);
4492204b427SNavdeep Parhar }
4502204b427SNavdeep Parhar
4512204b427SNavdeep Parhar int
t4_init_tx_sched(struct adapter * sc)4522204b427SNavdeep Parhar t4_init_tx_sched(struct adapter *sc)
4532204b427SNavdeep Parhar {
454ec8004ddSNavdeep Parhar int i;
4556beb67c7SNavdeep Parhar const int n = sc->params.nsched_cls;
4562204b427SNavdeep Parhar struct port_info *pi;
4572204b427SNavdeep Parhar
4582204b427SNavdeep Parhar mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF);
4592204b427SNavdeep Parhar TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc);
4602204b427SNavdeep Parhar for_each_port(sc, i) {
4612204b427SNavdeep Parhar pi = sc->port[i];
4622204b427SNavdeep Parhar pi->sched_params = malloc(sizeof(*pi->sched_params) +
463ec8004ddSNavdeep Parhar n * sizeof(struct tx_cl_rl_params), M_CXGBE, M_ZERO | M_WAITOK);
4642204b427SNavdeep Parhar }
4652204b427SNavdeep Parhar
4662204b427SNavdeep Parhar return (0);
4672204b427SNavdeep Parhar }
4682204b427SNavdeep Parhar
4692204b427SNavdeep Parhar int
t4_free_tx_sched(struct adapter * sc)4702204b427SNavdeep Parhar t4_free_tx_sched(struct adapter *sc)
4712204b427SNavdeep Parhar {
4722204b427SNavdeep Parhar int i;
4732204b427SNavdeep Parhar
4742204b427SNavdeep Parhar taskqueue_drain(taskqueue_thread, &sc->tc_task);
4752204b427SNavdeep Parhar
476cc2050c5SNavdeep Parhar for_each_port(sc, i) {
477cc2050c5SNavdeep Parhar if (sc->port[i] != NULL)
4782204b427SNavdeep Parhar free(sc->port[i]->sched_params, M_CXGBE);
479cc2050c5SNavdeep Parhar }
4802204b427SNavdeep Parhar
4812204b427SNavdeep Parhar if (mtx_initialized(&sc->tc_lock))
4822204b427SNavdeep Parhar mtx_destroy(&sc->tc_lock);
4832204b427SNavdeep Parhar
4842204b427SNavdeep Parhar return (0);
4852204b427SNavdeep Parhar }
4862204b427SNavdeep Parhar
4872204b427SNavdeep Parhar void
t4_update_tx_sched(struct adapter * sc)4882204b427SNavdeep Parhar t4_update_tx_sched(struct adapter *sc)
4892204b427SNavdeep Parhar {
4902204b427SNavdeep Parhar
4912204b427SNavdeep Parhar taskqueue_enqueue(taskqueue_thread, &sc->tc_task);
4922204b427SNavdeep Parhar }
4932204b427SNavdeep Parhar
4942204b427SNavdeep Parhar int
t4_reserve_cl_rl_kbps(struct adapter * sc,int port_id,u_int maxrate,int * tc_idx)4952204b427SNavdeep Parhar t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate,
4962204b427SNavdeep Parhar int *tc_idx)
4972204b427SNavdeep Parhar {
498ec8004ddSNavdeep Parhar int rc = 0, fa, fa2, i, pktsize, burstsize;
4991979b511SNavdeep Parhar bool update;
5002204b427SNavdeep Parhar struct tx_cl_rl_params *tc;
5011979b511SNavdeep Parhar struct port_info *pi;
5022204b427SNavdeep Parhar
5032204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports);
5042204b427SNavdeep Parhar
5051979b511SNavdeep Parhar pi = sc->port[port_id];
50609a7189fSNavdeep Parhar if (pi->sched_params->pktsize > 0)
50709a7189fSNavdeep Parhar pktsize = pi->sched_params->pktsize;
50809a7189fSNavdeep Parhar else
509954712e8SJustin Hibbits pktsize = if_getmtu(pi->vi[0].ifp);
51009a7189fSNavdeep Parhar if (pi->sched_params->burstsize > 0)
51109a7189fSNavdeep Parhar burstsize = pi->sched_params->burstsize;
51209a7189fSNavdeep Parhar else
51309a7189fSNavdeep Parhar burstsize = pktsize * 4;
5141979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[0];
51509a7189fSNavdeep Parhar
5161979b511SNavdeep Parhar update = false;
517ec8004ddSNavdeep Parhar fa = fa2 = -1;
5182204b427SNavdeep Parhar mtx_lock(&sc->tc_lock);
5196beb67c7SNavdeep Parhar for (i = 0; i < sc->params.nsched_cls; i++, tc++) {
520ec8004ddSNavdeep Parhar if (tc->state >= CS_PARAMS_SET &&
521ec8004ddSNavdeep Parhar tc->ratemode == FW_SCHED_PARAMS_RATE_ABS &&
5222204b427SNavdeep Parhar tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE &&
5232204b427SNavdeep Parhar tc->mode == FW_SCHED_PARAMS_MODE_FLOW &&
52409a7189fSNavdeep Parhar tc->maxrate == maxrate && tc->pktsize == pktsize &&
52509a7189fSNavdeep Parhar tc->burstsize == burstsize) {
5262204b427SNavdeep Parhar tc->refcount++;
5272204b427SNavdeep Parhar *tc_idx = i;
528ec8004ddSNavdeep Parhar if (tc->state == CS_PARAMS_SET) {
529ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_REQUESTED;
5301979b511SNavdeep Parhar update = true;
5311979b511SNavdeep Parhar }
5322204b427SNavdeep Parhar goto done;
5332204b427SNavdeep Parhar }
534ec8004ddSNavdeep Parhar
535ec8004ddSNavdeep Parhar if (fa < 0 && tc->state == CS_UNINITIALIZED) {
536ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0);
537ec8004ddSNavdeep Parhar fa = i; /* first available, never used. */
538ec8004ddSNavdeep Parhar }
539ec8004ddSNavdeep Parhar if (fa2 < 0 && tc->refcount == 0 && !(tc->flags & CF_USER)) {
540ec8004ddSNavdeep Parhar fa2 = i; /* first available, used previously. */
541ec8004ddSNavdeep Parhar }
5422204b427SNavdeep Parhar }
5432204b427SNavdeep Parhar /* Not found */
5446beb67c7SNavdeep Parhar MPASS(i == sc->params.nsched_cls);
545ec8004ddSNavdeep Parhar if (fa == -1)
546ec8004ddSNavdeep Parhar fa = fa2;
547ec8004ddSNavdeep Parhar if (fa == -1) {
548ec8004ddSNavdeep Parhar *tc_idx = -1;
549ec8004ddSNavdeep Parhar rc = ENOSPC;
550ec8004ddSNavdeep Parhar } else {
551ec8004ddSNavdeep Parhar MPASS(fa >= 0 && fa < sc->params.nsched_cls);
5521979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[fa];
553ec8004ddSNavdeep Parhar MPASS(!(tc->flags & CF_USER));
554ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0);
555ec8004ddSNavdeep Parhar
5562204b427SNavdeep Parhar tc->refcount = 1;
557ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_REQUESTED;
5582204b427SNavdeep Parhar tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
5592204b427SNavdeep Parhar tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
5602204b427SNavdeep Parhar tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
5612204b427SNavdeep Parhar tc->maxrate = maxrate;
56209a7189fSNavdeep Parhar tc->pktsize = pktsize;
56309a7189fSNavdeep Parhar tc->burstsize = burstsize;
5642204b427SNavdeep Parhar *tc_idx = fa;
5651979b511SNavdeep Parhar update = true;
5662204b427SNavdeep Parhar }
5672204b427SNavdeep Parhar done:
5682204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock);
569ec8004ddSNavdeep Parhar if (update)
5701979b511SNavdeep Parhar t4_update_tx_sched(sc);
5712204b427SNavdeep Parhar return (rc);
5722204b427SNavdeep Parhar }
5732204b427SNavdeep Parhar
5742204b427SNavdeep Parhar void
t4_release_cl_rl(struct adapter * sc,int port_id,int tc_idx)5751979b511SNavdeep Parhar t4_release_cl_rl(struct adapter *sc, int port_id, int tc_idx)
5762204b427SNavdeep Parhar {
5772204b427SNavdeep Parhar struct tx_cl_rl_params *tc;
5782204b427SNavdeep Parhar
5792204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports);
5806beb67c7SNavdeep Parhar MPASS(tc_idx >= 0 && tc_idx < sc->params.nsched_cls);
5812204b427SNavdeep Parhar
5822204b427SNavdeep Parhar mtx_lock(&sc->tc_lock);
5832204b427SNavdeep Parhar tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx];
5842204b427SNavdeep Parhar MPASS(tc->refcount > 0);
5852204b427SNavdeep Parhar tc->refcount--;
5862204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock);
5872204b427SNavdeep Parhar }
58867e07112SNavdeep Parhar
5891979b511SNavdeep Parhar int
sysctl_tc(SYSCTL_HANDLER_ARGS)5901979b511SNavdeep Parhar sysctl_tc(SYSCTL_HANDLER_ARGS)
5911979b511SNavdeep Parhar {
5921979b511SNavdeep Parhar struct vi_info *vi = arg1;
59343bbae19SNavdeep Parhar struct adapter *sc = vi->adapter;
5941979b511SNavdeep Parhar struct sge_txq *txq;
5951979b511SNavdeep Parhar int qidx = arg2, rc, tc_idx;
5961979b511SNavdeep Parhar
59743bbae19SNavdeep Parhar MPASS(qidx >= vi->first_txq && qidx < vi->first_txq + vi->ntxq);
5981979b511SNavdeep Parhar
59943bbae19SNavdeep Parhar txq = &sc->sge.txq[qidx];
6001979b511SNavdeep Parhar tc_idx = txq->tc_idx;
6011979b511SNavdeep Parhar rc = sysctl_handle_int(oidp, &tc_idx, 0, req);
6021979b511SNavdeep Parhar if (rc != 0 || req->newptr == NULL)
6031979b511SNavdeep Parhar return (rc);
6041979b511SNavdeep Parhar
6051979b511SNavdeep Parhar if (sc->flags & IS_VF)
6061979b511SNavdeep Parhar return (EPERM);
6076beb67c7SNavdeep Parhar if (!in_range(tc_idx, 0, sc->params.nsched_cls - 1))
6081979b511SNavdeep Parhar return (EINVAL);
6091979b511SNavdeep Parhar
6101979b511SNavdeep Parhar return (bind_txq_to_traffic_class(sc, txq, tc_idx));
6111979b511SNavdeep Parhar }
6121979b511SNavdeep Parhar
6131979b511SNavdeep Parhar int
sysctl_tc_params(SYSCTL_HANDLER_ARGS)6141979b511SNavdeep Parhar sysctl_tc_params(SYSCTL_HANDLER_ARGS)
6151979b511SNavdeep Parhar {
6161979b511SNavdeep Parhar struct adapter *sc = arg1;
6171979b511SNavdeep Parhar struct tx_cl_rl_params tc;
6181979b511SNavdeep Parhar struct sbuf *sb;
6191979b511SNavdeep Parhar int i, rc, port_id, mbps, gbps;
6201979b511SNavdeep Parhar
6211979b511SNavdeep Parhar rc = sysctl_wire_old_buffer(req, 0);
6221979b511SNavdeep Parhar if (rc != 0)
6231979b511SNavdeep Parhar return (rc);
6241979b511SNavdeep Parhar
6251979b511SNavdeep Parhar sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req);
6261979b511SNavdeep Parhar if (sb == NULL)
6271979b511SNavdeep Parhar return (ENOMEM);
6281979b511SNavdeep Parhar
6291979b511SNavdeep Parhar port_id = arg2 >> 16;
6301979b511SNavdeep Parhar MPASS(port_id < sc->params.nports);
6311979b511SNavdeep Parhar MPASS(sc->port[port_id] != NULL);
6321979b511SNavdeep Parhar i = arg2 & 0xffff;
6336beb67c7SNavdeep Parhar MPASS(i < sc->params.nsched_cls);
6341979b511SNavdeep Parhar
6351979b511SNavdeep Parhar mtx_lock(&sc->tc_lock);
6361979b511SNavdeep Parhar tc = sc->port[port_id]->sched_params->cl_rl[i];
6371979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock);
6381979b511SNavdeep Parhar
639ec8004ddSNavdeep Parhar if (tc.state < CS_PARAMS_SET) {
640ec8004ddSNavdeep Parhar sbuf_printf(sb, "uninitialized");
641ec8004ddSNavdeep Parhar goto done;
642ec8004ddSNavdeep Parhar }
643ec8004ddSNavdeep Parhar
6441979b511SNavdeep Parhar switch (tc.rateunit) {
6451979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_BITS:
6461979b511SNavdeep Parhar switch (tc.ratemode) {
6471979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_REL:
6481979b511SNavdeep Parhar /* XXX: top speed or actual link speed? */
6491979b511SNavdeep Parhar gbps = port_top_speed(sc->port[port_id]);
6501979b511SNavdeep Parhar sbuf_printf(sb, "%u%% of %uGbps", tc.maxrate, gbps);
6511979b511SNavdeep Parhar break;
6521979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_ABS:
6531979b511SNavdeep Parhar mbps = tc.maxrate / 1000;
6541979b511SNavdeep Parhar gbps = tc.maxrate / 1000000;
6551979b511SNavdeep Parhar if (tc.maxrate == gbps * 1000000)
6561979b511SNavdeep Parhar sbuf_printf(sb, "%uGbps", gbps);
6571979b511SNavdeep Parhar else if (tc.maxrate == mbps * 1000)
6581979b511SNavdeep Parhar sbuf_printf(sb, "%uMbps", mbps);
6591979b511SNavdeep Parhar else
6601979b511SNavdeep Parhar sbuf_printf(sb, "%uKbps", tc.maxrate);
6611979b511SNavdeep Parhar break;
6621979b511SNavdeep Parhar default:
6631979b511SNavdeep Parhar rc = ENXIO;
6641979b511SNavdeep Parhar goto done;
6651979b511SNavdeep Parhar }
6661979b511SNavdeep Parhar break;
6671979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_PKTS:
6681979b511SNavdeep Parhar sbuf_printf(sb, "%upps", tc.maxrate);
6691979b511SNavdeep Parhar break;
6701979b511SNavdeep Parhar default:
6711979b511SNavdeep Parhar rc = ENXIO;
6721979b511SNavdeep Parhar goto done;
6731979b511SNavdeep Parhar }
6741979b511SNavdeep Parhar
6751979b511SNavdeep Parhar switch (tc.mode) {
6761979b511SNavdeep Parhar case SCHED_CLASS_MODE_CLASS:
677ec8004ddSNavdeep Parhar /* Note that pktsize and burstsize are not used in this mode. */
6781979b511SNavdeep Parhar sbuf_printf(sb, " aggregate");
6791979b511SNavdeep Parhar break;
6801979b511SNavdeep Parhar case SCHED_CLASS_MODE_FLOW:
6811979b511SNavdeep Parhar sbuf_printf(sb, " per-flow");
6828a684e1fSNavdeep Parhar if (tc.pktsize > 0)
6838a684e1fSNavdeep Parhar sbuf_printf(sb, " pkt-size %u", tc.pktsize);
6848a684e1fSNavdeep Parhar if (tc.burstsize > 0)
6858a684e1fSNavdeep Parhar sbuf_printf(sb, " burst-size %u", tc.burstsize);
6861979b511SNavdeep Parhar break;
6871979b511SNavdeep Parhar default:
6881979b511SNavdeep Parhar rc = ENXIO;
6891979b511SNavdeep Parhar goto done;
6901979b511SNavdeep Parhar }
6911979b511SNavdeep Parhar
6921979b511SNavdeep Parhar done:
6931979b511SNavdeep Parhar if (rc == 0)
6941979b511SNavdeep Parhar rc = sbuf_finish(sb);
6951979b511SNavdeep Parhar sbuf_delete(sb);
6961979b511SNavdeep Parhar
6971979b511SNavdeep Parhar return (rc);
6981979b511SNavdeep Parhar }
6991979b511SNavdeep Parhar
70067e07112SNavdeep Parhar #ifdef RATELIMIT
70167e07112SNavdeep Parhar void
t4_init_etid_table(struct adapter * sc)70267e07112SNavdeep Parhar t4_init_etid_table(struct adapter *sc)
70367e07112SNavdeep Parhar {
70467e07112SNavdeep Parhar int i;
70567e07112SNavdeep Parhar struct tid_info *t;
70667e07112SNavdeep Parhar
70767e07112SNavdeep Parhar if (!is_ethoffload(sc))
70867e07112SNavdeep Parhar return;
70967e07112SNavdeep Parhar
71067e07112SNavdeep Parhar t = &sc->tids;
71167e07112SNavdeep Parhar MPASS(t->netids > 0);
71267e07112SNavdeep Parhar
71367e07112SNavdeep Parhar mtx_init(&t->etid_lock, "etid lock", NULL, MTX_DEF);
71467e07112SNavdeep Parhar t->etid_tab = malloc(sizeof(*t->etid_tab) * t->netids, M_CXGBE,
71567e07112SNavdeep Parhar M_ZERO | M_WAITOK);
71667e07112SNavdeep Parhar t->efree = t->etid_tab;
71767e07112SNavdeep Parhar t->etids_in_use = 0;
71867e07112SNavdeep Parhar for (i = 1; i < t->netids; i++)
71967e07112SNavdeep Parhar t->etid_tab[i - 1].next = &t->etid_tab[i];
72067e07112SNavdeep Parhar t->etid_tab[t->netids - 1].next = NULL;
72167e07112SNavdeep Parhar }
72267e07112SNavdeep Parhar
72367e07112SNavdeep Parhar void
t4_free_etid_table(struct adapter * sc)72467e07112SNavdeep Parhar t4_free_etid_table(struct adapter *sc)
72567e07112SNavdeep Parhar {
72667e07112SNavdeep Parhar struct tid_info *t;
72767e07112SNavdeep Parhar
72867e07112SNavdeep Parhar if (!is_ethoffload(sc))
72967e07112SNavdeep Parhar return;
73067e07112SNavdeep Parhar
73167e07112SNavdeep Parhar t = &sc->tids;
73267e07112SNavdeep Parhar MPASS(t->netids > 0);
73367e07112SNavdeep Parhar
73467e07112SNavdeep Parhar free(t->etid_tab, M_CXGBE);
73567e07112SNavdeep Parhar t->etid_tab = NULL;
73667e07112SNavdeep Parhar
73767e07112SNavdeep Parhar if (mtx_initialized(&t->etid_lock))
73867e07112SNavdeep Parhar mtx_destroy(&t->etid_lock);
73967e07112SNavdeep Parhar }
74067e07112SNavdeep Parhar
74167e07112SNavdeep Parhar /* etid services */
742e38a50e8SJohn Baldwin static int alloc_etid(struct adapter *, struct cxgbe_rate_tag *);
74367e07112SNavdeep Parhar static void free_etid(struct adapter *, int);
74467e07112SNavdeep Parhar
74567e07112SNavdeep Parhar static int
alloc_etid(struct adapter * sc,struct cxgbe_rate_tag * cst)746e38a50e8SJohn Baldwin alloc_etid(struct adapter *sc, struct cxgbe_rate_tag *cst)
74767e07112SNavdeep Parhar {
74867e07112SNavdeep Parhar struct tid_info *t = &sc->tids;
74967e07112SNavdeep Parhar int etid = -1;
75067e07112SNavdeep Parhar
75167e07112SNavdeep Parhar mtx_lock(&t->etid_lock);
75267e07112SNavdeep Parhar if (t->efree) {
75367e07112SNavdeep Parhar union etid_entry *p = t->efree;
75467e07112SNavdeep Parhar
75567e07112SNavdeep Parhar etid = p - t->etid_tab + t->etid_base;
75667e07112SNavdeep Parhar t->efree = p->next;
75767e07112SNavdeep Parhar p->cst = cst;
75867e07112SNavdeep Parhar t->etids_in_use++;
75967e07112SNavdeep Parhar }
76067e07112SNavdeep Parhar mtx_unlock(&t->etid_lock);
76167e07112SNavdeep Parhar return (etid);
76267e07112SNavdeep Parhar }
76367e07112SNavdeep Parhar
764e38a50e8SJohn Baldwin struct cxgbe_rate_tag *
lookup_etid(struct adapter * sc,int etid)76567e07112SNavdeep Parhar lookup_etid(struct adapter *sc, int etid)
76667e07112SNavdeep Parhar {
76767e07112SNavdeep Parhar struct tid_info *t = &sc->tids;
76867e07112SNavdeep Parhar
76967e07112SNavdeep Parhar return (t->etid_tab[etid - t->etid_base].cst);
77067e07112SNavdeep Parhar }
77167e07112SNavdeep Parhar
77267e07112SNavdeep Parhar static void
free_etid(struct adapter * sc,int etid)77367e07112SNavdeep Parhar free_etid(struct adapter *sc, int etid)
77467e07112SNavdeep Parhar {
77567e07112SNavdeep Parhar struct tid_info *t = &sc->tids;
77667e07112SNavdeep Parhar union etid_entry *p = &t->etid_tab[etid - t->etid_base];
77767e07112SNavdeep Parhar
77867e07112SNavdeep Parhar mtx_lock(&t->etid_lock);
77967e07112SNavdeep Parhar p->next = t->efree;
78067e07112SNavdeep Parhar t->efree = p;
78167e07112SNavdeep Parhar t->etids_in_use--;
78267e07112SNavdeep Parhar mtx_unlock(&t->etid_lock);
78367e07112SNavdeep Parhar }
78467e07112SNavdeep Parhar
785c782ea8bSJohn Baldwin static int cxgbe_rate_tag_modify(struct m_snd_tag *,
786c782ea8bSJohn Baldwin union if_snd_tag_modify_params *);
787c782ea8bSJohn Baldwin static int cxgbe_rate_tag_query(struct m_snd_tag *,
788c782ea8bSJohn Baldwin union if_snd_tag_query_params *);
789c782ea8bSJohn Baldwin static void cxgbe_rate_tag_free(struct m_snd_tag *);
790c782ea8bSJohn Baldwin
791c782ea8bSJohn Baldwin static const struct if_snd_tag_sw cxgbe_rate_tag_sw = {
792c782ea8bSJohn Baldwin .snd_tag_modify = cxgbe_rate_tag_modify,
793c782ea8bSJohn Baldwin .snd_tag_query = cxgbe_rate_tag_query,
794c782ea8bSJohn Baldwin .snd_tag_free = cxgbe_rate_tag_free,
795c782ea8bSJohn Baldwin .type = IF_SND_TAG_TYPE_RATE_LIMIT
796c782ea8bSJohn Baldwin };
797c782ea8bSJohn Baldwin
79867e07112SNavdeep Parhar int
cxgbe_rate_tag_alloc(if_t ifp,union if_snd_tag_alloc_params * params,struct m_snd_tag ** pt)799954712e8SJustin Hibbits cxgbe_rate_tag_alloc(if_t ifp, union if_snd_tag_alloc_params *params,
80067e07112SNavdeep Parhar struct m_snd_tag **pt)
80167e07112SNavdeep Parhar {
80267e07112SNavdeep Parhar int rc, schedcl;
803954712e8SJustin Hibbits struct vi_info *vi = if_getsoftc(ifp);
80467e07112SNavdeep Parhar struct port_info *pi = vi->pi;
80567e07112SNavdeep Parhar struct adapter *sc = pi->adapter;
806e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst;
80767e07112SNavdeep Parhar
808e38a50e8SJohn Baldwin MPASS(params->hdr.type == IF_SND_TAG_TYPE_RATE_LIMIT);
80967e07112SNavdeep Parhar
81067e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, pi->port_id,
81167e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl);
81267e07112SNavdeep Parhar if (rc != 0)
81367e07112SNavdeep Parhar return (rc);
8146beb67c7SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->params.nsched_cls);
81567e07112SNavdeep Parhar
81667e07112SNavdeep Parhar cst = malloc(sizeof(*cst), M_CXGBE, M_ZERO | M_NOWAIT);
81767e07112SNavdeep Parhar if (cst == NULL) {
81867e07112SNavdeep Parhar failed:
8191979b511SNavdeep Parhar t4_release_cl_rl(sc, pi->port_id, schedcl);
82067e07112SNavdeep Parhar return (ENOMEM);
82167e07112SNavdeep Parhar }
82267e07112SNavdeep Parhar
82367e07112SNavdeep Parhar cst->etid = alloc_etid(sc, cst);
82467e07112SNavdeep Parhar if (cst->etid < 0) {
82567e07112SNavdeep Parhar free(cst, M_CXGBE);
82667e07112SNavdeep Parhar goto failed;
82767e07112SNavdeep Parhar }
82867e07112SNavdeep Parhar
82967e07112SNavdeep Parhar mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF);
830786099deSNavdeep Parhar mbufq_init(&cst->pending_tx, INT_MAX);
831786099deSNavdeep Parhar mbufq_init(&cst->pending_fwack, INT_MAX);
832c782ea8bSJohn Baldwin m_snd_tag_init(&cst->com, ifp, &cxgbe_rate_tag_sw);
833786099deSNavdeep Parhar cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF;
83467e07112SNavdeep Parhar cst->adapter = sc;
83567e07112SNavdeep Parhar cst->port_id = pi->port_id;
83667e07112SNavdeep Parhar cst->schedcl = schedcl;
83767e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate;
838ac8ec5feSNavdeep Parhar cst->tx_credits = sc->params.eo_wr_cred;
83967e07112SNavdeep Parhar cst->tx_total = cst->tx_credits;
840786099deSNavdeep Parhar cst->plen = 0;
841c0236bd9SNavdeep Parhar cst->ctrl0 = htobe32(V_TXPKT_OPCODE(CPL_TX_PKT_XT) |
842edb518f4SNavdeep Parhar V_TXPKT_INTF(pi->tx_chan) | V_TXPKT_PF(sc->pf) |
843edb518f4SNavdeep Parhar V_TXPKT_VF(vi->vin) | V_TXPKT_VF_VLD(vi->vfvld));
84467e07112SNavdeep Parhar
84567e07112SNavdeep Parhar /*
84667e07112SNavdeep Parhar * Queues will be selected later when the connection flowid is available.
84767e07112SNavdeep Parhar */
84867e07112SNavdeep Parhar
84956fb710fSJohn Baldwin *pt = &cst->com;
85067e07112SNavdeep Parhar return (0);
85167e07112SNavdeep Parhar }
85267e07112SNavdeep Parhar
85367e07112SNavdeep Parhar /*
85467e07112SNavdeep Parhar * Change in parameters, no change in ifp.
85567e07112SNavdeep Parhar */
856c782ea8bSJohn Baldwin static int
cxgbe_rate_tag_modify(struct m_snd_tag * mst,union if_snd_tag_modify_params * params)857e38a50e8SJohn Baldwin cxgbe_rate_tag_modify(struct m_snd_tag *mst,
85867e07112SNavdeep Parhar union if_snd_tag_modify_params *params)
85967e07112SNavdeep Parhar {
86067e07112SNavdeep Parhar int rc, schedcl;
861e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst);
86267e07112SNavdeep Parhar struct adapter *sc = cst->adapter;
86367e07112SNavdeep Parhar
86467e07112SNavdeep Parhar /* XXX: is schedcl -1 ok here? */
8656beb67c7SNavdeep Parhar MPASS(cst->schedcl >= 0 && cst->schedcl < sc->params.nsched_cls);
86667e07112SNavdeep Parhar
867786099deSNavdeep Parhar mtx_lock(&cst->lock);
868786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF);
86967e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, cst->port_id,
87067e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl);
87167e07112SNavdeep Parhar if (rc != 0)
87267e07112SNavdeep Parhar return (rc);
8736beb67c7SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->params.nsched_cls);
8741979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl);
87567e07112SNavdeep Parhar cst->schedcl = schedcl;
87667e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate;
877786099deSNavdeep Parhar mtx_unlock(&cst->lock);
87867e07112SNavdeep Parhar
87967e07112SNavdeep Parhar return (0);
88067e07112SNavdeep Parhar }
88167e07112SNavdeep Parhar
882c782ea8bSJohn Baldwin static int
cxgbe_rate_tag_query(struct m_snd_tag * mst,union if_snd_tag_query_params * params)883e38a50e8SJohn Baldwin cxgbe_rate_tag_query(struct m_snd_tag *mst,
88467e07112SNavdeep Parhar union if_snd_tag_query_params *params)
88567e07112SNavdeep Parhar {
886e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst);
88767e07112SNavdeep Parhar
88867e07112SNavdeep Parhar params->rate_limit.max_rate = cst->max_rate;
88967e07112SNavdeep Parhar
89067e07112SNavdeep Parhar #define CST_TO_MST_QLEVEL_SCALE (IF_SND_QUEUE_LEVEL_MAX / cst->tx_total)
89167e07112SNavdeep Parhar params->rate_limit.queue_level =
89267e07112SNavdeep Parhar (cst->tx_total - cst->tx_credits) * CST_TO_MST_QLEVEL_SCALE;
89367e07112SNavdeep Parhar
89467e07112SNavdeep Parhar return (0);
89567e07112SNavdeep Parhar }
89667e07112SNavdeep Parhar
897786099deSNavdeep Parhar /*
898786099deSNavdeep Parhar * Unlocks cst and frees it.
899786099deSNavdeep Parhar */
90067e07112SNavdeep Parhar void
cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag * cst)901e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *cst)
90267e07112SNavdeep Parhar {
90367e07112SNavdeep Parhar struct adapter *sc = cst->adapter;
90467e07112SNavdeep Parhar
905786099deSNavdeep Parhar mtx_assert(&cst->lock, MA_OWNED);
906786099deSNavdeep Parhar MPASS((cst->flags & EO_SND_TAG_REF) == 0);
907786099deSNavdeep Parhar MPASS(cst->tx_credits == cst->tx_total);
908786099deSNavdeep Parhar MPASS(cst->plen == 0);
909786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_tx) == NULL);
910786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_fwack) == NULL);
911786099deSNavdeep Parhar
91267e07112SNavdeep Parhar if (cst->etid >= 0)
91367e07112SNavdeep Parhar free_etid(sc, cst->etid);
91467e07112SNavdeep Parhar if (cst->schedcl != -1)
9151979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl);
916786099deSNavdeep Parhar mtx_unlock(&cst->lock);
91767e07112SNavdeep Parhar mtx_destroy(&cst->lock);
91867e07112SNavdeep Parhar free(cst, M_CXGBE);
91967e07112SNavdeep Parhar }
920786099deSNavdeep Parhar
921c782ea8bSJohn Baldwin static void
cxgbe_rate_tag_free(struct m_snd_tag * mst)922e38a50e8SJohn Baldwin cxgbe_rate_tag_free(struct m_snd_tag *mst)
923786099deSNavdeep Parhar {
924e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst);
925786099deSNavdeep Parhar
926786099deSNavdeep Parhar mtx_lock(&cst->lock);
927786099deSNavdeep Parhar
928786099deSNavdeep Parhar /* The kernel is done with the snd_tag. Remove its reference. */
929786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF);
930786099deSNavdeep Parhar cst->flags &= ~EO_SND_TAG_REF;
931786099deSNavdeep Parhar
932786099deSNavdeep Parhar if (cst->ncompl == 0) {
933786099deSNavdeep Parhar /*
934786099deSNavdeep Parhar * No fw4_ack in flight. Free the tag right away if there are
935786099deSNavdeep Parhar * no outstanding credits. Request the firmware to return all
936786099deSNavdeep Parhar * credits for the etid otherwise.
937786099deSNavdeep Parhar */
938786099deSNavdeep Parhar if (cst->tx_credits == cst->tx_total) {
939e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(cst);
940786099deSNavdeep Parhar return; /* cst is gone. */
941786099deSNavdeep Parhar }
942786099deSNavdeep Parhar send_etid_flush_wr(cst);
943786099deSNavdeep Parhar }
944786099deSNavdeep Parhar mtx_unlock(&cst->lock);
945786099deSNavdeep Parhar }
94620abea66SRandall Stewart
94720abea66SRandall Stewart void
cxgbe_ratelimit_query(if_t ifp,struct if_ratelimit_query_results * q)948954712e8SJustin Hibbits cxgbe_ratelimit_query(if_t ifp, struct if_ratelimit_query_results *q)
94920abea66SRandall Stewart {
950954712e8SJustin Hibbits struct vi_info *vi = if_getsoftc(ifp);
951b8b01d9bSNavdeep Parhar struct adapter *sc = vi->adapter;
952b8b01d9bSNavdeep Parhar
95320abea66SRandall Stewart q->rate_table = NULL;
95420abea66SRandall Stewart q->flags = RT_IS_SELECTABLE;
955b8b01d9bSNavdeep Parhar /*
956b8b01d9bSNavdeep Parhar * Absolute max limits from the firmware configuration. Practical
957954712e8SJustin Hibbits * limits depend on the burstsize, pktsize (if_getmtu(ifp) ultimately) and
958b8b01d9bSNavdeep Parhar * the card's cclk.
959b8b01d9bSNavdeep Parhar */
960b8b01d9bSNavdeep Parhar q->max_flows = sc->tids.netids;
9616beb67c7SNavdeep Parhar q->number_of_rates = sc->params.nsched_cls;
962b8b01d9bSNavdeep Parhar q->min_segment_burst = 4; /* matches PKTSCHED_BURST in the firmware. */
963b8b01d9bSNavdeep Parhar
964b8b01d9bSNavdeep Parhar #if 1
965b8b01d9bSNavdeep Parhar if (chip_id(sc) < CHELSIO_T6) {
966b8b01d9bSNavdeep Parhar /* Based on testing by rrs@ with a T580 at burstsize = 4. */
967b8b01d9bSNavdeep Parhar MPASS(q->min_segment_burst == 4);
968e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows);
969b8b01d9bSNavdeep Parhar } else {
970b8b01d9bSNavdeep Parhar /* XXX: TBD, carried forward from T5 for now. */
971e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows);
972b8b01d9bSNavdeep Parhar }
973b8b01d9bSNavdeep Parhar
974b8b01d9bSNavdeep Parhar /*
975b8b01d9bSNavdeep Parhar * XXX: tcp_ratelimit.c grabs all available rates on link-up before it
976b8b01d9bSNavdeep Parhar * even knows whether hw pacing will be used or not. This prevents
977b8b01d9bSNavdeep Parhar * other consumers like SO_MAX_PACING_RATE or those using cxgbetool or
978b8b01d9bSNavdeep Parhar * the private ioctls from using any of traffic classes.
979b8b01d9bSNavdeep Parhar *
980b8b01d9bSNavdeep Parhar * Underreport the number of rates to tcp_ratelimit so that it doesn't
981b8b01d9bSNavdeep Parhar * hog all of them. This can be removed if/when tcp_ratelimit switches
982b8b01d9bSNavdeep Parhar * to making its allocations on first-use rather than link-up. There is
983b8b01d9bSNavdeep Parhar * nothing wrong with one particular consumer reserving all the classes
984b8b01d9bSNavdeep Parhar * but it should do so only if it'll actually use hw rate limiting.
985b8b01d9bSNavdeep Parhar */
986b8b01d9bSNavdeep Parhar q->number_of_rates /= 4;
987b8b01d9bSNavdeep Parhar #endif
98820abea66SRandall Stewart }
98967e07112SNavdeep Parhar #endif
990