cxgbe(4): Support routines for Tx traffic scheduling.
- Create a new file, t4_sched.c, and move all of the code related to traffic management from t4_main.c and t4_sge.c to this file. - Track both Channel Rate Limiter (ch_rl) and Class Rate Limiter (cl_rl) parameters in the PF driver. - Initialize all the cl_rl limiters with somewhat arbitrary default rates and provide routines to update them on the fly. - Provide routines to reserve and release traffic classes. MFC after: 1 month Sponsored by: Chelsio Communications
This commit is contained in:
parent
a535623c78
commit
2204b42716
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=317702
@ -1331,6 +1331,8 @@ dev/cxgbe/t4_main.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_netmap.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_sched.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_sge.c optional cxgbe pci \
|
||||
compile-with "${NORMAL_C} -I$S/dev/cxgbe"
|
||||
dev/cxgbe/t4_l2t.c optional cxgbe pci \
|
||||
|
@ -231,15 +231,36 @@ struct vi_info {
|
||||
uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */
|
||||
};
|
||||
|
||||
enum {
|
||||
/* tx_sched_class flags */
|
||||
TX_SC_OK = (1 << 0), /* Set up in hardware, active. */
|
||||
struct tx_ch_rl_params {
|
||||
enum fw_sched_params_rate ratemode; /* %port (REL) or kbps (ABS) */
|
||||
uint32_t maxrate;
|
||||
};
|
||||
|
||||
struct tx_sched_class {
|
||||
enum {
|
||||
TX_CLRL_REFRESH = (1 << 0), /* Need to update hardware state. */
|
||||
TX_CLRL_ERROR = (1 << 1), /* Error, hardware state unknown. */
|
||||
};
|
||||
|
||||
struct tx_cl_rl_params {
|
||||
int refcount;
|
||||
int flags;
|
||||
struct t4_sched_class_params params;
|
||||
u_int flags;
|
||||
enum fw_sched_params_rate ratemode; /* %port REL or ABS value */
|
||||
enum fw_sched_params_unit rateunit; /* kbps or pps (when ABS) */
|
||||
enum fw_sched_params_mode mode; /* aggr or per-flow */
|
||||
uint32_t maxrate;
|
||||
uint16_t pktsize;
|
||||
};
|
||||
|
||||
/* Tx scheduler parameters for a channel/port */
|
||||
struct tx_sched_params {
|
||||
/* Channel Rate Limiter */
|
||||
struct tx_ch_rl_params ch_rl;
|
||||
|
||||
/* Class WRR */
|
||||
/* XXX */
|
||||
|
||||
/* Class Rate Limiter */
|
||||
struct tx_cl_rl_params cl_rl[];
|
||||
};
|
||||
|
||||
struct port_info {
|
||||
@ -251,7 +272,7 @@ struct port_info {
|
||||
int up_vis;
|
||||
int uld_vis;
|
||||
|
||||
struct tx_sched_class *tc; /* traffic classes for this channel */
|
||||
struct tx_sched_params *sched_params;
|
||||
|
||||
struct mtx pi_lock;
|
||||
char lockname[16];
|
||||
@ -825,6 +846,9 @@ struct adapter {
|
||||
|
||||
struct memwin memwin[NUM_MEMWIN]; /* memory windows */
|
||||
|
||||
struct mtx tc_lock;
|
||||
struct task tc_task;
|
||||
|
||||
const char *last_op;
|
||||
const void *last_op_thr;
|
||||
int last_op_flags;
|
||||
@ -1106,8 +1130,6 @@ int t4_detach_common(device_t);
|
||||
int t4_filter_rpl(struct sge_iq *, const struct rss_header *, struct mbuf *);
|
||||
int t4_map_bars_0_and_4(struct adapter *);
|
||||
int t4_map_bar_2(struct adapter *);
|
||||
int t4_set_sched_class(struct adapter *, struct t4_sched_params *);
|
||||
int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *);
|
||||
int t4_setup_intr_handlers(struct adapter *);
|
||||
void t4_sysctls(struct adapter *);
|
||||
int begin_synchronized_op(struct adapter *, struct vi_info *, int, char *);
|
||||
@ -1168,6 +1190,15 @@ int t4_set_tracer(struct adapter *, struct t4_tracer *);
|
||||
int t4_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *);
|
||||
int t5_trace_pkt(struct sge_iq *, const struct rss_header *, struct mbuf *);
|
||||
|
||||
/* t4_sched.c */
|
||||
int t4_set_sched_class(struct adapter *, struct t4_sched_params *);
|
||||
int t4_set_sched_queue(struct adapter *, struct t4_sched_queue *);
|
||||
int t4_init_tx_sched(struct adapter *);
|
||||
int t4_free_tx_sched(struct adapter *);
|
||||
void t4_update_tx_sched(struct adapter *);
|
||||
int t4_reserve_cl_rl_kbps(struct adapter *, int, u_int, int *);
|
||||
void t4_release_cl_rl_kbps(struct adapter *, int, int);
|
||||
|
||||
static inline struct wrqe *
|
||||
alloc_wrqe(int wr_len, struct sge_wrq *wrq)
|
||||
{
|
||||
|
@ -774,6 +774,13 @@ 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,
|
||||
int sleep_ok);
|
||||
int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode,
|
||||
unsigned int maxrate, int sleep_ok);
|
||||
int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl,
|
||||
int weight, int sleep_ok);
|
||||
int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl,
|
||||
int mode, unsigned int maxrate, int pktsize,
|
||||
int sleep_ok);
|
||||
int t4_config_watchdog(struct adapter *adapter, unsigned int mbox,
|
||||
unsigned int pf, unsigned int vf,
|
||||
unsigned int timeout, unsigned int action);
|
||||
|
@ -9396,6 +9396,79 @@ int t4_sched_params(struct adapter *adapter, int type, int level, int mode,
|
||||
NULL, sleep_ok);
|
||||
}
|
||||
|
||||
int t4_sched_params_ch_rl(struct adapter *adapter, int channel, int ratemode,
|
||||
unsigned int maxrate, int sleep_ok)
|
||||
{
|
||||
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 = FW_SCHED_TYPE_PKTSCHED;
|
||||
cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CH_RL;
|
||||
cmd.u.params.ch = channel;
|
||||
cmd.u.params.rate = ratemode; /* REL or ABS */
|
||||
cmd.u.params.max = cpu_to_be32(maxrate);/* % or kbps */
|
||||
|
||||
return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
|
||||
NULL, sleep_ok);
|
||||
}
|
||||
|
||||
int t4_sched_params_cl_wrr(struct adapter *adapter, int channel, int cl,
|
||||
int weight, int sleep_ok)
|
||||
{
|
||||
struct fw_sched_cmd cmd;
|
||||
|
||||
if (weight < 0 || weight > 100)
|
||||
return -EINVAL;
|
||||
|
||||
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 = FW_SCHED_TYPE_PKTSCHED;
|
||||
cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
|
||||
cmd.u.params.ch = channel;
|
||||
cmd.u.params.cl = cl;
|
||||
cmd.u.params.weight = cpu_to_be16(weight);
|
||||
|
||||
return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
|
||||
NULL, sleep_ok);
|
||||
}
|
||||
|
||||
int t4_sched_params_cl_rl_kbps(struct adapter *adapter, int channel, int cl,
|
||||
int mode, unsigned int maxrate, int pktsize, int sleep_ok)
|
||||
{
|
||||
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 = FW_SCHED_TYPE_PKTSCHED;
|
||||
cmd.u.params.level = FW_SCHED_PARAMS_LEVEL_CL_RL;
|
||||
cmd.u.params.mode = mode;
|
||||
cmd.u.params.ch = channel;
|
||||
cmd.u.params.cl = cl;
|
||||
cmd.u.params.unit = FW_SCHED_PARAMS_UNIT_BITRATE;
|
||||
cmd.u.params.rate = FW_SCHED_PARAMS_RATE_ABS;
|
||||
cmd.u.params.max = cpu_to_be32(maxrate);
|
||||
cmd.u.params.pktsize = cpu_to_be16(pktsize);
|
||||
|
||||
return t4_wr_mbox_meat(adapter,adapter->mbox, &cmd, sizeof(cmd),
|
||||
NULL, sleep_ok);
|
||||
}
|
||||
|
||||
/*
|
||||
* t4_config_watchdog - configure (enable/disable) a watchdog timer
|
||||
* @adapter: the adapter
|
||||
|
@ -998,9 +998,6 @@ t4_attach(device_t dev)
|
||||
mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
|
||||
sc->chan_map[pi->tx_chan] = i;
|
||||
|
||||
pi->tc = malloc(sizeof(struct tx_sched_class) *
|
||||
sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK);
|
||||
|
||||
if (port_top_speed(pi) >= 10) {
|
||||
n10g++;
|
||||
} else {
|
||||
@ -1088,6 +1085,7 @@ t4_attach(device_t dev)
|
||||
M_ZERO | M_WAITOK);
|
||||
|
||||
t4_init_l2t(sc, M_WAITOK);
|
||||
t4_init_tx_sched(sc);
|
||||
|
||||
/*
|
||||
* Second pass over the ports. This time we know the number of rx and
|
||||
@ -1312,6 +1310,9 @@ t4_detach_common(device_t dev)
|
||||
for (i = 0; i < sc->intr_count; i++)
|
||||
t4_free_irq(sc, &sc->irq[i]);
|
||||
|
||||
if ((sc->flags & (IS_VF | FW_OK)) == FW_OK)
|
||||
t4_free_tx_sched(sc);
|
||||
|
||||
for (i = 0; i < MAX_NPORTS; i++) {
|
||||
pi = sc->port[i];
|
||||
if (pi) {
|
||||
@ -1321,7 +1322,6 @@ t4_detach_common(device_t dev)
|
||||
|
||||
mtx_destroy(&pi->pi_lock);
|
||||
free(pi->vi, M_CXGBE);
|
||||
free(pi->tc, M_CXGBE);
|
||||
free(pi, M_CXGBE);
|
||||
}
|
||||
}
|
||||
@ -5338,9 +5338,9 @@ cxgbe_sysctls(struct port_info *pi)
|
||||
* dev.(cxgbe|cxl).X.tc.
|
||||
*/
|
||||
oid = SYSCTL_ADD_NODE(ctx, children, OID_AUTO, "tc", CTLFLAG_RD, NULL,
|
||||
"Tx scheduler traffic classes");
|
||||
"Tx scheduler traffic classes (cl_rl)");
|
||||
for (i = 0; i < sc->chip_params->nsched_cls; i++) {
|
||||
struct tx_sched_class *tc = &pi->tc[i];
|
||||
struct tx_cl_rl_params *tc = &pi->sched_params->cl_rl[i];
|
||||
|
||||
snprintf(name, sizeof(name), "%d", i);
|
||||
children2 = SYSCTL_CHILDREN(SYSCTL_ADD_NODE(ctx,
|
||||
@ -7855,10 +7855,9 @@ static int
|
||||
sysctl_tc_params(SYSCTL_HANDLER_ARGS)
|
||||
{
|
||||
struct adapter *sc = arg1;
|
||||
struct tx_sched_class *tc;
|
||||
struct t4_sched_class_params p;
|
||||
struct tx_cl_rl_params tc;
|
||||
struct sbuf *sb;
|
||||
int i, rc, port_id, flags, mbps, gbps;
|
||||
int i, rc, port_id, mbps, gbps;
|
||||
|
||||
rc = sysctl_wire_old_buffer(req, 0);
|
||||
if (rc != 0)
|
||||
@ -7873,52 +7872,34 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS)
|
||||
MPASS(sc->port[port_id] != NULL);
|
||||
i = arg2 & 0xffff;
|
||||
MPASS(i < sc->chip_params->nsched_cls);
|
||||
tc = &sc->port[port_id]->tc[i];
|
||||
|
||||
rc = begin_synchronized_op(sc, NULL, HOLD_LOCK | SLEEP_OK | INTR_OK,
|
||||
"t4tc_p");
|
||||
if (rc)
|
||||
goto done;
|
||||
flags = tc->flags;
|
||||
p = tc->params;
|
||||
end_synchronized_op(sc, LOCK_HELD);
|
||||
mtx_lock(&sc->tc_lock);
|
||||
tc = sc->port[port_id]->sched_params->cl_rl[i];
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
|
||||
if ((flags & TX_SC_OK) == 0) {
|
||||
sbuf_printf(sb, "none");
|
||||
if (tc.flags & TX_CLRL_ERROR) {
|
||||
sbuf_printf(sb, "error");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (p.level == SCHED_CLASS_LEVEL_CL_WRR) {
|
||||
sbuf_printf(sb, "cl-wrr weight %u", p.weight);
|
||||
goto done;
|
||||
} else if (p.level == SCHED_CLASS_LEVEL_CL_RL)
|
||||
sbuf_printf(sb, "cl-rl");
|
||||
else if (p.level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
sbuf_printf(sb, "ch-rl");
|
||||
else {
|
||||
rc = ENXIO;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (p.ratemode == SCHED_CLASS_RATEMODE_REL) {
|
||||
if (tc.ratemode == SCHED_CLASS_RATEMODE_REL) {
|
||||
/* XXX: top speed or actual link speed? */
|
||||
gbps = port_top_speed(sc->port[port_id]);
|
||||
sbuf_printf(sb, " %u%% of %uGbps", p.maxrate, gbps);
|
||||
}
|
||||
else if (p.ratemode == SCHED_CLASS_RATEMODE_ABS) {
|
||||
switch (p.rateunit) {
|
||||
sbuf_printf(sb, " %u%% of %uGbps", tc.maxrate, gbps);
|
||||
} else if (tc.ratemode == SCHED_CLASS_RATEMODE_ABS) {
|
||||
switch (tc.rateunit) {
|
||||
case SCHED_CLASS_RATEUNIT_BITS:
|
||||
mbps = p.maxrate / 1000;
|
||||
gbps = p.maxrate / 1000000;
|
||||
if (p.maxrate == gbps * 1000000)
|
||||
mbps = tc.maxrate / 1000;
|
||||
gbps = tc.maxrate / 1000000;
|
||||
if (tc.maxrate == gbps * 1000000)
|
||||
sbuf_printf(sb, " %uGbps", gbps);
|
||||
else if (p.maxrate == mbps * 1000)
|
||||
else if (tc.maxrate == mbps * 1000)
|
||||
sbuf_printf(sb, " %uMbps", mbps);
|
||||
else
|
||||
sbuf_printf(sb, " %uKbps", p.maxrate);
|
||||
sbuf_printf(sb, " %uKbps", tc.maxrate);
|
||||
break;
|
||||
case SCHED_CLASS_RATEUNIT_PKTS:
|
||||
sbuf_printf(sb, " %upps", p.maxrate);
|
||||
sbuf_printf(sb, " %upps", tc.maxrate);
|
||||
break;
|
||||
default:
|
||||
rc = ENXIO;
|
||||
@ -7926,7 +7907,7 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS)
|
||||
}
|
||||
}
|
||||
|
||||
switch (p.mode) {
|
||||
switch (tc.mode) {
|
||||
case SCHED_CLASS_MODE_CLASS:
|
||||
sbuf_printf(sb, " aggregate");
|
||||
break;
|
||||
@ -8828,225 +8809,6 @@ 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_config(struct adapter *sc, int minmax)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (minmax < 0)
|
||||
return (EINVAL);
|
||||
|
||||
rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
|
||||
if (rc)
|
||||
return (rc);
|
||||
rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
|
||||
end_synchronized_op(sc, 0);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
|
||||
int sleep_ok)
|
||||
{
|
||||
int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
|
||||
struct port_info *pi;
|
||||
struct tx_sched_class *tc;
|
||||
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
|
||||
else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
|
||||
else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->mode == SCHED_CLASS_MODE_CLASS)
|
||||
fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
|
||||
else if (p->mode == SCHED_CLASS_MODE_FLOW)
|
||||
fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS)
|
||||
fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
|
||||
else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS)
|
||||
fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->ratemode == SCHED_CLASS_RATEMODE_REL)
|
||||
fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
|
||||
else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS)
|
||||
fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
/* Vet our parameters ... */
|
||||
if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
|
||||
return (ERANGE);
|
||||
|
||||
pi = sc->port[sc->chan_map[p->channel]];
|
||||
if (pi == NULL)
|
||||
return (ENXIO);
|
||||
MPASS(pi->tx_chan == p->channel);
|
||||
top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
|
||||
|
||||
if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) ||
|
||||
!in_range(p->minrate, 0, top_speed) ||
|
||||
!in_range(p->maxrate, 0, top_speed) ||
|
||||
!in_range(p->weight, 0, 100))
|
||||
return (ERANGE);
|
||||
|
||||
/*
|
||||
* Translate any unset parameters into the firmware's
|
||||
* nomenclature and/or fail the call if the parameters
|
||||
* are required ...
|
||||
*/
|
||||
if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (p->minrate < 0)
|
||||
p->minrate = 0;
|
||||
if (p->maxrate < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
|
||||
p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->maxrate = 0;
|
||||
}
|
||||
if (p->weight < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->weight = 0;
|
||||
}
|
||||
if (p->pktsize < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
|
||||
p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->pktsize = 0;
|
||||
}
|
||||
|
||||
rc = begin_synchronized_op(sc, NULL,
|
||||
sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
|
||||
if (rc)
|
||||
return (rc);
|
||||
tc = &pi->tc[p->cl];
|
||||
tc->params = *p;
|
||||
rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode,
|
||||
fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate,
|
||||
p->weight, p->pktsize, sleep_ok);
|
||||
if (rc == 0)
|
||||
tc->flags |= TX_SC_OK;
|
||||
else {
|
||||
/*
|
||||
* Unknown state at this point, see tc->params for what was
|
||||
* attempted.
|
||||
*/
|
||||
tc->flags &= ~TX_SC_OK;
|
||||
}
|
||||
end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
int
|
||||
t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
|
||||
{
|
||||
|
||||
if (p->type != SCHED_CLASS_TYPE_PACKET)
|
||||
return (EINVAL);
|
||||
|
||||
if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
|
||||
return (set_sched_class_config(sc, p->u.config.minmax));
|
||||
|
||||
if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
|
||||
return (set_sched_class_params(sc, &p->u.params, 1));
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
int
|
||||
t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
|
||||
{
|
||||
struct port_info *pi = NULL;
|
||||
struct vi_info *vi;
|
||||
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 (p->port >= sc->params.nports) {
|
||||
rc = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* XXX: Only supported for the main VI. */
|
||||
pi = sc->port[p->port];
|
||||
vi = &pi->vi[0];
|
||||
if (!(vi->flags & VI_INIT_DONE)) {
|
||||
/* tx queues not set up yet */
|
||||
rc = EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!in_range(p->queue, 0, vi->ntxq - 1) ||
|
||||
!in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) {
|
||||
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[vi->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(vi, 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)
|
||||
{
|
||||
|
461
sys/dev/cxgbe/t4_sched.c
Normal file
461
sys/dev/cxgbe/t4_sched.c
Normal file
@ -0,0 +1,461 @@
|
||||
/*-
|
||||
* Copyright (c) 2017 Chelsio Communications, Inc.
|
||||
* All rights reserved.
|
||||
* Written by: Navdeep Parhar <np@FreeBSD.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "opt_inet.h"
|
||||
#include "opt_inet6.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/malloc.h>
|
||||
#include <sys/queue.h>
|
||||
#include <sys/sbuf.h>
|
||||
#include <sys/taskqueue.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
#include "common/common.h"
|
||||
#include "common/t4_regs.h"
|
||||
#include "common/t4_regs_values.h"
|
||||
#include "common/t4_msg.h"
|
||||
|
||||
|
||||
static int
|
||||
in_range(int val, int lo, int hi)
|
||||
{
|
||||
|
||||
return (val < 0 || (val <= hi && val >= lo));
|
||||
}
|
||||
|
||||
static int
|
||||
set_sched_class_config(struct adapter *sc, int minmax)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (minmax < 0)
|
||||
return (EINVAL);
|
||||
|
||||
rc = begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK, "t4sscc");
|
||||
if (rc)
|
||||
return (rc);
|
||||
rc = -t4_sched_config(sc, FW_SCHED_TYPE_PKTSCHED, minmax, 1);
|
||||
end_synchronized_op(sc, 0);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static int
|
||||
set_sched_class_params(struct adapter *sc, struct t4_sched_class_params *p,
|
||||
int sleep_ok)
|
||||
{
|
||||
int rc, top_speed, fw_level, fw_mode, fw_rateunit, fw_ratemode;
|
||||
struct port_info *pi;
|
||||
struct tx_cl_rl_params *tc;
|
||||
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CL_RL;
|
||||
else if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CL_WRR;
|
||||
else if (p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
fw_level = FW_SCHED_PARAMS_LEVEL_CH_RL;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->mode == SCHED_CLASS_MODE_CLASS)
|
||||
fw_mode = FW_SCHED_PARAMS_MODE_CLASS;
|
||||
else if (p->mode == SCHED_CLASS_MODE_FLOW)
|
||||
fw_mode = FW_SCHED_PARAMS_MODE_FLOW;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->rateunit == SCHED_CLASS_RATEUNIT_BITS)
|
||||
fw_rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
|
||||
else if (p->rateunit == SCHED_CLASS_RATEUNIT_PKTS)
|
||||
fw_rateunit = FW_SCHED_PARAMS_UNIT_PKTRATE;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
if (p->ratemode == SCHED_CLASS_RATEMODE_REL)
|
||||
fw_ratemode = FW_SCHED_PARAMS_RATE_REL;
|
||||
else if (p->ratemode == SCHED_CLASS_RATEMODE_ABS)
|
||||
fw_ratemode = FW_SCHED_PARAMS_RATE_ABS;
|
||||
else
|
||||
return (EINVAL);
|
||||
|
||||
/* Vet our parameters ... */
|
||||
if (!in_range(p->channel, 0, sc->chip_params->nchan - 1))
|
||||
return (ERANGE);
|
||||
|
||||
pi = sc->port[sc->chan_map[p->channel]];
|
||||
if (pi == NULL)
|
||||
return (ENXIO);
|
||||
MPASS(pi->tx_chan == p->channel);
|
||||
top_speed = port_top_speed(pi) * 1000000; /* Gbps -> Kbps */
|
||||
|
||||
if (!in_range(p->cl, 0, sc->chip_params->nsched_cls) ||
|
||||
!in_range(p->minrate, 0, top_speed) ||
|
||||
!in_range(p->maxrate, 0, top_speed) ||
|
||||
!in_range(p->weight, 0, 100))
|
||||
return (ERANGE);
|
||||
|
||||
/*
|
||||
* Translate any unset parameters into the firmware's
|
||||
* nomenclature and/or fail the call if the parameters
|
||||
* are required ...
|
||||
*/
|
||||
if (p->rateunit < 0 || p->ratemode < 0 || p->channel < 0 || p->cl < 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (p->minrate < 0)
|
||||
p->minrate = 0;
|
||||
if (p->maxrate < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
|
||||
p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->maxrate = 0;
|
||||
}
|
||||
if (p->weight < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_WRR)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->weight = 0;
|
||||
}
|
||||
if (p->pktsize < 0) {
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL ||
|
||||
p->level == SCHED_CLASS_LEVEL_CH_RL)
|
||||
return (EINVAL);
|
||||
else
|
||||
p->pktsize = 0;
|
||||
}
|
||||
|
||||
rc = begin_synchronized_op(sc, NULL,
|
||||
sleep_ok ? (SLEEP_OK | INTR_OK) : HOLD_LOCK, "t4sscp");
|
||||
if (rc)
|
||||
return (rc);
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL) {
|
||||
tc = &pi->sched_params->cl_rl[p->cl];
|
||||
if (tc->refcount > 0) {
|
||||
rc = EBUSY;
|
||||
goto done;
|
||||
} else {
|
||||
tc->ratemode = fw_ratemode;
|
||||
tc->rateunit = fw_rateunit;
|
||||
tc->mode = fw_mode;
|
||||
tc->maxrate = p->maxrate;
|
||||
tc->pktsize = p->pktsize;
|
||||
}
|
||||
}
|
||||
rc = -t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED, fw_level, fw_mode,
|
||||
fw_rateunit, fw_ratemode, p->channel, p->cl, p->minrate, p->maxrate,
|
||||
p->weight, p->pktsize, sleep_ok);
|
||||
if (p->level == SCHED_CLASS_LEVEL_CL_RL && rc != 0) {
|
||||
/*
|
||||
* Unknown state at this point, see parameters in tc for what
|
||||
* was attempted.
|
||||
*/
|
||||
tc->flags |= TX_CLRL_ERROR;
|
||||
}
|
||||
done:
|
||||
end_synchronized_op(sc, sleep_ok ? 0 : LOCK_HELD);
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
static void
|
||||
update_tx_sched(void *context, int pending)
|
||||
{
|
||||
int i, j, mode, rateunit, ratemode, maxrate, pktsize, rc;
|
||||
struct port_info *pi;
|
||||
struct tx_cl_rl_params *tc;
|
||||
struct adapter *sc = context;
|
||||
const int n = sc->chip_params->nsched_cls;
|
||||
|
||||
mtx_lock(&sc->tc_lock);
|
||||
for_each_port(sc, i) {
|
||||
pi = sc->port[i];
|
||||
tc = &pi->sched_params->cl_rl[0];
|
||||
for (j = 0; j < n; j++, tc++) {
|
||||
MPASS(mtx_owned(&sc->tc_lock));
|
||||
if ((tc->flags & TX_CLRL_REFRESH) == 0)
|
||||
continue;
|
||||
|
||||
mode = tc->mode;
|
||||
rateunit = tc->rateunit;
|
||||
ratemode = tc->ratemode;
|
||||
maxrate = tc->maxrate;
|
||||
pktsize = tc->pktsize;
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
|
||||
if (begin_synchronized_op(sc, NULL, SLEEP_OK | INTR_OK,
|
||||
"t4utxs") != 0) {
|
||||
mtx_lock(&sc->tc_lock);
|
||||
continue;
|
||||
}
|
||||
rc = t4_sched_params(sc, FW_SCHED_TYPE_PKTSCHED,
|
||||
FW_SCHED_PARAMS_LEVEL_CL_RL, mode, rateunit,
|
||||
ratemode, pi->tx_chan, j, 0, maxrate, 0, pktsize,
|
||||
1);
|
||||
end_synchronized_op(sc, 0);
|
||||
|
||||
mtx_lock(&sc->tc_lock);
|
||||
if (rc != 0) {
|
||||
tc->flags |= TX_CLRL_ERROR;
|
||||
} else if (tc->mode == mode &&
|
||||
tc->rateunit == rateunit &&
|
||||
tc->maxrate == maxrate &&
|
||||
tc->pktsize == tc->pktsize) {
|
||||
tc->flags &= ~(TX_CLRL_REFRESH | TX_CLRL_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
}
|
||||
|
||||
int
|
||||
t4_set_sched_class(struct adapter *sc, struct t4_sched_params *p)
|
||||
{
|
||||
|
||||
if (p->type != SCHED_CLASS_TYPE_PACKET)
|
||||
return (EINVAL);
|
||||
|
||||
if (p->subcmd == SCHED_CLASS_SUBCMD_CONFIG)
|
||||
return (set_sched_class_config(sc, p->u.config.minmax));
|
||||
|
||||
if (p->subcmd == SCHED_CLASS_SUBCMD_PARAMS)
|
||||
return (set_sched_class_params(sc, &p->u.params, 1));
|
||||
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
int
|
||||
t4_set_sched_queue(struct adapter *sc, struct t4_sched_queue *p)
|
||||
{
|
||||
struct port_info *pi = NULL;
|
||||
struct vi_info *vi;
|
||||
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 (p->port >= sc->params.nports) {
|
||||
rc = EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* XXX: Only supported for the main VI. */
|
||||
pi = sc->port[p->port];
|
||||
vi = &pi->vi[0];
|
||||
if (!(vi->flags & VI_INIT_DONE)) {
|
||||
/* tx queues not set up yet */
|
||||
rc = EAGAIN;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!in_range(p->queue, 0, vi->ntxq - 1) ||
|
||||
!in_range(p->cl, 0, sc->chip_params->nsched_cls - 1)) {
|
||||
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[vi->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(vi, 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_init_tx_sched(struct adapter *sc)
|
||||
{
|
||||
int i, j;
|
||||
const int n = sc->chip_params->nsched_cls;
|
||||
struct port_info *pi;
|
||||
struct tx_cl_rl_params *tc;
|
||||
static const uint32_t init_kbps[] = {
|
||||
100 * 1000,
|
||||
200 * 1000,
|
||||
400 * 1000,
|
||||
500 * 1000,
|
||||
800 * 1000,
|
||||
1000 * 1000,
|
||||
1200 * 1000,
|
||||
1500 * 1000,
|
||||
1800 * 1000,
|
||||
2000 * 1000,
|
||||
2500 * 1000,
|
||||
3000 * 1000,
|
||||
3500 * 1000,
|
||||
4000 * 1000,
|
||||
5000 * 1000,
|
||||
10000 * 1000
|
||||
};
|
||||
|
||||
mtx_init(&sc->tc_lock, "tx_sched lock", NULL, MTX_DEF);
|
||||
TASK_INIT(&sc->tc_task, 0, update_tx_sched, sc);
|
||||
for_each_port(sc, i) {
|
||||
pi = sc->port[i];
|
||||
pi->sched_params = malloc(sizeof(*pi->sched_params) +
|
||||
n * sizeof(*tc), M_CXGBE, M_ZERO | M_WAITOK);
|
||||
tc = &pi->sched_params->cl_rl[0];
|
||||
for (j = 0; j < n; j++, tc++) {
|
||||
tc->flags = TX_CLRL_REFRESH;
|
||||
tc->refcount = 0;
|
||||
tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
|
||||
tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
|
||||
tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
|
||||
tc->maxrate = init_kbps[min(j, nitems(init_kbps) - 1)];
|
||||
tc->pktsize = ETHERMTU; /* XXX */
|
||||
|
||||
t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j, tc->mode,
|
||||
tc->maxrate, tc->pktsize, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
t4_free_tx_sched(struct adapter *sc)
|
||||
{
|
||||
int i;
|
||||
|
||||
taskqueue_drain(taskqueue_thread, &sc->tc_task);
|
||||
|
||||
for_each_port(sc, i)
|
||||
free(sc->port[i]->sched_params, M_CXGBE);
|
||||
|
||||
if (mtx_initialized(&sc->tc_lock))
|
||||
mtx_destroy(&sc->tc_lock);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
t4_update_tx_sched(struct adapter *sc)
|
||||
{
|
||||
|
||||
taskqueue_enqueue(taskqueue_thread, &sc->tc_task);
|
||||
}
|
||||
|
||||
int
|
||||
t4_reserve_cl_rl_kbps(struct adapter *sc, int port_id, u_int maxrate,
|
||||
int *tc_idx)
|
||||
{
|
||||
int rc = 0, fa = -1, i;
|
||||
struct tx_cl_rl_params *tc;
|
||||
|
||||
MPASS(port_id >= 0 && port_id < sc->params.nports);
|
||||
|
||||
tc = &sc->port[port_id]->sched_params->cl_rl[0];
|
||||
mtx_lock(&sc->tc_lock);
|
||||
for (i = 0; i < sc->chip_params->nsched_cls; i++, tc++) {
|
||||
if (fa < 0 && tc->refcount == 0)
|
||||
fa = i;
|
||||
|
||||
if (tc->ratemode == FW_SCHED_PARAMS_RATE_ABS &&
|
||||
tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE &&
|
||||
tc->mode == FW_SCHED_PARAMS_MODE_FLOW &&
|
||||
tc->maxrate == maxrate) {
|
||||
tc->refcount++;
|
||||
*tc_idx = i;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* Not found */
|
||||
MPASS(i == sc->chip_params->nsched_cls);
|
||||
if (fa != -1) {
|
||||
tc = &sc->port[port_id]->sched_params->cl_rl[fa];
|
||||
tc->flags = TX_CLRL_REFRESH;
|
||||
tc->refcount = 1;
|
||||
tc->ratemode = FW_SCHED_PARAMS_RATE_ABS;
|
||||
tc->rateunit = FW_SCHED_PARAMS_UNIT_BITRATE;
|
||||
tc->mode = FW_SCHED_PARAMS_MODE_FLOW;
|
||||
tc->maxrate = maxrate;
|
||||
tc->pktsize = ETHERMTU; /* XXX */
|
||||
*tc_idx = fa;
|
||||
t4_update_tx_sched(sc);
|
||||
} else {
|
||||
*tc_idx = -1;
|
||||
rc = ENOSPC;
|
||||
}
|
||||
done:
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
return (rc);
|
||||
}
|
||||
|
||||
void
|
||||
t4_release_cl_rl_kbps(struct adapter *sc, int port_id, int tc_idx)
|
||||
{
|
||||
struct tx_cl_rl_params *tc;
|
||||
|
||||
MPASS(port_id >= 0 && port_id < sc->params.nports);
|
||||
MPASS(tc_idx >= 0 && tc_idx < sc->chip_params->nsched_cls);
|
||||
|
||||
mtx_lock(&sc->tc_lock);
|
||||
tc = &sc->port[port_id]->sched_params->cl_rl[tc_idx];
|
||||
MPASS(tc->refcount > 0);
|
||||
MPASS(tc->ratemode == FW_SCHED_PARAMS_RATE_ABS);
|
||||
MPASS(tc->rateunit == FW_SCHED_PARAMS_UNIT_BITRATE);
|
||||
MPASS(tc->mode == FW_SCHED_PARAMS_MODE_FLOW);
|
||||
tc->refcount--;
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
}
|
@ -5243,7 +5243,7 @@ sysctl_tc(SYSCTL_HANDLER_ARGS)
|
||||
struct port_info *pi;
|
||||
struct adapter *sc;
|
||||
struct sge_txq *txq;
|
||||
struct tx_sched_class *tc;
|
||||
struct tx_cl_rl_params *tc;
|
||||
int qidx = arg2, rc, tc_idx;
|
||||
uint32_t fw_queue, fw_class;
|
||||
|
||||
@ -5257,14 +5257,14 @@ sysctl_tc(SYSCTL_HANDLER_ARGS)
|
||||
if (rc != 0 || req->newptr == NULL)
|
||||
return (rc);
|
||||
|
||||
if (sc->flags & IS_VF)
|
||||
return (EPERM);
|
||||
|
||||
/* Note that -1 is legitimate input (it means unbind). */
|
||||
if (tc_idx < -1 || tc_idx >= sc->chip_params->nsched_cls)
|
||||
return (EINVAL);
|
||||
|
||||
rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc");
|
||||
if (rc)
|
||||
return (rc);
|
||||
|
||||
mtx_lock(&sc->tc_lock);
|
||||
if (tc_idx == txq->tc_idx) {
|
||||
rc = 0; /* No change, nothing to do. */
|
||||
goto done;
|
||||
@ -5278,35 +5278,45 @@ sysctl_tc(SYSCTL_HANDLER_ARGS)
|
||||
fw_class = 0xffffffff; /* Unbind. */
|
||||
else {
|
||||
/*
|
||||
* Bind to a different class. Ethernet txq's are only allowed
|
||||
* to bind to cl-rl mode-class for now. XXX: too restrictive.
|
||||
* Bind to a different class.
|
||||
*/
|
||||
tc = &pi->tc[tc_idx];
|
||||
if (tc->flags & TX_SC_OK &&
|
||||
tc->params.level == SCHED_CLASS_LEVEL_CL_RL &&
|
||||
tc->params.mode == SCHED_CLASS_MODE_CLASS) {
|
||||
/* Ok to proceed. */
|
||||
fw_class = tc_idx;
|
||||
} else {
|
||||
rc = tc->flags & TX_SC_OK ? EBUSY : ENXIO;
|
||||
tc = &pi->sched_params->cl_rl[tc_idx];
|
||||
if (tc->flags & TX_CLRL_ERROR) {
|
||||
/* Previous attempt to set the cl-rl params failed. */
|
||||
rc = EIO;
|
||||
goto done;
|
||||
} else {
|
||||
/*
|
||||
* Ok to proceed. Place a reference on the new class
|
||||
* while still holding on to the reference on the
|
||||
* previous class, if any.
|
||||
*/
|
||||
fw_class = tc_idx;
|
||||
tc->refcount++;
|
||||
}
|
||||
}
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
|
||||
rc = begin_synchronized_op(sc, vi, SLEEP_OK | INTR_OK, "t4stc");
|
||||
if (rc)
|
||||
return (rc);
|
||||
rc = -t4_set_params(sc, sc->mbox, sc->pf, 0, 1, &fw_queue, &fw_class);
|
||||
end_synchronized_op(sc, 0);
|
||||
|
||||
mtx_lock(&sc->tc_lock);
|
||||
if (rc == 0) {
|
||||
if (txq->tc_idx != -1) {
|
||||
tc = &pi->tc[txq->tc_idx];
|
||||
tc = &pi->sched_params->cl_rl[txq->tc_idx];
|
||||
MPASS(tc->refcount > 0);
|
||||
tc->refcount--;
|
||||
}
|
||||
if (tc_idx != -1) {
|
||||
tc = &pi->tc[tc_idx];
|
||||
tc->refcount++;
|
||||
}
|
||||
txq->tc_idx = tc_idx;
|
||||
} else {
|
||||
tc = &pi->sched_params->cl_rl[tc_idx];
|
||||
MPASS(tc->refcount > 0);
|
||||
tc->refcount--;
|
||||
}
|
||||
done:
|
||||
end_synchronized_op(sc, 0);
|
||||
mtx_unlock(&sc->tc_lock);
|
||||
return (rc);
|
||||
}
|
||||
|
@ -659,9 +659,6 @@ t4vf_attach(device_t dev)
|
||||
mtx_init(&pi->pi_lock, pi->lockname, 0, MTX_DEF);
|
||||
sc->chan_map[pi->tx_chan] = i;
|
||||
|
||||
pi->tc = malloc(sizeof(struct tx_sched_class) *
|
||||
sc->chip_params->nsched_cls, M_CXGBE, M_ZERO | M_WAITOK);
|
||||
|
||||
if (port_top_speed(pi) >= 10) {
|
||||
n10g++;
|
||||
} else {
|
||||
|
@ -21,6 +21,7 @@ SRCS+= t4_l2t.c
|
||||
SRCS+= t4_main.c
|
||||
SRCS+= t4_mp_ring.c
|
||||
SRCS+= t4_netmap.c
|
||||
SRCS+= t4_sched.c
|
||||
SRCS+= t4_sge.c
|
||||
SRCS+= t4_tracer.c
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user