Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 861fb829 authored by Nogah Frankel's avatar Nogah Frankel Committed by David S. Miller
Browse files

mlxsw: spectrum: Support RED xstats



Add support for ndo_setup_tc with enum tc_setup_type value of
TC_SETUP_RED_XSTATS. This call returns the RED qdisc xstats from the cache
if the handle ID that is asked for matching the root qdisc ID and fails
otherwise.

Signed-off-by: default avatarNogah Frankel <nogahf@mellanox.com>
Signed-off-by: default avatarJiri Pirko <jiri@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 075ab8ad
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -48,6 +48,7 @@
#include <linux/notifier.h>
#include <net/psample.h>
#include <net/pkt_cls.h>
#include <net/red.h>

#include "port.h"
#include "core.h"
@@ -211,6 +212,14 @@ enum mlxsw_sp_qdisc_type {
struct mlxsw_sp_qdisc {
	u32 handle;
	enum mlxsw_sp_qdisc_type type;
	struct red_stats xstats_base;
	union {
		struct {
			u64 tail_drop_base;
			u64 ecn_base;
			u64 wred_drop_base;
		} red;
	} xstats;
};

/* No need an internal lock; At worse - miss a single periodic iteration */
+51 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@
#include <linux/errno.h>
#include <linux/netdevice.h>
#include <net/pkt_cls.h>
#include <net/red.h>

#include "spectrum.h"
#include "reg.h"
@@ -77,6 +78,27 @@ mlxsw_sp_tclass_congestion_disable(struct mlxsw_sp_port *mlxsw_sp_port,
	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(cwtpm), cwtpm_cmd);
}

static void
mlxsw_sp_setup_tc_qdisc_clean_stats(struct mlxsw_sp_port *mlxsw_sp_port,
				    struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
				    int tclass_num)
{
	struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
	struct mlxsw_sp_port_xstats *xstats;

	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;

	switch (mlxsw_sp_qdisc->type) {
	case MLXSW_SP_QDISC_RED:
		xstats_base->prob_mark = xstats->ecn;
		xstats_base->prob_drop = xstats->wred_drop[tclass_num];
		xstats_base->pdrop = xstats->tail_drop[tclass_num];
		break;
	default:
		break;
	}
}

static int
mlxsw_sp_qdisc_red_destroy(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
			   struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
@@ -135,6 +157,11 @@ mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
		goto err_config;

	mlxsw_sp_qdisc->type = MLXSW_SP_QDISC_RED;
	if (mlxsw_sp_qdisc->handle != handle)
		mlxsw_sp_setup_tc_qdisc_clean_stats(mlxsw_sp_port,
						    mlxsw_sp_qdisc,
						    tclass_num);

	mlxsw_sp_qdisc->handle = handle;
	return 0;

@@ -146,6 +173,26 @@ mlxsw_sp_qdisc_red_replace(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
	return err;
}

static int
mlxsw_sp_qdisc_get_red_xstats(struct mlxsw_sp_port *mlxsw_sp_port, u32 handle,
			      struct mlxsw_sp_qdisc *mlxsw_sp_qdisc,
			      int tclass_num, struct red_stats *res)
{
	struct red_stats *xstats_base = &mlxsw_sp_qdisc->xstats_base;
	struct mlxsw_sp_port_xstats *xstats;

	if (mlxsw_sp_qdisc->handle != handle ||
	    mlxsw_sp_qdisc->type != MLXSW_SP_QDISC_RED)
		return -EOPNOTSUPP;

	xstats = &mlxsw_sp_port->periodic_hw_stats.xstats;

	res->prob_drop = xstats->wred_drop[tclass_num] - xstats_base->prob_drop;
	res->prob_mark = xstats->ecn - xstats_base->prob_mark;
	res->pdrop = xstats->tail_drop[tclass_num] - xstats_base->pdrop;
	return 0;
}

#define MLXSW_SP_PORT_DEFAULT_TCLASS 0

int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
@@ -168,6 +215,10 @@ int mlxsw_sp_setup_tc_red(struct mlxsw_sp_port *mlxsw_sp_port,
	case TC_RED_DESTROY:
		return mlxsw_sp_qdisc_red_destroy(mlxsw_sp_port, p->handle,
						  mlxsw_sp_qdisc, tclass_num);
	case TC_RED_XSTATS:
		return mlxsw_sp_qdisc_get_red_xstats(mlxsw_sp_port, p->handle,
						     mlxsw_sp_qdisc, tclass_num,
						     p->xstats);
	default:
		return -EOPNOTSUPP;
	}