Author: jhb
Date: Fri Nov  4 21:59:27 2016
New Revision: 308321
URL: https://svnweb.freebsd.org/changeset/base/308321

Log:
  MFC 301516,301520,301531,301535,301540,301542,301628: Traffic scheduling
  updates.
  
  301516:
  cxgbetool: Allow max-rate > 10Gbps for rate-limited traffic.
  
  301520:
  cxgbe(4): Create a reusable struct type for scheduling class parameters.
  
  301531:
  cxgbe(4): Break up set_sched_class.  Validate the channel number and
  min/max rates against their actual limits (which are chip and port
  specific) instead of hardcoded constants.
  
  301535:
  cxgbe(4): Track the state of the hardware traffic schedulers in the
  driver.  This works as long as everyone uses set_sched_class_params
  to program them.
  
  301540:
  cxgbe(4): Provide information about traffic classes in the sysctl mib.
  
  301542:
  cxgbe(4): A couple of fixes to set_sched_queue.
  
  - Validate the scheduling class against the actual limit (which is chip
    specific) instead of a magic number.
  
  - Return an error if an attempt is made to manipulate the tx queues of a
    VI that hasn't been initialized.
  
  301628:
  cxgbe(4): Add a sysctl to manage the binding of a txq to a traffic class.
  
  Sponsored by: Chelsio Communications

Modified:
  stable/10/sys/dev/cxgbe/adapter.h
  stable/10/sys/dev/cxgbe/t4_ioctl.h
  stable/10/sys/dev/cxgbe/t4_main.c
  stable/10/sys/dev/cxgbe/t4_sge.c
  stable/10/tools/tools/cxgbetool/cxgbetool.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/dev/cxgbe/adapter.h
==============================================================================
--- stable/10/sys/dev/cxgbe/adapter.h   Fri Nov  4 21:52:48 2016        
(r308320)
+++ stable/10/sys/dev/cxgbe/adapter.h   Fri Nov  4 21:59:27 2016        
(r308321)
@@ -48,6 +48,7 @@
 #include <netinet/tcp_lro.h>
 
 #include "offload.h"
+#include "t4_ioctl.h"
 #include "common/t4_msg.h"
 #include "firmware/t4fw_interface.h"
 
@@ -261,6 +262,17 @@ struct vi_info {
        uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */
 };
 
+enum {
+       /* tx_sched_class flags */
+       TX_SC_OK        = (1 << 0),     /* Set up in hardware, active. */
+};
+
+struct tx_sched_class {
+       int refcount;
+       int flags;
+       struct t4_sched_class_params params;
+};
+
 struct port_info {
        device_t dev;
        struct adapter *adapter;
@@ -270,6 +282,8 @@ struct port_info {
        int up_vis;
        int uld_vis;
 
+       struct tx_sched_class *tc;      /* traffic classes for this channel */
+
        struct mtx pi_lock;
        char lockname[16];
        unsigned long flags;
@@ -523,6 +537,7 @@ struct sge_txq {
        struct tx_sdesc *sdesc; /* KVA of software descriptor ring */
        struct sglist *gl;
        __be32 cpl_ctrl0;       /* for convenience */
+       int tc_idx;             /* traffic class */
 
        struct task tx_reclaim_task;
        /* stats for common events first */

Modified: stable/10/sys/dev/cxgbe/t4_ioctl.h
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_ioctl.h  Fri Nov  4 21:52:48 2016        
(r308320)
+++ stable/10/sys/dev/cxgbe/t4_ioctl.h  Fri Nov  4 21:59:27 2016        
(r308321)
@@ -215,6 +215,20 @@ struct t4_filter {
        struct t4_filter_specification fs;
 };
 
+/* Tx Scheduling Class parameters */
+struct t4_sched_class_params {
+       int8_t   level;         /* scheduler hierarchy level */
+       int8_t   mode;          /* per-class or per-flow */
+       int8_t   rateunit;      /* bit or packet rate */
+       int8_t   ratemode;      /* %port relative or kbps absolute */
+       int8_t   channel;       /* scheduler channel [0..N] */
+       int8_t   cl;            /* scheduler class [0..N] */
+       int32_t  minrate;       /* minimum rate */
+       int32_t  maxrate;       /* maximum rate */
+       int16_t  weight;        /* percent weight */
+       int16_t  pktsize;       /* average packet size */
+};
+
 /*
  * Support for "sched-class" command to allow a TX Scheduling Class to be
  * programmed with various parameters.
@@ -226,19 +240,7 @@ struct t4_sched_params {
                struct {                /* sub-command SCHED_CLASS_CONFIG */
                        int8_t   minmax;        /* minmax enable */
                } config;
-               struct {                /* sub-command SCHED_CLASS_PARAMS */
-                       int8_t   level;         /* scheduler hierarchy level */
-                       int8_t   mode;          /* per-class or per-flow */
-                       int8_t   rateunit;      /* bit or packet rate */
-                       int8_t   ratemode;      /* %port relative or kbps
-                                                  absolute */
-                       int8_t   channel;       /* scheduler channel [0..N] */
-                       int8_t   cl;            /* scheduler class [0..N] */
-                       int32_t  minrate;       /* minimum rate */
-                       int32_t  maxrate;       /* maximum rate */
-                       int16_t  weight;        /* percent weight */
-                       int16_t  pktsize;       /* average packet size */
-               } params;
+               struct t4_sched_class_params params;
                uint8_t     reserved[6 + 8 * 8];
        } u;
 };

