From: Nogah Frankel <nogahf@mellanox.com>
Date: Mon, 6 Nov 2017 07:23:48 +0100
Subject: mlxsw: spectrum: Support RED xstats
Patch-mainline: v4.15-rc1
Git-commit: 861fb8294d83ad950dfaa62b0bf8384c66e2cd5e
References: bsc#1112374
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: Nogah Frankel <nogahf@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Acked-by: Thomas Bogendoerfer <tbogendoerfer@suse.de>
---
drivers/net/ethernet/mellanox/mlxsw/spectrum.h | 9 +++
drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c | 51 +++++++++++++++++++
2 files changed, 60 insertions(+)
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum.h
@@ -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 */
--- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
+++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_qdisc.c
@@ -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(struc
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_
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 @@ err_config:
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_s
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;
}