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 482204b427SNavdeep Parhar static int 492204b427SNavdeep Parhar in_range(int val, int lo, int hi) 502204b427SNavdeep Parhar { 512204b427SNavdeep Parhar 522204b427SNavdeep Parhar return (val < 0 || (val <= hi && val >= lo)); 532204b427SNavdeep Parhar } 542204b427SNavdeep Parhar 552204b427SNavdeep Parhar static int 562204b427SNavdeep Parhar set_sched_class_config(struct adapter *sc, int minmax) 572204b427SNavdeep Parhar { 582204b427SNavdeep Parhar int rc; 592204b427SNavdeep Parhar 602204b427SNavdeep Parhar if (minmax < 0) 612204b427SNavdeep Parhar return (EINVAL); 622204b427SNavdeep Parhar 632204b427SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc"); 642204b427SNavdeep Parhar if (rc) 652204b427SNavdeep Parhar return (rc); 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 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); 1719c3b8b3cSNavdeep Parhar if (!in_range(p->cl, 0, sc->chip_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); 1789c3b8b3cSNavdeep Parhar if (!in_range(p->pktsize, 64, pi->vi[0].ifp->if_mtu)) 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); 1851979b511SNavdeep Parhar if (tc->refcount > 0 || tc->flags & (CLRL_SYNC | CLRL_ASYNC)) 1862204b427SNavdeep Parhar rc = EBUSY; 1871979b511SNavdeep Parhar else { 1881979b511SNavdeep Parhar tc->flags |= CLRL_SYNC | CLRL_USER; 1892204b427SNavdeep Parhar tc->ratemode = fw_ratemode; 1902204b427SNavdeep Parhar tc->rateunit = fw_rateunit; 1912204b427SNavdeep Parhar tc->mode = fw_mode; 1922204b427SNavdeep Parhar tc->maxrate = p->maxrate; 1932204b427SNavdeep Parhar tc->pktsize = p->pktsize; 1941979b511SNavdeep Parhar rc = 0; 1951979b511SNavdeep Parhar old= *tc; 1962204b427SNavdeep Parhar } 1971979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 1981979b511SNavdeep Parhar if (rc != 0) 1991979b511SNavdeep Parhar return (rc); 2001979b511SNavdeep Parhar } 2011979b511SNavdeep Parhar 2021979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, 2031979b511SNavdeep Parhar sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); 2041979b511SNavdeep Parhar if (rc != 0) { 2051979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 2061979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 2071979b511SNavdeep Parhar *tc = old; 2081979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2091979b511SNavdeep Parhar } 2101979b511SNavdeep Parhar return (rc); 2112204b427SNavdeep Parhar } 2122204b427SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode, 2132204b427SNavdeep Parhar fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate, 21409a7189fSNavdeep Parhar p->weight, p->pktsize, 0, sleep_ok); 2152204b427SNavdeep Parhar end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD); 2162204b427SNavdeep Parhar 2171979b511SNavdeep Parhar if (p->level == SCHED_CLASS_LEVEL_CL_RL) { 2181979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 2191979b511SNavdeep Parhar MPASS(tc->flags & CLRL_SYNC); 2201979b511SNavdeep Parhar MPASS(tc->flags & CLRL_USER); 2211979b511SNavdeep Parhar MPASS(tc->refcount == 0); 2221979b511SNavdeep Parhar 2231979b511SNavdeep Parhar tc->flags &= ~CLRL_SYNC; 2241979b511SNavdeep Parhar if (rc == 0) 2251979b511SNavdeep Parhar tc->flags &= ~CLRL_ERR; 2261979b511SNavdeep Parhar else 2271979b511SNavdeep Parhar tc->flags |= CLRL_ERR; 2281979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2291979b511SNavdeep Parhar } 2301979b511SNavdeep Parhar 2312204b427SNavdeep Parhar return (rc); 2322204b427SNavdeep Parhar } 2332204b427SNavdeep Parhar 2342204b427SNavdeep Parhar static void 2352204b427SNavdeep Parhar update_tx_sched(void *context, int pending) 2362204b427SNavdeep Parhar { 2371979b511SNavdeep Parhar int i, j, rc; 2382204b427SNavdeep Parhar struct port_info *pi; 2392204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 2402204b427SNavdeep Parhar struct adapter *sc = context; 2412204b427SNavdeep Parhar const int n = sc->chip_params->nsched_cls; 2422204b427SNavdeep Parhar 2432204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 2442204b427SNavdeep Parhar for_each_port(sc, i) { 2452204b427SNavdeep Parhar pi = sc->port[i]; 2462204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[0]; 2472204b427SNavdeep Parhar for (j = 0; j < n; j++, tc++) { 2482204b427SNavdeep Parhar MPASS(mtx_owned(&sc->tc_lock)); 2491979b511SNavdeep Parhar if ((tc->flags & CLRL_ASYNC) == 0) 2502204b427SNavdeep Parhar continue; 2512204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2522204b427SNavdeep Parhar 2532204b427SNavdeep Parhar if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, 2542204b427SNavdeep Parhar "t4utxs") != 0) { 2552204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 2562204b427SNavdeep Parhar continue; 2572204b427SNavdeep Parhar } 2581979b511SNavdeep Parhar rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, 2591979b511SNavdeep Parhar FW_SCHED_PARAMS_LEVEL_CL_RL, tc->mode, tc->rateunit, 2601979b511SNavdeep Parhar tc->ratemode, pi->tx_chan, j, 0, tc->maxrate, 0, 26109a7189fSNavdeep Parhar tc->pktsize, tc->burstsize, 1); 2622204b427SNavdeep Parhar end_synchronized_op(sc, 0); 2632204b427SNavdeep Parhar 2642204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 2651979b511SNavdeep Parhar MPASS(tc->flags & CLRL_ASYNC); 2661979b511SNavdeep Parhar tc->flags &= ~CLRL_ASYNC; 2671979b511SNavdeep Parhar if (rc == 0) 2681979b511SNavdeep Parhar tc->flags &= ~CLRL_ERR; 2691979b511SNavdeep Parhar else 2701979b511SNavdeep Parhar tc->flags |= CLRL_ERR; 2712204b427SNavdeep Parhar } 2722204b427SNavdeep Parhar } 2732204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 2742204b427SNavdeep Parhar } 2752204b427SNavdeep Parhar 2762204b427SNavdeep Parhar int 2772204b427SNavdeep Parhar t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p) 2782204b427SNavdeep Parhar { 2792204b427SNavdeep Parhar 2802204b427SNavdeep Parhar if (p->type != SCHED_CLASS_TYPE_PACKET) 2812204b427SNavdeep Parhar return (EINVAL); 2822204b427SNavdeep Parhar 2832204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG) 2842204b427SNavdeep Parhar return (set_sched_class_config(sc, p->u.config.minmax)); 2852204b427SNavdeep Parhar 2862204b427SNavdeep Parhar if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS) 2872204b427SNavdeep Parhar return (set_sched_class_params(sc, &p->u.params, 1)); 2882204b427SNavdeep Parhar 2892204b427SNavdeep Parhar return (EINVAL); 2902204b427SNavdeep Parhar } 2912204b427SNavdeep Parhar 2921979b511SNavdeep Parhar static int 2931979b511SNavdeep Parhar bind_txq_to_traffic_class(struct adapter *sc, struct sge_txq *txq, int idx) 2941979b511SNavdeep Parhar { 2951979b511SNavdeep Parhar struct tx_cl_rl_params *tc0, *tc; 2961979b511SNavdeep Parhar int rc, old_idx; 2971979b511SNavdeep Parhar uint32_t fw_mnem, fw_class; 2981979b511SNavdeep Parhar 2991979b511SNavdeep Parhar if (!(txq->eq.flags & EQ_ALLOCATED)) 3001979b511SNavdeep Parhar return (EAGAIN); 3011979b511SNavdeep Parhar 3021979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 3031979b511SNavdeep Parhar if (txq->tc_idx == -2) { 3041979b511SNavdeep Parhar rc = EBUSY; /* Another bind/unbind in progress already. */ 3051979b511SNavdeep Parhar goto done; 3061979b511SNavdeep Parhar } 3071979b511SNavdeep Parhar if (idx == txq->tc_idx) { 3081979b511SNavdeep Parhar rc = 0; /* No change, nothing to do. */ 3091979b511SNavdeep Parhar goto done; 3101979b511SNavdeep Parhar } 3111979b511SNavdeep Parhar 3121979b511SNavdeep Parhar tc0 = &sc->port[txq->eq.tx_chan]->sched_params->cl_rl[0]; 3131979b511SNavdeep Parhar if (idx != -1) { 3141979b511SNavdeep Parhar /* 3151979b511SNavdeep Parhar * Bind to a different class at index idx. 3161979b511SNavdeep Parhar */ 3171979b511SNavdeep Parhar tc = &tc0[idx]; 3181979b511SNavdeep Parhar if (tc->flags & CLRL_ERR) { 3191979b511SNavdeep Parhar rc = ENXIO; 3201979b511SNavdeep Parhar goto done; 3211979b511SNavdeep Parhar } else { 3221979b511SNavdeep Parhar /* 3231979b511SNavdeep Parhar * Ok to proceed. Place a reference on the new class 3241979b511SNavdeep Parhar * while still holding on to the reference on the 3251979b511SNavdeep Parhar * previous class, if any. 3261979b511SNavdeep Parhar */ 3271979b511SNavdeep Parhar tc->refcount++; 3281979b511SNavdeep Parhar } 3291979b511SNavdeep Parhar } 3301979b511SNavdeep Parhar /* Mark as busy before letting go of the lock. */ 3311979b511SNavdeep Parhar old_idx = txq->tc_idx; 3321979b511SNavdeep Parhar txq->tc_idx = -2; 3331979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 3341979b511SNavdeep Parhar 3351979b511SNavdeep Parhar rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4btxq"); 3361979b511SNavdeep Parhar if (rc != 0) 3371979b511SNavdeep Parhar return (rc); 3381979b511SNavdeep Parhar fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | 3391979b511SNavdeep Parhar V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH) | 3401979b511SNavdeep Parhar V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); 3411979b511SNavdeep Parhar fw_class = idx < 0 ? 0xffffffff : idx; 3421979b511SNavdeep Parhar rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_mnem, &fw_class); 3431979b511SNavdeep Parhar end_synchronized_op(sc, 0); 3441979b511SNavdeep Parhar 3451979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 3461979b511SNavdeep Parhar MPASS(txq->tc_idx == -2); 3471979b511SNavdeep Parhar if (rc == 0) { 3481979b511SNavdeep Parhar /* 3491979b511SNavdeep Parhar * Unbind, bind, or bind to a different class succeeded. Remove 3501979b511SNavdeep Parhar * the reference on the old traffic class, if any. 3511979b511SNavdeep Parhar */ 3521979b511SNavdeep Parhar if (old_idx != -1) { 3531979b511SNavdeep Parhar tc = &tc0[old_idx]; 3541979b511SNavdeep Parhar MPASS(tc->refcount > 0); 3551979b511SNavdeep Parhar tc->refcount--; 3561979b511SNavdeep Parhar } 3571979b511SNavdeep Parhar txq->tc_idx = idx; 3581979b511SNavdeep Parhar } else { 3591979b511SNavdeep Parhar /* 3601979b511SNavdeep Parhar * Unbind, bind, or bind to a different class failed. Remove 3611979b511SNavdeep Parhar * the anticipatory reference on the new traffic class, if any. 3621979b511SNavdeep Parhar */ 3631979b511SNavdeep Parhar if (idx != -1) { 3641979b511SNavdeep Parhar tc = &tc0[idx]; 3651979b511SNavdeep Parhar MPASS(tc->refcount > 0); 3661979b511SNavdeep Parhar tc->refcount--; 3671979b511SNavdeep Parhar } 3681979b511SNavdeep Parhar txq->tc_idx = old_idx; 3691979b511SNavdeep Parhar } 3701979b511SNavdeep Parhar done: 3711979b511SNavdeep Parhar MPASS(txq->tc_idx >= -1 && txq->tc_idx < sc->chip_params->nsched_cls); 3721979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 3731979b511SNavdeep Parhar return (rc); 3741979b511SNavdeep Parhar } 3751979b511SNavdeep Parhar 3762204b427SNavdeep Parhar int 3772204b427SNavdeep Parhar t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) 3782204b427SNavdeep Parhar { 3792204b427SNavdeep Parhar struct port_info *pi = NULL; 3802204b427SNavdeep Parhar struct vi_info *vi; 3812204b427SNavdeep Parhar struct sge_txq *txq; 3822204b427SNavdeep Parhar int i, rc; 3832204b427SNavdeep Parhar 3841979b511SNavdeep Parhar if (p->port >= sc->params.nports) 3851979b511SNavdeep Parhar return (EINVAL); 3862204b427SNavdeep Parhar 3871979b511SNavdeep Parhar /* 3881979b511SNavdeep Parhar * XXX: cxgbetool allows the user to specify the physical port only. So 3891979b511SNavdeep Parhar * we always operate on the main VI. 3901979b511SNavdeep Parhar */ 3912204b427SNavdeep Parhar pi = sc->port[p->port]; 3922204b427SNavdeep Parhar vi = &pi->vi[0]; 3931979b511SNavdeep Parhar 3941979b511SNavdeep Parhar /* Checking VI_INIT_DONE outside a synch-op is a harmless race here. */ 3951979b511SNavdeep Parhar if (!(vi->flags & VI_INIT_DONE)) 3961979b511SNavdeep Parhar return (EAGAIN); 397eb6f5d6eSNavdeep Parhar MPASS(vi->ntxq > 0); 3982204b427SNavdeep Parhar 3992204b427SNavdeep Parhar if (!in_range(p->queue, 0, vi->ntxq - 1) || 4001979b511SNavdeep Parhar !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) 4011979b511SNavdeep Parhar return (EINVAL); 4022204b427SNavdeep Parhar 4031979b511SNavdeep Parhar if (p->queue < 0) { 4042204b427SNavdeep Parhar /* 4052204b427SNavdeep Parhar * Change the scheduling on all the TX queues for the 4062204b427SNavdeep Parhar * interface. 4072204b427SNavdeep Parhar */ 4082204b427SNavdeep Parhar for_each_txq(vi, i, txq) { 4091979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl); 4101979b511SNavdeep Parhar if (rc != 0) 4111979b511SNavdeep Parhar break; 4121979b511SNavdeep Parhar } 4131979b511SNavdeep Parhar } else { 4141979b511SNavdeep Parhar /* 4151979b511SNavdeep Parhar * If op.queue is non-negative, then we're only changing the 4161979b511SNavdeep Parhar * scheduling on a single specified TX queue. 4171979b511SNavdeep Parhar */ 4181979b511SNavdeep Parhar txq = &sc->sge.txq[vi->first_txq + p->queue]; 4191979b511SNavdeep Parhar rc = bind_txq_to_traffic_class(sc, txq, p->cl); 4202204b427SNavdeep Parhar } 4212204b427SNavdeep Parhar 4222204b427SNavdeep Parhar return (rc); 4232204b427SNavdeep Parhar } 4242204b427SNavdeep Parhar 4252204b427SNavdeep Parhar int 4262204b427SNavdeep Parhar t4_init_tx_sched(struct adapter *sc) 4272204b427SNavdeep Parhar { 4282204b427SNavdeep Parhar int i, j; 4292204b427SNavdeep Parhar const int n = sc->chip_params->nsched_cls; 4302204b427SNavdeep Parhar struct port_info *pi; 4312204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 4322204b427SNavdeep Parhar 4332204b427SNavdeep Parhar mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF); 4342204b427SNavdeep Parhar TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc); 4352204b427SNavdeep Parhar for_each_port(sc, i) { 4362204b427SNavdeep Parhar pi = sc->port[i]; 4372204b427SNavdeep Parhar pi->sched_params = malloc(sizeof(*pi->sched_params) + 4382204b427SNavdeep Parhar n * sizeof(*tc), M_CXGBE, M_ZERO | M_WAITOK); 4392204b427SNavdeep Parhar tc = &pi->sched_params->cl_rl[0]; 4402204b427SNavdeep Parhar for (j = 0; j < n; j++, tc++) { 4412204b427SNavdeep Parhar tc->refcount = 0; 4422204b427SNavdeep Parhar tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; 4432204b427SNavdeep Parhar tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 444f7c6e092SNavdeep Parhar tc->mode = FW_SCHED_PARAMS_MODE_CLASS; 445f7c6e092SNavdeep Parhar tc->maxrate = 1000 * 1000; /* 1 Gbps. Arbitrary */ 4462204b427SNavdeep Parhar 4471dc02549SNavdeep Parhar if (t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j, 4481979b511SNavdeep Parhar tc->mode, tc->maxrate, tc->pktsize, 1) != 0) 4491979b511SNavdeep Parhar tc->flags = CLRL_ERR; 4502204b427SNavdeep Parhar } 4512204b427SNavdeep Parhar } 4522204b427SNavdeep Parhar 4532204b427SNavdeep Parhar return (0); 4542204b427SNavdeep Parhar } 4552204b427SNavdeep Parhar 4562204b427SNavdeep Parhar int 4572204b427SNavdeep Parhar t4_free_tx_sched(struct adapter *sc) 4582204b427SNavdeep Parhar { 4592204b427SNavdeep Parhar int i; 4602204b427SNavdeep Parhar 4612204b427SNavdeep Parhar taskqueue_drain(taskqueue_thread, &sc->tc_task); 4622204b427SNavdeep Parhar 463cc2050c5SNavdeep Parhar for_each_port(sc, i) { 464cc2050c5SNavdeep Parhar if (sc->port[i] != NULL) 4652204b427SNavdeep Parhar free(sc->port[i]->sched_params, M_CXGBE); 466cc2050c5SNavdeep Parhar } 4672204b427SNavdeep Parhar 4682204b427SNavdeep Parhar if (mtx_initialized(&sc->tc_lock)) 4692204b427SNavdeep Parhar mtx_destroy(&sc->tc_lock); 4702204b427SNavdeep Parhar 4712204b427SNavdeep Parhar return (0); 4722204b427SNavdeep Parhar } 4732204b427SNavdeep Parhar 4742204b427SNavdeep Parhar void 4752204b427SNavdeep Parhar t4_update_tx_sched(struct adapter *sc) 4762204b427SNavdeep Parhar { 4772204b427SNavdeep Parhar 4782204b427SNavdeep Parhar taskqueue_enqueue(taskqueue_thread, &sc->tc_task); 4792204b427SNavdeep Parhar } 4802204b427SNavdeep Parhar 4812204b427SNavdeep Parhar int 4822204b427SNavdeep Parhar t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate, 4832204b427SNavdeep Parhar int *tc_idx) 4842204b427SNavdeep Parhar { 48509a7189fSNavdeep Parhar int rc = 0, fa = -1, i, pktsize, burstsize; 4861979b511SNavdeep Parhar bool update; 4872204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 4881979b511SNavdeep Parhar struct port_info *pi; 4892204b427SNavdeep Parhar 4902204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports); 4912204b427SNavdeep Parhar 4921979b511SNavdeep Parhar pi = sc->port[port_id]; 49309a7189fSNavdeep Parhar if (pi->sched_params->pktsize > 0) 49409a7189fSNavdeep Parhar pktsize = pi->sched_params->pktsize; 49509a7189fSNavdeep Parhar else 49609a7189fSNavdeep Parhar pktsize = pi->vi[0].ifp->if_mtu; 49709a7189fSNavdeep Parhar if (pi->sched_params->burstsize > 0) 49809a7189fSNavdeep Parhar burstsize = pi->sched_params->burstsize; 49909a7189fSNavdeep Parhar else 50009a7189fSNavdeep Parhar burstsize = pktsize * 4; 5011979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[0]; 50209a7189fSNavdeep Parhar 5031979b511SNavdeep Parhar update = false; 5042204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 5052204b427SNavdeep Parhar for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) { 5061979b511SNavdeep Parhar if (fa < 0 && tc->refcount == 0 && !(tc->flags & CLRL_USER)) 5071979b511SNavdeep Parhar fa = i; /* first available */ 5082204b427SNavdeep Parhar 5092204b427SNavdeep Parhar if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS && 5102204b427SNavdeep Parhar tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE && 5112204b427SNavdeep Parhar tc->mode == FW_SCHED_PARAMS_MODE_FLOW && 51209a7189fSNavdeep Parhar tc->maxrate == maxrate && tc->pktsize == pktsize && 51309a7189fSNavdeep Parhar tc->burstsize == burstsize) { 5142204b427SNavdeep Parhar tc->refcount++; 5152204b427SNavdeep Parhar *tc_idx = i; 5161979b511SNavdeep Parhar if ((tc->flags & (CLRL_ERR | CLRL_ASYNC | CLRL_SYNC)) == 5171979b511SNavdeep Parhar CLRL_ERR) { 5181979b511SNavdeep Parhar update = true; 5191979b511SNavdeep Parhar } 5202204b427SNavdeep Parhar goto done; 5212204b427SNavdeep Parhar } 5222204b427SNavdeep Parhar } 5232204b427SNavdeep Parhar /* Not found */ 5242204b427SNavdeep Parhar MPASS(i == sc->chip_params->nsched_cls); 5252204b427SNavdeep Parhar if (fa != -1) { 5261979b511SNavdeep Parhar tc = &pi->sched_params->cl_rl[fa]; 5272204b427SNavdeep Parhar tc->refcount = 1; 5282204b427SNavdeep Parhar tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; 5292204b427SNavdeep Parhar tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; 5302204b427SNavdeep Parhar tc->mode = FW_SCHED_PARAMS_MODE_FLOW; 5312204b427SNavdeep Parhar tc->maxrate = maxrate; 53209a7189fSNavdeep Parhar tc->pktsize = pktsize; 53309a7189fSNavdeep Parhar tc->burstsize = burstsize; 5342204b427SNavdeep Parhar *tc_idx = fa; 5351979b511SNavdeep Parhar update = true; 5362204b427SNavdeep Parhar } else { 5372204b427SNavdeep Parhar *tc_idx = -1; 5382204b427SNavdeep Parhar rc = ENOSPC; 5392204b427SNavdeep Parhar } 5402204b427SNavdeep Parhar done: 5412204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 5421979b511SNavdeep Parhar if (update) { 5431979b511SNavdeep Parhar tc->flags |= CLRL_ASYNC; 5441979b511SNavdeep Parhar t4_update_tx_sched(sc); 5451979b511SNavdeep Parhar } 5462204b427SNavdeep Parhar return (rc); 5472204b427SNavdeep Parhar } 5482204b427SNavdeep Parhar 5492204b427SNavdeep Parhar void 5501979b511SNavdeep Parhar t4_release_cl_rl(struct adapter *sc, int port_id, int tc_idx) 5512204b427SNavdeep Parhar { 5522204b427SNavdeep Parhar struct tx_cl_rl_params *tc; 5532204b427SNavdeep Parhar 5542204b427SNavdeep Parhar MPASS(port_id >= 0 && port_id < sc->params.nports); 5552204b427SNavdeep Parhar MPASS(tc_idx >= 0 && tc_idx < sc->chip_params->nsched_cls); 5562204b427SNavdeep Parhar 5572204b427SNavdeep Parhar mtx_lock(&sc->tc_lock); 5582204b427SNavdeep Parhar tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx]; 5592204b427SNavdeep Parhar MPASS(tc->refcount > 0); 5602204b427SNavdeep Parhar tc->refcount--; 5612204b427SNavdeep Parhar mtx_unlock(&sc->tc_lock); 5622204b427SNavdeep Parhar } 56367e07112SNavdeep Parhar 5641979b511SNavdeep Parhar int 5651979b511SNavdeep Parhar sysctl_tc(SYSCTL_HANDLER_ARGS) 5661979b511SNavdeep Parhar { 5671979b511SNavdeep Parhar struct vi_info *vi = arg1; 5681979b511SNavdeep Parhar struct port_info *pi; 5691979b511SNavdeep Parhar struct adapter *sc; 5701979b511SNavdeep Parhar struct sge_txq *txq; 5711979b511SNavdeep Parhar int qidx = arg2, rc, tc_idx; 5721979b511SNavdeep Parhar 5731979b511SNavdeep Parhar MPASS(qidx >= 0 && qidx < vi->ntxq); 5741979b511SNavdeep Parhar pi = vi->pi; 5751979b511SNavdeep Parhar sc = pi->adapter; 5761979b511SNavdeep Parhar txq = &sc->sge.txq[vi->first_txq + qidx]; 5771979b511SNavdeep Parhar 5781979b511SNavdeep Parhar tc_idx = txq->tc_idx; 5791979b511SNavdeep Parhar rc = sysctl_handle_int(oidp, &tc_idx, 0, req); 5801979b511SNavdeep Parhar if (rc != 0 || req->newptr == NULL) 5811979b511SNavdeep Parhar return (rc); 5821979b511SNavdeep Parhar 5831979b511SNavdeep Parhar if (sc->flags & IS_VF) 5841979b511SNavdeep Parhar return (EPERM); 5851979b511SNavdeep Parhar if (!in_range(tc_idx, 0, sc->chip_params->nsched_cls - 1)) 5861979b511SNavdeep Parhar return (EINVAL); 5871979b511SNavdeep Parhar 5881979b511SNavdeep Parhar return (bind_txq_to_traffic_class(sc, txq, tc_idx)); 5891979b511SNavdeep Parhar } 5901979b511SNavdeep Parhar 5911979b511SNavdeep Parhar int 5921979b511SNavdeep Parhar sysctl_tc_params(SYSCTL_HANDLER_ARGS) 5931979b511SNavdeep Parhar { 5941979b511SNavdeep Parhar struct adapter *sc = arg1; 5951979b511SNavdeep Parhar struct tx_cl_rl_params tc; 5961979b511SNavdeep Parhar struct sbuf *sb; 5971979b511SNavdeep Parhar int i, rc, port_id, mbps, gbps; 5981979b511SNavdeep Parhar 5991979b511SNavdeep Parhar rc = sysctl_wire_old_buffer(req, 0); 6001979b511SNavdeep Parhar if (rc != 0) 6011979b511SNavdeep Parhar return (rc); 6021979b511SNavdeep Parhar 6031979b511SNavdeep Parhar sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); 6041979b511SNavdeep Parhar if (sb == NULL) 6051979b511SNavdeep Parhar return (ENOMEM); 6061979b511SNavdeep Parhar 6071979b511SNavdeep Parhar port_id = arg2 >> 16; 6081979b511SNavdeep Parhar MPASS(port_id < sc->params.nports); 6091979b511SNavdeep Parhar MPASS(sc->port[port_id] != NULL); 6101979b511SNavdeep Parhar i = arg2 & 0xffff; 6111979b511SNavdeep Parhar MPASS(i < sc->chip_params->nsched_cls); 6121979b511SNavdeep Parhar 6131979b511SNavdeep Parhar mtx_lock(&sc->tc_lock); 6141979b511SNavdeep Parhar tc = sc->port[port_id]->sched_params->cl_rl[i]; 6151979b511SNavdeep Parhar mtx_unlock(&sc->tc_lock); 6161979b511SNavdeep Parhar 6171979b511SNavdeep Parhar switch (tc.rateunit) { 6181979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_BITS: 6191979b511SNavdeep Parhar switch (tc.ratemode) { 6201979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_REL: 6211979b511SNavdeep Parhar /* XXX: top speed or actual link speed? */ 6221979b511SNavdeep Parhar gbps = port_top_speed(sc->port[port_id]); 6231979b511SNavdeep Parhar sbuf_printf(sb, "%u%% of %uGbps", tc.maxrate, gbps); 6241979b511SNavdeep Parhar break; 6251979b511SNavdeep Parhar case SCHED_CLASS_RATEMODE_ABS: 6261979b511SNavdeep Parhar mbps = tc.maxrate / 1000; 6271979b511SNavdeep Parhar gbps = tc.maxrate / 1000000; 6281979b511SNavdeep Parhar if (tc.maxrate == gbps * 1000000) 6291979b511SNavdeep Parhar sbuf_printf(sb, "%uGbps", gbps); 6301979b511SNavdeep Parhar else if (tc.maxrate == mbps * 1000) 6311979b511SNavdeep Parhar sbuf_printf(sb, "%uMbps", mbps); 6321979b511SNavdeep Parhar else 6331979b511SNavdeep Parhar sbuf_printf(sb, "%uKbps", tc.maxrate); 6341979b511SNavdeep Parhar break; 6351979b511SNavdeep Parhar default: 6361979b511SNavdeep Parhar rc = ENXIO; 6371979b511SNavdeep Parhar goto done; 6381979b511SNavdeep Parhar } 6391979b511SNavdeep Parhar break; 6401979b511SNavdeep Parhar case SCHED_CLASS_RATEUNIT_PKTS: 6411979b511SNavdeep Parhar sbuf_printf(sb, "%upps", tc.maxrate); 6421979b511SNavdeep Parhar break; 6431979b511SNavdeep Parhar default: 6441979b511SNavdeep Parhar rc = ENXIO; 6451979b511SNavdeep Parhar goto done; 6461979b511SNavdeep Parhar } 6471979b511SNavdeep Parhar 6481979b511SNavdeep Parhar switch (tc.mode) { 6491979b511SNavdeep Parhar case SCHED_CLASS_MODE_CLASS: 6501979b511SNavdeep Parhar sbuf_printf(sb, " aggregate"); 6511979b511SNavdeep Parhar break; 6521979b511SNavdeep Parhar case SCHED_CLASS_MODE_FLOW: 6531979b511SNavdeep Parhar sbuf_printf(sb, " per-flow"); 6548a684e1fSNavdeep Parhar if (tc.pktsize > 0) 6558a684e1fSNavdeep Parhar sbuf_printf(sb, " pkt-size %u", tc.pktsize); 6568a684e1fSNavdeep Parhar if (tc.burstsize > 0) 6578a684e1fSNavdeep Parhar sbuf_printf(sb, " burst-size %u", tc.burstsize); 6581979b511SNavdeep Parhar break; 6591979b511SNavdeep Parhar default: 6601979b511SNavdeep Parhar rc = ENXIO; 6611979b511SNavdeep Parhar goto done; 6621979b511SNavdeep Parhar } 6631979b511SNavdeep Parhar 6641979b511SNavdeep Parhar done: 6651979b511SNavdeep Parhar if (rc == 0) 6661979b511SNavdeep Parhar rc = sbuf_finish(sb); 6671979b511SNavdeep Parhar sbuf_delete(sb); 6681979b511SNavdeep Parhar 6691979b511SNavdeep Parhar return (rc); 6701979b511SNavdeep Parhar } 6711979b511SNavdeep Parhar 67267e07112SNavdeep Parhar #ifdef RATELIMIT 67367e07112SNavdeep Parhar void 67467e07112SNavdeep Parhar t4_init_etid_table(struct adapter *sc) 67567e07112SNavdeep Parhar { 67667e07112SNavdeep Parhar int i; 67767e07112SNavdeep Parhar struct tid_info *t; 67867e07112SNavdeep Parhar 67967e07112SNavdeep Parhar if (!is_ethoffload(sc)) 68067e07112SNavdeep Parhar return; 68167e07112SNavdeep Parhar 68267e07112SNavdeep Parhar t = &sc->tids; 68367e07112SNavdeep Parhar MPASS(t->netids > 0); 68467e07112SNavdeep Parhar 68567e07112SNavdeep Parhar mtx_init(&t->etid_lock, "etid lock", NULL, MTX_DEF); 68667e07112SNavdeep Parhar t->etid_tab = malloc(sizeof(*t->etid_tab) * t->netids, M_CXGBE, 68767e07112SNavdeep Parhar M_ZERO | M_WAITOK); 68867e07112SNavdeep Parhar t->efree = t->etid_tab; 68967e07112SNavdeep Parhar t->etids_in_use = 0; 69067e07112SNavdeep Parhar for (i = 1; i < t->netids; i++) 69167e07112SNavdeep Parhar t->etid_tab[i - 1].next = &t->etid_tab[i]; 69267e07112SNavdeep Parhar t->etid_tab[t->netids - 1].next = NULL; 69367e07112SNavdeep Parhar } 69467e07112SNavdeep Parhar 69567e07112SNavdeep Parhar void 69667e07112SNavdeep Parhar t4_free_etid_table(struct adapter *sc) 69767e07112SNavdeep Parhar { 69867e07112SNavdeep Parhar struct tid_info *t; 69967e07112SNavdeep Parhar 70067e07112SNavdeep Parhar if (!is_ethoffload(sc)) 70167e07112SNavdeep Parhar return; 70267e07112SNavdeep Parhar 70367e07112SNavdeep Parhar t = &sc->tids; 70467e07112SNavdeep Parhar MPASS(t->netids > 0); 70567e07112SNavdeep Parhar 70667e07112SNavdeep Parhar free(t->etid_tab, M_CXGBE); 70767e07112SNavdeep Parhar t->etid_tab = NULL; 70867e07112SNavdeep Parhar 70967e07112SNavdeep Parhar if (mtx_initialized(&t->etid_lock)) 71067e07112SNavdeep Parhar mtx_destroy(&t->etid_lock); 71167e07112SNavdeep Parhar } 71267e07112SNavdeep Parhar 71367e07112SNavdeep Parhar /* etid services */ 714e38a50e8SJohn Baldwin static int alloc_etid(struct adapter *, struct cxgbe_rate_tag *); 71567e07112SNavdeep Parhar static void free_etid(struct adapter *, int); 71667e07112SNavdeep Parhar 71767e07112SNavdeep Parhar static int 718e38a50e8SJohn Baldwin alloc_etid(struct adapter *sc, struct cxgbe_rate_tag *cst) 71967e07112SNavdeep Parhar { 72067e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 72167e07112SNavdeep Parhar int etid = -1; 72267e07112SNavdeep Parhar 72367e07112SNavdeep Parhar mtx_lock(&t->etid_lock); 72467e07112SNavdeep Parhar if (t->efree) { 72567e07112SNavdeep Parhar union etid_entry *p = t->efree; 72667e07112SNavdeep Parhar 72767e07112SNavdeep Parhar etid = p - t->etid_tab + t->etid_base; 72867e07112SNavdeep Parhar t->efree = p->next; 72967e07112SNavdeep Parhar p->cst = cst; 73067e07112SNavdeep Parhar t->etids_in_use++; 73167e07112SNavdeep Parhar } 73267e07112SNavdeep Parhar mtx_unlock(&t->etid_lock); 73367e07112SNavdeep Parhar return (etid); 73467e07112SNavdeep Parhar } 73567e07112SNavdeep Parhar 736e38a50e8SJohn Baldwin struct cxgbe_rate_tag * 73767e07112SNavdeep Parhar lookup_etid(struct adapter *sc, int etid) 73867e07112SNavdeep Parhar { 73967e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 74067e07112SNavdeep Parhar 74167e07112SNavdeep Parhar return (t->etid_tab[etid - t->etid_base].cst); 74267e07112SNavdeep Parhar } 74367e07112SNavdeep Parhar 74467e07112SNavdeep Parhar static void 74567e07112SNavdeep Parhar free_etid(struct adapter *sc, int etid) 74667e07112SNavdeep Parhar { 74767e07112SNavdeep Parhar struct tid_info *t = &sc->tids; 74867e07112SNavdeep Parhar union etid_entry *p = &t->etid_tab[etid - t->etid_base]; 74967e07112SNavdeep Parhar 75067e07112SNavdeep Parhar mtx_lock(&t->etid_lock); 75167e07112SNavdeep Parhar p->next = t->efree; 75267e07112SNavdeep Parhar t->efree = p; 75367e07112SNavdeep Parhar t->etids_in_use--; 75467e07112SNavdeep Parhar mtx_unlock(&t->etid_lock); 75567e07112SNavdeep Parhar } 75667e07112SNavdeep Parhar 75767e07112SNavdeep Parhar int 758e38a50e8SJohn Baldwin cxgbe_rate_tag_alloc(struct ifnet *ifp, union if_snd_tag_alloc_params *params, 75967e07112SNavdeep Parhar struct m_snd_tag **pt) 76067e07112SNavdeep Parhar { 76167e07112SNavdeep Parhar int rc, schedcl; 76267e07112SNavdeep Parhar struct vi_info *vi = ifp->if_softc; 76367e07112SNavdeep Parhar struct port_info *pi = vi->pi; 76467e07112SNavdeep Parhar struct adapter *sc = pi->adapter; 765e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst; 76667e07112SNavdeep Parhar 767e38a50e8SJohn Baldwin MPASS(params->hdr.type == IF_SND_TAG_TYPE_RATE_LIMIT); 76867e07112SNavdeep Parhar 76967e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, pi->port_id, 77067e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl); 77167e07112SNavdeep Parhar if (rc != 0) 77267e07112SNavdeep Parhar return (rc); 77367e07112SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->chip_params->nsched_cls); 77467e07112SNavdeep Parhar 77567e07112SNavdeep Parhar cst = malloc(sizeof(*cst), M_CXGBE, M_ZERO | M_NOWAIT); 77667e07112SNavdeep Parhar if (cst == NULL) { 77767e07112SNavdeep Parhar failed: 7781979b511SNavdeep Parhar t4_release_cl_rl(sc, pi->port_id, schedcl); 77967e07112SNavdeep Parhar return (ENOMEM); 78067e07112SNavdeep Parhar } 78167e07112SNavdeep Parhar 78267e07112SNavdeep Parhar cst->etid = alloc_etid(sc, cst); 78367e07112SNavdeep Parhar if (cst->etid < 0) { 78467e07112SNavdeep Parhar free(cst, M_CXGBE); 78567e07112SNavdeep Parhar goto failed; 78667e07112SNavdeep Parhar } 78767e07112SNavdeep Parhar 78867e07112SNavdeep Parhar mtx_init(&cst->lock, "cst_lock", NULL, MTX_DEF); 789786099deSNavdeep Parhar mbufq_init(&cst->pending_tx, INT_MAX); 790786099deSNavdeep Parhar mbufq_init(&cst->pending_fwack, INT_MAX); 79156fb710fSJohn Baldwin m_snd_tag_init(&cst->com, ifp, IF_SND_TAG_TYPE_RATE_LIMIT); 792786099deSNavdeep Parhar cst->flags |= EO_FLOWC_PENDING | EO_SND_TAG_REF; 79367e07112SNavdeep Parhar cst->adapter = sc; 79467e07112SNavdeep Parhar cst->port_id = pi->port_id; 79567e07112SNavdeep Parhar cst->schedcl = schedcl; 79667e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate; 797ac8ec5feSNavdeep Parhar cst->tx_credits = sc->params.eo_wr_cred; 79867e07112SNavdeep Parhar cst->tx_total = cst->tx_credits; 799786099deSNavdeep Parhar cst->plen = 0; 800c0236bd9SNavdeep Parhar cst->ctrl0 = htobe32(V_TXPKT_OPCODE(CPL_TX_PKT_XT) | 801edb518f4SNavdeep Parhar V_TXPKT_INTF(pi->tx_chan) | V_TXPKT_PF(sc->pf) | 802edb518f4SNavdeep Parhar V_TXPKT_VF(vi->vin) | V_TXPKT_VF_VLD(vi->vfvld)); 80367e07112SNavdeep Parhar 80467e07112SNavdeep Parhar /* 80567e07112SNavdeep Parhar * Queues will be selected later when the connection flowid is available. 80667e07112SNavdeep Parhar */ 80767e07112SNavdeep Parhar 80856fb710fSJohn Baldwin *pt = &cst->com; 80967e07112SNavdeep Parhar return (0); 81067e07112SNavdeep Parhar } 81167e07112SNavdeep Parhar 81267e07112SNavdeep Parhar /* 81367e07112SNavdeep Parhar * Change in parameters, no change in ifp. 81467e07112SNavdeep Parhar */ 81567e07112SNavdeep Parhar int 816e38a50e8SJohn Baldwin cxgbe_rate_tag_modify(struct m_snd_tag *mst, 81767e07112SNavdeep Parhar union if_snd_tag_modify_params *params) 81867e07112SNavdeep Parhar { 81967e07112SNavdeep Parhar int rc, schedcl; 820e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 82167e07112SNavdeep Parhar struct adapter *sc = cst->adapter; 82267e07112SNavdeep Parhar 82367e07112SNavdeep Parhar /* XXX: is schedcl -1 ok here? */ 82467e07112SNavdeep Parhar MPASS(cst->schedcl >= 0 && cst->schedcl < sc->chip_params->nsched_cls); 82567e07112SNavdeep Parhar 826786099deSNavdeep Parhar mtx_lock(&cst->lock); 827786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF); 82867e07112SNavdeep Parhar rc = t4_reserve_cl_rl_kbps(sc, cst->port_id, 82967e07112SNavdeep Parhar (params->rate_limit.max_rate * 8ULL / 1000), &schedcl); 83067e07112SNavdeep Parhar if (rc != 0) 83167e07112SNavdeep Parhar return (rc); 83267e07112SNavdeep Parhar MPASS(schedcl >= 0 && schedcl < sc->chip_params->nsched_cls); 8331979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl); 83467e07112SNavdeep Parhar cst->schedcl = schedcl; 83567e07112SNavdeep Parhar cst->max_rate = params->rate_limit.max_rate; 836786099deSNavdeep Parhar mtx_unlock(&cst->lock); 83767e07112SNavdeep Parhar 83867e07112SNavdeep Parhar return (0); 83967e07112SNavdeep Parhar } 84067e07112SNavdeep Parhar 84167e07112SNavdeep Parhar int 842e38a50e8SJohn Baldwin cxgbe_rate_tag_query(struct m_snd_tag *mst, 84367e07112SNavdeep Parhar union if_snd_tag_query_params *params) 84467e07112SNavdeep Parhar { 845e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 84667e07112SNavdeep Parhar 84767e07112SNavdeep Parhar params->rate_limit.max_rate = cst->max_rate; 84867e07112SNavdeep Parhar 84967e07112SNavdeep Parhar #define CST_TO_MST_QLEVEL_SCALE (IF_SND_QUEUE_LEVEL_MAX / cst->tx_total) 85067e07112SNavdeep Parhar params->rate_limit.queue_level = 85167e07112SNavdeep Parhar (cst->tx_total - cst->tx_credits) * CST_TO_MST_QLEVEL_SCALE; 85267e07112SNavdeep Parhar 85367e07112SNavdeep Parhar return (0); 85467e07112SNavdeep Parhar } 85567e07112SNavdeep Parhar 856786099deSNavdeep Parhar /* 857786099deSNavdeep Parhar * Unlocks cst and frees it. 858786099deSNavdeep Parhar */ 85967e07112SNavdeep Parhar void 860e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(struct cxgbe_rate_tag *cst) 86167e07112SNavdeep Parhar { 86267e07112SNavdeep Parhar struct adapter *sc = cst->adapter; 86367e07112SNavdeep Parhar 864786099deSNavdeep Parhar mtx_assert(&cst->lock, MA_OWNED); 865786099deSNavdeep Parhar MPASS((cst->flags & EO_SND_TAG_REF) == 0); 866786099deSNavdeep Parhar MPASS(cst->tx_credits == cst->tx_total); 867786099deSNavdeep Parhar MPASS(cst->plen == 0); 868786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_tx) == NULL); 869786099deSNavdeep Parhar MPASS(mbufq_first(&cst->pending_fwack) == NULL); 870786099deSNavdeep Parhar 87167e07112SNavdeep Parhar if (cst->etid >= 0) 87267e07112SNavdeep Parhar free_etid(sc, cst->etid); 87367e07112SNavdeep Parhar if (cst->schedcl != -1) 8741979b511SNavdeep Parhar t4_release_cl_rl(sc, cst->port_id, cst->schedcl); 875786099deSNavdeep Parhar mtx_unlock(&cst->lock); 87667e07112SNavdeep Parhar mtx_destroy(&cst->lock); 87767e07112SNavdeep Parhar free(cst, M_CXGBE); 87867e07112SNavdeep Parhar } 879786099deSNavdeep Parhar 880786099deSNavdeep Parhar void 881e38a50e8SJohn Baldwin cxgbe_rate_tag_free(struct m_snd_tag *mst) 882786099deSNavdeep Parhar { 883e38a50e8SJohn Baldwin struct cxgbe_rate_tag *cst = mst_to_crt(mst); 884786099deSNavdeep Parhar 885786099deSNavdeep Parhar mtx_lock(&cst->lock); 886786099deSNavdeep Parhar 887786099deSNavdeep Parhar /* The kernel is done with the snd_tag. Remove its reference. */ 888786099deSNavdeep Parhar MPASS(cst->flags & EO_SND_TAG_REF); 889786099deSNavdeep Parhar cst->flags &= ~EO_SND_TAG_REF; 890786099deSNavdeep Parhar 891786099deSNavdeep Parhar if (cst->ncompl == 0) { 892786099deSNavdeep Parhar /* 893786099deSNavdeep Parhar * No fw4_ack in flight. Free the tag right away if there are 894786099deSNavdeep Parhar * no outstanding credits. Request the firmware to return all 895786099deSNavdeep Parhar * credits for the etid otherwise. 896786099deSNavdeep Parhar */ 897786099deSNavdeep Parhar if (cst->tx_credits == cst->tx_total) { 898e38a50e8SJohn Baldwin cxgbe_rate_tag_free_locked(cst); 899786099deSNavdeep Parhar return; /* cst is gone. */ 900786099deSNavdeep Parhar } 901786099deSNavdeep Parhar send_etid_flush_wr(cst); 902786099deSNavdeep Parhar } 903786099deSNavdeep Parhar mtx_unlock(&cst->lock); 904786099deSNavdeep Parhar } 90520abea66SRandall Stewart 90620abea66SRandall Stewart void 907b8b01d9bSNavdeep Parhar cxgbe_ratelimit_query(struct ifnet *ifp, struct if_ratelimit_query_results *q) 90820abea66SRandall Stewart { 909b8b01d9bSNavdeep Parhar struct vi_info *vi = ifp->if_softc; 910b8b01d9bSNavdeep Parhar struct adapter *sc = vi->adapter; 911b8b01d9bSNavdeep Parhar 91220abea66SRandall Stewart q->rate_table = NULL; 91320abea66SRandall Stewart q->flags = RT_IS_SELECTABLE; 914b8b01d9bSNavdeep Parhar /* 915b8b01d9bSNavdeep Parhar * Absolute max limits from the firmware configuration. Practical 916b8b01d9bSNavdeep Parhar * limits depend on the burstsize, pktsize (ifp->if_mtu ultimately) and 917b8b01d9bSNavdeep Parhar * the card's cclk. 918b8b01d9bSNavdeep Parhar */ 919b8b01d9bSNavdeep Parhar q->max_flows = sc->tids.netids; 920b8b01d9bSNavdeep Parhar q->number_of_rates = sc->chip_params->nsched_cls; 921b8b01d9bSNavdeep Parhar q->min_segment_burst = 4; /* matches PKTSCHED_BURST in the firmware. */ 922b8b01d9bSNavdeep Parhar 923b8b01d9bSNavdeep Parhar #if 1 924b8b01d9bSNavdeep Parhar if (chip_id(sc) < CHELSIO_T6) { 925b8b01d9bSNavdeep Parhar /* Based on testing by rrs@ with a T580 at burstsize = 4. */ 926b8b01d9bSNavdeep Parhar MPASS(q->min_segment_burst == 4); 927*e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows); 928b8b01d9bSNavdeep Parhar } else { 929b8b01d9bSNavdeep Parhar /* XXX: TBD, carried forward from T5 for now. */ 930*e2e43aafSNavdeep Parhar q->max_flows = min(4000, q->max_flows); 931b8b01d9bSNavdeep Parhar } 932b8b01d9bSNavdeep Parhar 933b8b01d9bSNavdeep Parhar /* 934b8b01d9bSNavdeep Parhar * XXX: tcp_ratelimit.c grabs all available rates on link-up before it 935b8b01d9bSNavdeep Parhar * even knows whether hw pacing will be used or not. This prevents 936b8b01d9bSNavdeep Parhar * other consumers like SO_MAX_PACING_RATE or those using cxgbetool or 937b8b01d9bSNavdeep Parhar * the private ioctls from using any of traffic classes. 938b8b01d9bSNavdeep Parhar * 939b8b01d9bSNavdeep Parhar * Underreport the number of rates to tcp_ratelimit so that it doesn't 940b8b01d9bSNavdeep Parhar * hog all of them. This can be removed if/when tcp_ratelimit switches 941b8b01d9bSNavdeep Parhar * to making its allocations on first-use rather than link-up. There is 942b8b01d9bSNavdeep Parhar * nothing wrong with one particular consumer reserving all the classes 943b8b01d9bSNavdeep Parhar * but it should do so only if it'll actually use hw rate limiting. 944b8b01d9bSNavdeep Parhar */ 945b8b01d9bSNavdeep Parhar q->number_of_rates /= 4; 946b8b01d9bSNavdeep Parhar #endif 94720abea66SRandall Stewart } 94867e07112SNavdeep Parhar #endif 949