Modified: stable/10/sys/dev/cxgbe/t4_main.c
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_main.c   Fri Nov  4 21:52:48 2016        
(r308320)
+++ stable/10/sys/dev/cxgbe/t4_main.c   Fri Nov  4 21:59:27 2016        
(r308321)
@@ -505,6 +505,7 @@ static int sysctl_tp_la(SYSCTL_HANDLER_A
 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);
 #endif
 #ifdef TCP_OFFLOAD
 static int sysctl_tp_tick(SYSCTL_HANDLER_ARGS);
@@ -883,6 +884,9 @@ t4_attach(device_t dev)
                mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
                sc->chan_map[pi->tx_chan] = i;
 
+               pi->tc = malloc(sizeof(struct tx_sched_class) *
+                   sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK);
+
                if (is_10G_port(pi) || is_40G_port(pi)) {
                        n10g++;
                } else {
@@ -1130,6 +1134,7 @@ t4_detach(device_t dev)
 
                        mtx_destroy(&pi->pi_lock);
                        free(pi->vi, M_CXGBE);
+                       free(pi->tc, M_CXGBE);
                        free(pi, M_CXGBE);
                }
        }
@@ -4964,8 +4969,10 @@ cxgbe_sysctls(struct port_info *pi)
 {
        struct sysctl_ctx_list *ctx;
        struct sysctl_oid *oid;
-       struct sysctl_oid_list *children;
+       struct sysctl_oid_list *children, *children2;
        struct adapter *sc = pi->adapter;
+       int i;
+       char name[16];
 
        ctx = device_get_sysctl_ctx(pi->dev);
 
@@ -4994,6 +5001,29 @@ cxgbe_sysctls(struct port_info *pi)
            port_top_speed(pi), "max speed (in Gbps)");
 
        /*
+        * dev.(cxgbe|cxl).X.tc.
+        */
+       oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL,
+           "Tx scheduler traffic classes");
+       for (i = 0; i < sc->chip_params->nsched_cls; i++) {
+               struct tx_sched_class *tc = &pi->tc[i];
+
+               snprintf(name, sizeof(name), "%d", i);
+               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_UINT(ctx, children2, OID_AUTO, "refcount",
+                   CTLFLAG_RD, &tc->refcount, 0, "references to this class");
+#ifdef SBUF_DRAIN
+               SYSCTL_ADD_PROC(ctx, children2, OID_AUTO, "params",
+                   CTLTYPE_STRING | CTLFLAG_RD, sc, (pi->port_id << 16) | i,
+                   sysctl_tc_params, "A", "traffic class parameters");
+#endif
+       }
+
+       /*
         * dev.cxgbe.X.stats.
         */
        oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "stats", CTLFLAG_RD,
