Author: np
Date: Wed May  7 15:24:24 2014
New Revision: 265552
URL: http://svnweb.freebsd.org/changeset/base/265552

Log:
  MFC r258879:
  cxgbe(4):  T4_SET_SCHED_CLASS and T4_SET_SCHED_QUEUE ioctls to program
  scheduling classes in the chip and to bind tx queue(s) to a scheduling
  class respectively.  These can be used for various kinds of tx traffic
  throttling (to force selected tx queues to drain at a fixed Kbps rate,
  or a % of the port's total bandwidth, or at a fixed pps rate, etc.).

Modified:
  stable/9/sys/dev/cxgbe/common/common.h
  stable/9/sys/dev/cxgbe/common/t4_hw.c
  stable/9/sys/dev/cxgbe/t4_ioctl.h
  stable/9/sys/dev/cxgbe/t4_main.c
Directory Properties:
  stable/9/sys/   (props changed)
  stable/9/sys/dev/   (props changed)

Modified: stable/9/sys/dev/cxgbe/common/common.h
==============================================================================
--- stable/9/sys/dev/cxgbe/common/common.h      Wed May  7 15:13:57 2014        
(r265551)
+++ stable/9/sys/dev/cxgbe/common/common.h      Wed May  7 15:24:24 2014        
(r265552)
@@ -587,4 +587,8 @@ int t4_sge_ctxt_rd_bd(struct adapter *ad
 int t4_sge_ctxt_flush(struct adapter *adap, unsigned int mbox);
 int t4_handle_fw_rpl(struct adapter *adap, const __be64 *rpl);
 int t4_fwaddrspace_write(struct adapter *adap, unsigned int mbox, u32 addr, 
u32 val);
+int t4_sched_config(struct adapter *adapter, int type, int minmaxen);
+int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+                   int rateunit, int ratemode, int channel, int cl,
+                   int minrate, int maxrate, int weight, int pktsize);
 #endif /* __CHELSIO_COMMON_H */

Modified: stable/9/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- stable/9/sys/dev/cxgbe/common/t4_hw.c       Wed May  7 15:13:57 2014        
(r265551)
+++ stable/9/sys/dev/cxgbe/common/t4_hw.c       Wed May  7 15:24:24 2014        
(r265552)
@@ -5659,3 +5659,50 @@ int __devinit t4_port_init(struct port_i
 
        return 0;
 }
+
+int t4_sched_config(struct adapter *adapter, int type, int minmaxen)
+{
+       struct fw_sched_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
+                                     F_FW_CMD_REQUEST |
+                                     F_FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+       cmd.u.config.sc = FW_SCHED_SC_CONFIG;
+       cmd.u.config.type = type;
+       cmd.u.config.minmaxen = minmaxen;
+
+       return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
+                              NULL, 1);
+}
+
+int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
+                   int rateunit, int ratemode, int channel, int cl,
+                   int minrate, int maxrate, int weight, int pktsize)
+{
+       struct fw_sched_cmd cmd;
+
+       memset(&cmd, 0, sizeof(cmd));
+       cmd.op_to_write = cpu_to_be32(V_FW_CMD_OP(FW_SCHED_CMD) |
+                                     F_FW_CMD_REQUEST |
+                                     F_FW_CMD_WRITE);
+       cmd.retval_len16 = cpu_to_be32(FW_LEN16(cmd));
+
+       cmd.u.params.sc = FW_SCHED_SC_PARAMS;
+       cmd.u.params.type = type;
+       cmd.u.params.level = level;
+       cmd.u.params.mode = mode;
+       cmd.u.params.ch = channel;
+       cmd.u.params.cl = cl;
+       cmd.u.params.unit = rateunit;
+       cmd.u.params.rate = ratemode;
+       cmd.u.params.min = cpu_to_be32(minrate);
+       cmd.u.params.max = cpu_to_be32(maxrate);
+       cmd.u.params.weight = cpu_to_be16(weight);
+       cmd.u.params.pktsize = cpu_to_be16(pktsize);
+
+       return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
+                              NULL, 1);
+}

