Commit 79da2aaa authored by Sanman Pradhan's avatar Sanman Pradhan Committed by Jakub Kicinski
Browse files

eth: fbnic: add RPC hardware statistics



Report Rx parser statistics via ethtool -S.

The parser stats are 32b, so we need to add refresh to the service
task to make sure we don't miss overflows.

Signed-off-by: default avatarSanman Pradhan <sanman.p211993@gmail.com>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241115015344.757567-6-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 25ba596d
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -31,6 +31,19 @@ separate entry.
Statistics
----------

RPC (Rx parser)
~~~~~~~~~~~~~~~

 - ``rpc_unkn_etype``: frames containing unknown EtherType
 - ``rpc_unkn_ext_hdr``: frames containing unknown IPv6 extension header
 - ``rpc_ipv4_frag``: frames containing IPv4 fragment
 - ``rpc_ipv6_frag``: frames containing IPv6 fragment
 - ``rpc_ipv4_esp``: frames with IPv4 ESP encapsulation
 - ``rpc_ipv6_esp``: frames with IPv6 ESP encapsulation
 - ``rpc_tcp_opt_err``: frames which encountered TCP option parsing error
 - ``rpc_out_of_hdr_err``: frames where header was larger than parsable region
 - ``ovr_size_err``: oversized frames

PCIe
~~~~

+10 −0
Original line number Diff line number Diff line
@@ -638,6 +638,16 @@ enum {
		    FBNIC_RPC_RSS_KEY_DWORD_LEN * 32 - \
		    FBNIC_RPC_RSS_KEY_BIT_LEN)

#define FBNIC_RPC_CNTR_TCP_OPT_ERR	0x0849e		/* 0x21278 */
#define FBNIC_RPC_CNTR_UNKN_ETYPE	0x0849f		/* 0x2127c */
#define FBNIC_RPC_CNTR_IPV4_FRAG	0x084a0		/* 0x21280 */
#define FBNIC_RPC_CNTR_IPV6_FRAG	0x084a1		/* 0x21284 */
#define FBNIC_RPC_CNTR_IPV4_ESP		0x084a2		/* 0x21288 */
#define FBNIC_RPC_CNTR_IPV6_ESP		0x084a3		/* 0x2128c */
#define FBNIC_RPC_CNTR_UNKN_EXT_HDR	0x084a4		/* 0x21290 */
#define FBNIC_RPC_CNTR_OUT_OF_HDR_ERR	0x084a5		/* 0x21294 */
#define FBNIC_RPC_CNTR_OVR_SIZE_ERR	0x084a6		/* 0x21298 */

#define FBNIC_RPC_TCAM_MACDA_VALIDATE	0x0852d		/* 0x214b4 */
#define FBNIC_CSR_END_RPC		0x0856b	/* CSR section delimiter */

+71 −0
Original line number Diff line number Diff line
@@ -9,6 +9,37 @@
#include "fbnic_netdev.h"
#include "fbnic_tlv.h"

struct fbnic_stat {
	u8 string[ETH_GSTRING_LEN];
	unsigned int size;
	unsigned int offset;
};

#define FBNIC_STAT_FIELDS(type, name, stat) { \
	.string = name, \
	.size = sizeof_field(struct type, stat), \
	.offset = offsetof(struct type, stat), \
}

/* Hardware statistics not captured in rtnl_link_stats */
#define FBNIC_HW_STAT(name, stat) \
	FBNIC_STAT_FIELDS(fbnic_hw_stats, name, stat)