@@ -7387,6 +7417,101 @@ sysctl_wcwr_stats(SYSCTL_HANDLER_ARGS)
 
        return (rc);
 }
+
+static int
+sysctl_tc_params(SYSCTL_HANDLER_ARGS)
+{
+       struct adapter *sc = arg1;
+       struct tx_sched_class *tc;
+       struct t4_sched_class_params p;
+       struct sbuf *sb;
+       int i, rc, port_id, flags, 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);
+       tc = &sc->port[port_id]->tc[i];
+
+       rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
+           "t4tc_p");
+       if (rc)
+               goto done;
+       flags = tc->flags;
+       p = tc->params;
+       end_synchronized_op(sc, LOCK_HELD);
+
+       if ((flags & TX_SC_OK) == 0) {
+               sbuf_printf(sb, "none");
+               goto done;
+       }
+
+       if (p.level == SCHED_CLASS_LEVEL_CL_WRR) {
+               sbuf_printf(sb, "cl-wrr weight %u", p.weight);
+               goto done;
+       } else if (p.level == SCHED_CLASS_LEVEL_CL_RL)
+               sbuf_printf(sb, "cl-rl");
+       else if (p.level == SCHED_CLASS_LEVEL_CH_RL)
+               sbuf_printf(sb, "ch-rl");
+       else {
+               rc = ENXIO;
+               goto done;
+       }
+
+       if (p.ratemode == 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", p.maxrate, gbps);
+       }
+       else if (p.ratemode == SCHED_CLASS_RATEMODE_ABS) {
+               switch (p.rateunit) {
+               case SCHED_CLASS_RATEUNIT_BITS:
+                       mbps = p.maxrate / 1000;
+                       gbps = p.maxrate / 1000000;
+                       if (p.maxrate == gbps * 1000000)
+                               sbuf_printf(sb, " %uGbps", gbps);
+                       else if (p.maxrate == mbps * 1000)
+                               sbuf_printf(sb, " %uMbps", mbps);
+                       else
+                               sbuf_printf(sb, " %uKbps", p.maxrate);
+                       break;
+               case SCHED_CLASS_RATEUNIT_PKTS:
+                       sbuf_printf(sb, " %upps", p.maxrate);
+                       break;
+               default:
+                       rc = ENXIO;
+                       goto done;
+               }
+       }
+
+       switch (p.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);
+}
 #endif
 
 #ifdef TCP_OFFLOAD
@@ -8232,155 +8357,147 @@ in_range(int val, int lo, int hi)
 }
 
 static int
-set_sched_class(struct adapter *sc, struct t4_sched_params *p)
+set_sched_class_config(struct adapter *sc, int minmax)
 {
-       int fw_subcmd, fw_type, rc;
+       int rc;
+
+       if (minmax < 0)
+               return (EINVAL);
 
-       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsc");
+       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
        if (rc)
                return (rc);
+       rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
+       end_synchronized_op(sc, 0);
 
-       if (!(sc->flags & FULL_INIT_DONE)) {
-               rc = EAGAIN;
-               goto done;
-       }
+       return (rc);
+}
 
