* @mq.prev_stats: previously reported @mq.stats
*
* @red: RED Qdisc specific parameters and state
- * @red.threshold: ECN marking threshold
- * @red.stats: current stats of the RED Qdisc
- * @red.prev_stats: previously reported @red.stats
- * @red.xstats: extended stats for RED - current
- * @red.prev_xstats: extended stats for RED - previously reported
+ * @red.num_bands: Number of valid entries in the @red.band table
+ * @red.band: Per-band array of RED instances
+ * @red.band.threshold: ECN marking threshold
+ * @red.band.stats: current stats of the RED Qdisc
+ * @red.band.prev_stats: previously reported @red.stats
+ * @red.band.xstats: extended stats for RED - current
+ * @red.band.prev_xstats: extended stats for RED - previously reported
*/
struct nfp_qdisc {
struct net_device *netdev;
} mq;
/* TC_SETUP_QDISC_RED */
struct {
- u32 threshold;
- struct nfp_alink_stats stats;
- struct nfp_alink_stats prev_stats;
- struct nfp_alink_xstats xstats;
- struct nfp_alink_xstats prev_xstats;
+ unsigned int num_bands;
+
+ struct {
+ u32 threshold;
+ struct nfp_alink_stats stats;
+ struct nfp_alink_stats prev_stats;
+ struct nfp_alink_xstats xstats;
+ struct nfp_alink_xstats prev_xstats;
+ } band[1];
} red;
};
};
unsigned int queue)
{
struct nfp_cpp *cpp = alink->abm->app->cpp;
+ unsigned int i;
int err;
if (!qdisc->offloaded)
return;
- err = nfp_abm_ctrl_read_q_stats(alink, 0, queue, &qdisc->red.stats);
- if (err)
- nfp_err(cpp, "RED stats (%d, %d) read failed with error %d\n",
- 0, queue, err);
-
- err = nfp_abm_ctrl_read_q_xstats(alink, 0, queue, &qdisc->red.xstats);
- if (err)
- nfp_err(cpp, "RED xstats (%d, %d) read failed with error %d\n",
- 0, queue, err);
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ err = nfp_abm_ctrl_read_q_stats(alink, i, queue,
+ &qdisc->red.band[i].stats);
+ if (err)
+ nfp_err(cpp, "RED stats (%d, %d) read failed with error %d\n",
+ i, queue, err);
+
+ err = nfp_abm_ctrl_read_q_xstats(alink, i, queue,
+ &qdisc->red.band[i].xstats);
+ if (err)
+ nfp_err(cpp, "RED xstats (%d, %d) read failed with error %d\n",
+ i, queue, err);
+ }
}
static void
static void
nfp_abm_qdisc_offload_stop(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc)
{
+ unsigned int i;
+
/* Don't complain when qdisc is getting unlinked */
if (qdisc->use_cnt)
nfp_warn(alink->abm->app->cpp, "Offload of '%08x' stopped\n",
if (!nfp_abm_qdisc_is_red(qdisc))
return;
- qdisc->red.stats.backlog_pkts = 0;
- qdisc->red.stats.backlog_bytes = 0;
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ qdisc->red.band[i].stats.backlog_pkts = 0;
+ qdisc->red.band[i].stats.backlog_bytes = 0;
+ }
}
static int
nfp_abm_stats_init(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
- return __nfp_abm_stats_init(alink, 0, queue,
- &qdisc->red.prev_stats,
- &qdisc->red.prev_xstats);
+ unsigned int i;
+ int err;
+
+ for (i = 0; i < qdisc->red.num_bands; i++) {
+ err = __nfp_abm_stats_init(alink, i, queue,
+ &qdisc->red.band[i].prev_stats,
+ &qdisc->red.band[i].prev_xstats);
+ if (err)
+ return err;
+ }
+
+ return 0;
}
static void
nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
unsigned int queue)
{
+ unsigned int i;
+
qdisc->offload_mark = qdisc->type == NFP_QDISC_RED &&
qdisc->params_ok &&
qdisc->use_cnt == 1 &&
if (!qdisc->offload_mark)
return;
- nfp_abm_ctrl_set_q_lvl(alink, 0, queue, qdisc->red.threshold);
+ for (i = 0; i < alink->abm->num_bands; i++)
+ nfp_abm_ctrl_set_q_lvl(alink, i, queue,
+ qdisc->red.band[i].threshold);
}
static void
size_t i;
/* Mark all thresholds as unconfigured */
- __bitmap_set(abm->threshold_undef,
- alink->queue_base, alink->total_queues);
+ for (i = 0; i < abm->num_bands; i++)
+ __bitmap_set(abm->threshold_undef,
+ i * NFP_NET_MAX_RX_RINGS + alink->queue_base,
+ alink->total_queues);
/* Clear offload marks */
radix_tree_for_each_slot(slot, &alink->qdiscs, &iter, 0) {
if (!qdisc || !qdisc->offloaded)
return -EOPNOTSUPP;
- nfp_abm_stats_red_calculate(&qdisc->red.xstats,
- &qdisc->red.prev_xstats,
+ nfp_abm_stats_red_calculate(&qdisc->red.band[0].xstats,
+ &qdisc->red.band[0].prev_xstats,
opt->xstats);
- qdisc->red.prev_xstats = qdisc->red.xstats;
+ qdisc->red.band[0].prev_xstats = qdisc->red.band[0].xstats;
return 0;
}
* counters back so carry on even if qdisc is not currently offloaded.
*/
- nfp_abm_stats_calculate(&qdisc->red.stats,
- &qdisc->red.prev_stats,
+ nfp_abm_stats_calculate(&qdisc->red.band[0].stats,
+ &qdisc->red.band[0].prev_stats,
stats->bstats, stats->qstats);
- qdisc->red.prev_stats = qdisc->red.stats;
+ qdisc->red.band[0].prev_stats = qdisc->red.band[0].stats;
return qdisc->offloaded ? 0 : -EOPNOTSUPP;
}
}
qdisc->params_ok = nfp_abm_red_check_params(alink, opt);
- if (qdisc->params_ok)
- qdisc->red.threshold = opt->set.min;
+ if (qdisc->params_ok) {
+ qdisc->red.num_bands = 1;
+ qdisc->red.band[0].threshold = opt->set.min;
+ }
if (qdisc->use_cnt == 1)
nfp_abm_qdisc_offload_update(alink);
struct tc_qopt_offload_stats *stats)
{
struct nfp_qdisc *qdisc, *red;
- unsigned int i;
+ unsigned int i, j;
qdisc = nfp_abm_qdisc_find(alink, handle);
if (!qdisc)
continue;
red = qdisc->children[i];
- nfp_abm_stats_propagate(&qdisc->mq.stats,
- &red->red.stats);
- nfp_abm_stats_propagate(&qdisc->mq.prev_stats,
- &red->red.prev_stats);
+ for (j = 0; j < red->red.num_bands; j++) {
+ nfp_abm_stats_propagate(&qdisc->mq.stats,
+ &red->red.band[j].stats);
+ nfp_abm_stats_propagate(&qdisc->mq.prev_stats,
+ &red->red.band[j].prev_stats);
+ }
}
nfp_abm_stats_calculate(&qdisc->mq.stats, &qdisc->mq.prev_stats,