svn commit: r265552 - in stable/9/sys/dev/cxgbe: . common
Navdeep Parhar
np at FreeBSD.org
Wed May 7 15:24:26 UTC 2014
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;
}
More information about the svn-src-stable-9
mailing list