-       /*
-        * Translate the cxgbetool parameters into T4 firmware parameters.  (The
-        * sub-command and type are in common locations.)
-        */
-       if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
-               fw_subcmd = FW_SCHED_SC_CONFIG;
-       else if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
-               fw_subcmd = FW_SCHED_SC_PARAMS;
-       else {
-               rc = EINVAL;
-               goto done;
-       }
-       if (p->type == SCHED_CLASS_TYPE_PACKET)
-               fw_type = FW_SCHED_TYPE_PKTSCHED;
-       else {
-               rc = EINVAL;
-               goto done;
-       }
+static int
+set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
+    int sleep_ok)
+{
+       int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
+       struct port_info *pi;
+       struct tx_sched_class *tc;
 
-       if (fw_subcmd == FW_SCHED_SC_CONFIG) {
-               /* Vet our parameters ..*/
-               if (p->u.config.minmax < 0) {
-                       rc = EINVAL;
-                       goto done;
-               }
+       if (p->level == SCHED_CLASS_LEVEL_CL_RL)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
+       else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
+       else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
+               fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
+       else
+               return (EINVAL);
 
-               /* And pass the request to the firmware ...*/
-               rc = -t4_sched_config(sc, fw_type, p->u.config.minmax, 1);
-               goto done;
-       }
+       if (p->mode == SCHED_CLASS_MODE_CLASS)
+               fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
+       else if (p->mode == SCHED_CLASS_MODE_FLOW)
+               fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
+       else
+               return (EINVAL);
 
-       if (fw_subcmd == FW_SCHED_SC_PARAMS) {
-               int fw_level;
-               int fw_mode;
-               int fw_rateunit;
-               int fw_ratemode;
-
-               if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL)
-                       fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
-               else if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR)
-                       fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
-               else if (p->u.params.level == SCHED_CLASS_LEVEL_CH_RL)
-                       fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
-               else {
-                       rc = EINVAL;
-                       goto done;
-               }
+       if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS)
+               fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
+       else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS)
+               fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
+       else
+               return (EINVAL);
 
-               if (p->u.params.mode == SCHED_CLASS_MODE_CLASS)
-                       fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
-               else if (p->u.params.mode == SCHED_CLASS_MODE_FLOW)
-                       fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
-               else {
-                       rc = EINVAL;
-                       goto done;
-               }
+       if (p->ratemode == SCHED_CLASS_RATEMODE_REL)
+               fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
+       else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS)
+               fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
+       else
+               return (EINVAL);
 
-               if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_BITS)
-                       fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
-               else if (p->u.params.rateunit == SCHED_CLASS_RATEUNIT_PKTS)
-                       fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
-               else {
-                       rc = EINVAL;
-                       goto done;
-               }
+       /* Vet our parameters ... */
+       if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
+               return (ERANGE);
 
-               if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_REL)
-                       fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
-               else if (p->u.params.ratemode == SCHED_CLASS_RATEMODE_ABS)
-                       fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
-               else {
-                       rc = EINVAL;
-                       goto done;
-               }
+       pi = sc->port[sc->chan_map[p->channel]];
+       if (pi == NULL)
+               return (ENXIO);
+       MPASS(pi->tx_chan == p->channel);
+       top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
 
-               /* Vet our parameters ... */
-               if (!in_range(p->u.params.channel, 0, 3) ||
-                   !in_range(p->u.params.cl, 0, sc->chip_params->nsched_cls) ||
-                   !in_range(p->u.params.minrate, 0, 10000000) ||
-                   !in_range(p->u.params.maxrate, 0, 10000000) ||
-                   !in_range(p->u.params.weight, 0, 100)) {
-                       rc = ERANGE;
-                       goto done;
-               }
+       if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) ||
+           !in_range(p->minrate, 0, top_speed) ||
+           !in_range(p->maxrate, 0, top_speed) ||
+           !in_range(p->weight, 0, 100))
+               return (ERANGE);
+
+       /*
+        * Translate any unset parameters into the firmware's
+        * nomenclature and/or fail the call if the parameters
+        * are required ...
+        */
+       if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0)
+               return (EINVAL);
+
+       if (p->minrate < 0)
+               p->minrate = 0;
+       if (p->maxrate < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
+                   p->level == SCHED_CLASS_LEVEL_CH_RL)
+                       return (EINVAL);
+               else
+                       p->maxrate = 0;
+       }
+       if (p->weight < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
+                       return (EINVAL);
+               else
+                       p->weight = 0;
+       }
+       if (p->pktsize < 0) {
+               if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
+                   p->level == SCHED_CLASS_LEVEL_CH_RL)
+                       return (EINVAL);
+               else
+                       p->pktsize = 0;
+       }
 
