summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornp <np@FreeBSD.org>2017-05-25 01:43:28 +0000
committernp <np@FreeBSD.org>2017-05-25 01:43:28 +0000
commit510c4d20397e4424bfaea550ac3e9b1613fcf3d0 (patch)
tree54125eb3f5add861ebf3b38f0ebb97484fd1fca5
parent770a812c2e327bf934bed62b602bdc8127932ea2 (diff)
downloadFreeBSD-src-510c4d20397e4424bfaea550ac3e9b1613fcf3d0.zip
FreeBSD-src-510c4d20397e4424bfaea550ac3e9b1613fcf3d0.tar.gz
MFC r317702, r317847, r318307
r317702: 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. r317847: cxgbe(4): The Tx scheduler initialization either works or doesn't. It doesn't need a refresh in either case. r318307: cxgbe(4): Avoid an out of bounds access when an attempt to unbind a tx queue from a traffic class fails. Sponsored by: Chelsio Communications
-rw-r--r--sys/conf/files2
-rw-r--r--sys/dev/cxgbe/adapter.h47
-rw-r--r--sys/dev/cxgbe/common/common.h7
-rw-r--r--sys/dev/cxgbe/common/t4_hw.c73
-rw-r--r--sys/dev/cxgbe/t4_main.c286
-rw-r--r--sys/dev/cxgbe/t4_sched.c463
-rw-r--r--sys/dev/cxgbe/t4_sge.c52
-rw-r--r--sys/dev/cxgbe/t4_vf.c3
-rw-r--r--sys/modules/cxgbe/if_cxgbe/Makefile1
9 files changed, 640 insertions, 294 deletions
diff --git a/sys/conf/files b/sys/conf/files
index ed66827..939daac 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1151,6 +1151,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 \
diff --git a/sys/dev/cxgbe/adapter.h b/sys/dev/cxgbe/adapter.h
index 5801140..c203fb2 100644
--- a/sys/dev/cxgbe/adapter.h
+++ b/sys/dev/cxgbe/adapter.h
@@ -225,15 +225,36 @@ struct vi_info {
uint8_t hw_addr[ETHER_ADDR_LEN]; /* factory MAC address, won't change */
};
+struct tx_ch_rl_params {
+ enum fw_sched_params_rate ratemode; /* %port (REL) or kbps (ABS) */
+ uint32_t maxrate;
+};
+
enum {
- /* tx_sched_class flags */
- TX_SC_OK = (1 << 0), /* Set up in hardware, active. */
+ TX_CLRL_REFRESH = (1 << 0), /* Need to update hardware state. */
+ TX_CLRL_ERROR = (1 << 1), /* Error, hardware state unknown. */
};
-struct tx_sched_class {
+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 {
@@ -245,7 +266,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];
@@ -817,6 +838,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;
@@ -1098,8 +1122,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 *);
@@ -1160,6 +1182,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)
{
diff --git a/sys/dev/cxgbe/common/common.h b/sys/dev/cxgbe/common/common.h
index f1904fb..2a6868a 100644
--- a/sys/dev/cxgbe/common/common.h
+++ b/sys/dev/cxgbe/common/common.h
@@ -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);
diff --git a/sys/dev/cxgbe/common/t4_hw.c b/sys/dev/cxgbe/common/t4_hw.c
index ff457ae..62dd465 100644
--- a/sys/dev/cxgbe/common/t4_hw.c
+++ b/sys/dev/cxgbe/common/t4_hw.c
@@ -9393,6 +9393,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
diff --git a/sys/dev/cxgbe/t4_main.c b/sys/dev/cxgbe/t4_main.c
index fd5a517..3a1d1a2 100644
--- a/sys/dev/cxgbe/t4_main.c
+++ b/sys/dev/cxgbe/t4_main.c
@@ -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
@@ -1251,6 +1249,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) {
@@ -1260,7 +1261,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);
}
}
@@ -5204,9 +5204,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,
@@ -7722,10 +7722,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)
@@ -7740,52 +7739,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);
- if ((flags & TX_SC_OK) == 0) {
- sbuf_printf(sb, "none");
- goto done;
- }
+ mtx_lock(&sc->tc_lock);
+ tc = sc->port[port_id]->sched_params->cl_rl[i];
+ mtx_unlock(&sc->tc_lock);
- 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;
+ if (tc.flags & TX_CLRL_ERROR) {
+ sbuf_printf(sb, "error");
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;
@@ -7793,7 +7774,7 @@ sysctl_tc_params(SYSCTL_HANDLER_ARGS)
}
}
- switch (p.mode) {
+ switch (tc.mode) {
case SCHED_CLASS_MODE_CLASS:
sbuf_printf(sb, " aggregate");
break;
@@ -8695,225 +8676,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)
{
diff --git a/sys/dev/cxgbe/t4_sched.c b/sys/dev/cxgbe/t4_sched.c
new file mode 100644
index 0000000..c2d3cde
--- /dev/null
+++ b/sys/dev/cxgbe/t4_sched.c
@@ -0,0 +1,463 @@
+/*-
+ * 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->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 */
+
+ if (t4_sched_params_cl_rl_kbps(sc, pi->tx_chan, j,
+ tc->mode, tc->maxrate, tc->pktsize, 1) == 0)
+ tc->flags = 0;
+ else
+ tc->flags = TX_CLRL_ERROR;
+ }
+ }
+
+ 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);
+}
diff --git a/sys/dev/cxgbe/t4_sge.c b/sys/dev/cxgbe/t4_sge.c
index affa241..03952b3 100644
--- a/sys/dev/cxgbe/t4_sge.c
+++ b/sys/dev/cxgbe/t4_sge.c
@@ -5187,7 +5187,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;
@@ -5201,14 +5201,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;
@@ -5222,35 +5222,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 if (tc_idx != -1) {
+ 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);
}
diff --git a/sys/dev/cxgbe/t4_vf.c b/sys/dev/cxgbe/t4_vf.c
index 501f70b..e6d6e4c 100644
--- a/sys/dev/cxgbe/t4_vf.c
+++ b/sys/dev/cxgbe/t4_vf.c
@@ -675,9 +675,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 {
diff --git a/sys/modules/cxgbe/if_cxgbe/Makefile b/sys/modules/cxgbe/if_cxgbe/Makefile
index 73c773b..5d94952 100644
--- a/sys/modules/cxgbe/if_cxgbe/Makefile
+++ b/sys/modules/cxgbe/if_cxgbe/Makefile
@@ -20,6 +20,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
OpenPOWER on IntegriCloud