static const struct fbnic_stat fbnic_gstrings_hw_stats[] = {
	/* RPC */
	FBNIC_HW_STAT("rpc_unkn_etype", rpc.unkn_etype),
	FBNIC_HW_STAT("rpc_unkn_ext_hdr", rpc.unkn_ext_hdr),
	FBNIC_HW_STAT("rpc_ipv4_frag", rpc.ipv4_frag),
	FBNIC_HW_STAT("rpc_ipv6_frag", rpc.ipv6_frag),
	FBNIC_HW_STAT("rpc_ipv4_esp", rpc.ipv4_esp),
	FBNIC_HW_STAT("rpc_ipv6_esp", rpc.ipv6_esp),
	FBNIC_HW_STAT("rpc_tcp_opt_err", rpc.tcp_opt_err),
	FBNIC_HW_STAT("rpc_out_of_hdr_err", rpc.out_of_hdr_err),
};

#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats)
#define FBNIC_HW_STATS_LEN	FBNIC_HW_FIXED_STATS_LEN

static int
fbnic_get_ts_info(struct net_device *netdev,
		  struct kernel_ethtool_ts_info *tsinfo)
@@ -54,6 +85,43 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
		*stat = counter->value;
}

static void fbnic_get_strings(struct net_device *dev, u32 sset, u8 *data)
{
	int i;

	switch (sset) {
	case ETH_SS_STATS:
		for (i = 0; i < FBNIC_HW_STATS_LEN; i++)
			ethtool_puts(&data, fbnic_gstrings_hw_stats[i].string);
		break;
	}
}

static int fbnic_get_sset_count(struct net_device *dev, int sset)
{
	switch (sset) {
	case ETH_SS_STATS:
		return FBNIC_HW_STATS_LEN;
	default:
		return -EOPNOTSUPP;
	}
}

static void fbnic_get_ethtool_stats(struct net_device *dev,
				    struct ethtool_stats *stats, u64 *data)
{
	struct fbnic_net *fbn = netdev_priv(dev);
	const struct fbnic_stat *stat;
	int i;

	fbnic_get_hw_stats(fbn->fbd);

	for (i = 0; i < FBNIC_HW_STATS_LEN; i++) {
		stat = &fbnic_gstrings_hw_stats[i];
		data[i] = *(u64 *)((u8 *)&fbn->fbd->hw_stats + stat->offset);
	}
}

static void
fbnic_get_eth_mac_stats(struct net_device *netdev,
			struct ethtool_eth_mac_stats *eth_mac_stats)
@@ -138,6 +206,9 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
	.get_drvinfo		= fbnic_get_drvinfo,
	.get_regs_len		= fbnic_get_regs_len,
	.get_regs		= fbnic_get_regs,
	.get_strings		= fbnic_get_strings,
	.get_ethtool_stats	= fbnic_get_ethtool_stats,
	.get_sset_count		= fbnic_get_sset_count,
	.get_ts_info		= fbnic_get_ts_info,
	.get_ts_stats		= fbnic_get_ts_stats,
	.get_eth_mac_stats	= fbnic_get_eth_mac_stats,
+76 −0
Original line number Diff line number Diff line
@@ -3,6 +3,27 @@

#include "fbnic.h"

static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg,
				struct fbnic_stat_counter *stat)
{
	/* We do not touch the "value" field here.
	 * It gets zeroed out on fbd structure allocation.
	 * After that we want it to grow continuously
	 * through device resets and power state changes.
	 */
	stat->u.old_reg_value_32 = rd32(fbd, reg);
}

static void fbnic_hw_stat_rd32(struct fbnic_dev *fbd, u32 reg,
			       struct fbnic_stat_counter *stat)
{
	u32 new_reg_value;

	new_reg_value = rd32(fbd, reg);
	stat->value += new_reg_value - stat->u.old_reg_value_32;
	stat->u.old_reg_value_32 = new_reg_value;
}

