Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 9 Dec 2013 22:40:23 +0000 (UTC)
From:      Navdeep Parhar <np@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r259142 - in stable/10: sys/dev/cxgbe sys/dev/cxgbe/common tools/tools/cxgbetool
Message-ID:  <201312092240.rB9MeNG9023345@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: np
Date: Mon Dec  9 22:40:22 2013
New Revision: 259142
URL: http://svnweb.freebsd.org/changeset/base/259142

Log:
  MFC r257654, r257772, r258441, r258689, r258698, r258879, r259048, and
  r259103.
  
  r257654:
  cxgbe(4): Exclude MPS_RPLC_MAP_CTL (0x11114) from the register dump.  Turns
  out it's a write-only register with strange side effects on read.
  
  r257772:
  cxgbe(4): Tidy up the display for payload memory statistics (pm_stats).
  
  r258441:
  cxgbe(4): update the internal list of device features.
  
  r258689:
  Disable an assertion that relies on some code[1] that isn't in HEAD yet.
  
  r258698:
  cxgbetool: "modinfo" command to display SFP+ module information.
  
  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.).
  
  r259048:
  Two new cxgbetool subcommands to set up scheduler classes and to bind
  them to NIC queues.
  
  r259103:
  cxgbe(4): save a copy of the RSS map for each port for the driver's use.

Modified:
  stable/10/sys/dev/cxgbe/adapter.h
  stable/10/sys/dev/cxgbe/common/common.h
  stable/10/sys/dev/cxgbe/common/t4_hw.c
  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/Makefile
  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	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/adapter.h	Mon Dec  9 22:40:22 2013	(r259142)
@@ -194,6 +194,7 @@ struct port_info {
 	unsigned long flags;
 	int if_flags;
 
+	uint16_t *rss;
 	uint16_t viid;
 	int16_t  xact_addr_filt;/* index of exact MAC address filter */
 	uint16_t rss_size;	/* size of VI's RSS table slice */

Modified: stable/10/sys/dev/cxgbe/common/common.h
==============================================================================
--- stable/10/sys/dev/cxgbe/common/common.h	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/common/common.h	Mon Dec  9 22:40:22 2013	(r259142)
@@ -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/10/sys/dev/cxgbe/common/t4_hw.c
==============================================================================
--- stable/10/sys/dev/cxgbe/common/t4_hw.c	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/common/t4_hw.c	Mon Dec  9 22:40:22 2013	(r259142)
@@ -5661,3 +5661,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/10/sys/dev/cxgbe/t4_ioctl.h
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_ioctl.h	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/t4_ioctl.h	Mon Dec  9 22:40:22 2013	(r259142)
@@ -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: stable/10/sys/dev/cxgbe/t4_main.c
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_main.c	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/t4_main.c	Mon Dec  9 22:40:22 2013	(r259142)
@@ -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
@@ -3155,7 +3157,7 @@ port_full_init(struct port_info *pi)
 	struct ifnet *ifp = pi->ifp;
 	uint16_t *rss;
 	struct sge_rxq *rxq;
-	int rc, i;
+	int rc, i, j;
 
 	ASSERT_SYNCHRONIZED_OP(sc);
 	KASSERT((pi->flags & PORT_INIT_DONE) == 0,
@@ -3172,21 +3174,25 @@ port_full_init(struct port_info *pi)
 		goto done;	/* error message displayed already */
 
 	/*
-	 * Setup RSS for this port.
+	 * Setup RSS for this port.  Save a copy of the RSS table for later use.
 	 */
-	rss = malloc(pi->nrxq * sizeof (*rss), M_CXGBE,
-	    M_ZERO | M_WAITOK);
-	for_each_rxq(pi, i, rxq) {
-		rss[i] = rxq->iq.abs_id;
+	rss = malloc(pi->rss_size * sizeof (*rss), M_CXGBE, M_ZERO | M_WAITOK);
+	for (i = 0; i < pi->rss_size;) {
+		for_each_rxq(pi, j, rxq) {
+			rss[i++] = rxq->iq.abs_id;
+			if (i == pi->rss_size)
+				break;
+		}
 	}
-	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0,
-	    pi->rss_size, rss, pi->nrxq);
-	free(rss, M_CXGBE);
+
+	rc = -t4_config_rss_range(sc, sc->mbox, pi->viid, 0, pi->rss_size, rss,
+	    pi->rss_size);
 	if (rc != 0) {
 		if_printf(ifp, "rss_config failed: %d\n", rc);
 		goto done;
 	}
 
+	pi->rss = rss;
 	pi->flags |= PORT_INIT_DONE;
 done:
 	if (rc != 0)
@@ -3235,6 +3241,7 @@ port_full_uninit(struct port_info *pi)
 			quiesce_fl(sc, &ofld_rxq->fl);
 		}
 #endif
+		free(pi->rss, M_CXGBE);
 	}
 
 	t4_teardown_port_queues(pi);
