svn commit: r258879 - in head/sys/dev/cxgbe: . common

Navdeep Parhar np at FreeBSD.org
Tue Dec 3 18:34:54 UTC 2013


Author: np
Date: Tue Dec  3 18:34:52 2013
New Revision: 258879
URL: http://svnweb.freebsd.org/changeset/base/258879

Log:
  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.).
  
  Obtained from:	Chelsio

Modified:
  head/sys/dev/cxgbe/common/common.h
  head/sys/dev/cxgbe/common/t4_hw.c
  head/sys/dev/cxgbe/t4_ioctl.h
  head/sys/dev/cxgbe/t4_main.c

Modified: head/sys/dev/cxgbe/common/common.h
==============================================================================
--- head/sys/dev/cxgbe/common/common.h	Tue Dec  3 18:31:27 2013	(r258878)
+++ head/sys/dev/cxgbe/common/common.h	Tue Dec  3 18:34:52 2013	(r258879)
@@ -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: head/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- head/sys/dev/cxgbe/common/t4_hw.c	Tue Dec  3 18:31:27 2013	(r258878)
+++ head/sys/dev/cxgbe/common/t4_hw.c	Tue Dec  3 18:34:52 2013	(r258879)
@@ -5664,3 +5664,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: head/sys/dev/cxgbe/t4_ioctl.h
==============================================================================
--- head/sys/dev/cxgbe/t4_ioctl.h	Tue Dec  3 18:31:27 2013	(r258878)
+++ head/sys/dev/cxgbe/t4_ioctl.h	Tue Dec  3 18:34:52 2013	(r258879)
@@ -208,6 +208,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,
@@ -261,6 +329,10 @@ struct t4_tracer {
 #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)
 #define CHELSIO_T4_GET_TRACER	_IOWR('f', T4_GET_TRACER, struct t4_tracer)
 #define CHELSIO_T4_SET_TRACER	_IOW('f', T4_SET_TRACER, struct t4_tracer)
 #endif

Modified: head/sys/dev/cxgbe/t4_main.c
==============================================================================
--- head/sys/dev/cxgbe/t4_main.c	Tue Dec  3 18:31:27 2013	(r258878)
+++ head/sys/dev/cxgbe/t4_main.c	Tue Dec  3 18:34:52 2013	(r258879)
@@ -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
@@ -7295,6 +7297,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)
 {
@@ -7538,6 +7762,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;
 	case CHELSIO_T4_GET_TRACER:
 		rc = t4_get_tracer(sc, (struct t4_tracer *)data);
 		break;


More information about the svn-src-head mailing list