linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Steen Hegelund <steen.hegelund@microchip.com>
To: "David S. Miller" <davem@davemloft.net>,
	Jakub Kicinski <kuba@kernel.org>
Cc: Steen Hegelund <steen.hegelund@microchip.com>,
	Andrew Lunn <andrew@lunn.ch>,
	Russell King <linux@armlinux.org.uk>,
	Lars Povlsen <lars.povlsen@microchip.com>,
	Bjarni Jonasson <bjarni.jonasson@microchip.com>,
	Microchip Linux Driver Support <UNGLinuxDriver@microchip.com>,
	Alexandre Belloni <alexandre.belloni@bootlin.com>,
	Madalin Bucur <madalin.bucur@oss.nxp.com>,
	Nicolas Ferre <nicolas.ferre@microchip.com>,
	Mark Einon <mark.einon@gmail.com>,
	Masahiro Yamada <masahiroy@kernel.org>,
	Arnd Bergmann <arnd@arndb.de>, <netdev@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>
Subject: [RFC PATCH v3 7/8] net: sparx5: add ethtool configuration and statistics support
Date: Fri, 15 Jan 2021 14:53:38 +0100	[thread overview]
Message-ID: <20210115135339.3127198-8-steen.hegelund@microchip.com> (raw)
In-Reply-To: <20210115135339.3127198-1-steen.hegelund@microchip.com>

This adds statistic counters for the network interfaces provided
by the driver.  It also adds CPU port counters (which are not
exposed by ethtool).
This also adds support for configuring the network interface
parameters via ethtool: speed, duplex, aneg etc.

Signed-off-by: Steen Hegelund <steen.hegelund@microchip.com>
Signed-off-by: Bjarni Jonasson <bjarni.jonasson@microchip.com>
Signed-off-by: Lars Povlsen <lars.povlsen@microchip.com>
---
 .../net/ethernet/microchip/sparx5/Makefile    |   3 +-
 .../microchip/sparx5/sparx5_ethtool.c         | 969 ++++++++++++++++++
 .../ethernet/microchip/sparx5/sparx5_main.c   |   4 +
 .../ethernet/microchip/sparx5/sparx5_main.h   |  12 +
 .../ethernet/microchip/sparx5/sparx5_netdev.c |   2 +
 5 files changed, 989 insertions(+), 1 deletion(-)
 create mode 100644 drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c

diff --git a/drivers/net/ethernet/microchip/sparx5/Makefile b/drivers/net/ethernet/microchip/sparx5/Makefile
index 17654ab90ce1..de3155cd582c 100644
--- a/drivers/net/ethernet/microchip/sparx5/Makefile
+++ b/drivers/net/ethernet/microchip/sparx5/Makefile
@@ -7,4 +7,5 @@ obj-$(CONFIG_SPARX5_SWITCH) += sparx5-switch.o
 
 sparx5-switch-objs  := sparx5_main.o sparx5_switchdev.o \
  sparx5_vlan.o sparx5_mactable.o sparx5_packet.o \
