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 __FBSDID("$FreeBSD$"); 302204b427SNavdeep Parhar 312204b427SNavdeep Parhar #include "opt_inet.h" 322204b427SNavdeep Parhar #include "opt_inet6.h" 3367e07112SNavdeep Parhar #include "opt_ratelimit.h" 342204b427SNavdeep Parhar 352204b427SNavdeep Parhar #include <sys/types.h> 362204b427SNavdeep Parhar #include <sys/malloc.h> 372204b427SNavdeep Parhar #include <sys/queue.h> 382204b427SNavdeep Parhar #include <sys/sbuf.h> 392204b427SNavdeep Parhar #include <sys/taskqueue.h> 402204b427SNavdeep Parhar #include <sys/sysctl.h> 412204b427SNavdeep Parhar 422204b427SNavdeep Parhar #include "common/common.h" 432204b427SNavdeep Parhar #include "common/t4_regs.h" 442204b427SNavdeep Parhar #include "common/t4_regs_values.h" 452204b427SNavdeep Parhar #include "common/t4_msg.h" 462204b427SNavdeep Parhar 472204b427SNavdeep Parhar static int 482204b427SNavdeep Parhar in_range(int val, int lo, int hi) 492204b427SNavdeep Parhar { 502204b427SNavdeep Parhar 512204b427SNavdeep Parhar return (val < 0 || (val <= hi && val >= lo)); 522204b427SNavdeep Parhar } 532204b427SNavdeep Parhar 542204b427SNavdeep Parhar static int 552204b427SNavdeep Parhar set_sched_class_config(struct adapter *sc, int minmax) 562204b427SNavdeep Parhar { 572204b427SNavdeep Parhar int rc; 582204b427SNavdeep Parhar 592204b427SNavdeep Parhar if (minmax < 0) 602204b427SNavdeep Parhar return (EINVAL); 612204b427SNavdeep Parhar 622204b427SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc"); 632204b427SNavdeep Parhar if (rc) 642204b427SNavdeep Parhar return (rc); 6583b5cda1SNavdeep Parhar if (hw_off_limits(sc)) 6683b5cda1SNavdeep Parhar rc = ENXIO; 6783b5cda1SNavdeep Parhar else 682204b427SNavdeep Parhar rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1); 692204b427SNavdeep Parhar end_synchronized_op(sc, 0); 702204b427SNavdeep Parhar 712204b427SNavdeep Parhar return (rc); 722204b427SNavdeep Parhar } 732204b427SNavdeep Parhar 742204b427SNavdeep Parhar static int 752204b427SNavdeep Parhar set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p, 762204b427SNavdeep Parhar int sleep_ok) 772204b427SNavdeep Parhar { 782204b427SNavdeep Parhar int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode; 792204b427SNavdeep Parhar struct port_info *pi; 801979b511SNavdeep Parhar struct tx_cl_rl_params *tc, old; 819c3b8b3cSNavdeep Parhar bool check_pktsize = false; 822204b427SNavdeep Parhar 832204b427SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) 842204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL; 852204b427SNavdeep Parhar else if (p->level == SCHED_CLASS_LEVEL_CL_WRR) 862204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR; 872204b427SNavdeep Parhar else if (p->level == SCHED_CLASS_LEVEL_CH_RL) 882204b427SNavdeep Parhar fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL; 892204b427SNavdeep Parhar else 902204b427SNavdeep Parhar return (EINVAL); 912204b427SNavdeep Parhar 929c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 932204b427SNavdeep Parhar if (p->mode == SCHED_CLASS_MODE_CLASS) 942204b427SNavdeep Parhar fw_mode = FW_SCHED_PARAMS_MODE_CLASS; 959c3b8b3cSNavdeep Parhar else if (p->mode == SCHED_CLASS_MODE_FLOW) { 969c3b8b3cSNavdeep Parhar check_pktsize = true; 972204b427SNavdeep Parhar fw_mode = FW_SCHED_PARAMS_MODE_FLOW; 989c3b8b3cSNavdeep Parhar } else 992204b427SNavdeep Parhar return (EINVAL); 1009c3b8b3cSNavdeep Parhar } else 1019c3b8b3cSNavdeep Parhar fw_mode = 0; 1022204b427SNavdeep Parhar 1039c3b8b3cSNavdeep Parhar /* Valid channel must always be provided. */ 1049c3b8b3cSNavdeep Parhar if (p->channel < 0) 1052204b427SNavdeep Parhar return (EINVAL); 1062204b427SNavdeep Parhar if (!in_range(p->channel, 0, sc->chip_params->nchan - 1)) 1072204b427SNavdeep Parhar return (ERANGE); 1082204b427SNavdeep Parhar 1092204b427SNavdeep Parhar pi = sc->port[sc->chan_map[p->channel]]; 1102204b427SNavdeep Parhar if (pi == NULL) 1112204b427SNavdeep Parhar return (ENXIO); 1122204b427SNavdeep Parhar MPASS(pi->tx_chan == p->channel); 1132204b427SNavdeep Parhar top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */ 1142204b427SNavdeep Parhar 1159c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL || 1169c3b8b3cSNavdeep Parhar p->level == SCHED_CLASS_LEVEL_CH_RL) { 1172204b427SNavdeep Parhar /* 1189c3b8b3cSNavdeep Parhar * Valid rate (mode, unit and values) must be provided. 1192204b427SNavdeep Parhar */ 1202204b427SNavdeep Parhar 1212204b427SNavdeep Parhar if (p->minrate < 0) 1222204b427SNavdeep Parhar p->minrate = 0; 1239c3b8b3cSNavdeep Parhar if (p->maxrate < 0) 1242204b427SNavdeep Parhar return (EINVAL); 1259c3b8b3cSNavdeep Parhar 1269c3b8b3cSNavdeep Parhar if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS) { 1279c3b8b3cSNavdeep Parhar fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 1289c3b8b3cSNavdeep Parhar /* ratemode could be relative (%) or absolute. */ 1299c3b8b3cSNavdeep Parhar if (p->ratemode == SCHED_CLASS_RATEMODE_REL) { 1309c3b8b3cSNavdeep Parhar fw_ratemode = FW_SCHED_PARAMS_RATE_REL; 1319c3b8b3cSNavdeep Parhar /* maxrate is % of port bandwidth. */ 1329c3b8b3cSNavdeep Parhar if (!in_range(p->minrate, 0, 100) || 1339c3b8b3cSNavdeep Parhar !in_range(p->maxrate, 0, 100)) { 1349c3b8b3cSNavdeep Parhar return (ERANGE); 1352204b427SNavdeep Parhar } 1369c3b8b3cSNavdeep Parhar } else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS) { 1379c3b8b3cSNavdeep Parhar fw_ratemode = FW_SCHED_PARAMS_RATE_ABS; 1389c3b8b3cSNavdeep Parhar /* maxrate is absolute value in kbps. */ 1399c3b8b3cSNavdeep Parhar if (!in_range(p->minrate, 0, top_speed) || 1409c3b8b3cSNavdeep Parhar !in_range(p->maxrate, 0, top_speed)) { 1419c3b8b3cSNavdeep Parhar return (ERANGE); 1422204b427SNavdeep Parhar } 1439c3b8b3cSNavdeep Parhar } else 1442204b427SNavdeep Parhar return (EINVAL); 1459c3b8b3cSNavdeep Parhar } else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS) { 1469c3b8b3cSNavdeep Parhar /* maxrate is the absolute value in pps. */ 1479c3b8b3cSNavdeep Parhar check_pktsize = true; 1489c3b8b3cSNavdeep Parhar fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE; 1499c3b8b3cSNavdeep Parhar } else 1509c3b8b3cSNavdeep Parhar return (EINVAL); 1519c3b8b3cSNavdeep Parhar } else { 1529c3b8b3cSNavdeep Parhar MPASS(p->level == SCHED_CLASS_LEVEL_CL_WRR); 1539c3b8b3cSNavdeep Parhar 1549c3b8b3cSNavdeep Parhar /* 1559c3b8b3cSNavdeep Parhar * Valid weight must be provided. 1569c3b8b3cSNavdeep Parhar */ 1579c3b8b3cSNavdeep Parhar if (p->weight < 0) 1589c3b8b3cSNavdeep Parhar return (EINVAL); 1599c3b8b3cSNavdeep Parhar if (!in_range(p->weight, 1, 99)) 1609c3b8b3cSNavdeep Parhar return (ERANGE); 1619c3b8b3cSNavdeep Parhar 1629c3b8b3cSNavdeep Parhar fw_rateunit = 0; 1639c3b8b3cSNavdeep Parhar fw_ratemode = 0; 1649c3b8b3cSNavdeep Parhar } 1659c3b8b3cSNavdeep Parhar 1669c3b8b3cSNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL || 1679c3b8b3cSNavdeep Parhar p->level == SCHED_CLASS_LEVEL_CL_WRR) { 1689c3b8b3cSNavdeep Parhar /* 1699c3b8b3cSNavdeep Parhar * Valid scheduling class must be provided. 1709c3b8b3cSNavdeep Parhar */ 1719c3b8b3cSNavdeep Parhar if (p->cl < 0) 1729c3b8b3cSNavdeep Parhar return (EINVAL); 1736beb67c7SNavdeep Parhar if (!in_range(p->cl, 0, sc->params.nsched_cls - 1)) 1749c3b8b3cSNavdeep Parhar return (ERANGE); 1759c3b8b3cSNavdeep Parhar } 1769c3b8b3cSNavdeep Parhar 1779c3b8b3cSNavdeep Parhar if (check_pktsize) { 1789c3b8b3cSNavdeep Parhar if (p->pktsize < 0) 1799c3b8b3cSNavdeep Parhar return (EINVAL); 180*954712e8SJustin Hibbits if (!in_range(p->pktsize, 64, if_getmtu(pi->vi[0].ifp))) 1819c3b8b3cSNavdeep Parhar return (ERANGE); 1822204b427SNavdeep Parhar } 1832204b427SNavdeep Parhar 1842204b427SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 1852204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[p->cl]; 1861979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 187ec8004ddSNavdeep Parhar if (tc->refcount > 0 || tc->state == CS_HW_UPDATE_IN_PROGRESS) 1882204b427SNavdeep Parhar rc = EBUSY; 1891979b511SNavdeep Parhar else { 190ec8004ddSNavdeep Parhar old = *tc; 191ec8004ddSNavdeep Parhar 192ec8004ddSNavdeep Parhar tc->flags |= CF_USER; 193ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_IN_PROGRESS; 1942204b427SNavdeep Parhar tc->ratemode = fw_ratemode; 1952204b427SNavdeep Parhar tc->rateunit = fw_rateunit; 1962204b427SNavdeep Parhar tc->mode = fw_mode; 1972204b427SNavdeep Parhar tc->maxrate = p->maxrate; 1982204b427SNavdeep Parhar tc->pktsize = p->pktsize; 1991979b511SNavdeep Parhar rc = 0; 2002204b427SNavdeep Parhar } 2011979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2021979b511SNavdeep Parhar if (rc != 0) 2031979b511SNavdeep Parhar return (rc); 2041979b511SNavdeep Parhar } 2051979b511SNavdeep Parhar 2061979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, 2071979b511SNavdeep Parhar sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); 2081979b511SNavdeep Parhar if (rc != 0) { 2091979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 2101979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 211ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0); 212ec8004ddSNavdeep Parhar MPASS(tc->flags & CF_USER); 213ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_IN_PROGRESS); 2141979b511SNavdeep Parhar *tc = old; 2151979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2161979b511SNavdeep Parhar } 2171979b511SNavdeep Parhar return (rc); 2182204b427SNavdeep Parhar } 21983b5cda1SNavdeep Parhar if (!hw_off_limits(sc)) { 22083b5cda1SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, 22183b5cda1SNavdeep Parhar fw_mode, fw_rateunit, fw_ratemode, p->channel, p->cl, 22283b5cda1SNavdeep Parhar p->minrate, p->maxrate, p->weight, p->pktsize, 0, sleep_ok); 22383b5cda1SNavdeep Parhar } 2242204b427SNavdeep Parhar end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD); 2252204b427SNavdeep Parhar 2261979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 2271979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 2281979b511SNavdeep Parhar MPASS(tc->refcount == 0); 229ec8004ddSNavdeep Parhar MPASS(tc->flags & CF_USER); 230ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_IN_PROGRESS); 2311979b511SNavdeep Parhar 2321979b511SNavdeep Parhar if (rc == 0) 233ec8004ddSNavdeep Parhar tc->state = CS_HW_CONFIGURED; 234ec8004ddSNavdeep Parhar else { 235ec8004ddSNavdeep Parhar /* parameters failed so we don't park at params_set */ 236ec8004ddSNavdeep Parhar tc->state = CS_UNINITIALIZED; 237ec8004ddSNavdeep Parhar tc->flags &= ~CF_USER; 238ec8004ddSNavdeep Parhar CH_ERR(pi, "failed to configure traffic class %d: %d. " 239ec8004ddSNavdeep Parhar "params: mode %d, rateunit %d, ratemode %d, " 240ec8004ddSNavdeep Parhar "channel %d, minrate %d, maxrate %d, pktsize %d, " 241ec8004ddSNavdeep Parhar "burstsize %d\n", p->cl, rc, fw_mode, fw_rateunit, 242ec8004ddSNavdeep Parhar fw_ratemode, p->channel, p->minrate, p->maxrate, 243ec8004ddSNavdeep Parhar p->pktsize, 0); 244ec8004ddSNavdeep Parhar } 2451979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2461979b511SNavdeep Parhar } 2471979b511SNavdeep Parhar 2482204b427SNavdeep Parhar return (rc); 2492204b427SNavdeep Parhar } 2502204b427SNavdeep Parhar 2512204b427SNavdeep Parhar static void 2522204b427SNavdeep Parhar update_tx_sched(void *context, int pending) 2532204b427SNavdeep Parhar { 2541979b511SNavdeep Parhar int i, j, rc; 2552204b427SNavdeep Parhar struct port_info *pi; 2562204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 2572204b427SNavdeep Parhar struct adapter *sc = context; 2586beb67c7SNavdeep Parhar const int n = sc->params.nsched_cls; 2592204b427SNavdeep Parhar 2602204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 2612204b427SNavdeep Parhar for_each_port(sc, i) { 2622204b427SNavdeep Parhar pi = sc->port[i]; 2632204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[0]; 2642204b427SNavdeep Parhar for (j = 0; j < n; j++, tc++) { 2652204b427SNavdeep Parhar MPASS(mtx_owned(&sc->tc_lock)); 266ec8004ddSNavdeep Parhar if (tc->state != CS_HW_UPDATE_REQUESTED) 2672204b427SNavdeep Parhar continue; 2682204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2692204b427SNavdeep Parhar 2702204b427SNavdeep Parhar if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 2712204b427SNavdeep Parhar "t4utxs") != 0) { 2722204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 2732204b427SNavdeep Parhar continue; 2742204b427SNavdeep Parhar } 2751979b511SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, 2761979b511SNavdeep Parhar FW_SCHED_PARAMS_LEVEL_CL_RL, tc->mode, tc->rateunit, 2771979b511SNavdeep Parhar tc->ratemode, pi->tx_chan, j, 0, tc->maxrate, 0, 27809a7189fSNavdeep Parhar tc->pktsize, tc->burstsize, 1); 2792204b427SNavdeep Parhar end_synchronized_op(sc, 0); 2802204b427SNavdeep Parhar 2812204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 282ec8004ddSNavdeep Parhar MPASS(tc->state == CS_HW_UPDATE_REQUESTED); 283ec8004ddSNavdeep Parhar if (rc == 0) { 284ec8004ddSNavdeep Parhar tc->state = CS_HW_CONFIGURED; 285ec8004ddSNavdeep Parhar continue; 286ec8004ddSNavdeep Parhar } 287ec8004ddSNavdeep Parhar /* parameters failed so we try to avoid params_set */ 288ec8004ddSNavdeep Parhar if (tc->refcount > 0) 289ec8004ddSNavdeep Parhar tc->state = CS_PARAMS_SET; 2901979b511SNavdeep Parhar else 291ec8004ddSNavdeep Parhar tc->state = CS_UNINITIALIZED; 292ec8004ddSNavdeep Parhar CH_ERR(pi, "failed to configure traffic class %d: %d. " 293ec8004ddSNavdeep Parhar "params: mode %d, rateunit %d, ratemode %d, " 294ec8004ddSNavdeep Parhar "channel %d, minrate %d, maxrate %d, pktsize %d, " 295ec8004ddSNavdeep Parhar "burstsize %d\n", j, rc, tc->mode, tc->rateunit, 296ec8004ddSNavdeep Parhar tc->ratemode, pi->tx_chan, 0, tc->maxrate, 297ec8004ddSNavdeep Parhar tc->pktsize, tc->burstsize); 2982204b427SNavdeep Parhar } 2992204b427SNavdeep Parhar } 3002204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 3012204b427SNavdeep Parhar } 3022204b427SNavdeep Parhar 3032204b427SNavdeep Parhar int 3042204b427SNavdeep Parhar t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p) 3052204b427SNavdeep Parhar { 3062204b427SNavdeep Parhar 3072204b427SNavdeep Parhar if (p->type != SCHED_CLASS_TYPE_PACKET) 3082204b427SNavdeep Parhar return (EINVAL); 3092204b427SNavdeep Parhar 3102204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) 3112204b427SNavdeep Parhar return (set_sched_class_config(sc, p->u.config.minmax)); 3122204b427SNavdeep Parhar 3132204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) 3142204b427SNavdeep Parhar return (set_sched_class_params(sc, &p->u.params, 1)); 3152204b427SNavdeep Parhar 3162204b427SNavdeep Parhar return (EINVAL); 3172204b427SNavdeep Parhar } 3182204b427SNavdeep Parhar 3191979b511SNavdeep Parhar static int 3201979b511SNavdeep Parhar bind_txq_to_traffic_class(struct adapter *sc, struct sge_txq *txq, int idx) 3211979b511SNavdeep Parhar { 3221979b511SNavdeep Parhar struct tx_cl_rl_params *tc0, *tc; 3231979b511SNavdeep Parhar int rc, old_idx; 3241979b511SNavdeep Parhar uint32_t fw_mnem, fw_class; 3251979b511SNavdeep Parhar 32643bbae19SNavdeep Parhar if (!(txq->eq.flags & EQ_HW_ALLOCATED)) 32743bbae19SNavdeep Parhar return (ENXIO); 3281979b511SNavdeep Parhar 3291979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 3301979b511SNavdeep Parhar if (txq->tc_idx == -2) { 3311979b511SNavdeep Parhar rc = EBUSY; /* Another bind/unbind in progress already. */ 3321979b511SNavdeep Parhar goto done; 3331979b511SNavdeep Parhar } 3341979b511SNavdeep Parhar if (idx == txq->tc_idx) { 3351979b511SNavdeep Parhar rc = 0; /* No change, nothing to do. */ 3361979b511SNavdeep Parhar goto done; 3371979b511SNavdeep Parhar } 3381979b511SNavdeep Parhar 3391979b511SNavdeep Parhar tc0 = &sc->port[txq->eq.tx_chan]->sched_params->cl_rl[0]; 3401979b511SNavdeep Parhar if (idx != -1) { 3411979b511SNavdeep Parhar /* 3421979b511SNavdeep Parhar * Bind to a different class at index idx. 3431979b511SNavdeep Parhar */ 3441979b511SNavdeep Parhar tc = &tc0[idx]; 345ec8004ddSNavdeep Parhar if (tc->state != CS_HW_CONFIGURED) { 3461979b511SNavdeep Parhar rc = ENXIO; 3471979b511SNavdeep Parhar goto done; 3481979b511SNavdeep Parhar } else { 3491979b511SNavdeep Parhar /* 3501979b511SNavdeep Parhar * Ok to proceed. Place a reference on the new class 3511979b511SNavdeep Parhar * while still holding on to the reference on the 3521979b511SNavdeep Parhar * previous class, if any. 3531979b511SNavdeep Parhar */ 3541979b511SNavdeep Parhar tc->refcount++; 3551979b511SNavdeep Parhar } 3561979b511SNavdeep Parhar } 3571979b511SNavdeep Parhar /* Mark as busy before letting go of the lock. */ 3581979b511SNavdeep Parhar old_idx = txq->tc_idx; 3591979b511SNavdeep Parhar txq->tc_idx = -2; 3601979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 3611979b511SNavdeep Parhar 3621979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4btxq"); 363ec8004ddSNavdeep Parhar if (rc == 0) { 3641979b511SNavdeep Parhar fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | 3651979b511SNavdeep Parhar V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH) | 3661979b511SNavdeep Parhar V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 3671979b511SNavdeep Parhar fw_class = idx < 0 ? 0xffffffff : idx; 368ec8004ddSNavdeep Parhar rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_mnem, 369ec8004ddSNavdeep Parhar &fw_class); 3701979b511SNavdeep Parhar end_synchronized_op(sc, 0); 371ec8004ddSNavdeep Parhar } 3721979b511SNavdeep Parhar 3731979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 3741979b511SNavdeep Parhar MPASS(txq->tc_idx == -2); 3751979b511SNavdeep Parhar if (rc == 0) { 3761979b511SNavdeep Parhar /* 3771979b511SNavdeep Parhar * Unbind, bind, or bind to a different class succeeded. Remove 3781979b511SNavdeep Parhar * the reference on the old traffic class, if any. 3791979b511SNavdeep Parhar */ 3801979b511SNavdeep Parhar if (old_idx != -1) { 3811979b511SNavdeep Parhar tc = &tc0[old_idx]; 3821979b511SNavdeep Parhar MPASS(tc->refcount > 0); 3831979b511SNavdeep Parhar tc->refcount--; 3841979b511SNavdeep Parhar } 3851979b511SNavdeep Parhar txq->tc_idx = idx; 3861979b511SNavdeep Parhar } else { 3871979b511SNavdeep Parhar /* 3881979b511SNavdeep Parhar * Unbind, bind, or bind to a different class failed. Remove 3891979b511SNavdeep Parhar * the anticipatory reference on the new traffic class, if any. 3901979b511SNavdeep Parhar */ 3911979b511SNavdeep Parhar if (idx != -1) { 3921979b511SNavdeep Parhar tc = &tc0[idx]; 3931979b511SNavdeep Parhar MPASS(tc->refcount > 0); 3941979b511SNavdeep Parhar tc->refcount--; 3951979b511SNavdeep Parhar } 3961979b511SNavdeep Parhar txq->tc_idx = old_idx; 3971979b511SNavdeep Parhar } 3981979b511SNavdeep Parhar done: 3996beb67c7SNavdeep Parhar MPASS(txq->tc_idx >= -1 && txq->tc_idx < sc->params.nsched_cls); 4001979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 4011979b511SNavdeep Parhar return (rc); 4021979b511SNavdeep Parhar } 4031979b511SNavdeep Parhar 4042204b427SNavdeep Parhar int 4052204b427SNavdeep Parhar t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) 4062204b427SNavdeep Parhar { 4072204b427SNavdeep Parhar struct port_info *pi = NULL; 4082204b427SNavdeep Parhar struct vi_info *vi; 4092204b427SNavdeep Parhar struct sge_txq *txq; 4102204b427SNavdeep Parhar int i, rc; 4112204b427SNavdeep Parhar 4121979b511SNavdeep Parhar if (p->port >= sc->params.nports) 4131979b511SNavdeep Parhar return (EINVAL); 4142204b427SNavdeep Parhar 4151979b511SNavdeep Parhar /* 4161979b511SNavdeep Parhar * XXX: cxgbetool allows the user to specify the physical port only. So 4171979b511SNavdeep Parhar * we always operate on the main VI. 4181979b511SNavdeep Parhar */ 4192204b427SNavdeep Parhar pi = sc->port[p->port]; 4202204b427SNavdeep Parhar vi = &pi->vi[0]; 4211979b511SNavdeep Parhar 4221979b511SNavdeep Parhar /* Checking VI_INIT_DONE outside a synch-op is a harmless race here. */ 4231979b511SNavdeep Parhar if (!(vi->flags & VI_INIT_DONE)) 4241979b511SNavdeep Parhar return (EAGAIN); 425eb6f5d6eSNavdeep Parhar MPASS(vi->ntxq > 0); 4262204b427SNavdeep Parhar 4272204b427SNavdeep Parhar if (!in_range(p->queue, 0, vi->ntxq - 1) || 4286beb67c7SNavdeep Parhar !in_range(p->cl, 0, sc->params.nsched_cls - 1)) 4291979b511SNavdeep Parhar return (EINVAL); 4302204b427SNavdeep Parhar 4311979b511SNavdeep Parhar if (p->queue < 0) { 4322204b427SNavdeep Parhar /* 4332204b427SNavdeep Parhar * Change the scheduling on all the TX queues for the 4342204b427SNavdeep Parhar * interface. 4352204b427SNavdeep Parhar */ 4362204b427SNavdeep Parhar for_each_txq(vi, i, txq) { 4371979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl); 4381979b511SNavdeep Parhar if (rc != 0) 4391979b511SNavdeep Parhar break; 4401979b511SNavdeep Parhar } 4411979b511SNavdeep Parhar } else { 4421979b511SNavdeep Parhar /* 4431979b511SNavdeep Parhar * If op.queue is non-negative, then we're only changing the 4441979b511SNavdeep Parhar * scheduling on a single specified TX queue. 4451979b511SNavdeep Parhar */ 4461979b511SNavdeep Parhar txq = &sc->sge.txq[vi->first_txq + p->queue]; 4471979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl); 4482204b427SNavdeep Parhar } 4492204b427SNavdeep Parhar 4502204b427SNavdeep Parhar return (rc); 4512204b427SNavdeep Parhar } 4522204b427SNavdeep Parhar 4532204b427SNavdeep Parhar int 4542204b427SNavdeep Parhar t4_init_tx_sched(struct adapter *sc) 4552204b427SNavdeep Parhar { 456ec8004ddSNavdeep Parhar int i; 4576beb67c7SNavdeep Parhar const int n = sc->params.nsched_cls; 4582204b427SNavdeep Parhar struct port_info *pi; 4592204b427SNavdeep Parhar 4602204b427SNavdeep Parhar mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF); 4612204b427SNavdeep Parhar TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc); 4622204b427SNavdeep Parhar for_each_port(sc, i) { 4632204b427SNavdeep Parhar pi = sc->port[i]; 4642204b427SNavdeep Parhar pi->sched_params = malloc(sizeof(*pi->sched_params) + 465ec8004ddSNavdeep Parhar n * sizeof(struct tx_cl_rl_params), M_CXGBE, M_ZERO | M_WAITOK); 4662204b427SNavdeep Parhar } 4672204b427SNavdeep Parhar 4682204b427SNavdeep Parhar return (0); 4692204b427SNavdeep Parhar } 4702204b427SNavdeep Parhar 4712204b427SNavdeep Parhar int 4722204b427SNavdeep Parhar t4_free_tx_sched(struct adapter *sc) 4732204b427SNavdeep Parhar { 4742204b427SNavdeep Parhar int i; 4752204b427SNavdeep Parhar 4762204b427SNavdeep Parhar taskqueue_drain(taskqueue_thread, &sc->tc_task); 4772204b427SNavdeep Parhar 478cc2050c5SNavdeep Parhar for_each_port(sc, i) { 479cc2050c5SNavdeep Parhar if (sc->port[i] != NULL) 4802204b427SNavdeep Parhar free(sc->port[i]->sched_params, M_CXGBE); 481cc2050c5SNavdeep Parhar } 4822204b427SNavdeep Parhar 4832204b427SNavdeep Parhar if (mtx_initialized(&sc->tc_lock)) 4842204b427SNavdeep Parhar mtx_destroy(&sc->tc_lock); 4852204b427SNavdeep Parhar 4862204b427SNavdeep Parhar return (0); 4872204b427SNavdeep Parhar } 4882204b427SNavdeep Parhar 4892204b427SNavdeep Parhar void 4902204b427SNavdeep Parhar t4_update_tx_sched(struct adapter *sc) 4912204b427SNavdeep Parhar { 4922204b427SNavdeep Parhar 4932204b427SNavdeep Parhar taskqueue_enqueue(taskqueue_thread, &sc->tc_task); 4942204b427SNavdeep Parhar } 4952204b427SNavdeep Parhar 4962204b427SNavdeep Parhar int 4972204b427SNavdeep Parhar t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate, 4982204b427SNavdeep Parhar int *tc_idx) 4992204b427SNavdeep Parhar { 500ec8004ddSNavdeep Parhar int rc = 0, fa, fa2, i, pktsize, burstsize; 5011979b511SNavdeep Parhar bool update; 5022204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 5031979b511SNavdeep Parhar struct port_info *pi; 5042204b427SNavdeep Parhar 5052204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports); 5062204b427SNavdeep Parhar 5071979b511SNavdeep Parhar pi = sc->port[port_id]; 50809a7189fSNavdeep Parhar if (pi->sched_params->pktsize > 0) 50909a7189fSNavdeep Parhar pktsize = pi->sched_params->pktsize; 51009a7189fSNavdeep Parhar else 511*954712e8SJustin Hibbits pktsize = if_getmtu(pi->vi[0].ifp); 51209a7189fSNavdeep Parhar if (pi->sched_params->burstsize > 0) 51309a7189fSNavdeep Parhar burstsize = pi->sched_params->burstsize; 51409a7189fSNavdeep Parhar else 51509a7189fSNavdeep Parhar burstsize = pktsize * 4; 5161979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[0]; 51709a7189fSNavdeep Parhar 5181979b511SNavdeep Parhar update = false; 519ec8004ddSNavdeep Parhar fa = fa2 = -1; 5202204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 5216beb67c7SNavdeep Parhar for (i = 0; i < sc->params.nsched_cls; i++, tc++) { 522ec8004ddSNavdeep Parhar if (tc->state >= CS_PARAMS_SET && 523ec8004ddSNavdeep Parhar tc->ratemode == FW_SCHED_PARAMS_RATE_ABS && 5242204b427SNavdeep Parhar tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE && 5252204b427SNavdeep Parhar tc->mode == FW_SCHED_PARAMS_MODE_FLOW && 52609a7189fSNavdeep Parhar tc->maxrate == maxrate && tc->pktsize == pktsize && 52709a7189fSNavdeep Parhar tc->burstsize == burstsize) { 5282204b427SNavdeep Parhar tc->refcount++; 5292204b427SNavdeep Parhar *tc_idx = i; 530ec8004ddSNavdeep Parhar if (tc->state == CS_PARAMS_SET) { 531ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_REQUESTED; 5321979b511SNavdeep Parhar update = true; 5331979b511SNavdeep Parhar } 5342204b427SNavdeep Parhar goto done; 5352204b427SNavdeep Parhar } 536ec8004ddSNavdeep Parhar 537ec8004ddSNavdeep Parhar if (fa < 0 && tc->state == CS_UNINITIALIZED) { 538ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0); 539ec8004ddSNavdeep Parhar fa = i; /* first available, never used. */ 540ec8004ddSNavdeep Parhar } 541ec8004ddSNavdeep Parhar if (fa2 < 0 && tc->refcount == 0 && !(tc->flags & CF_USER)) { 542ec8004ddSNavdeep Parhar fa2 = i; /* first available, used previously. */ 543ec8004ddSNavdeep Parhar } 5442204b427SNavdeep Parhar } 5452204b427SNavdeep Parhar /* Not found */ 5466beb67c7SNavdeep Parhar MPASS(i == sc->params.nsched_cls); 547ec8004ddSNavdeep Parhar if (fa == -1) 548ec8004ddSNavdeep Parhar fa = fa2; 549ec8004ddSNavdeep Parhar if (fa == -1) { 550ec8004ddSNavdeep Parhar *tc_idx = -1; 551ec8004ddSNavdeep Parhar rc = ENOSPC; 552ec8004ddSNavdeep Parhar } else { 553ec8004ddSNavdeep Parhar MPASS(fa >= 0 && fa < sc->params.nsched_cls); 5541979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[fa]; 555ec8004ddSNavdeep Parhar MPASS(!(tc->flags & CF_USER)); 556ec8004ddSNavdeep Parhar MPASS(tc->refcount == 0); 557ec8004ddSNavdeep Parhar 5582204b427SNavdeep Parhar tc->refcount = 1; 559ec8004ddSNavdeep Parhar tc->state = CS_HW_UPDATE_REQUESTED; 5602204b427SNavdeep Parhar tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; 5612204b427SNavdeep Parhar tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 5622204b427SNavdeep Parhar tc->mode = FW_SCHED_PARAMS_MODE_FLOW; 5632204b427SNavdeep Parhar tc->maxrate = maxrate; 56409a7189fSNavdeep Parhar tc->pktsize = pktsize; 56509a7189fSNavdeep Parhar tc->burstsize = burstsize; 5662204b427SNavdeep Parhar *tc_idx = fa; 5671979b511SNavdeep Parhar update = true; 5682204b427SNavdeep Parhar } 5692204b427SNavdeep Parhar done: 5702204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 571ec8004ddSNavdeep Parhar if (update) 5721979b511SNavdeep Parhar t4_update_tx_sched(sc); 5732204b427SNavdeep Parhar return (rc); 5742204b427SNavdeep Parhar } 5752204b427SNavdeep Parhar 5762204b427SNavdeep Parhar void 5771979b511SNavdeep Parhar t4_release_cl_rl(struct adapter *sc, int port_id, int tc_idx) 5782204b427SNavdeep Parhar { 5792204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 5802204b427SNavdeep Parhar 5812204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports); 5826beb67c7SNavdeep Parhar MPASS(tc_idx >= 0 && tc_idx < sc->params.nsched_cls); 5832204b427SNavdeep Parhar 5842204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 5852204b427SNavdeep Parhar tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx]; 5862204b427SNavdeep Parhar MPASS(tc->refcount > 0); 5872204b427SNavdeep Parhar tc->refcount--; 5882204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 5892204b427SNavdeep Parhar } 59067e07112SNavdeep Parhar 5911979b511SNavdeep Parhar int 5921979b511SNavdeep Parhar sysctl_tc(SYSCTL_HANDLER_ARGS) 5931979b511SNavdeep Parhar { 5941979b511SNavdeep Parhar struct vi_info *vi = arg1; 59543bbae19SNavdeep Parhar struct adapter *sc = vi->adapter; 5961979b511SNavdeep Parhar struct sge_txq *txq; 5971979b511SNavdeep Parhar int qidx = arg2, rc, tc_idx; 5981979b511SNavdeep Parhar 59943bbae19SNavdeep Parhar MPASS(qidx >= vi->first_txq && qidx < vi->first_txq + vi->ntxq); 6001979b511SNavdeep Parhar 60143bbae19SNavdeep Parhar txq = &sc->sge.txq[qidx]; 6021979b511SNavdeep Parhar tc_idx = txq->tc_idx; 6031979b511SNavdeep Parhar rc = sysctl_handle_int(oidp, &tc_idx, 0, req); 6041979b511SNavdeep Parhar if (rc != 0 || req->newptr == NULL) 6051979b511SNavdeep Parhar return (rc); 6061979b511SNavdeep Parhar 6071979b511SNavdeep Parhar if (sc->flags & IS_VF) 6081979b511SNavdeep Parhar return (EPERM); 6096beb67c7SNavdeep Parhar if (!in_range(tc_idx, 0, sc->params.nsched_cls - 1)) 6101979b511SNavdeep Parhar return (EINVAL); 6111979b511SNavdeep Parhar 6121979b511SNavdeep Parhar return (bind_txq_to_traffic_class(sc, txq, tc_idx)); 6131979b511SNavdeep Parhar } 6141979b511SNavdeep Parhar 6151979b511SNavdeep Parhar int 6161979b511SNavdeep Parhar sysctl_tc_params(SYSCTL_HANDLER_ARGS) 6171979b511SNavdeep Parhar { 6181979b511SNavdeep Parhar struct adapter *sc = arg1; 6191979b511SNavdeep Parhar struct tx_cl_rl_params tc; 6201979b511SNavdeep Parhar struct sbuf *sb; 6211979b511SNavdeep Parhar int i, rc, port_id, mbps, gbps; 6221979b511SNavdeep Parhar 6231979b511SNavdeep Parhar rc = sysctl_wire_old_buffer(req, 0); 6241979b511SNavdeep Parhar if (rc != 0) 6251979b511SNavdeep Parhar return (rc); 6261979b511SNavdeep Parhar 6271979b511SNavdeep Parhar sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6281979b511SNavdeep Parhar if (sb == NULL) 6291979b511SNavdeep Parhar return (ENOMEM); 6301979b511SNavdeep Parhar 6311979b511SNavdeep Parhar port_id = arg2 >> 16; 6321979b511SNavdeep Parhar MPASS(port_id < sc->params.nports); 6331979b511SNavdeep Parhar MPASS(sc->port[port_id] != NULL); 6341979b511SNavdeep Parhar i = arg2 & 0xffff; 6356beb67c7SNavdeep Parhar MPASS(i < sc->params.nsched_cls); 6361979b511SNavdeep Parhar 6371979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 6381979b511SNavdeep Parhar tc = sc->port[port_id]->sched_params->cl_rl[i]; 6391979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 6401979b511SNavdeep Parhar 641ec8004ddSNavdeep Parhar if (tc.state < CS_PARAMS_SET) { 642ec8004ddSNavdeep Parhar sbuf_printf(sb, "uninitialized"); 643ec8004ddSNavdeep Parhar goto done; 644ec8004ddSNavdeep Parhar } 645ec8004ddSNavdeep Parhar 6461979b511SNavdeep Parhar switch (tc.rateunit) { 6471979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_BITS: 6481979b511SNavdeep Parhar switch (tc.ratemode) { 6491979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_REL: 6501979b511SNavdeep Parhar /* XXX: top speed or actual link speed? */ 6511979b511SNavdeep Parhar gbps = port_top_speed(sc->port[port_id]); 6521979b511SNavdeep Parhar sbuf_printf(sb, "%u%% of %uGbps", tc.maxrate, gbps); 6531979b511SNavdeep Parhar break; 6541979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_ABS: 6551979b511SNavdeep Parhar mbps = tc.maxrate / 1000; 6561979b511SNavdeep Parhar gbps = tc.maxrate / 1000000; 6571979b511SNavdeep Parhar if (tc.maxrate == gbps * 1000000) 6581979b511SNavdeep Parhar sbuf_printf(sb, "%uGbps", gbps); 6591979b511SNavdeep Parhar else if (tc.maxrate == mbps * 1000) 6601979b511SNavdeep Parhar sbuf_printf(sb, "%uMbps", mbps); 6611979b511SNavdeep Parhar else 6621979b511SNavdeep Parhar sbuf_printf(sb, "%uKbps", tc.maxrate); 6631979b511SNavdeep Parhar break; 6641979b511SNavdeep Parhar default: 6651979b511SNavdeep Parhar rc = ENXIO; 6661979b511SNavdeep Parhar goto done; 6671979b511SNavdeep Parhar } 6681979b511SNavdeep Parhar break; 6691979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_PKTS: 6701979b511SNavdeep Parhar sbuf_printf(sb, "%upps", tc.maxrate); 6711979b511SNavdeep Parhar break; 6721979b511SNavdeep Parhar default: 6731979b511SNavdeep Parhar rc = ENXIO; 6741979b511SNavdeep Parhar goto done; 6751979b511SNavdeep Parhar } 6761979b511SNavdeep Parhar 6771979b511SNavdeep Parhar switch (tc.mode) { 6781979b511SNavdeep Parhar case SCHED_CLASS_MODE_CLASS: 679ec8004ddSNavdeep Parhar /* Note that pktsize and burstsize are not used in this mode. */ 6801979b511SNavdeep Parhar sbuf_printf(sb, " aggregate"); 6811979b511SNavdeep Parhar break; 6821979b511SNavdeep Parhar case SCHED_CLASS_MODE_FLOW: 6831979b511SNavdeep Parhar sbuf_printf(sb, " per-flow"); 6848a684e1fSNavdeep Parhar if (tc.pktsize > 0) 6858a684e1fSNavdeep Parhar sbuf_printf(sb, " pkt-size %u", tc.pktsize); 6868a684e1fSNavdeep Parhar if (tc.burstsize > 0) 6878a684e1fSNavdeep Parhar sbuf_printf(sb, " burst-size %u", tc.burstsize); 6881979b511SNavdeep Parhar break; 6891979b511SNavdeep Parhar default: 6901979b511SNavdeep Parhar rc = ENXIO; 6911979b511SNavdeep Parhar goto done; 6921979b511SNavdeep Parhar } 6931979b511SNavdeep Parhar 6941979b511SNavdeep Parhar done: 6951979b511SNavdeep Parhar if (rc == 0) 6961979b511SNavdeep Parhar rc = sbuf_finish(sb); 6971979b511SNavdeep Parhar sbuf_delete(sb); 6981979b511SNavdeep Parhar 6991979b511SNavdeep Parhar return (rc); 7001979b511SNavdeep Parhar } 7011979b511SNavdeep Parhar 70267e07112SNavdeep Parhar #ifdef RATELIMIT 70367e07112SNavdeep Parhar void 70467e07112SNavdeep Parhar t4_init_etid_table(struct adapter *sc) 70567e07112SNavdeep Parhar { 70667e07112SNavdeep Parhar int i; 70767e07112SNavdeep Parhar struct tid_info *t; 70867e07112SNavdeep Parhar 70967e07112SNavdeep Parhar if (!is_ethoffload(sc)) 71067e07112SNavdeep Parhar return; 71167e07112SNavdeep Parhar 71267e07112SNavdeep Parhar t = &sc->tids; 71367e07112SNavdeep Parhar MPASS(t->netids > 0); 71467e07112SNavdeep Parhar 71567e07112SNavdeep Parhar mtx_init(&t->etid_lock, "etid lock", NULL, MTX_DEF); 71667e07112SNavdeep Parhar t->etid_tab = malloc(sizeof(*t->etid_tab) * t->netids, M_CXGBE, 71767e07112SNavdeep Parhar M_ZERO | M_WAITOK); 71867e07112SNavdeep Parhar t->efree = t->etid_tab; 71967e07112SNavdeep Parhar t->etids_in_use = 0; 72067e07112SNavdeep Parhar for (i = 1; i < t->netids; i++) 72167e07112SNavdeep Parhar t->etid_tab[i - 1].next = &t->etid_tab[i]; 72267e07112SNavdeep Parhar t->etid_tab[t->netids - 1].next = NULL; 72367e07112SNavdeep Parhar } 72467e07112SNavdeep Parhar 72567e07112SNavdeep Parhar void 72667e07112SNavdeep Parhar t4_free_etid_table(struct adapter *sc) 72767e07112SNavdeep Parhar { 72867e07112SNavdeep Parhar struct tid_info *t; 72967e07112SNavdeep Parhar 73067e07112SNavdeep Parhar if (!is_ethoffload(sc)) 73167e07112SNavdeep Parhar return; 73267e07112SNavdeep Parhar 73367e07112SNavdeep Parhar t = &sc->tids; 73467e07112SNavdeep Parhar MPASS(t->netids > 0); 73567e07112SNavdeep Parhar 73667e07112SNavdeep Parhar free(t->etid_tab, M_CXGBE); 73767e07112SNavdeep Parhar t->etid_tab = NULL; 73867e07112SNavdeep Parhar 73967e07112SNavdeep Parhar if (mtx_initialized(&t->etid_lock)) 74067e07112SNavdeep Parhar mtx_destroy(&t->etid_lock); 74167e07112SNavdeep Parhar } 74267e07112SNavdeep Parhar 74367e07112SNavdeep Parhar /* etid services */ 744e38a50e8SJohn Baldwin static int alloc_etid(struct adapter *, struct cxgbe_rate_tag *); 74567e07112SNavdeep Parhar static void free_etid(struct adapter *, int); 74667e07112SNavdeep Parhar 74767e07112SNavdeep Parhar static int 748e38a50e8SJohn Baldwin alloc_etid(struct adapter *sc, struct cxgbe_rate_tag *cst) 74967e07112SNavdeep Parhar { 75067e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 75167e07112SNavdeep Parhar int etid = -1; 75267e07112SNavdeep Parhar 75367e07112SNavdeep Parhar mtx_lock(&t->etid_lock); 75467e07112SNavdeep Parhar if (t->efree) { 75567e07112SNavdeep Parhar union etid_entry *p = t->efree; 75667e07112SNavdeep Parhar 75767e07112SNavdeep Parhar etid = p - t->etid_tab + t->etid_base; 75867e07112SNavdeep Parhar t->efree = p->next; 75967e07112SNavdeep Parhar p->cst = cst; 76067e07112SNavdeep Parhar t->etids_in_use++; 76167e07112SNavdeep Parhar } 76267e07112SNavdeep Parhar mtx_unlock(&t->etid_lock); 76367e07112SNavdeep Parhar return (etid); 76467e07112SNavdeep Parhar } 76567e07112SNavdeep Parhar 766e38a50e8SJohn Baldwin struct cxgbe_rate_tag * 76767e07112SNavdeep Parhar lookup_etid(struct adapter *sc, int etid) 76867e07112SNavdeep Parhar { 76967e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 77067e07112SNavdeep Parhar 77167e07112SNavdeep Parhar return (t->etid_tab[etid - t->etid_base].cst); 77267e07112SNavdeep Parhar } 77367e07112SNavdeep Parhar 77467e07112SNavdeep Parhar static void 77567e07112SNavdeep Parhar free_etid(struct adapter *sc, int etid) 77667e07112SNavdeep Parhar { 77767e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 77867e07112SNavdeep Parhar union etid_entry *p = &t->etid_tab[etid - t->etid_base]; 77967e07112SNavdeep Parhar 78067e07112SNavdeep Parhar mtx_lock(&t->etid_lock); 78167e07112SNavdeep Parhar p->next = t->efree; 78267e07112SNavdeep Parhar t->efree = p; 78367e07112SNavdeep Parhar t->etids_in_use--; 78467e07112SNavdeep Parhar mtx_unlock(&t->etid_lock); 78567e07112SNavdeep Parhar } 78667e07112SNavdeep Parhar 787c782ea8bSJohn Baldwin static int cxgbe_rate_tag_modify(struct m_snd_tag *, 788c782ea8bSJohn Baldwin union if_snd_tag_modify_params *); 789c782ea8bSJohn Baldwin static int cxgbe_rate_tag_query(struct m_snd_tag *, 790c782ea8bSJohn Baldwin union if_snd_tag_query_params *); 791c782ea8bSJohn Baldwin static void cxgbe_rate_tag_free(struct m_snd_tag *); 792c782ea8bSJohn Baldwin 793c782ea8bSJohn Baldwin static const struct if_snd_tag_sw cxgbe_rate_tag_sw = { 794c782ea8bSJohn Baldwin .snd_tag_modify = cxgbe_rate_tag_modify, 795c782ea8bSJohn Baldwin .snd_tag_query = cxgbe_rate_tag_query, 796c782ea8bSJohn Baldwin .snd_tag_free = cxgbe_rate_tag_free, 797c782ea8bSJohn Baldwin .type = IF_SND_TAG_TYPE_RATE_LIMIT 798c782ea8bSJohn Baldwin }; 799c782ea8bSJohn Baldwin 80067e07112SNavdeep Parhar int 801*954712e8SJustin Hibbits cxgbe_rate_tag_alloc(if_t ifp, union if_snd_tag_alloc_params *params, 80267e07112SNavdeep Parhar struct m_snd_tag **pt) 80367e07112SNavdeep Parhar { 80467e07112SNavdeep Parhar int rc, schedcl; 805*954712e8SJustin Hibbits struct vi_info *vi = if_getsoftc(ifp); 80667e07112SNavdeep Parhar struct port_info *pi = vi->pi; 80767e07112SNavdeep Parhar struct adapter *sc = pi->adapter; 808e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst; 80967e07112SNavdeep Parhar 810e38a50e8SJohn Baldwin MPASS(params->hdr.type == IF_SND_TAG_TYPE_RATE_LIMIT); 81167e07112SNavdeep Parhar 81267e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, pi->port_id, 81367e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl); 81467e07112SNavdeep Parhar if (rc != 0) 81567e07112SNavdeep Parhar return (rc); 8166beb67c7SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->params.nsched_cls); 81767e07112SNavdeep Parhar 81867e07112SNavdeep Parhar cst = malloc(sizeof(*cst), M_CXGBE, M_ZERO | M_NOWAIT); 81967e07112SNavdeep Parhar if (cst == NULL) { 82067e07112SNavdeep Parhar failed: 8211979b511SNavdeep Parhar t4_release_cl_rl(sc, pi->port_id, schedcl); 82267e07112SNavdeep Parhar return (ENOMEM); 82367e07112SNavdeep Parhar } 82467e07112SNavdeep Parhar 82567e07112SNavdeep Parhar cst->etid = alloc_etid(sc, cst); 82667e07112SNavdeep Parhar if (cst->etid < 0) { 82767e07112SNavdeep Parhar free(cst, M_CXGBE); 82867e07112SNavdeep Parhar goto failed; 82967e07112SNavdeep Parhar } 83067e07112SNavdeep Parhar 83167e07112SNavdeep Parhar mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF); 832786099deSNavdeep Parhar mbufq_init(&cst->pending_tx, INT_MAX); 833786099deSNavdeep Parhar mbufq_init(&cst->pending_fwack, INT_MAX); 834c782ea8bSJohn Baldwin m_snd_tag_init(&cst->com, ifp, &cxgbe_rate_tag_sw); 835786099deSNavdeep Parhar cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF; 83667e07112SNavdeep Parhar cst->adapter = sc; 83767e07112SNavdeep Parhar cst->port_id = pi->port_id; 83867e07112SNavdeep Parhar cst->schedcl = schedcl; 83967e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate; 840ac8ec5feSNavdeep Parhar cst->tx_credits = sc->params.eo_wr_cred; 84167e07112SNavdeep Parhar cst->tx_total = cst->tx_credits; 842786099deSNavdeep Parhar cst->plen = 0; 843c0236bd9SNavdeep Parhar cst->ctrl0 = htobe32(V_TXPKT_OPCODE(CPL_TX_PKT_XT) | 844edb518f4SNavdeep Parhar V_TXPKT_INTF(pi->tx_chan) | V_TXPKT_PF(sc->pf) | 845edb518f4SNavdeep Parhar V_TXPKT_VF(vi->vin) | V_TXPKT_VF_VLD(vi->vfvld)); 84667e07112SNavdeep Parhar 84767e07112SNavdeep Parhar /* 84867e07112SNavdeep Parhar * Queues will be selected later when the connection flowid is available. 84967e07112SNavdeep Parhar */ 85067e07112SNavdeep Parhar 85156fb710fSJohn Baldwin *pt = &cst->com; 85267e07112SNavdeep Parhar return (0); 85367e07112SNavdeep Parhar } 85467e07112SNavdeep Parhar 85567e07112SNavdeep Parhar /* 85667e07112SNavdeep Parhar * Change in parameters, no change in ifp. 85767e07112SNavdeep Parhar */ 858c782ea8bSJohn Baldwin static int 859e38a50e8SJohn Baldwin cxgbe_rate_tag_modify(struct m_snd_tag *mst, 86067e07112SNavdeep Parhar union if_snd_tag_modify_params *params) 86167e07112SNavdeep Parhar { 86267e07112SNavdeep Parhar int rc, schedcl; 863e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 86467e07112SNavdeep Parhar struct adapter *sc = cst->adapter; 86567e07112SNavdeep Parhar 86667e07112SNavdeep Parhar /* XXX: is schedcl -1 ok here? */ 8676beb67c7SNavdeep Parhar MPASS(cst->schedcl >= 0 && cst->schedcl < sc->params.nsched_cls); 86867e07112SNavdeep Parhar 869786099deSNavdeep Parhar mtx_lock(&cst->lock); 870786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF); 87167e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, cst->port_id, 87267e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl); 87367e07112SNavdeep Parhar if (rc != 0) 87467e07112SNavdeep Parhar return (rc); 8756beb67c7SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->params.nsched_cls); 8761979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl); 87767e07112SNavdeep Parhar cst->schedcl = schedcl; 87867e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate; 879786099deSNavdeep Parhar mtx_unlock(&cst->lock); 88067e07112SNavdeep Parhar 88167e07112SNavdeep Parhar return (0); 88267e07112SNavdeep Parhar } 88367e07112SNavdeep Parhar 884c782ea8bSJohn Baldwin static int 885e38a50e8SJohn Baldwin cxgbe_rate_tag_query(struct m_snd_tag *mst, 88667e07112SNavdeep Parhar union if_snd_tag_query_params *params) 88767e07112SNavdeep Parhar { 888e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 88967e07112SNavdeep Parhar 89067e07112SNavdeep Parhar params->rate_limit.max_rate = cst->max_rate; 89167e07112SNavdeep Parhar 89267e07112SNavdeep Parhar #define CST_TO_MST_QLEVEL_SCALE (IF_SND_QUEUE_LEVEL_MAX / cst->tx_total) 89367e07112SNavdeep Parhar params->rate_limit.queue_level = 89467e07112SNavdeep Parhar (cst->tx_total - cst->tx_credits) * CST_TO_MST_QLEVEL_SCALE; 89567e07112SNavdeep Parhar 89667e07112SNavdeep Parhar return (0); 89767e07112SNavdeep Parhar } 89867e07112SNavdeep Parhar 899786099deSNavdeep Parhar /* 900786099deSNavdeep Parhar * Unlocks cst and frees it. 901786099deSNavdeep Parhar */ 90267e07112SNavdeep Parhar void 903e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *cst) 90467e07112SNavdeep Parhar { 90567e07112SNavdeep Parhar struct adapter *sc = cst->adapter; 90667e07112SNavdeep Parhar 907786099deSNavdeep Parhar mtx_assert(&cst->lock, MA_OWNED); 908786099deSNavdeep Parhar MPASS((cst->flags & EO_SND_TAG_REF) == 0); 909786099deSNavdeep Parhar MPASS(cst->tx_credits == cst->tx_total); 910786099deSNavdeep Parhar MPASS(cst->plen == 0); 911786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_tx) == NULL); 912786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_fwack) == NULL); 913786099deSNavdeep Parhar 91467e07112SNavdeep Parhar if (cst->etid >= 0) 91567e07112SNavdeep Parhar free_etid(sc, cst->etid); 91667e07112SNavdeep Parhar if (cst->schedcl != -1) 9171979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl); 918786099deSNavdeep Parhar mtx_unlock(&cst->lock); 91967e07112SNavdeep Parhar mtx_destroy(&cst->lock); 92067e07112SNavdeep Parhar free(cst, M_CXGBE); 92167e07112SNavdeep Parhar } 922786099deSNavdeep Parhar 923c782ea8bSJohn Baldwin static void 924e38a50e8SJohn Baldwin cxgbe_rate_tag_free(struct m_snd_tag *mst) 925786099deSNavdeep Parhar { 926e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 927786099deSNavdeep Parhar 928786099deSNavdeep Parhar mtx_lock(&cst->lock); 929786099deSNavdeep Parhar 930786099deSNavdeep Parhar /* The kernel is done with the snd_tag. Remove its reference. */ 931786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF); 932786099deSNavdeep Parhar cst->flags &= ~EO_SND_TAG_REF; 933786099deSNavdeep Parhar 934786099deSNavdeep Parhar if (cst->ncompl == 0) { 935786099deSNavdeep Parhar /* 936786099deSNavdeep Parhar * No fw4_ack in flight. Free the tag right away if there are 937786099deSNavdeep Parhar * no outstanding credits. Request the firmware to return all 938786099deSNavdeep Parhar * credits for the etid otherwise. 939786099deSNavdeep Parhar */ 940786099deSNavdeep Parhar if (cst->tx_credits == cst->tx_total) { 941e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(cst); 942786099deSNavdeep Parhar return; /* cst is gone. */ 943786099deSNavdeep Parhar } 944786099deSNavdeep Parhar send_etid_flush_wr(cst); 945786099deSNavdeep Parhar } 946786099deSNavdeep Parhar mtx_unlock(&cst->lock); 947786099deSNavdeep Parhar } 94820abea66SRandall Stewart 94920abea66SRandall Stewart void 950*954712e8SJustin Hibbits cxgbe_ratelimit_query(if_t ifp, struct if_ratelimit_query_results *q) 95120abea66SRandall Stewart { 952*954712e8SJustin Hibbits struct vi_info *vi = if_getsoftc(ifp); 953b8b01d9bSNavdeep Parhar struct adapter *sc = vi->adapter; 954b8b01d9bSNavdeep Parhar 95520abea66SRandall Stewart q->rate_table = NULL; 95620abea66SRandall Stewart q->flags = RT_IS_SELECTABLE; 957b8b01d9bSNavdeep Parhar /* 958b8b01d9bSNavdeep Parhar * Absolute max limits from the firmware configuration. Practical 959*954712e8SJustin Hibbits * limits depend on the burstsize, pktsize (if_getmtu(ifp) ultimately) and 960b8b01d9bSNavdeep Parhar * the card's cclk. 961b8b01d9bSNavdeep Parhar */ 962b8b01d9bSNavdeep Parhar q->max_flows = sc->tids.netids; 9636beb67c7SNavdeep Parhar q->number_of_rates = sc->params.nsched_cls; 964b8b01d9bSNavdeep Parhar q->min_segment_burst = 4; /* matches PKTSCHED_BURST in the firmware. */ 965b8b01d9bSNavdeep Parhar 966b8b01d9bSNavdeep Parhar #if 1 967b8b01d9bSNavdeep Parhar if (chip_id(sc) < CHELSIO_T6) { 968b8b01d9bSNavdeep Parhar /* Based on testing by rrs@ with a T580 at burstsize = 4. */ 969b8b01d9bSNavdeep Parhar MPASS(q->min_segment_burst == 4); 970e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows); 971b8b01d9bSNavdeep Parhar } else { 972b8b01d9bSNavdeep Parhar /* XXX: TBD, carried forward from T5 for now. */ 973e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows); 974b8b01d9bSNavdeep Parhar } 975b8b01d9bSNavdeep Parhar 976b8b01d9bSNavdeep Parhar /* 977b8b01d9bSNavdeep Parhar * XXX: tcp_ratelimit.c grabs all available rates on link-up before it 978b8b01d9bSNavdeep Parhar * even knows whether hw pacing will be used or not. This prevents 979b8b01d9bSNavdeep Parhar * other consumers like SO_MAX_PACING_RATE or those using cxgbetool or 980b8b01d9bSNavdeep Parhar * the private ioctls from using any of traffic classes. 981b8b01d9bSNavdeep Parhar * 982b8b01d9bSNavdeep Parhar * Underreport the number of rates to tcp_ratelimit so that it doesn't 983b8b01d9bSNavdeep Parhar * hog all of them. This can be removed if/when tcp_ratelimit switches 984b8b01d9bSNavdeep Parhar * to making its allocations on first-use rather than link-up. There is 985b8b01d9bSNavdeep Parhar * nothing wrong with one particular consumer reserving all the classes 986b8b01d9bSNavdeep Parhar * but it should do so only if it'll actually use hw rate limiting. 987b8b01d9bSNavdeep Parhar */ 988b8b01d9bSNavdeep Parhar q->number_of_rates /= 4; 989b8b01d9bSNavdeep Parhar #endif 99020abea66SRandall Stewart } 99167e07112SNavdeep Parhar #endif 992