Commit 990b50a5 authored by Jakub Kicinski's avatar Jakub Kicinski Committed by David S. Miller
Browse files

nfp: abm: wrap RED parameters in bands



Wrap RED parameters and stats into a structure, and a 1-element
array.  Upcoming GRED offload will add the support for more bands.

Signed-off-by: default avatarJakub Kicinski <jakub.kicinski@netronome.com>
Reviewed-by: default avatarJohn Hurley <john.hurley@netronome.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent e49efd52
Loading
Loading
Loading
Loading
+16 −10
Original line number Diff line number Diff line
@@ -112,11 +112,13 @@ enum nfp_qdisc_type {
 * @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;
@@ -138,12 +140,16 @@ struct nfp_qdisc {
			struct nfp_alink_stats prev_stats;
		} mq;
		/* TC_SETUP_QDISC_RED */
		struct {
			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;
	};
};
+58 −30
Original line number Diff line number Diff line
@@ -46,20 +46,25 @@ nfp_abm_stats_update_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
			 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);
	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",
			0, queue, err);
				i, queue, err);

	err = nfp_abm_ctrl_read_q_xstats(alink, 0, queue, &qdisc->red.xstats);
		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",
			0, queue, err);
				i, queue, err);
	}
}

static void
@@ -113,6 +118,8 @@ nfp_abm_qdisc_unlink_children(struct nfp_qdisc *qdisc,
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",
@@ -121,8 +128,10 @@ nfp_abm_qdisc_offload_stop(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc)
	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
@@ -164,15 +173,26 @@ 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 &&
@@ -186,7 +206,9 @@ nfp_abm_offload_compile_red(struct nfp_abm_link *alink, struct nfp_qdisc *qdisc,
	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
@@ -217,8 +239,10 @@ void nfp_abm_qdisc_offload_update(struct nfp_abm_link *alink)
	size_t i;

	/* Mark all thresholds as unconfigured */
	for (i = 0; i < abm->num_bands; i++)
		__bitmap_set(abm->threshold_undef,
		     alink->queue_base, alink->total_queues);
			     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) {
@@ -451,10 +475,10 @@ nfp_abm_red_xstats(struct nfp_abm_link *alink, struct tc_red_qopt_offload *opt)
	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;
}

@@ -473,10 +497,10 @@ nfp_abm_red_stats(struct nfp_abm_link *alink, u32 handle,
	 * 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;
}
@@ -538,8 +562,10 @@ nfp_abm_red_replace(struct net_device *netdev, struct nfp_abm_link *alink,
	}

	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);
@@ -592,7 +618,7 @@ nfp_abm_mq_stats(struct nfp_abm_link *alink, u32 handle,
		 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)
@@ -614,10 +640,12 @@ nfp_abm_mq_stats(struct nfp_abm_link *alink, u32 handle,
			continue;
		red = qdisc->children[i];

		for (j = 0; j < red->red.num_bands; j++) {
			nfp_abm_stats_propagate(&qdisc->mq.stats,
					&red->red.stats);
						&red->red.band[j].stats);
			nfp_abm_stats_propagate(&qdisc->mq.prev_stats,
					&red->red.prev_stats);
						&red->red.band[j].prev_stats);
		}
	}

	nfp_abm_stats_calculate(&qdisc->mq.stats, &qdisc->mq.prev_stats,