- sparx5_netdev.o sparx5_port.o sparx5_phylink.o sparx5_calendar.o
+ sparx5_ethtool.o sparx5_netdev.o sparx5_port.o \
+ sparx5_phylink.o sparx5_calendar.o
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
new file mode 100644
index 000000000000..4deb51011722
--- /dev/null
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_ethtool.c
@@ -0,0 +1,969 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Microchip Sparx5 Switch driver
+ *
+ * Copyright (c) 2020 Microchip Technology Inc. and its subsidiaries.
+ */
+
+#include <linux/ethtool.h>
+
+#include "sparx5_main_regs.h"
+#include "sparx5_main.h"
+#include "sparx5_port.h"
+
+/* Add a potentially wrapping 32 bit value to a 64 bit counter */
+static void sparx5_update_counter(u64 *cnt, u32 val)
+{
+	if (val < (*cnt & U32_MAX))
+		*cnt += (u64)1 << 32; /* value has wrapped */
+
+	*cnt = (*cnt & ~(u64)U32_MAX) + val;
+}
+
+/* Get a set of Queue System statistics */
+static void sparx5_xqs_prio_stats(struct sparx5 *sparx5,
+				  u32 addr,
+				  u64 *stats)
+{
+	int idx;
+
+	for (idx = 0; idx < 2 * SPX5_PRIOS; ++idx, ++addr, ++stats)
+		sparx5_update_counter(stats, spx5_rd(sparx5, XQS_CNT(addr)));
+}
+
+#define SPX5_STAT_GET(sname)        portstats[spx5_stats_##sname]
+#define SPX5_STAT_SUM(sname)        (portstats[spx5_stats_##sname] + \
+				     portstats[spx5_stats_pmac_##sname])
+#define SPX5_STAT_XQS_PRIOS_COUNTER_SUM(sname)    \
+	(portstats[spx5_stats_green_p0_##sname] + \
+	portstats[spx5_stats_green_p1_##sname] +  \
+	portstats[spx5_stats_green_p2_##sname] +  \
+	portstats[spx5_stats_green_p3_##sname] +  \
+	portstats[spx5_stats_green_p4_##sname] +  \
+	portstats[spx5_stats_green_p5_##sname] +  \
+	portstats[spx5_stats_green_p6_##sname] +  \
+	portstats[spx5_stats_green_p7_##sname] +  \
+	portstats[spx5_stats_yellow_p0_##sname] + \
+	portstats[spx5_stats_yellow_p1_##sname] + \
+	portstats[spx5_stats_yellow_p2_##sname] + \
+	portstats[spx5_stats_yellow_p3_##sname] + \
+	portstats[spx5_stats_yellow_p4_##sname] + \
+	portstats[spx5_stats_yellow_p5_##sname] + \
+	portstats[spx5_stats_yellow_p6_##sname] + \
+	portstats[spx5_stats_yellow_p7_##sname])
+
+enum sparx5_stats_entry {
+	spx5_stats_rx_in_bytes,
+	spx5_stats_rx_symbol_err,
+	spx5_stats_rx_pause,
+	spx5_stats_rx_unsup_opcode,
+	spx5_stats_rx_ok_bytes,
+	spx5_stats_rx_bad_bytes,
+	spx5_stats_rx_unicast,
+	spx5_stats_rx_multicast,
+	spx5_stats_rx_broadcast,
+	spx5_stats_rx_crc_err,
+	spx5_stats_rx_undersize,
+	spx5_stats_rx_fragments,
+	spx5_stats_rx_inrangelen_err,
+	spx5_stats_rx_outofrangelen_err,
+	spx5_stats_rx_oversize,
+	spx5_stats_rx_jabbers,
+	spx5_stats_rx_size64,
+	spx5_stats_rx_size65_127,
+	spx5_stats_rx_size128_255,
+	spx5_stats_rx_size256_511,
+	spx5_stats_rx_size512_1023,
+	spx5_stats_rx_size1024_1518,
+	spx5_stats_rx_size1519_max,
+	spx5_stats_pmac_rx_symbol_err,
+	spx5_stats_pmac_rx_pause,
+	spx5_stats_pmac_rx_unsup_opcode,
+	spx5_stats_pmac_rx_ok_bytes,
+	spx5_stats_pmac_rx_bad_bytes,
+	spx5_stats_pmac_rx_unicast,
+	spx5_stats_pmac_rx_multicast,
+	spx5_stats_pmac_rx_broadcast,
+	spx5_stats_pmac_rx_crc_err,
+	spx5_stats_pmac_rx_undersize,
+	spx5_stats_pmac_rx_fragments,
+	spx5_stats_pmac_rx_inrangelen_err,
+	spx5_stats_pmac_rx_outofrangelen_err,
+	spx5_stats_pmac_rx_oversize,
+	spx5_stats_pmac_rx_jabbers,
+	spx5_stats_pmac_rx_size64,
+	spx5_stats_pmac_rx_size65_127,
+	spx5_stats_pmac_rx_size128_255,
+	spx5_stats_pmac_rx_size256_511,
+	spx5_stats_pmac_rx_size512_1023,
+	spx5_stats_pmac_rx_size1024_1518,
+	spx5_stats_pmac_rx_size1519_max,
+	spx5_stats_green_p0_rx_fwd,
+	spx5_stats_green_p1_rx_fwd,
+	spx5_stats_green_p2_rx_fwd,
+	spx5_stats_green_p3_rx_fwd,
+	spx5_stats_green_p4_rx_fwd,
+	spx5_stats_green_p5_rx_fwd,
+	spx5_stats_green_p6_rx_fwd,
+	spx5_stats_green_p7_rx_fwd,
+	spx5_stats_yellow_p0_rx_fwd,
+	spx5_stats_yellow_p1_rx_fwd,
+	spx5_stats_yellow_p2_rx_fwd,
+	spx5_stats_yellow_p3_rx_fwd,
+	spx5_stats_yellow_p4_rx_fwd,
+	spx5_stats_yellow_p5_rx_fwd,
+	spx5_stats_yellow_p6_rx_fwd,
+	spx5_stats_yellow_p7_rx_fwd,
+	spx5_stats_green_p0_rx_port_drop,
+	spx5_stats_green_p1_rx_port_drop,
+	spx5_stats_green_p2_rx_port_drop,
+	spx5_stats_green_p3_rx_port_drop,
+	spx5_stats_green_p4_rx_port_drop,
+	spx5_stats_green_p5_rx_port_drop,
+	spx5_stats_green_p6_rx_port_drop,
+	spx5_stats_green_p7_rx_port_drop,
+	spx5_stats_yellow_p0_rx_port_drop,
+	spx5_stats_yellow_p1_rx_port_drop,
+	spx5_stats_yellow_p2_rx_port_drop,
+	spx5_stats_yellow_p3_rx_port_drop,
+	spx5_stats_yellow_p4_rx_port_drop,
+	spx5_stats_yellow_p5_rx_port_drop,
+	spx5_stats_yellow_p6_rx_port_drop,
+	spx5_stats_yellow_p7_rx_port_drop,
+	spx5_stats_rx_local_drop,
+	spx5_stats_rx_port_policer_drop,
+	spx5_stats_tx_out_bytes,
+	spx5_stats_tx_pause,
+	spx5_stats_tx_ok_bytes,
+	spx5_stats_tx_unicast,
+	spx5_stats_tx_multicast,
+	spx5_stats_tx_broadcast,
+	spx5_stats_tx_size64,
+	spx5_stats_tx_size65_127,
+	spx5_stats_tx_size128_255,
+	spx5_stats_tx_size256_511,
+	spx5_stats_tx_size512_1023,
+	spx5_stats_tx_size1024_1518,
+	spx5_stats_tx_size1519_max,
+	spx5_stats_tx_multi_coll,
+	spx5_stats_tx_late_coll,
+	spx5_stats_tx_xcoll,
+	spx5_stats_tx_defer,
+	spx5_stats_tx_xdefer,
+	spx5_stats_tx_backoff1,
+	spx5_stats_pmac_tx_pause,
+	spx5_stats_pmac_tx_ok_bytes,
+	spx5_stats_pmac_tx_unicast,
+	spx5_stats_pmac_tx_multicast,
+	spx5_stats_pmac_tx_broadcast,
+	spx5_stats_pmac_tx_size64,
+	spx5_stats_pmac_tx_size65_127,
+	spx5_stats_pmac_tx_size128_255,
+	spx5_stats_pmac_tx_size256_511,
+	spx5_stats_pmac_tx_size512_1023,
+	spx5_stats_pmac_tx_size1024_1518,
+	spx5_stats_pmac_tx_size1519_max,
+	spx5_stats_green_p0_tx_port,
+	spx5_stats_green_p1_tx_port,
+	spx5_stats_green_p2_tx_port,
+	spx5_stats_green_p3_tx_port,
+	spx5_stats_green_p4_tx_port,
+	spx5_stats_green_p5_tx_port,
+	spx5_stats_green_p6_tx_port,
+	spx5_stats_green_p7_tx_port,
+	spx5_stats_yellow_p0_tx_port,
+	spx5_stats_yellow_p1_tx_port,
+	spx5_stats_yellow_p2_tx_port,
+	spx5_stats_yellow_p3_tx_port,
+	spx5_stats_yellow_p4_tx_port,
+	spx5_stats_yellow_p5_tx_port,
+	spx5_stats_yellow_p6_tx_port,
+	spx5_stats_yellow_p7_tx_port,
+	spx5_stats_tx_local_drop,
+};
+
+static const char *const sparx5_stats_layout[] = {
+	"rx_in_bytes",
+	"rx_symbol_err",
+	"rx_pause",
+	"rx_unsup_opcode",
+	"rx_ok_bytes",
+	"rx_bad_bytes",
+	"rx_unicast",
+	"rx_multicast",
+	"rx_broadcast",
+	"rx_crc_err",
+	"rx_undersize",
+	"rx_fragments",
+	"rx_inrangelen_err",
+	"rx_outofrangelen_err",
+	"rx_oversize",
+	"rx_jabbers",
+	"rx_size64",
+	"rx_size65_127",
+	"rx_size128_255",
+	"rx_size256_511",
+	"rx_size512_1023",
+	"rx_size1024_1518",
+	"rx_size1519_max",
+	"pmac_rx_symbol_err",
+	"pmac_rx_pause",
+	"pmac_rx_unsup_opcode",
+	"pmac_rx_ok_bytes",
+	"pmac_rx_bad_bytes",
+	"pmac_rx_unicast",
+	"pmac_rx_multicast",
+	"pmac_rx_broadcast",
+	"pmac_rx_crc_err",
+	"pmac_rx_undersize",
+	"pmac_rx_fragments",
+	"pmac_rx_inrangelen_err",
+	"pmac_rx_outofrangelen_err",
+	"pmac_rx_oversize",
+	"pmac_rx_jabbers",
+	"pmac_rx_size64",
+	"pmac_rx_size65_127",
+	"pmac_rx_size128_255",
+	"pmac_rx_size256_511",
+	"pmac_rx_size512_1023",
+	"pmac_rx_size1024_1518",
+	"pmac_rx_size1519_max",
+	"rx_fwd_green_p0_q",
+	"rx_fwd_green_p1_q",
+	"rx_fwd_green_p2_q",
+	"rx_fwd_green_p3_q",
+	"rx_fwd_green_p4_q",
+	"rx_fwd_green_p5_q",
+	"rx_fwd_green_p6_q",
+	"rx_fwd_green_p7_q",
+	"rx_fwd_yellow_p0_q",
+	"rx_fwd_yellow_p1_q",
+	"rx_fwd_yellow_p2_q",
+	"rx_fwd_yellow_p3_q",
+	"rx_fwd_yellow_p4_q",
+	"rx_fwd_yellow_p5_q",
+	"rx_fwd_yellow_p6_q",
+	"rx_fwd_yellow_p7_q",
+	"rx_port_drop_green_p0_q",
+	"rx_port_drop_green_p1_q",
+	"rx_port_drop_green_p2_q",
+	"rx_port_drop_green_p3_q",
+	"rx_port_drop_green_p4_q",
+	"rx_port_drop_green_p5_q",
+	"rx_port_drop_green_p6_q",
+	"rx_port_drop_green_p7_q",
+	"rx_port_drop_yellow_p0_q",
+	"rx_port_drop_yellow_p1_q",
+	"rx_port_drop_yellow_p2_q",
+	"rx_port_drop_yellow_p3_q",
+	"rx_port_drop_yellow_p4_q",
+	"rx_port_drop_yellow_p5_q",
+	"rx_port_drop_yellow_p6_q",
+	"rx_port_drop_yellow_p7_q",
+	"rx_local_drop",
+	"rx_port_policer_drop",
+	"tx_out_bytes",
+	"tx_pause",
+	"tx_ok_bytes",
+	"tx_unicast",
+	"tx_multicast",
+	"tx_broadcast",
+	"tx_size64",
+	"tx_size65_127",
+	"tx_size128_255",
+	"tx_size256_511",
+	"tx_size512_1023",
+	"tx_size1024_1518",
+	"tx_size1519_max",
+	"tx_multi_coll",
+	"tx_late_coll",
+	"tx_xcoll",
+	"tx_defer",
+	"tx_xdefer",
+	"tx_backoff1",
+	"pmac_tx_pause",
+	"pmac_tx_ok_bytes",
+	"pmac_tx_unicast",
+	"pmac_tx_multicast",
+	"pmac_tx_broadcast",
+	"pmac_tx_size64",
+	"pmac_tx_size65_127",
+	"pmac_tx_size128_255",
+	"pmac_tx_size256_511",
+	"pmac_tx_size512_1023",
+	"pmac_tx_size1024_1518",
+	"pmac_tx_size1519_max",
+	"tx_port_green_p0_q",
+	"tx_port_green_p1_q",
+	"tx_port_green_p2_q",
+	"tx_port_green_p3_q",
+	"tx_port_green_p4_q",
+	"tx_port_green_p5_q",
+	"tx_port_green_p6_q",
+	"tx_port_green_p7_q",
+	"tx_port_yellow_p0_q",
+	"tx_port_yellow_p1_q",
+	"tx_port_yellow_p2_q",
+	"tx_port_yellow_p3_q",
+	"tx_port_yellow_p4_q",
+	"tx_port_yellow_p5_q",
+	"tx_port_yellow_p6_q",
+	"tx_port_yellow_p7_q",
+	"tx_local_drop",
+};
+
+/* Device Statistics */
+static void sparx5_get_device_stats(struct sparx5 *sparx5, int portno)
+{
+	u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
+	u32 dev = sparx5_to_high_dev(portno);
+	u32 tinst = sparx5_port_dev_index(portno);
+	void __iomem *inst = spx5_inst_get(sparx5, dev, tinst);
+
+	sparx5_update_counter(&portstats[spx5_stats_rx_in_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_IN_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_symbol_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SYMBOL_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_pause],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_PAUSE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_unsup_opcode],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_OK_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_bad_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_BAD_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_unicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_UC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_multicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_MC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_broadcast],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_BC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_crc_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_CRC_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_undersize],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_UNDERSIZE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_fragments],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_FRAGMENTS_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_inrangelen_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_IN_RANGE_LEN_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_outofrangelen_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_OUT_OF_RANGE_LEN_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_oversize],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_OVERSIZE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_jabbers],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_JABBERS_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size64],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE64_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size65_127],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE65TO127_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size128_255],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE128TO255_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size256_511],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE256TO511_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size512_1023],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE512TO1023_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE1024TO1518_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size1519_max],
+			      spx5_inst_rd(inst,
+					   DEV5G_RX_SIZE1519TOMAX_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_symbol_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SYMBOL_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_pause],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_PAUSE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unsup_opcode],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_UNSUP_OPCODE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_OK_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bad_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_BAD_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_UC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_multicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_MC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_broadcast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_BC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_crc_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_CRC_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_undersize],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_UNDERSIZE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_fragments],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_FRAGMENTS_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_inrangelen_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_IN_RANGE_LEN_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_outofrangelen_err],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_OVERSIZE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_jabbers],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_JABBERS_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size64],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE64_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size65_127],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE65TO127_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size128_255],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE128TO255_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size256_511],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE256TO511_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size512_1023],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE512TO1023_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE1024TO1518_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1519_max],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_RX_SIZE1519TOMAX_CNT(tinst)));
+	sparx5_xqs_prio_stats(sparx5,
+			      0,
+			      &portstats[spx5_stats_green_p0_rx_fwd]);
+	sparx5_xqs_prio_stats(sparx5,
+			      16,
+			      &portstats[spx5_stats_green_p0_rx_port_drop]);
+	sparx5_update_counter(&portstats[spx5_stats_rx_local_drop],
+			      spx5_rd(sparx5, XQS_CNT(32)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_port_policer_drop],
+			      spx5_rd(sparx5,
+				      ANA_AC_PORT_STAT_LSB_CNT(portno, 1)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_out_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_OUT_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_pause],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_PAUSE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_OK_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_unicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_UC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_multicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_MC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_broadcast],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_BC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size64],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE64_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size65_127],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE65TO127_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size128_255],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE128TO255_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size256_511],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE256TO511_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size512_1023],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE512TO1023_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE1024TO1518_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size1519_max],
+			      spx5_inst_rd(inst,
+					   DEV5G_TX_SIZE1519TOMAX_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_pause],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_PAUSE_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_OK_BYTES_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_unicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_UC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_multicast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_MC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_broadcast],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_BC_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size64],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE64_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size65_127],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE65TO127_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size128_255],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE128TO255_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size256_511],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE256TO511_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size512_1023],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE512TO1023_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE1024TO1518_CNT(tinst)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1519_max],
+			      spx5_inst_rd(inst,
+					   DEV5G_PMAC_TX_SIZE1519TOMAX_CNT(tinst)));
+	sparx5_xqs_prio_stats(sparx5,
+			      256,
+			      &portstats[spx5_stats_green_p0_tx_port]);
+	sparx5_update_counter(&portstats[spx5_stats_tx_local_drop],
+			      spx5_rd(sparx5, XQS_CNT(272)));
+}
+
+/* ASM Statistics */
+static void sparx5_get_asm_stats(struct sparx5 *sparx5, int portno)
+{
+	u64 *portstats = &sparx5->stats[portno * sparx5->num_stats];
+	u32 dev = TARGET_ASM;
+	void __iomem *inst = spx5_inst_get(sparx5, dev, 0);
+
+	sparx5_update_counter(&portstats[spx5_stats_rx_in_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_RX_IN_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_symbol_err],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SYMBOL_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_pause],
+			      spx5_inst_rd(inst,
+					   ASM_RX_PAUSE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_unsup_opcode],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_UNSUP_OPCODE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_RX_OK_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_bad_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_RX_BAD_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_unicast],
+			      spx5_inst_rd(inst,
+					   ASM_RX_UC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_multicast],
+			      spx5_inst_rd(inst,
+					   ASM_RX_MC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_broadcast],
+			      spx5_inst_rd(inst,
+					   ASM_RX_BC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_crc_err],
+			      spx5_inst_rd(inst,
+					   ASM_RX_CRC_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_undersize],
+			      spx5_inst_rd(inst,
+					   ASM_RX_UNDERSIZE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_fragments],
+			      spx5_inst_rd(inst,
+					   ASM_RX_FRAGMENTS_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_inrangelen_err],
+			      spx5_inst_rd(inst,
+					   ASM_RX_IN_RANGE_LEN_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_outofrangelen_err],
+			      spx5_inst_rd(inst,
+					   ASM_RX_OUT_OF_RANGE_LEN_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_oversize],
+			      spx5_inst_rd(inst,
+					   ASM_RX_OVERSIZE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_jabbers],
+			      spx5_inst_rd(inst,
+					   ASM_RX_JABBERS_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size64],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE64_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size65_127],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE65TO127_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size128_255],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE128TO255_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size256_511],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE256TO511_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size512_1023],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE512TO1023_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE1024TO1518_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_size1519_max],
+			      spx5_inst_rd(inst,
+					   ASM_RX_SIZE1519TOMAX_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_symbol_err],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SYMBOL_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_pause],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_PAUSE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unsup_opcode],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_UNSUP_OPCODE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_OK_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_bad_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_BAD_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_unicast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_UC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_multicast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_MC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_broadcast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_BC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_crc_err],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_CRC_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_undersize],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_UNDERSIZE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_fragments],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_FRAGMENTS_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_inrangelen_err],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_IN_RANGE_LEN_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_outofrangelen_err],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_OUT_OF_RANGE_LEN_ERR_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_oversize],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_OVERSIZE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_jabbers],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_JABBERS_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size64],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE64_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size65_127],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE65TO127_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size128_255],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE128TO255_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size256_511],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE256TO511_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size512_1023],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE512TO1023_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE1024TO1518_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_rx_size1519_max],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_RX_SIZE1519TOMAX_CNT(portno)));
+	sparx5_xqs_prio_stats(sparx5,
+			      0,
+			      &portstats[spx5_stats_green_p0_rx_fwd]);
+	sparx5_xqs_prio_stats(sparx5,
+			      16,
+			      &portstats[spx5_stats_green_p0_rx_port_drop]);
+	sparx5_update_counter(&portstats[spx5_stats_rx_local_drop],
+			      spx5_rd(sparx5, XQS_CNT(32)));
+	sparx5_update_counter(&portstats[spx5_stats_rx_port_policer_drop],
+			      spx5_rd(sparx5,
+				      ANA_AC_PORT_STAT_LSB_CNT(portno, 1)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_out_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_TX_OUT_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_pause],
+			      spx5_inst_rd(inst,
+					   ASM_TX_PAUSE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_TX_OK_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_unicast],
+			      spx5_inst_rd(inst,
+					   ASM_TX_UC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_multicast],
+			      spx5_inst_rd(inst,
+					   ASM_TX_MC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_broadcast],
+			      spx5_inst_rd(inst,
+					   ASM_TX_BC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size64],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE64_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size65_127],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE65TO127_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size128_255],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE128TO255_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size256_511],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE256TO511_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size512_1023],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE512TO1023_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE1024TO1518_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_size1519_max],
+			      spx5_inst_rd(inst,
+					   ASM_TX_SIZE1519TOMAX_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_multi_coll],
+			      spx5_inst_rd(inst,
+					   ASM_TX_MULTI_COLL_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_late_coll],
+			      spx5_inst_rd(inst,
+					   ASM_TX_LATE_COLL_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_xcoll],
+			      spx5_inst_rd(inst,
+					   ASM_TX_XCOLL_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_defer],
+			      spx5_inst_rd(inst,
+					   ASM_TX_DEFER_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_xdefer],
+			      spx5_inst_rd(inst,
+					   ASM_TX_XDEFER_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_tx_backoff1],
+			      spx5_inst_rd(inst,
+					   ASM_TX_BACKOFF1_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_pause],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_PAUSE_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_ok_bytes],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_OK_BYTES_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_unicast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_UC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_multicast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_MC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_broadcast],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_BC_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size64],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE64_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size65_127],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE65TO127_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size128_255],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE128TO255_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size256_511],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE256TO511_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size512_1023],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE512TO1023_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1024_1518],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE1024TO1518_CNT(portno)));
+	sparx5_update_counter(&portstats[spx5_stats_pmac_tx_size1519_max],
+			      spx5_inst_rd(inst,
+					   ASM_PMAC_TX_SIZE1519TOMAX_CNT(portno)));
+	sparx5_xqs_prio_stats(sparx5,
+			      256,
+			      &portstats[spx5_stats_green_p0_tx_port]);
+	sparx5_update_counter(&portstats[spx5_stats_tx_local_drop],
+			      spx5_rd(sparx5, XQS_CNT(272)));
+}
+
+static void sparx5_update_port_stats(struct sparx5 *sparx5, int portno)
+{
+	/* Set XQS port number */
+	spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(portno), sparx5, XQS_STAT_CFG);
+	if (sparx5_is_high_speed_device(&sparx5->ports[portno]->conf))
+		sparx5_get_device_stats(sparx5, portno);
+	else
+		sparx5_get_asm_stats(sparx5, portno);
+}
+
+static void sparx5_update_stats(struct sparx5 *sparx5)
+{
+	int idx;
+
+	for (idx = 0; idx < SPX5_PORTS; idx++)
+		if (sparx5->ports[idx])
+			sparx5_update_port_stats(sparx5, idx);
+}
+
+static void sparx5_check_stats_work(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct sparx5 *sparx5 = container_of(dwork, struct sparx5,
+					     stats_work);
+
+	sparx5_update_stats(sparx5);
+
+	queue_delayed_work(sparx5->stats_queue, &sparx5->stats_work,
+			   SPX5_STATS_CHECK_DELAY);
+}
+
+static int sparx5_get_sset_count(struct net_device *ndev, int sset)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+	struct sparx5  *sparx5 = port->sparx5;
+
+	if (sset != ETH_SS_STATS)
+		return -EOPNOTSUPP;
+	return sparx5->num_stats;
+}
+
+static void sparx5_get_sset_strings(struct net_device *ndev, u32 sset, u8 *data)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+	struct sparx5  *sparx5 = port->sparx5;
+	int idx;
+
+	if (sset != ETH_SS_STATS)
+		return;
+
+	for (idx = 0; idx < sparx5->num_stats; idx++)
+		strncpy(data + idx * ETH_GSTRING_LEN,
+			sparx5->stats_layout[idx], ETH_GSTRING_LEN);
+}
+
+static void sparx5_get_stats(struct net_device *ndev,
+			     struct ethtool_stats *stats, u64 *data)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+	struct sparx5  *sparx5 = port->sparx5;
+	u64 *portstats = &sparx5->stats[port->portno * sparx5->num_stats];
+	int idx;
+
+	/* Copy port counters to the ethtool buffer */
+	for (idx = 0; idx < sparx5->num_stats; idx++)
+		*data++ = portstats[idx];
+}
+
+void sparx5_get_stats64(struct net_device *ndev,
+			struct rtnl_link_stats64 *stats)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+	struct sparx5 *sparx5 = port->sparx5;
+	u64 *portstats;
+
+	if (!sparx5->stats)
+		return; /* Not initialized yet */
+
+	portstats = &sparx5->stats[port->portno * sparx5->num_stats];
+
+	stats->rx_errors = SPX5_STAT_SUM(rx_crc_err) +
+		SPX5_STAT_SUM(rx_undersize) + SPX5_STAT_SUM(rx_oversize) +
+		SPX5_STAT_SUM(rx_outofrangelen_err) +
+		SPX5_STAT_SUM(rx_symbol_err) + SPX5_STAT_SUM(rx_jabbers) +
+		SPX5_STAT_SUM(rx_fragments);
+
+	stats->rx_bytes = SPX5_STAT_SUM(rx_ok_bytes) +
+		SPX5_STAT_SUM(rx_bad_bytes);
+
+	stats->rx_packets = SPX5_STAT_SUM(rx_unicast) +
+		SPX5_STAT_SUM(rx_multicast) + SPX5_STAT_SUM(rx_broadcast) +
+		stats->rx_errors;
+
+	stats->multicast = SPX5_STAT_SUM(rx_unicast);
+
+	stats->rx_dropped = SPX5_STAT_GET(rx_port_policer_drop) +
+		SPX5_STAT_XQS_PRIOS_COUNTER_SUM(rx_port_drop);
+
+	/* Get Tx stats */
+	stats->tx_bytes = SPX5_STAT_SUM(tx_ok_bytes);
+
+	stats->tx_packets = SPX5_STAT_SUM(tx_unicast) +
+		SPX5_STAT_SUM(tx_multicast) + SPX5_STAT_SUM(tx_broadcast);
+
+	stats->tx_dropped = SPX5_STAT_GET(tx_local_drop);
+
+	stats->collisions = SPX5_STAT_GET(tx_multi_coll) +
+		SPX5_STAT_GET(tx_late_coll) +
+		SPX5_STAT_GET(tx_xcoll) +
+		SPX5_STAT_GET(tx_backoff1);
+}
+
+static int sparx5_get_link_settings(struct net_device *ndev,
+				    struct ethtool_link_ksettings *cmd)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_get(port->phylink, cmd);
+}
+
+static int sparx5_set_link_settings(struct net_device *ndev,
+				    const struct ethtool_link_ksettings *cmd)
+{
+	struct sparx5_port *port = netdev_priv(ndev);
+
+	return phylink_ethtool_ksettings_set(port->phylink, cmd);
+}
+
+const struct ethtool_ops sparx5_ethtool_ops = {
+	.get_sset_count         = sparx5_get_sset_count,
+	.get_strings            = sparx5_get_sset_strings,
+	.get_ethtool_stats      = sparx5_get_stats,
+	.get_link_ksettings	= sparx5_get_link_settings,
+	.set_link_ksettings	= sparx5_set_link_settings,
+	.get_link               = ethtool_op_get_link,
+};
+
+int sparx_stats_init(struct sparx5 *sparx5)
+{
+	char queue_name[32];
+	int portno;
+
+	sparx5->stats_layout = sparx5_stats_layout;
+	sparx5->num_stats = ARRAY_SIZE(sparx5_stats_layout);
+	sparx5->stats = devm_kcalloc(sparx5->dev,
+				     SPX5_PORTS_ALL * sparx5->num_stats,
+				     sizeof(u64), GFP_KERNEL);
+	if (!sparx5->stats)
+		return -ENOMEM;
+
+	for (portno = 0; portno < SPX5_PORTS; portno++)
+		if (sparx5->ports[portno]) {
+			/* Clear Queue System counters */
+			spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(portno) |
+				XQS_STAT_CFG_STAT_CLEAR_SHOT_SET(3), sparx5,
+				XQS_STAT_CFG);
+		}
+
+	snprintf(queue_name, sizeof(queue_name), "%s-stats",
+		 dev_name(sparx5->dev));
+	sparx5->stats_queue = create_singlethread_workqueue(queue_name);
+	INIT_DELAYED_WORK(&sparx5->stats_work, sparx5_check_stats_work);
+	queue_delayed_work(sparx5->stats_queue, &sparx5->stats_work,
+			   SPX5_STATS_CHECK_DELAY);
+
+	return 0;
+}
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
index e612d7cab131..5ba6bfdceb8d 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.c
@@ -613,6 +613,10 @@ static int sparx5_start(struct sparx5 *sparx5)
 	if (err)
 		return err;
 