+       rc = begin_synchronized_op(sc, NULL,
+           sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
+       if (rc)
+               return (rc);
+       tc = &pi->tc[p->cl];
+       tc->params = *p;
+       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 (rc == 0)
+               tc->flags |= TX_SC_OK;
+       else {
                /*
-                * Translate any unset parameters into the firmware's
-                * nomenclature and/or fail the call if the parameters
-                * are required ...
+                * Unknown state at this point, see tc->params for what was
+                * attempted.
                 */
-               if (p->u.params.rateunit < 0 || p->u.params.ratemode < 0 ||
-                   p->u.params.channel < 0 || p->u.params.cl < 0) {
-                       rc = EINVAL;
-                       goto done;
-               }
-               if (p->u.params.minrate < 0)
-                       p->u.params.minrate = 0;
-               if (p->u.params.maxrate < 0) {
-                       if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
-                           p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) {
-                               rc = EINVAL;
-                               goto done;
-                       } else
-                               p->u.params.maxrate = 0;
-               }
-               if (p->u.params.weight < 0) {
-                       if (p->u.params.level == SCHED_CLASS_LEVEL_CL_WRR) {
-                               rc = EINVAL;
-                               goto done;
-                       } else
-                               p->u.params.weight = 0;
-               }
-               if (p->u.params.pktsize < 0) {
-                       if (p->u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
-                           p->u.params.level == SCHED_CLASS_LEVEL_CH_RL) {
-                               rc = EINVAL;
-                               goto done;
-                       } else
-                               p->u.params.pktsize = 0;
-               }
-
-               /* See what the firmware thinks of the request ... */
-               rc = -t4_sched_params(sc, fw_type, fw_level, fw_mode,
-                   fw_rateunit, fw_ratemode, p->u.params.channel,
-                   p->u.params.cl, p->u.params.minrate, p->u.params.maxrate,
-                   p->u.params.weight, p->u.params.pktsize, 1);
-               goto done;
+               tc->flags &= ~TX_SC_OK;
        }
+       end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
 
-       rc = EINVAL;
-done:
-       end_synchronized_op(sc, 0);
        return (rc);
 }
 
 static int