Modified: stable/9/sys/dev/cxgbe/t4_ioctl.h
==============================================================================
--- stable/9/sys/dev/cxgbe/t4_ioctl.h   Wed May  7 15:13:57 2014        
(r265551)
+++ stable/9/sys/dev/cxgbe/t4_ioctl.h   Wed May  7 15:24:24 2014        
(r265552)
@@ -206,6 +206,74 @@ struct t4_filter {
        struct t4_filter_specification fs;
 };
 
+/*
+ * Support for "sched-class" command to allow a TX Scheduling Class to be
+ * programmed with various parameters.
+ */
+struct t4_sched_params {
+       int8_t   subcmd;                /* sub-command */
+       int8_t   type;                  /* packet or flow */
+       union {
+               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;
+               uint8_t     reserved[6 + 8 * 8];
+       } u;
+};
+
+enum {
+       SCHED_CLASS_SUBCMD_CONFIG,      /* config sub-command */
+       SCHED_CLASS_SUBCMD_PARAMS,      /* params sub-command */
+};
+
+enum {
+       SCHED_CLASS_TYPE_PACKET,
+};
+
+enum {
+       SCHED_CLASS_LEVEL_CL_RL,        /* class rate limiter */
+       SCHED_CLASS_LEVEL_CL_WRR,       /* class weighted round robin */
+       SCHED_CLASS_LEVEL_CH_RL,        /* channel rate limiter */
+};
+
+enum {
+       SCHED_CLASS_MODE_CLASS,         /* per-class scheduling */
+       SCHED_CLASS_MODE_FLOW,          /* per-flow scheduling */
+};
+
+enum {
+       SCHED_CLASS_RATEUNIT_BITS,      /* bit rate scheduling */
+       SCHED_CLASS_RATEUNIT_PKTS,      /* packet rate scheduling */
+};
+
+enum {
+       SCHED_CLASS_RATEMODE_REL,       /* percent of port bandwidth */
+       SCHED_CLASS_RATEMODE_ABS,       /* Kb/s */
+};
+
+/*
+ * Support for "sched_queue" command to allow one or more NIC TX Queues to be
+ * bound to a TX Scheduling Class.
+ */
+struct t4_sched_queue {
+       uint8_t  port;
+       int8_t   queue; /* queue index; -1 => all queues */
+       int8_t   cl;    /* class index; -1 => unbind */
+};
+
 #define T4_SGE_CONTEXT_SIZE 24
 enum {
        SGE_CONTEXT_EGRESS,
@@ -240,4 +308,8 @@ struct t4_mem_range {
 #define CHELSIO_T4_GET_MEM     _IOW('f', T4_GET_MEM, struct t4_mem_range)
 #define CHELSIO_T4_GET_I2C     _IOWR('f', T4_GET_I2C, struct t4_i2c_data)
 #define CHELSIO_T4_CLEAR_STATS _IOW('f', T4_CLEAR_STATS, uint32_t)
+#define CHELSIO_T4_SCHED_CLASS  _IOW('f', T4_SET_SCHED_CLASS, \
+    struct t4_sched_params)
+#define CHELSIO_T4_SCHED_QUEUE  _IOW('f', T4_SET_SCHED_QUEUE, \
+    struct t4_sched_queue)
 #endif