+	/* Init stats */
+	err = sparx_stats_init(sparx5);
+	if (err)
+		return err;
 
 	/* Init mact_sw struct */
 	mutex_init(&sparx5->mact_lock);
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
index a375f6e236a7..3d0e80facfa5 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_main.h
@@ -130,6 +130,13 @@ struct sparx5 {
 	/* port structures are in net device */
 	struct sparx5_port                    *ports[SPX5_PORTS];
 	enum sparx5_core_clockfreq            coreclock;
+	/* Statistics */
+	u32                                   num_stats;
+	const char * const                    *stats_layout;
+	u64                                   *stats;
+	/* Workqueue for reading stats */
+	struct delayed_work                   stats_work;
+	struct workqueue_struct               *stats_queue;
 	/* Notifiers */
 	struct notifier_block                 netdevice_nb;
 	struct notifier_block                 switchdev_nb;
@@ -195,6 +202,10 @@ void sparx5_vlan_port_apply(struct sparx5 *sparx5, struct sparx5_port *port);
 int sparx5_config_auto_calendar(struct sparx5 *sparx5);
 int sparx5_config_dsm_calendar(struct sparx5 *sparx5);
 
+/* sparx5_ethtool.c */
+void sparx5_get_stats64(struct net_device *ndev, struct rtnl_link_stats64 *stats);
+int sparx_stats_init(struct sparx5 *sparx5);
+
 /* sparx5_netdev.c */
 bool sparx5_netdevice_check(const struct net_device *dev);
 struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno);