@@ -3401,7 +3408,8 @@ t4_get_regs(struct adapter *sc, struct t
 		0xd004, 0xd03c,
 		0xdfc0, 0xdfe0,
 		0xe000, 0xea7c,
-		0xf000, 0x11190,
+		0xf000, 0x11110,
+		0x11118, 0x11190,
 		0x19040, 0x1906c,
 		0x19078, 0x19080,
 		0x1908c, 0x19124,
@@ -3607,7 +3615,8 @@ t4_get_regs(struct adapter *sc, struct t
 		0xd004, 0xd03c,
 		0xdfc0, 0xdfe0,
 		0xe000, 0x11088,
-		0x1109c, 0x1117c,
+		0x1109c, 0x11110,
+		0x11118, 0x1117c,
 		0x11190, 0x11204,
 		0x19040, 0x1906c,
 		0x19078, 0x19080,
@@ -4165,13 +4174,15 @@ t4_sysctls(struct adapter *sc)
 	struct sysctl_oid_list *children, *c0;
 	static char *caps[] = {
 		"\20\1PPP\2QFC\3DCBX",			/* caps[0] linkcaps */
-		"\20\1NIC\2VM\3IDS\4UM\5UM_ISGL",	/* caps[1] niccaps */
+		"\20\1NIC\2VM\3IDS\4UM\5UM_ISGL"	/* caps[1] niccaps */
+		    "\6HASHFILTER\7ETHOFLD",
 		"\20\1TOE",				/* caps[2] toecaps */
 		"\20\1RDDP\2RDMAC",			/* caps[3] rdmacaps */
 		"\20\1INITIATOR_PDU\2TARGET_PDU"	/* caps[4] iscsicaps */
 		    "\3INITIATOR_CNXOFLD\4TARGET_CNXOFLD"
 		    "\5INITIATOR_SSNOFLD\6TARGET_SSNOFLD",
 		"\20\1INITIATOR\2TARGET\3CTRL_OFLD"	/* caps[5] fcoecaps */
+		    "\4PO_INITIAOR\5PO_TARGET"
 	};
 	static char *doorbells = {"\20\1UDB\2WCWR\3UDBWC\4KDB"};
 
@@ -5953,10 +5964,13 @@ sysctl_pm_stats(SYSCTL_HANDLER_ARGS)
 	struct adapter *sc = arg1;
 	struct sbuf *sb;
 	int rc, i;
-	uint32_t tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS];
-	uint64_t tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS];
-	static const char *pm_stats[] = {
-		"Read:", "Write bypass:", "Write mem:", "Flush:", "FIFO wait:"
+	uint32_t cnt[PM_NSTATS];
+	uint64_t cyc[PM_NSTATS];
+	static const char *rx_stats[] = {
+		"Read:", "Write bypass:", "Write mem:", "Flush:"
+	};
+	static const char *tx_stats[] = {
+		"Read:", "Write bypass:", "Write mem:", "Bypass + mem:"
 	};
 
 	rc = sysctl_wire_old_buffer(req, 0);
@@ -5967,14 +5981,17 @@ sysctl_pm_stats(SYSCTL_HANDLER_ARGS)
 	if (sb == NULL)
 		return (ENOMEM);
 
-	t4_pmtx_get_stats(sc, tx_cnt, tx_cyc);
-	t4_pmrx_get_stats(sc, rx_cnt, rx_cyc);
-
-	sbuf_printf(sb, "                Tx count            Tx cycles    "
-	    "Rx count            Rx cycles");
-	for (i = 0; i < PM_NSTATS; i++)
-		sbuf_printf(sb, "\n%-13s %10u %20ju  %10u %20ju",
-		    pm_stats[i], tx_cnt[i], tx_cyc[i], rx_cnt[i], rx_cyc[i]);
+	t4_pmtx_get_stats(sc, cnt, cyc);
+	sbuf_printf(sb, "                Tx pcmds             Tx bytes");
+	for (i = 0; i < ARRAY_SIZE(tx_stats); i++)
+		sbuf_printf(sb, "\n%-13s %10u %20ju", tx_stats[i], cnt[i],
+		    cyc[i]);
+
+	t4_pmrx_get_stats(sc, cnt, cyc);
+	sbuf_printf(sb, "\n                Rx pcmds             Rx bytes");
+	for (i = 0; i < ARRAY_SIZE(rx_stats); i++)
+		sbuf_printf(sb, "\n%-13s %10u %20ju", rx_stats[i], cnt[i],
+		    cyc[i]);
 
 	rc = sbuf_finish(sb);
 	sbuf_delete(sb);
@@ -7285,6 +7302,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)
 {
@@ -7528,6 +7767,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;

Modified: stable/10/sys/dev/cxgbe/t4_sge.c
==============================================================================
--- stable/10/sys/dev/cxgbe/t4_sge.c	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/sys/dev/cxgbe/t4_sge.c	Mon Dec  9 22:40:22 2013	(r259142)
@@ -1391,7 +1391,7 @@ rxb_free(struct mbuf *m, void *arg1, voi
 {
 	uma_zone_t zone = arg1;
 	caddr_t cl = arg2;
-#ifdef INVARIANTS
+#ifdef notyet
 	u_int refcount;
 
 	refcount = *find_buf_refcnt(cl);
@@ -1677,7 +1677,7 @@ t4_eth_rx(struct sge_iq *iq, const struc
 
 	m0->m_pkthdr.rcvif = ifp;
 	m0->m_flags |= M_FLOWID;
-	m0->m_pkthdr.flowid = rss->hash_val;
+	m0->m_pkthdr.flowid = be32toh(rss->hash_val);
 
 	if (cpl->csum_calc && !cpl->err_vec) {
 		if (ifp->if_capenable & IFCAP_RXCSUM &&

Modified: stable/10/tools/tools/cxgbetool/Makefile
==============================================================================
--- stable/10/tools/tools/cxgbetool/Makefile	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/tools/tools/cxgbetool/Makefile	Mon Dec  9 22:40:22 2013	(r259142)
@@ -3,7 +3,7 @@
 PROG=	cxgbetool
 SRCS=	cxgbetool.c
 NO_MAN=
-CFLAGS+= -I${.CURDIR}/../../../sys/dev/cxgbe -I.
+CFLAGS+= -I${.CURDIR}/../../../sys/dev/cxgbe -I${.CURDIR}/../../../sys -I.
 BINDIR?= /usr/sbin
 
 .include <bsd.prog.mk>

Modified: stable/10/tools/tools/cxgbetool/cxgbetool.c
==============================================================================
--- stable/10/tools/tools/cxgbetool/cxgbetool.c	Mon Dec  9 21:32:36 2013	(r259141)
+++ stable/10/tools/tools/cxgbetool/cxgbetool.c	Mon Dec  9 22:40:22 2013	(r259142)
@@ -46,11 +46,12 @@ __FBSDID("$FreeBSD$");
 #include <net/ethernet.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
+#include <net/sff8472.h>
 
 #include "t4_ioctl.h"
 
 #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
+#define in_range(val, lo, hi) ( val < 0 || (val <= hi && val >= lo))
 #define	max(x, y) ((x) > (y) ? (x) : (y))
 
 static const char *progname, *nexus;
@@ -94,12 +95,15 @@ usage(FILE *fp)
 	    "\ti2c <port> <devaddr> <addr> [<len>] read from i2c device\n"
 	    "\tloadfw <fw-image.bin>               install firmware\n"
 	    "\tmemdump <addr> <len>                dump a memory range\n"
+	    "\tmodinfo <port>                      optics/cable information\n"
 	    "\treg <address>[=<val>]               read/write register\n"
 	    "\treg64 <address>[=<val>]             read/write 64 bit register\n"
 	    "\tregdump [<module>] ...              dump registers\n"
+	    "\tsched-class params <param> <val> .. configure TX scheduler class\n"
+	    "\tsched-queue <port> <queue> <class>  bind NIC queues to TX Scheduling class\n"
 	    "\tstdio                               interactive mode\n"
 	    "\ttcb <tid>                           read TCB\n"
-	    "\ttracer <idx> tx<n>|rx<n>            set and enable a tracer)\n"
+	    "\ttracer <idx> tx<n>|rx<n>            set and enable a tracer\n"
 	    "\ttracer <idx> disable|enable         disable or enable a tracer\n"
 	    "\ttracer list                         list all tracers\n"
 	    );
@@ -321,7 +325,7 @@ dump_regs_t4(int argc, const char *argv[
 		T4_MODREGS(ma),
 		{ "edc0", t4_edc_0_regs },
 		{ "edc1", t4_edc_1_regs },
-		T4_MODREGS(cim), 
+		T4_MODREGS(cim),
 		T4_MODREGS(tp),
 		T4_MODREGS(ulp_rx),
 		T4_MODREGS(ulp_tx),
@@ -333,7 +337,7 @@ dump_regs_t4(int argc, const char *argv[
 		{ "i2c", t4_i2cm_regs },
 		T4_MODREGS(mi),
 		T4_MODREGS(uart),
-		T4_MODREGS(pmu), 
+		T4_MODREGS(pmu),
 		T4_MODREGS(sf),
 		T4_MODREGS(pl),
 		T4_MODREGS(le),
@@ -1869,6 +1873,420 @@ tracer_cmd(int argc, const char *argv[])
 }
 
 static int
+modinfo(int argc, const char *argv[])
+{
+	long port;
+	char string[16], *p;
+	struct t4_i2c_data i2cd;
+	int rc, i;
+	uint16_t temp, vcc, tx_bias, tx_power, rx_power;
+
+	if (argc != 1) {
+		warnx("must supply a port");
+		return (EINVAL);
+	}
+
+	p = str_to_number(argv[0], &port, NULL);
+	if (*p || port > UCHAR_MAX) {
+		warnx("invalid port id \"%s\"", argv[0]);
+		return (EINVAL);
+	}
+
+	bzero(&i2cd, sizeof(i2cd));
+	i2cd.len = 1;
+	i2cd.port_id = port;
+	i2cd.dev_addr = SFF_8472_BASE;
+
+	i2cd.offset = SFF_8472_ID;
+	if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+		goto fail;
+
+	if (i2cd.data[0] > SFF_8472_ID_LAST)
+		printf("Unknown ID\n");
+	else
+		printf("ID: %s\n", sff_8472_id[i2cd.data[0]]);
+
+	bzero(&string, sizeof(string));
+	for (i = SFF_8472_VENDOR_START; i < SFF_8472_VENDOR_END; i++) {
+		i2cd.offset = i;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		string[i - SFF_8472_VENDOR_START] = i2cd.data[0];
+	}
+	printf("Vendor %s\n", string);
+
+	bzero(&string, sizeof(string));
+	for (i = SFF_8472_SN_START; i < SFF_8472_SN_END; i++) {
+		i2cd.offset = i;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		string[i - SFF_8472_SN_START] = i2cd.data[0];
+	}
+	printf("SN %s\n", string);
+
+	bzero(&string, sizeof(string));
+	for (i = SFF_8472_PN_START; i < SFF_8472_PN_END; i++) {
+		i2cd.offset = i;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		string[i - SFF_8472_PN_START] = i2cd.data[0];
+	}
+	printf("PN %s\n", string);
+
+	bzero(&string, sizeof(string));
+	for (i = SFF_8472_REV_START; i < SFF_8472_REV_END; i++) {
+		i2cd.offset = i;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		string[i - SFF_8472_REV_START] = i2cd.data[0];
+	}
+	printf("Rev %s\n", string);
+
+	i2cd.offset = SFF_8472_DIAG_TYPE;
+	if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+		goto fail;
+
+	if ((char )i2cd.data[0] & (SFF_8472_DIAG_IMPL |
+				   SFF_8472_DIAG_INTERNAL)) {
+
+		/* Switch to reading from the Diagnostic address. */
+		i2cd.dev_addr = SFF_8472_DIAG;
+		i2cd.len = 1;
+
+		i2cd.offset = SFF_8472_TEMP;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		temp = i2cd.data[0] << 8;
+		printf("Temp: ");
+		if ((temp & SFF_8472_TEMP_SIGN) == SFF_8472_TEMP_SIGN)
+			printf("-");
+		else
+			printf("+");
+		printf("%dC\n", (temp & SFF_8472_TEMP_MSK) >>
+		    SFF_8472_TEMP_SHIFT);
+
+		i2cd.offset = SFF_8472_VCC;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		vcc = i2cd.data[0] << 8;
+		printf("Vcc %fV\n", vcc / SFF_8472_VCC_FACTOR);
+
+		i2cd.offset = SFF_8472_TX_BIAS;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		tx_bias = i2cd.data[0] << 8;
+		printf("TX Bias %fuA\n", tx_bias / SFF_8472_BIAS_FACTOR);
+
+		i2cd.offset = SFF_8472_TX_POWER;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		tx_power = i2cd.data[0] << 8;
+		printf("TX Power %fmW\n", tx_power / SFF_8472_POWER_FACTOR);
+
+		i2cd.offset = SFF_8472_RX_POWER;
+		if ((rc = doit(CHELSIO_T4_GET_I2C, &i2cd)) != 0)
+			goto fail;
+		rx_power = i2cd.data[0] << 8;
+		printf("RX Power %fmW\n", rx_power / SFF_8472_POWER_FACTOR);
+
+	} else
+		printf("Diagnostics not supported.\n");
+
+	return(0);
+
+fail:
+	if (rc == EPERM)
+		warnx("No module/cable in port %ld", port);
+	return (rc);
+
+}
+
+/* XXX: pass in a low/high and do range checks as well */
+static int
+get_sched_param(const char *param, const char *args[], long *val)
+{
+	char *p;
+
+	if (strcmp(param, args[0]) != 0)
+		return (EINVAL);
+
+	p = str_to_number(args[1], val, NULL);
+	if (*p) {
+		warnx("parameter \"%s\" has bad value \"%s\"", args[0],
+		    args[1]);
+		return (EINVAL);
+	}
+
+	return (0);
+}
+
+static int
+sched_class(int argc, const char *argv[])
+{
+	struct t4_sched_params op;
+	int errs, i;
+
+	memset(&op, 0xff, sizeof(op));
+	op.subcmd = -1;
+	op.type = -1;
+	if (argc == 0) {
+		warnx("missing scheduling sub-command");
+		return (EINVAL);
+	}
+	if (!strcmp(argv[0], "config")) {
+		op.subcmd = SCHED_CLASS_SUBCMD_CONFIG;
+		op.u.config.minmax = -1;
+	} else if (!strcmp(argv[0], "params")) {
+		op.subcmd = SCHED_CLASS_SUBCMD_PARAMS;
+		op.u.params.level = op.u.params.mode = op.u.params.rateunit =
+		    op.u.params.ratemode = op.u.params.channel =
+		    op.u.params.cl = op.u.params.minrate = op.u.params.maxrate =
+		    op.u.params.weight = op.u.params.pktsize = -1;
+	} else {
+		warnx("invalid scheduling sub-command \"%s\"", argv[0]);
+		return (EINVAL);
+	}
+
+	/* Decode remaining arguments ... */
+	errs = 0;
+	for (i = 1; i < argc; i += 2) {
+		const char **args = &argv[i];
+		long l;
+
+		if (i + 1 == argc) {
+			warnx("missing argument for \"%s\"", args[0]);
+			errs++;
+			break;
+		}
+
+		if (!strcmp(args[0], "type")) {
+			if (!strcmp(args[1], "packet"))
+				op.type = SCHED_CLASS_TYPE_PACKET;
+			else {
+				warnx("invalid type parameter \"%s\"", args[1]);
+				errs++;
+			}
+
+			continue;
+		}
+
+		if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) {
+			if(!get_sched_param("minmax", args, &l))
+				op.u.config.minmax = (int8_t)l;
+			else {
+				warnx("unknown scheduler config parameter "
+				    "\"%s\"", args[0]);
+				errs++;
+			}
+
+			continue;
+		}
+
+		/* Rest applies only to SUBCMD_PARAMS */
+		if (op.subcmd != SCHED_CLASS_SUBCMD_PARAMS)
+			continue;
+
+		if (!strcmp(args[0], "level")) {
+			if (!strcmp(args[1], "cl-rl"))
+				op.u.params.level = SCHED_CLASS_LEVEL_CL_RL;
+			else if (!strcmp(args[1], "cl-wrr"))
+				op.u.params.level = SCHED_CLASS_LEVEL_CL_WRR;
+			else if (!strcmp(args[1], "ch-rl"))
+				op.u.params.level = SCHED_CLASS_LEVEL_CH_RL;
+			else {
+				warnx("invalid level parameter \"%s\"",
+				    args[1]);
+				errs++;
+			}
+		} else if (!strcmp(args[0], "mode")) {
+			if (!strcmp(args[1], "class"))
+				op.u.params.mode = SCHED_CLASS_MODE_CLASS;
+			else if (!strcmp(args[1], "flow"))
+				op.u.params.mode = SCHED_CLASS_MODE_FLOW;
+			else {
+				warnx("invalid mode parameter \"%s\"", args[1]);
+				errs++;
+			}
+		} else if (!strcmp(args[0], "rate-unit")) {
+			if (!strcmp(args[1], "bits"))
+				op.u.params.rateunit = SCHED_CLASS_RATEUNIT_BITS;
+			else if (!strcmp(args[1], "pkts"))
+				op.u.params.rateunit = SCHED_CLASS_RATEUNIT_PKTS;
+			else {
+				warnx("invalid rate-unit parameter \"%s\"",
+				    args[1]);
+				errs++;
+			}
+		} else if (!strcmp(args[0], "rate-mode")) {
+			if (!strcmp(args[1], "relative"))
+				op.u.params.ratemode = SCHED_CLASS_RATEMODE_REL;
+			else if (!strcmp(args[1], "absolute"))
+				op.u.params.ratemode = SCHED_CLASS_RATEMODE_ABS;
+			else {
+				warnx("invalid rate-mode parameter \"%s\"",
+				    args[1]);
+				errs++;
+			}
+		} else if (!get_sched_param("channel", args, &l))
+			op.u.params.channel = (int8_t)l;
+		else if (!get_sched_param("class", args, &l))
+			op.u.params.cl = (int8_t)l;
+		else if (!get_sched_param("min-rate", args, &l))
+			op.u.params.minrate = (int32_t)l;
+		else if (!get_sched_param("max-rate", args, &l))
+			op.u.params.maxrate = (int32_t)l;
+		else if (!get_sched_param("weight", args, &l))
+			op.u.params.weight = (int16_t)l;
+		else if (!get_sched_param("pkt-size", args, &l))
+			op.u.params.pktsize = (int16_t)l;
+		else {
+			warnx("unknown scheduler parameter \"%s\"", args[0]);
+			errs++;
+		}
+	}
+
+	/*
+	 * Catch some logical fallacies in terms of argument combinations here
+	 * so we can offer more than just the EINVAL return from the driver.
+	 * The driver will be able to catch a lot more issues since it knows
+	 * the specifics of the device hardware capabilities like how many
+	 * channels, classes, etc. the device supports.
+	 */
+	if (op.type < 0) {
+		warnx("sched \"type\" parameter missing");
+		errs++;
+	}
+	if (op.subcmd == SCHED_CLASS_SUBCMD_CONFIG) {
+		if (op.u.config.minmax < 0) {
+			warnx("sched config \"minmax\" parameter missing");
+			errs++;
+		}
+	}
+	if (op.subcmd == SCHED_CLASS_SUBCMD_PARAMS) {
+		if (op.u.params.level < 0) {
+			warnx("sched params \"level\" parameter missing");
+			errs++;
+		}
+		if (op.u.params.mode < 0) {
+			warnx("sched params \"mode\" parameter missing");
+			errs++;
+		}
+		if (op.u.params.rateunit < 0) {
+			warnx("sched params \"rate-unit\" parameter missing");
+			errs++;
+		}
+		if (op.u.params.ratemode < 0) {
+			warnx("sched params \"rate-mode\" parameter missing");
+			errs++;
+		}
+		if (op.u.params.channel < 0) {
+			warnx("sched params \"channel\" missing");
+			errs++;
+		}
+		if (op.u.params.cl < 0) {
+			warnx("sched params \"class\" missing");
+			errs++;
+		}
+		if (op.u.params.maxrate < 0 &&
+		    (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
+		    op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) {
+			warnx("sched params \"max-rate\" missing for "
+			    "rate-limit level");
+			errs++;
+		}
+		if (op.u.params.weight < 0 &&
+		    op.u.params.level == SCHED_CLASS_LEVEL_CL_WRR) {
+			warnx("sched params \"weight\" missing for "
+			    "weighted-round-robin level");
+			errs++;
+		}
+		if (op.u.params.pktsize < 0 &&
+		    (op.u.params.level == SCHED_CLASS_LEVEL_CL_RL ||
+		    op.u.params.level == SCHED_CLASS_LEVEL_CH_RL)) {
+			warnx("sched params \"pkt-size\" missing for "
+			    "rate-limit level");
+			errs++;
+		}
+		if (op.u.params.mode == SCHED_CLASS_MODE_FLOW &&
+		    op.u.params.ratemode != SCHED_CLASS_RATEMODE_ABS) {
+			warnx("sched params mode flow needs rate-mode absolute");
+			errs++;
+		}
+		if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_REL &&
+		    !in_range(op.u.params.maxrate, 1, 100)) {
+                        warnx("sched params \"max-rate\" takes "
+			    "percentage value(1-100) for rate-mode relative");
+                        errs++;
+                }
+                if (op.u.params.ratemode == SCHED_CLASS_RATEMODE_ABS &&
+		    !in_range(op.u.params.maxrate, 1, 10000000)) {
+                        warnx("sched params \"max-rate\" takes "
+			    "value(1-10000000) for rate-mode absolute");
+                        errs++;
+                }
+                if (op.u.params.maxrate > 0 &&
+		    op.u.params.maxrate < op.u.params.minrate) {
+                        warnx("sched params \"max-rate\" is less than "
+			    "\"min-rate\"");
+                        errs++;
+                }
+	}
+
+	if (errs > 0) {
+		warnx("%d error%s in sched-class command", errs,
+		    errs == 1 ? "" : "s");
+		return (EINVAL);
+	}
+
+	return doit(CHELSIO_T4_SCHED_CLASS, &op);
+}

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201312092240.rB9MeNG9023345>