Modified: stable/9/sys/dev/cxgbe/t4_main.c
==============================================================================
--- stable/9/sys/dev/cxgbe/t4_main.c    Wed May  7 15:13:57 2014        
(r265551)
+++ stable/9/sys/dev/cxgbe/t4_main.c    Wed May  7 15:24:24 2014        
(r265552)
@@ -425,6 +425,8 @@ static int get_sge_context(struct adapte
 static int load_fw(struct adapter *, struct t4_data *);
 static int read_card_mem(struct adapter *, int, struct t4_mem_range *);
 static int read_i2c(struct adapter *, struct t4_i2c_data *);
+static int set_sched_class(struct adapter *, struct t4_sched_params *);
+static int set_sched_queue(struct adapter *, struct t4_sched_queue *);
 #ifdef TCP_OFFLOAD
 static int toe_capability(struct port_info *, int);
 #endif
@@ -7265,6 +7267,228 @@ read_i2c(struct adapter *sc, struct t4_i
        return (rc);
 }
 
+static int
+in_range(int val, int lo, int hi)
+{
+
+       return (val < 0 || (val <= hi && val >= lo));
+}
+
+static int
+set_sched_class(struct adapter *sc, struct t4_sched_params *p)
+{
+       int fw_subcmd, fw_type, rc;
+
+       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsc");
+       if (rc)
+               return (rc);
+
+       if (!(sc->flags & FULL_INIT_DONE)) {
+               rc = EAGAIN;
+               goto done;
+       }
+
+       /*
+        * 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;
+       }
+
+       if (fw_subcmd == FW_SCHED_SC_CONFIG) {
+               /* Vet our parameters ..*/
+               if (p->u.config.minmax < 0) {
+                       rc = EINVAL;
+                       goto done;
+               }
+
+               /* And pass the request to the firmware ...*/
+               rc = -t4_sched_config(sc, fw_type, p->u.config.minmax);
+               goto done;
+       }
+
+       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->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->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;
+               }
+
+               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;
+               }
+
+               /* Vet our parameters ... */
+               if (!in_range(p->u.params.channel, 0, 3) ||
+                   !in_range(p->u.params.cl, 0, is_t4(sc) ? 15 : 16) ||
+                   !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;
+               }
+
+               /*
+                * Translate any unset parameters into the firmware's
+                * nomenclature and/or fail the call if the parameters
+                * are required ...
+                */
+               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);
+               goto done;
+       }
+
+       rc = EINVAL;
+done:
+       end_synchronized_op(sc, 0);
+       return (rc);
+}
+
+static int
+set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
+{
+       struct port_info *pi = NULL;
+       struct sge_txq *txq;
+       uint32_t fw_mnem, fw_queue, fw_class;
+       int i, rc;
+
+       rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4setsq");
+       if (rc)
+               return (rc);
+
+       if (!(sc->flags & FULL_INIT_DONE)) {
+               rc = EAGAIN;
+               goto done;
+       }
+
+       if (p->port >= sc->params.nports) {
+               rc = EINVAL;
+               goto done;
+       }
+
+       pi = sc->port[p->port];
+       if (!in_range(p->queue, 0, pi->ntxq - 1) || !in_range(p->cl, 0, 7)) {
+               rc = EINVAL;
+               goto done;
+       }
+
+       /*
+        * Create a template for the FW_PARAMS_CMD mnemonic and value (TX
+        * Scheduling Class in this case).
+        */
+       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;
+
+       /*
+        * 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[pi->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;
+       }
+
+       /*
+        * Change the scheduling on all the TX queues for the
+        * interface.
+        */
+       for_each_txq(pi, 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;
+       }
+
+       rc = 0;
+done:
+       end_synchronized_op(sc, 0);
+       return (rc);
+}
+
 int
 t4_os_find_pci_capability(struct adapter *sc, int cap)
 {
@@ -7508,6 +7732,12 @@ t4_ioctl(struct cdev *dev, unsigned long
                }
                break;
        }
+       case CHELSIO_T4_SCHED_CLASS:
+               rc = set_sched_class(sc, (struct t4_sched_params *)data);
+               break;
+       case CHELSIO_T4_SCHED_QUEUE:
+               rc = set_sched_queue(sc, (struct t4_sched_queue *)data);
+               break;
        default:
                rc = EINVAL;
        }
_______________________________________________
svn-src-stable-9@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-stable-9
To unsubscribe, send any mail to "svn-src-stable-9-unsubscr...@freebsd.org"

Reply via email to