u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset)
{
	u32 prev_upper, upper, lower, diff;
@@ -49,6 +70,53 @@ static void fbnic_hw_stat_rd64(struct fbnic_dev *fbd, u32 reg, s32 offset,
	stat->u.old_reg_value_64 = new_reg_value;
}

static void fbnic_reset_rpc_stats(struct fbnic_dev *fbd,
				  struct fbnic_rpc_stats *rpc)
{
	fbnic_hw_stat_rst32(fbd,
			    FBNIC_RPC_CNTR_UNKN_ETYPE,
			    &rpc->unkn_etype);
	fbnic_hw_stat_rst32(fbd,
			    FBNIC_RPC_CNTR_UNKN_EXT_HDR,
			    &rpc->unkn_ext_hdr);
	fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag);
	fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag);
	fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp);
	fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp);
	fbnic_hw_stat_rst32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err);
	fbnic_hw_stat_rst32(fbd,
			    FBNIC_RPC_CNTR_OUT_OF_HDR_ERR,
			    &rpc->out_of_hdr_err);
	fbnic_hw_stat_rst32(fbd,
			    FBNIC_RPC_CNTR_OVR_SIZE_ERR,
			    &rpc->ovr_size_err);
}

static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd,
				  struct fbnic_rpc_stats *rpc)
{
	fbnic_hw_stat_rd32(fbd,
			   FBNIC_RPC_CNTR_UNKN_ETYPE,
			   &rpc->unkn_etype);
	fbnic_hw_stat_rd32(fbd,
			   FBNIC_RPC_CNTR_UNKN_EXT_HDR,
			   &rpc->unkn_ext_hdr);

	fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_FRAG, &rpc->ipv4_frag);
	fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_FRAG, &rpc->ipv6_frag);

	fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV4_ESP, &rpc->ipv4_esp);
	fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_IPV6_ESP, &rpc->ipv6_esp);

	fbnic_hw_stat_rd32(fbd, FBNIC_RPC_CNTR_TCP_OPT_ERR, &rpc->tcp_opt_err);
	fbnic_hw_stat_rd32(fbd,
			   FBNIC_RPC_CNTR_OUT_OF_HDR_ERR,
			   &rpc->out_of_hdr_err);
	fbnic_hw_stat_rd32(fbd,
			   FBNIC_RPC_CNTR_OVR_SIZE_ERR,
			   &rpc->ovr_size_err);
}

static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd,
					struct fbnic_pcie_stats *pcie)
{
@@ -135,10 +203,18 @@ static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd,

void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
{
	fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc);
	fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie);
}

void fbnic_get_hw_stats32(struct fbnic_dev *fbd)
{
	fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc);
}

void fbnic_get_hw_stats(struct fbnic_dev *fbd)
{
	fbnic_get_hw_stats32(fbd);

	fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie);
}
+8 −0
Original line number Diff line number Diff line
@@ -37,6 +37,12 @@ struct fbnic_mac_stats {
	struct fbnic_eth_mac_stats eth_mac;
};

struct fbnic_rpc_stats {
	struct fbnic_stat_counter unkn_etype, unkn_ext_hdr;
	struct fbnic_stat_counter ipv4_frag, ipv6_frag, ipv4_esp, ipv6_esp;
	struct fbnic_stat_counter tcp_opt_err, out_of_hdr_err, ovr_size_err;
};

struct fbnic_pcie_stats {
	struct fbnic_stat_counter ob_rd_tlp, ob_rd_dword;
	struct fbnic_stat_counter ob_wr_tlp, ob_wr_dword;
@@ -49,12 +55,14 @@ struct fbnic_pcie_stats {

struct fbnic_hw_stats {
	struct fbnic_mac_stats mac;
	struct fbnic_rpc_stats rpc;
	struct fbnic_pcie_stats pcie;
};

u64 fbnic_stat_rd64(struct fbnic_dev *fbd, u32 reg, u32 offset);

void fbnic_reset_hw_stats(struct fbnic_dev *fbd);
void fbnic_get_hw_stats32(struct fbnic_dev *fbd);
void fbnic_get_hw_stats(struct fbnic_dev *fbd);

#endif /* _FBNIC_HW_STATS_H_ */
Loading