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.
This commit is contained in:
parent
44822de64a
commit
7777b8aff6
@ -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 */
|
||||
|
@ -587,4 +587,8 @@ int t4_sge_ctxt_rd_bd(struct adapter *adap, unsigned int cid, enum ctxt_type cty
|
||||
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 */
|
||||
|
@ -5661,3 +5661,50 @@ int __devinit t4_port_init(struct port_info *p, int mbox, int pf, int vf)
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -425,6 +425,8 @@ static int get_sge_context(struct adapter *, struct t4_sge_context *);
|
||||
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 t4_regdump *regs, uint8_t *buf)
|
||||
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 t4_regdump *regs, uint8_t *buf)
|
||||
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);
|
||||
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]);
|
||||
|
||||
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_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_i2c_data *i2cd)
|
||||
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 cmd, caddr_t data, int fflag,
|
||||
}
|
||||
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;
|
||||
|
@ -1391,7 +1391,7 @@ rxb_free(struct mbuf *m, void *arg1, void *arg2)
|
||||
{
|
||||
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 struct rss_header *rss, struct mbuf *m0)
|
||||
|
||||
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 &&
|
||||
|
@ -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>
|
||||
|
@ -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[], const uint32_t *regs)
|
||||
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[], const uint32_t *regs)
|
||||
{ "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),
|
||||
@ -1868,6 +1872,420 @@ tracer_cmd(int argc, const char *argv[])
|
||||
return set_tracer(idx, argc - 1, argv + 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static int
|
||||
sched_queue(int argc, const char *argv[])
|
||||
{
|
||||
struct t4_sched_queue op = {0};
|
||||
char *p;
|
||||
long val;
|
||||
|
||||
if (argc != 3) {
|
||||
/* need "<port> <queue> <class> */
|
||||
warnx("incorrect number of arguments.");
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
p = str_to_number(argv[0], &val, NULL);
|
||||
if (*p || val > UCHAR_MAX) {
|
||||
warnx("invalid port id \"%s\"", argv[0]);
|
||||
return (EINVAL);
|
||||
}
|
||||
op.port = (uint8_t)val;
|
||||
|
||||
if (!strcmp(argv[1], "all") || !strcmp(argv[1], "*"))
|
||||
op.queue = -1;
|
||||
else {
|
||||
p = str_to_number(argv[1], &val, NULL);
|
||||
if (*p || val < -1) {
|
||||
warnx("invalid queue \"%s\"", argv[1]);
|
||||
return (EINVAL);
|
||||
}
|
||||
op.queue = (int8_t)val;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[2], "unbind") || !strcmp(argv[2], "clear"))
|
||||
op.cl = -1;
|
||||
else {
|
||||
p = str_to_number(argv[2], &val, NULL);
|
||||
if (*p || val < -1) {
|
||||
warnx("invalid class \"%s\"", argv[2]);
|
||||
return (EINVAL);
|
||||
}
|
||||
op.cl = (int8_t)val;
|
||||
}
|
||||
|
||||
return doit(CHELSIO_T4_SCHED_QUEUE, &op);
|
||||
}
|
||||
|
||||
static int
|
||||
run_cmd(int argc, const char *argv[])
|
||||
{
|
||||
@ -1900,6 +2318,12 @@ run_cmd(int argc, const char *argv[])
|
||||
rc = clearstats(argc, argv);
|
||||
else if (!strcmp(cmd, "tracer"))
|
||||
rc = tracer_cmd(argc, argv);
|
||||
else if (!strcmp(cmd, "modinfo"))
|
||||
rc = modinfo(argc, argv);
|
||||
else if (!strcmp(cmd, "sched-class"))
|
||||
rc = sched_class(argc, argv);
|
||||
else if (!strcmp(cmd, "sched-queue"))
|
||||
rc = sched_queue(argc, argv);
|
||||
else {
|
||||
rc = EINVAL;
|
||||
warnx("invalid command \"%s\"", cmd);
|
||||
|
Loading…
Reference in New Issue
Block a user