@@ -216,6 +227,7 @@ static inline u32 sparx5_clk_period(enum sparx5_core_clockfreq cclock)
 }
 
 extern const struct phylink_mac_ops sparx5_phylink_mac_ops;
+extern const struct ethtool_ops sparx5_ethtool_ops;
 
 /* Calculate raw offset */
 static inline __pure int spx5_offset(int id, int tinst, int tcnt,
diff --git a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
index cf9dc7a340cb..27922c3fc0f5 100644
--- a/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
+++ b/drivers/net/ethernet/microchip/sparx5/sparx5_netdev.c
@@ -177,6 +177,7 @@ static const struct net_device_ops sparx5_port_netdev_ops = {
 	.ndo_get_phys_port_name = sparx5_port_get_phys_port_name,
 	.ndo_set_mac_address    = sparx5_set_mac_address,
 	.ndo_validate_addr      = eth_validate_addr,
+	.ndo_get_stats64        = sparx5_get_stats64,
 	.ndo_get_port_parent_id = sparx5_get_port_parent_id,
 };
 
@@ -204,6 +205,7 @@ struct net_device *sparx5_create_netdev(struct sparx5 *sparx5, u32 portno)
 	snprintf(ndev->name, IFNAMSIZ, "eth%d", portno);
 
 	ndev->netdev_ops = &sparx5_port_netdev_ops;
+	ndev->ethtool_ops = &sparx5_ethtool_ops;
 	ndev->features |= NETIF_F_LLTX; /* software tx */
 
 	val = ether_addr_to_u64(sparx5->base_mac) + portno + 1;
-- 
2.29.2


  parent reply	other threads:[~2021-01-15 13:56 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-01-15 13:53 [RFC PATCH v3 0/8] Adding the Sparx5 Switch Driver Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 1/8] dt-bindings: net: sparx5: Add sparx5-switch bindings Steen Hegelund
2021-01-15 15:39   ` Rob Herring
2021-01-15 16:04   ` Rob Herring
2021-01-15 16:34     ` Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 2/8] net: sparx5: add the basic sparx5 driver Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 3/8] net: sparx5: add hostmode with phylink support Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 4/8] net: sparx5: add port module support Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 5/8] net: sparx5: add switching, vlan and mactable support Steen Hegelund
2021-01-15 13:53 ` [RFC PATCH v3 6/8] net: sparx5: add calendar bandwidth allocation support Steen Hegelund
2021-01-15 13:53 ` Steen Hegelund [this message]
2021-01-15 13:53 ` [RFC PATCH v3 8/8] arm64: dts: sparx5: Add the Sparx5 switch node Steen Hegelund

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210115135339.3127198-8-steen.hegelund@microchip.com \
    --to=steen.hegelund@microchip.com \
    --cc=UNGLinuxDriver@microchip.com \
    --cc=alexandre.belloni@bootlin.com \
    --cc=andrew@lunn.ch \
    --cc=arnd@arndb.de \
    --cc=bjarni.jonasson@microchip.com \
    --cc=davem@davemloft.net \
    --cc=kuba@kernel.org \
    --cc=lars.povlsen@microchip.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux@armlinux.org.uk \
    --cc=madalin.bucur@oss.nxp.com \
    --cc=mark.einon@gmail.com \
    --cc=masahiroy@kernel.org \
    --cc=netdev@vger.kernel.org \
    --cc=nicolas.ferre@microchip.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).