From owner-svn-src-all@freebsd.org Mon Aug 6 23:21:15 2018 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 470501069357; Mon, 6 Aug 2018 23:21:15 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id EDA70704AC; Mon, 6 Aug 2018 23:21:14 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id CEABE139EA; Mon, 6 Aug 2018 23:21:14 +0000 (UTC) (envelope-from np@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w76NLEPF092045; Mon, 6 Aug 2018 23:21:14 GMT (envelope-from np@FreeBSD.org) Received: (from np@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w76NLDO6092038; Mon, 6 Aug 2018 23:21:13 GMT (envelope-from np@FreeBSD.org) Message-Id: <201808062321.w76NLDO6092038@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: np set sender to np@FreeBSD.org using -f From: Navdeep Parhar Date: Mon, 6 Aug 2018 23:21:13 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r337398 - in head/sys/dev/cxgbe: . tom X-SVN-Group: head X-SVN-Commit-Author: np X-SVN-Commit-Paths: in head/sys/dev/cxgbe: . tom X-SVN-Commit-Revision: 337398 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.27 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 06 Aug 2018 23:21:15 -0000 Author: np Date: Mon Aug 6 23:21:13 2018 New Revision: 337398 URL: https://svnweb.freebsd.org/changeset/base/337398 Log: cxgbe(4): Allow user-configured and driver-configured traffic classes to be used simultaneously. Move sysctl_tc and sysctl_tc_params to t4_sched.c while here. MFC after: 3 weeks Sponsored by: Chelsio Communications Modified: head/sys/dev/cxgbe/adapter.h head/sys/dev/cxgbe/t4_main.c head/sys/dev/cxgbe/t4_sched.c head/sys/dev/cxgbe/t4_sge.c head/sys/dev/cxgbe/tom/t4_cpl_io.c head/sys/dev/cxgbe/tom/t4_tom.c Modified: head/sys/dev/cxgbe/adapter.h ============================================================================== --- head/sys/dev/cxgbe/adapter.h Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/adapter.h Mon Aug 6 23:21:13 2018 (r337398) @@ -235,13 +235,15 @@ struct tx_ch_rl_params { }; enum { - TX_CLRL_REFRESH = (1 << 0), /* Need to update hardware state. */ - TX_CLRL_ERROR = (1 << 1), /* Error, hardware state unknown. */ + CLRL_USER = (1 << 0), /* allocated manually. */ + CLRL_SYNC = (1 << 1), /* sync hw update in progress. */ + CLRL_ASYNC = (1 << 2), /* async hw update requested. */ + CLRL_ERR = (1 << 3), /* last hw setup ended in error. */ }; struct tx_cl_rl_params { int refcount; - u_int flags; + uint8_t flags; enum fw_sched_params_rate ratemode; /* %port REL or ABS value */ enum fw_sched_params_unit rateunit; /* kbps or pps (when ABS) */ enum fw_sched_params_mode mode; /* aggr or per-flow */ @@ -1237,7 +1239,9 @@ int t4_init_tx_sched(struct adapter *); int t4_free_tx_sched(struct adapter *); void t4_update_tx_sched(struct adapter *); int t4_reserve_cl_rl_kbps(struct adapter *, int, u_int, int *); -void t4_release_cl_rl_kbps(struct adapter *, int, int); +void t4_release_cl_rl(struct adapter *, int, int); +int sysctl_tc(SYSCTL_HANDLER_ARGS); +int sysctl_tc_params(SYSCTL_HANDLER_ARGS); #ifdef RATELIMIT void t4_init_etid_table(struct adapter *); void t4_free_etid_table(struct adapter *); Modified: head/sys/dev/cxgbe/t4_main.c ============================================================================== --- head/sys/dev/cxgbe/t4_main.c Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/t4_main.c Mon Aug 6 23:21:13 2018 (r337398) @@ -589,7 +589,6 @@ static int sysctl_tp_la(SYSCTL_HANDLER_ARGS); static int sysctl_tx_rate(SYSCTL_HANDLER_ARGS); static int sysctl_ulprx_la(SYSCTL_HANDLER_ARGS); static int sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS); -static int sysctl_tc_params(SYSCTL_HANDLER_ARGS); static int sysctl_cpus(SYSCTL_HANDLER_ARGS); #ifdef TCP_OFFLOAD static int sysctl_tls_rx_ports(SYSCTL_HANDLER_ARGS); @@ -5963,6 +5962,7 @@ cxgbe_sysctls(struct port_info *pi) struct adapter *sc = pi->adapter; int i; char name[16]; + static char *tc_flags = {"\20\1USER\2SYNC\3ASYNC\4ERR"}; ctx = device_get_sysctl_ctx(pi->dev); @@ -6015,8 +6015,9 @@ cxgbe_sysctls(struct port_info *pi) children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx, SYSCTL_CHILDREN(oid), OID_AUTO, name, CTLFLAG_RD, NULL, "traffic class")); - SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "flags", CTLFLAG_RD, - &tc->flags, 0, "flags"); + SYSCTL_ADD_PROC(ctx, children2, OID_AUTO, "flags", + CTLTYPE_STRING | CTLFLAG_RD, tc_flags, (uintptr_t)&tc->flags, + sysctl_bitfield_8b, "A", "flags"); SYSCTL_ADD_UINT(ctx, children2, OID_AUTO, "refcount", CTLFLAG_RD, &tc->refcount, 0, "references to this class"); SYSCTL_ADD_PROC(ctx, children2, OID_AUTO, "params", @@ -8607,83 +8608,6 @@ sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS) } } rc = sbuf_finish(sb); - sbuf_delete(sb); - - return (rc); -} - -static int -sysctl_tc_params(SYSCTL_HANDLER_ARGS) -{ - struct adapter *sc = arg1; - struct tx_cl_rl_params tc; - struct sbuf *sb; - int i, rc, port_id, mbps, gbps; - - rc = sysctl_wire_old_buffer(req, 0); - if (rc != 0) - return (rc); - - sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); - if (sb == NULL) - return (ENOMEM); - - port_id = arg2 >> 16; - MPASS(port_id < sc->params.nports); - MPASS(sc->port[port_id] != NULL); - i = arg2 & 0xffff; - MPASS(i < sc->chip_params->nsched_cls); - - mtx_lock(&sc->tc_lock); - tc = sc->port[port_id]->sched_params->cl_rl[i]; - mtx_unlock(&sc->tc_lock); - - switch (tc.rateunit) { - case SCHED_CLASS_RATEUNIT_BITS: - switch (tc.ratemode) { - case SCHED_CLASS_RATEMODE_REL: - /* XXX: top speed or actual link speed? */ - gbps = port_top_speed(sc->port[port_id]); - sbuf_printf(sb, "%u%% of %uGbps", tc.maxrate, gbps); - break; - case SCHED_CLASS_RATEMODE_ABS: - mbps = tc.maxrate / 1000; - gbps = tc.maxrate / 1000000; - if (tc.maxrate == gbps * 1000000) - sbuf_printf(sb, "%uGbps", gbps); - else if (tc.maxrate == mbps * 1000) - sbuf_printf(sb, "%uMbps", mbps); - else - sbuf_printf(sb, "%uKbps", tc.maxrate); - break; - default: - rc = ENXIO; - goto done; - } - break; - case SCHED_CLASS_RATEUNIT_PKTS: - sbuf_printf(sb, "%upps", tc.maxrate); - break; - default: - rc = ENXIO; - goto done; - } - - switch (tc.mode) { - case SCHED_CLASS_MODE_CLASS: - sbuf_printf(sb, " aggregate"); - break; - case SCHED_CLASS_MODE_FLOW: - sbuf_printf(sb, " per-flow"); - break; - default: - rc = ENXIO; - goto done; - } - -done: - if (rc == 0) - rc = sbuf_finish(sb); sbuf_delete(sb); return (rc); Modified: head/sys/dev/cxgbe/t4_sched.c ============================================================================== --- head/sys/dev/cxgbe/t4_sched.c Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/t4_sched.c Mon Aug 6 23:21:13 2018 (r337398) @@ -75,7 +75,7 @@ set_sched_class_params(struct adapter *sc, struct t4_s { int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode; struct port_info *pi; - struct tx_cl_rl_params *tc; + struct tx_cl_rl_params *tc, old; bool check_pktsize = false; if (p->level == SCHED_CLASS_LEVEL_CL_RL) @@ -179,43 +179,62 @@ set_sched_class_params(struct adapter *sc, struct t4_s return (ERANGE); } - rc = begin_synchronized_op(sc, NULL, - sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); - if (rc) - return (rc); if (p->level == SCHED_CLASS_LEVEL_CL_RL) { tc = &pi->sched_params->cl_rl[p->cl]; - if (tc->refcount > 0) { + mtx_lock(&sc->tc_lock); + if (tc->refcount > 0 || tc->flags & (CLRL_SYNC | CLRL_ASYNC)) rc = EBUSY; - goto done; - } else { + else { + tc->flags |= CLRL_SYNC | CLRL_USER; tc->ratemode = fw_ratemode; tc->rateunit = fw_rateunit; tc->mode = fw_mode; tc->maxrate = p->maxrate; tc->pktsize = p->pktsize; + rc = 0; + old= *tc; } + mtx_unlock(&sc->tc_lock); + if (rc != 0) + return (rc); } + + rc = begin_synchronized_op(sc, NULL, + sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp"); + if (rc != 0) { + if (p->level == SCHED_CLASS_LEVEL_CL_RL) { + mtx_lock(&sc->tc_lock); + *tc = old; + mtx_unlock(&sc->tc_lock); + } + return (rc); + } rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode, fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate, p->weight, p->pktsize, sleep_ok); - if (p->level == SCHED_CLASS_LEVEL_CL_RL && rc != 0) { - /* - * Unknown state at this point, see parameters in tc for what - * was attempted. - */ - tc->flags |= TX_CLRL_ERROR; - } -done: end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD); + if (p->level == SCHED_CLASS_LEVEL_CL_RL) { + mtx_lock(&sc->tc_lock); + MPASS(tc->flags & CLRL_SYNC); + MPASS(tc->flags & CLRL_USER); + MPASS(tc->refcount == 0); + + tc->flags &= ~CLRL_SYNC; + if (rc == 0) + tc->flags &= ~CLRL_ERR; + else + tc->flags |= CLRL_ERR; + mtx_unlock(&sc->tc_lock); + } + return (rc); } static void update_tx_sched(void *context, int pending) { - int i, j, mode, rateunit, ratemode, maxrate, pktsize, rc; + int i, j, rc; struct port_info *pi; struct tx_cl_rl_params *tc; struct adapter *sc = context; @@ -227,14 +246,8 @@ update_tx_sched(void *context, int pending) tc = &pi->sched_params->cl_rl[0]; for (j = 0; j < n; j++, tc++) { MPASS(mtx_owned(&sc->tc_lock)); - if ((tc->flags & TX_CLRL_REFRESH) == 0) + if ((tc->flags & CLRL_ASYNC) == 0) continue; - - mode = tc->mode; - rateunit = tc->rateunit; - ratemode = tc->ratemode; - maxrate = tc->maxrate; - pktsize = tc->pktsize; mtx_unlock(&sc->tc_lock); if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, @@ -242,21 +255,19 @@ update_tx_sched(void *context, int pending) mtx_lock(&sc->tc_lock); continue; } - rc = t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, - FW_SCHED_PARAMS_LEVEL_CL_RL, mode, rateunit, - ratemode, pi->tx_chan, j, 0, maxrate, 0, pktsize, - 1); + rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, + FW_SCHED_PARAMS_LEVEL_CL_RL, tc->mode, tc->rateunit, + tc->ratemode, pi->tx_chan, j, 0, tc->maxrate, 0, + tc->pktsize, 1); end_synchronized_op(sc, 0); mtx_lock(&sc->tc_lock); - if (rc != 0) { - tc->flags |= TX_CLRL_ERROR; - } else if (tc->mode == mode && - tc->rateunit == rateunit && - tc->maxrate == maxrate && - tc->pktsize == tc->pktsize) { - tc->flags &= ~(TX_CLRL_REFRESH | TX_CLRL_ERROR); - } + MPASS(tc->flags & CLRL_ASYNC); + tc->flags &= ~CLRL_ASYNC; + if (rc == 0) + tc->flags &= ~CLRL_ERR; + else + tc->flags |= CLRL_ERR; } } mtx_unlock(&sc->tc_lock); @@ -278,74 +289,135 @@ t4_set_sched_class(struct adapter *sc, struct t4_sched return (EINVAL); } -int -t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) +static int +bind_txq_to_traffic_class(struct adapter *sc, struct sge_txq *txq, int idx) { - struct port_info *pi = NULL; - struct vi_info *vi; - struct sge_txq *txq; - uint32_t fw_mnem, fw_queue, fw_class; - int i, rc; + struct tx_cl_rl_params *tc0, *tc; + int rc, old_idx; + uint32_t fw_mnem, fw_class; - rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq"); - if (rc) - return (rc); + if (!(txq->eq.flags & EQ_ALLOCATED)) + return (EAGAIN); - if (p->port >= sc->params.nports) { - rc = EINVAL; + mtx_lock(&sc->tc_lock); + if (txq->tc_idx == -2) { + rc = EBUSY; /* Another bind/unbind in progress already. */ goto done; } - - /* XXX: Only supported for the main VI. */ - pi = sc->port[p->port]; - vi = &pi->vi[0]; - if (!(vi->flags & VI_INIT_DONE)) { - /* tx queues not set up yet */ - rc = EAGAIN; + if (idx == txq->tc_idx) { + rc = 0; /* No change, nothing to do. */ goto done; } - if (!in_range(p->queue, 0, vi->ntxq - 1) || - !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) { - rc = EINVAL; - goto done; + tc0 = &sc->port[txq->eq.tx_chan]->sched_params->cl_rl[0]; + if (idx != -1) { + /* + * Bind to a different class at index idx. + */ + tc = &tc0[idx]; + if (tc->flags & CLRL_ERR) { + rc = ENXIO; + goto done; + } else { + /* + * Ok to proceed. Place a reference on the new class + * while still holding on to the reference on the + * previous class, if any. + */ + tc->refcount++; + } } + /* Mark as busy before letting go of the lock. */ + old_idx = txq->tc_idx; + txq->tc_idx = -2; + mtx_unlock(&sc->tc_lock); - /* - * Create a template for the FW_PARAMS_CMD mnemonic and value (TX - * Scheduling Class in this case). - */ + rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4btxq"); + if (rc != 0) + return (rc); fw_mnem = (V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | - V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH)); - fw_class = p->cl < 0 ? 0xffffffff : p->cl; + V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH) | + V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); + fw_class = idx < 0 ? 0xffffffff : idx; + rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_mnem, &fw_class); + end_synchronized_op(sc, 0); - /* - * If op.queue is non-negative, then we're only changing the scheduling - * on a single specified TX queue. - */ - if (p->queue >= 0) { - txq = &sc->sge.txq[vi->first_txq + p->queue]; - fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); - rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, - &fw_class); - goto done; + mtx_lock(&sc->tc_lock); + MPASS(txq->tc_idx == -2); + if (rc == 0) { + /* + * Unbind, bind, or bind to a different class succeeded. Remove + * the reference on the old traffic class, if any. + */ + if (old_idx != -1) { + tc = &tc0[old_idx]; + MPASS(tc->refcount > 0); + tc->refcount--; + } + txq->tc_idx = idx; + } else { + /* + * Unbind, bind, or bind to a different class failed. Remove + * the anticipatory reference on the new traffic class, if any. + */ + if (idx != -1) { + tc = &tc0[idx]; + MPASS(tc->refcount > 0); + tc->refcount--; + } + txq->tc_idx = old_idx; } +done: + MPASS(txq->tc_idx >= -1 && txq->tc_idx < sc->chip_params->nsched_cls); + mtx_unlock(&sc->tc_lock); + return (rc); +} +int +t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p) +{ + struct port_info *pi = NULL; + struct vi_info *vi; + struct sge_txq *txq; + int i, rc; + + if (p->port >= sc->params.nports) + return (EINVAL); + /* - * Change the scheduling on all the TX queues for the - * interface. + * XXX: cxgbetool allows the user to specify the physical port only. So + * we always operate on the main VI. */ - for_each_txq(vi, i, txq) { - fw_queue = (fw_mnem | V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id)); - rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, - &fw_class); - if (rc) - goto done; + pi = sc->port[p->port]; + vi = &pi->vi[0]; + + /* Checking VI_INIT_DONE outside a synch-op is a harmless race here. */ + if (!(vi->flags & VI_INIT_DONE)) + return (EAGAIN); + + if (!in_range(p->queue, 0, vi->ntxq - 1) || + !in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) + return (EINVAL); + + if (p->queue < 0) { + /* + * Change the scheduling on all the TX queues for the + * interface. + */ + for_each_txq(vi, i, txq) { + rc = bind_txq_to_traffic_class(sc, txq, p->cl); + if (rc != 0) + break; + } + } else { + /* + * If op.queue is non-negative, then we're only changing the + * scheduling on a single specified TX queue. + */ + txq = &sc->sge.txq[vi->first_txq + p->queue]; + rc = bind_txq_to_traffic_class(sc, txq, p->cl); } - rc = 0; -done: - end_synchronized_op(sc, 0); return (rc); } @@ -372,10 +444,8 @@ t4_init_tx_sched(struct adapter *sc) tc->maxrate = 1000 * 1000; /* 1 Gbps. Arbitrary */ if (t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j, - tc->mode, tc->maxrate, tc->pktsize, 1) == 0) - tc->flags = 0; - else - tc->flags = TX_CLRL_ERROR; + tc->mode, tc->maxrate, tc->pktsize, 1) != 0) + tc->flags = CLRL_ERR; } } @@ -412,49 +482,61 @@ t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, int *tc_idx) { int rc = 0, fa = -1, i; + bool update; struct tx_cl_rl_params *tc; + struct port_info *pi; MPASS(port_id >= 0 && port_id < sc->params.nports); - tc = &sc->port[port_id]->sched_params->cl_rl[0]; + pi = sc->port[port_id]; + tc = &pi->sched_params->cl_rl[0]; + update = false; mtx_lock(&sc->tc_lock); for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) { - if (fa < 0 && tc->refcount == 0) - fa = i; + if (fa < 0 && tc->refcount == 0 && !(tc->flags & CLRL_USER)) + fa = i; /* first available */ if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS && tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE && tc->mode == FW_SCHED_PARAMS_MODE_FLOW && - tc->maxrate == maxrate) { + tc->maxrate == maxrate && + tc->pktsize == pi->vi[0].ifp->if_mtu) { tc->refcount++; *tc_idx = i; + if ((tc->flags & (CLRL_ERR | CLRL_ASYNC | CLRL_SYNC)) == + CLRL_ERR) { + update = true; + } goto done; } } /* Not found */ MPASS(i == sc->chip_params->nsched_cls); if (fa != -1) { - tc = &sc->port[port_id]->sched_params->cl_rl[fa]; - tc->flags = TX_CLRL_REFRESH; + tc = &pi->sched_params->cl_rl[fa]; tc->refcount = 1; tc->ratemode = FW_SCHED_PARAMS_RATE_ABS; tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE; tc->mode = FW_SCHED_PARAMS_MODE_FLOW; tc->maxrate = maxrate; - tc->pktsize = ETHERMTU; /* XXX */ + tc->pktsize = pi->vi[0].ifp->if_mtu; *tc_idx = fa; - t4_update_tx_sched(sc); + update = true; } else { *tc_idx = -1; rc = ENOSPC; } done: mtx_unlock(&sc->tc_lock); + if (update) { + tc->flags |= CLRL_ASYNC; + t4_update_tx_sched(sc); + } return (rc); } void -t4_release_cl_rl_kbps(struct adapter *sc, int port_id, int tc_idx) +t4_release_cl_rl(struct adapter *sc, int port_id, int tc_idx) { struct tx_cl_rl_params *tc; @@ -464,13 +546,114 @@ t4_release_cl_rl_kbps(struct adapter *sc, int port_id, mtx_lock(&sc->tc_lock); tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx]; MPASS(tc->refcount > 0); - MPASS(tc->ratemode == FW_SCHED_PARAMS_RATE_ABS); - MPASS(tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE); - MPASS(tc->mode == FW_SCHED_PARAMS_MODE_FLOW); tc->refcount--; mtx_unlock(&sc->tc_lock); } +int +sysctl_tc(SYSCTL_HANDLER_ARGS) +{ + struct vi_info *vi = arg1; + struct port_info *pi; + struct adapter *sc; + struct sge_txq *txq; + int qidx = arg2, rc, tc_idx; + + MPASS(qidx >= 0 && qidx < vi->ntxq); + pi = vi->pi; + sc = pi->adapter; + txq = &sc->sge.txq[vi->first_txq + qidx]; + + tc_idx = txq->tc_idx; + rc = sysctl_handle_int(oidp, &tc_idx, 0, req); + if (rc != 0 || req->newptr == NULL) + return (rc); + + if (sc->flags & IS_VF) + return (EPERM); + if (!in_range(tc_idx, 0, sc->chip_params->nsched_cls - 1)) + return (EINVAL); + + return (bind_txq_to_traffic_class(sc, txq, tc_idx)); +} + +int +sysctl_tc_params(SYSCTL_HANDLER_ARGS) +{ + struct adapter *sc = arg1; + struct tx_cl_rl_params tc; + struct sbuf *sb; + int i, rc, port_id, mbps, gbps; + + rc = sysctl_wire_old_buffer(req, 0); + if (rc != 0) + return (rc); + + sb = sbuf_new_for_sysctl(NULL, NULL, 4096, req); + if (sb == NULL) + return (ENOMEM); + + port_id = arg2 >> 16; + MPASS(port_id < sc->params.nports); + MPASS(sc->port[port_id] != NULL); + i = arg2 & 0xffff; + MPASS(i < sc->chip_params->nsched_cls); + + mtx_lock(&sc->tc_lock); + tc = sc->port[port_id]->sched_params->cl_rl[i]; + mtx_unlock(&sc->tc_lock); + + switch (tc.rateunit) { + case SCHED_CLASS_RATEUNIT_BITS: + switch (tc.ratemode) { + case SCHED_CLASS_RATEMODE_REL: + /* XXX: top speed or actual link speed? */ + gbps = port_top_speed(sc->port[port_id]); + sbuf_printf(sb, "%u%% of %uGbps", tc.maxrate, gbps); + break; + case SCHED_CLASS_RATEMODE_ABS: + mbps = tc.maxrate / 1000; + gbps = tc.maxrate / 1000000; + if (tc.maxrate == gbps * 1000000) + sbuf_printf(sb, "%uGbps", gbps); + else if (tc.maxrate == mbps * 1000) + sbuf_printf(sb, "%uMbps", mbps); + else + sbuf_printf(sb, "%uKbps", tc.maxrate); + break; + default: + rc = ENXIO; + goto done; + } + break; + case SCHED_CLASS_RATEUNIT_PKTS: + sbuf_printf(sb, "%upps", tc.maxrate); + break; + default: + rc = ENXIO; + goto done; + } + + switch (tc.mode) { + case SCHED_CLASS_MODE_CLASS: + sbuf_printf(sb, " aggregate"); + break; + case SCHED_CLASS_MODE_FLOW: + sbuf_printf(sb, " per-flow"); + break; + default: + rc = ENXIO; + goto done; + } + +done: + if (rc == 0) + rc = sbuf_finish(sb); + sbuf_delete(sb); + + return (rc); +} + #ifdef RATELIMIT void t4_init_etid_table(struct adapter *sc) @@ -578,7 +761,7 @@ cxgbe_snd_tag_alloc(struct ifnet *ifp, union if_snd_ta cst = malloc(sizeof(*cst), M_CXGBE, M_ZERO | M_NOWAIT); if (cst == NULL) { failed: - t4_release_cl_rl_kbps(sc, pi->port_id, schedcl); + t4_release_cl_rl(sc, pi->port_id, schedcl); return (ENOMEM); } @@ -634,7 +817,7 @@ cxgbe_snd_tag_modify(struct m_snd_tag *mst, if (rc != 0) return (rc); MPASS(schedcl >= 0 && schedcl < sc->chip_params->nsched_cls); - t4_release_cl_rl_kbps(sc, cst->port_id, cst->schedcl); + t4_release_cl_rl(sc, cst->port_id, cst->schedcl); cst->schedcl = schedcl; cst->max_rate = params->rate_limit.max_rate; mtx_unlock(&cst->lock); @@ -675,7 +858,7 @@ cxgbe_snd_tag_free_locked(struct cxgbe_snd_tag *cst) if (cst->etid >= 0) free_etid(sc, cst->etid); if (cst->schedcl != -1) - t4_release_cl_rl_kbps(sc, cst->port_id, cst->schedcl); + t4_release_cl_rl(sc, cst->port_id, cst->schedcl); mtx_unlock(&cst->lock); mtx_destroy(&cst->lock); free(cst, M_CXGBE); Modified: head/sys/dev/cxgbe/t4_sge.c ============================================================================== --- head/sys/dev/cxgbe/t4_sge.c Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/t4_sge.c Mon Aug 6 23:21:13 2018 (r337398) @@ -296,7 +296,6 @@ static void drain_wrq_wr_list(struct adapter *, struct static int sysctl_uint16(SYSCTL_HANDLER_ARGS); static int sysctl_bufsizes(SYSCTL_HANDLER_ARGS); -static int sysctl_tc(SYSCTL_HANDLER_ARGS); #ifdef RATELIMIT static inline u_int txpkt_eo_len16(u_int, u_int, u_int); static int ethofld_fw4_ack(struct sge_iq *, const struct rss_header *, @@ -5365,91 +5364,6 @@ sysctl_bufsizes(SYSCTL_HANDLER_ARGS) sbuf_finish(&sb); rc = sysctl_handle_string(oidp, sbuf_data(&sb), sbuf_len(&sb), req); sbuf_delete(&sb); - return (rc); -} - -static int -sysctl_tc(SYSCTL_HANDLER_ARGS) -{ - struct vi_info *vi = arg1; - struct port_info *pi; - struct adapter *sc; - struct sge_txq *txq; - struct tx_cl_rl_params *tc; - int qidx = arg2, rc, tc_idx; - uint32_t fw_queue, fw_class; - - MPASS(qidx >= 0 && qidx < vi->ntxq); - pi = vi->pi; - sc = pi->adapter; - txq = &sc->sge.txq[vi->first_txq + qidx]; - - tc_idx = txq->tc_idx; - rc = sysctl_handle_int(oidp, &tc_idx, 0, req); - if (rc != 0 || req->newptr == NULL) - return (rc); - - if (sc->flags & IS_VF) - return (EPERM); - - /* Note that -1 is legitimate input (it means unbind). */ - if (tc_idx < -1 || tc_idx >= sc->chip_params->nsched_cls) - return (EINVAL); - - mtx_lock(&sc->tc_lock); - if (tc_idx == txq->tc_idx) { - rc = 0; /* No change, nothing to do. */ - goto done; - } - - fw_queue = V_FW_PARAMS_MNEM(FW_PARAMS_MNEM_DMAQ) | - V_FW_PARAMS_PARAM_X(FW_PARAMS_PARAM_DMAQ_EQ_SCHEDCLASS_ETH) | - V_FW_PARAMS_PARAM_YZ(txq->eq.cntxt_id); - - if (tc_idx == -1) - fw_class = 0xffffffff; /* Unbind. */ - else { - /* - * Bind to a different class. - */ - tc = &pi->sched_params->cl_rl[tc_idx]; - if (tc->flags & TX_CLRL_ERROR) { - /* Previous attempt to set the cl-rl params failed. */ - rc = EIO; - goto done; - } else { - /* - * Ok to proceed. Place a reference on the new class - * while still holding on to the reference on the - * previous class, if any. - */ - fw_class = tc_idx; - tc->refcount++; - } - } - mtx_unlock(&sc->tc_lock); - - rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc"); - if (rc) - return (rc); - rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, &fw_class); - end_synchronized_op(sc, 0); - - mtx_lock(&sc->tc_lock); - if (rc == 0) { - if (txq->tc_idx != -1) { - tc = &pi->sched_params->cl_rl[txq->tc_idx]; - MPASS(tc->refcount > 0); - tc->refcount--; - } - txq->tc_idx = tc_idx; - } else if (tc_idx != -1) { - tc = &pi->sched_params->cl_rl[tc_idx]; - MPASS(tc->refcount > 0); - tc->refcount--; - } -done: - mtx_unlock(&sc->tc_lock); return (rc); } Modified: head/sys/dev/cxgbe/tom/t4_cpl_io.c ============================================================================== --- head/sys/dev/cxgbe/tom/t4_cpl_io.c Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/tom/t4_cpl_io.c Mon Aug 6 23:21:13 2018 (r337398) @@ -231,7 +231,7 @@ update_tx_rate_limit(struct adapter *sc, struct toepcb if (toep->tx_credits < flowclen16 || toep->txsd_avail == 0 || (wr = alloc_wrqe(roundup2(flowclen, 16), toep->ofld_txq)) == NULL) { if (tc_idx >= 0) - t4_release_cl_rl_kbps(sc, port_id, tc_idx); + t4_release_cl_rl(sc, port_id, tc_idx); return (ENOMEM); } @@ -259,7 +259,7 @@ update_tx_rate_limit(struct adapter *sc, struct toepcb } if (toep->tc_idx >= 0) - t4_release_cl_rl_kbps(sc, port_id, toep->tc_idx); + t4_release_cl_rl(sc, port_id, toep->tc_idx); toep->tc_idx = tc_idx; return (0); Modified: head/sys/dev/cxgbe/tom/t4_tom.c ============================================================================== --- head/sys/dev/cxgbe/tom/t4_tom.c Mon Aug 6 21:54:51 2018 (r337397) +++ head/sys/dev/cxgbe/tom/t4_tom.c Mon Aug 6 23:21:13 2018 (r337398) @@ -317,10 +317,9 @@ release_offload_resources(struct toepcb *toep) if (toep->ce) release_lip(td, toep->ce); -#ifdef RATELIMIT if (toep->tc_idx != -1) - t4_release_cl_rl_kbps(sc, toep->vi->pi->port_id, toep->tc_idx); -#endif + t4_release_cl_rl(sc, toep->vi->pi->port_id, toep->tc_idx); + mtx_lock(&td->toep_list_lock); TAILQ_REMOVE(&td->toep_list, toep, link); mtx_unlock(&td->toep_list_lock);