+set_sched_class(struct adapter *sc, struct t4_sched_params *p)
+{
+
+       if (p->type != SCHED_CLASS_TYPE_PACKET)
+               return (EINVAL);
+
+       if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
+               return (set_sched_class_config(sc, p->u.config.minmax));
+
+       if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
+               return (set_sched_class_params(sc, &p->u.params, 1));
+
+       return (EINVAL);
+}
+
+static int
 set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
 {
        struct port_info *pi = NULL;
@@ -8393,11 +8510,6 @@ set_sched_queue(struct adapter *sc, stru
        if (rc)
                return (rc);
 
-       if (!(sc->flags & FULL_INIT_DONE)) {
-               rc = EAGAIN;
-               goto done;
-       }
-
        if (p->port >= sc->params.nports) {
                rc = EINVAL;
                goto done;
@@ -8406,7 +8518,14 @@ set_sched_queue(struct adapter *sc, stru
        /* XXX: Only supported for the main VI. */
        pi = sc->port[p->port];
        vi = &pi->vi[0];
-       if (!in_range(p->queue, 0, vi->ntxq - 1) || !in_range(p->cl, 0, 7)) {
+       if (!(vi->flags & VI_INIT_DONE)) {
+               /* tx queues not set up yet */
+               rc = EAGAIN;
+               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;
        }

Modified: stable/10/sys/dev/cxgbe/t4_sge.c
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_sge.c    Fri Nov  4 21:52:48 2016        
(r308320)
+++ stable/10/sys/dev/cxgbe/t4_sge.c    Fri Nov  4 21:59:27 2016        
(r308321)
@@ -247,6 +247,7 @@ static void drain_wrq_wr_list(struct ada
 
 static int sysctl_uint16(SYSCTL_HANDLER_ARGS);
 static int sysctl_bufsizes(SYSCTL_HANDLER_ARGS);
+static int sysctl_tc(SYSCTL_HANDLER_ARGS);
 
 static counter_u64_t extfree_refs;
 static counter_u64_t extfree_rels;
@@ -3458,6 +3459,7 @@ alloc_txq(struct vi_info *vi, struct sge
        txq->cpl_ctrl0 = htobe32(V_TXPKT_OPCODE(CPL_TX_PKT) |
            V_TXPKT_INTF(pi->tx_chan) | V_TXPKT_VF_VLD(1) |
            V_TXPKT_VF(vi->viid));
+       txq->tc_idx = -1;
        txq->sdesc = malloc(eq->sidx * sizeof(struct tx_sdesc), M_CXGBE,
            M_ZERO | M_WAITOK);
 
@@ -3475,6 +3477,10 @@ alloc_txq(struct vi_info *vi, struct sge
            CTLTYPE_INT | CTLFLAG_RD, &eq->pidx, 0, sysctl_uint16, "I",
            "producer index");
 
+       SYSCTL_ADD_PROC(&vi->ctx, children, OID_AUTO, "tc",
+           CTLTYPE_INT | CTLFLAG_RW, vi, idx, sysctl_tc, "I",
+           "traffic class (-1 means none)");
+
        SYSCTL_ADD_UQUAD(&vi->ctx, children, OID_AUTO, "txcsum", CTLFLAG_RD,
            &txq->txcsum, "# of times hardware assisted with checksum");
        SYSCTL_ADD_UQUAD(&vi->ctx, children, OID_AUTO, "vlan_insertion",
@@ -4708,3 +4714,78 @@ sysctl_bufsizes(SYSCTL_HANDLER_ARGS)
        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_sched_class *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);
+
+       /* Note that -1 is legitimate input (it means unbind). */
+       if (tc_idx < -1 || tc_idx >= sc->chip_params->nsched_cls)
+               return (EINVAL);
+
+       rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc");
+       if (rc)
+               return (rc);
+
+       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.  Ethernet txq's are only allowed
+                * to bind to cl-rl mode-class for now.  XXX: too restrictive.
+                */
+               tc = &pi->tc[tc_idx];
+               if (tc->flags & TX_SC_OK &&
+                   tc->params.level == SCHED_CLASS_LEVEL_CL_RL &&
+                   tc->params.mode == SCHED_CLASS_MODE_CLASS) {
+                       /* Ok to proceed. */
+                       fw_class = tc_idx;
+               } else {
+                       rc = tc->flags & TX_SC_OK ? EBUSY : ENXIO;
+                       goto done;
+               }
+       }
+
+       rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, &fw_class);
+       if (rc == 0) {
+               if (txq->tc_idx != -1) {
+                       tc = &pi->tc[txq->tc_idx];
+                       MPASS(tc->refcount > 0);
+                       tc->refcount--;
+               }
+               if (tc_idx != -1) {
+                       tc = &pi->tc[tc_idx];
+                       tc->refcount++;
+               }
+               txq->tc_idx = tc_idx;
+       }
+done:
+       end_synchronized_op(sc, 0);
+       return (rc);
+}

Modified: stable/10/tools/tools/cxgbetool/cxgbetool.c
==============================================================================
--- stable/10/tools/tools/cxgbetool/cxgbetool.c Fri Nov  4 21:52:48 2016        
(r308320)
+++ stable/10/tools/tools/cxgbetool/cxgbetool.c Fri Nov  4 21:59:27 2016        
(r308321)
@@ -2526,9 +2526,9 @@ sched_class(int argc, const char *argv[]
                         errs++;
                 }
                 if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_ABS &&
-                   !in_range(op.u.params.maxrate, 1, 10000000)) {
+                   !in_range(op.u.params.maxrate, 1, 100000000)) {
                         warnx("sched params \"max-rate\" takes "
-                           "value(1-10000000) for rate-mode absolute");
+                           "value(1-100000000) for rate-mode absolute");
                         errs++;
                 }
                 if (op.u.params.maxrate > 0 &&
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to