Commit d4854be4 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'eth-fbnic-extend-hw-stats-support'

Jakub Kicinski says:

====================
eth: fbnic: Extend hw stats support

Mohsin says:

Extend hardware stats support for fbnic by adding the ability to reset
hardware stats when the device experience a reset due to a PCI error and
include MAC stats in the hardware stats reset. Additionally, expand
hardware stats coverage to include FEC, PHY, and Pause stats.

v1: https://lore.kernel.org/20250822164731.1461754-1-kuba@kernel.org
====================

Link: https://patch.msgid.link/20250825200206.2357713-1-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents ef5ca972 e9faf4db
Loading
Loading
Loading
Loading
+0 −3
Original line number Diff line number Diff line
@@ -84,9 +84,6 @@ struct fbnic_dev {
	/* Local copy of hardware statistics */
	struct fbnic_hw_stats hw_stats;

	/* Lock protecting access to hw_stats */
	spinlock_t hw_stats_lock;

	struct fbnic_fw_log fw_log;
};

+19 −0
Original line number Diff line number Diff line
@@ -790,6 +790,21 @@ enum {
#define FBNIC_CSR_END_PCS		0x10668 /* CSR section delimiter */

#define FBNIC_CSR_START_RSFEC		0x10800 /* CSR section delimiter */

/* We have 4 RSFEC engines present in our part, however we are only using 1.
 * As such only CCW(0) and NCCW(0) will never be non-zero and the other
 * registers can be ignored.
 */
#define FBNIC_RSFEC_CCW_LO(n)	(0x10802 + 8 * (n))	/* 0x42008 + 32*n */
#define FBNIC_RSFEC_CCW_HI(n)	(0x10803 + 8 * (n))	/* 0x4200c + 32*n */
#define FBNIC_RSFEC_NCCW_LO(n)	(0x10804 + 8 * (n))	/* 0x42010 + 32*n */
#define FBNIC_RSFEC_NCCW_HI(n)	(0x10805 + 8 * (n))	/* 0x42014 + 32*n */

#define FBNIC_PCS_MAX_LANES			4
#define FBNIC_PCS_SYMBLERR_LO(n) \
				(0x10880 + 2 * (n))	/* 0x42200 + 8*n */
#define FBNIC_PCS_SYMBLERR_HI(n) \
				(0x10881 + 2 * (n))	/* 0x42204 + 8*n */
#define FBNIC_CSR_END_RSFEC		0x108c8 /* CSR section delimiter */

/* MAC MAC registers (ASIC only) */
@@ -829,6 +844,10 @@ enum {
#define FBNIC_CSR_END_SIG		0x1184e /* CSR section delimiter */

#define FBNIC_CSR_START_MAC_STAT	0x11a00
#define FBNIC_MAC_STAT_RX_XOFF_STB_L	0x11a00		/* 0x46800 */
#define FBNIC_MAC_STAT_RX_XOFF_STB_H	0x11a01		/* 0x46804 */
#define FBNIC_MAC_STAT_TX_XOFF_STB_L	0x11a04		/* 0x46810 */
#define FBNIC_MAC_STAT_TX_XOFF_STB_H	0x11a05		/* 0x46814 */
#define FBNIC_MAC_STAT_RX_BYTE_COUNT_L	0x11a08		/* 0x46820 */
#define FBNIC_MAC_STAT_RX_BYTE_COUNT_H	0x11a09		/* 0x46824 */
#define FBNIC_MAC_STAT_RX_ALIGN_ERROR_L	0x11a0a		/* 0x46828 */
+61 −2
Original line number Diff line number Diff line
@@ -518,7 +518,7 @@ static void fbnic_get_ethtool_stats(struct net_device *dev,

	fbnic_get_hw_stats(fbn->fbd);

	spin_lock(&fbd->hw_stats_lock);
	spin_lock(&fbd->hw_stats.lock);
	fbnic_report_hw_stats(fbnic_gstrings_hw_stats, &fbd->hw_stats,
			      FBNIC_HW_FIXED_STATS_LEN, &data);

@@ -555,7 +555,7 @@ static void fbnic_get_ethtool_stats(struct net_device *dev,
		fbnic_report_hw_stats(fbnic_gstrings_hw_q_stats, hw_q,
				      FBNIC_HW_Q_STATS_LEN, &data);
	}
	spin_unlock(&fbd->hw_stats_lock);
	spin_unlock(&fbd->hw_stats.lock);

	for (i = 0; i < FBNIC_MAX_XDPQS; i++)
		fbnic_get_xdp_queue_stats(fbn->tx[i + FBNIC_MAX_TXQS], &data);
@@ -1641,6 +1641,62 @@ static void fbnic_set_counter(u64 *stat, struct fbnic_stat_counter *counter)
		*stat = counter->value;
}

static void
fbnic_get_pause_stats(struct net_device *netdev,
		      struct ethtool_pause_stats *pause_stats)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	struct fbnic_mac_stats *mac_stats;
	struct fbnic_dev *fbd = fbn->fbd;

	mac_stats = &fbd->hw_stats.mac;

	fbd->mac->get_pause_stats(fbd, false, &mac_stats->pause);

	pause_stats->tx_pause_frames = mac_stats->pause.tx_pause_frames.value;
	pause_stats->rx_pause_frames = mac_stats->pause.rx_pause_frames.value;
}

static void
fbnic_get_fec_stats(struct net_device *netdev,
		    struct ethtool_fec_stats *fec_stats)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	struct fbnic_phy_stats *phy_stats;
	struct fbnic_dev *fbd = fbn->fbd;

	fbnic_get_hw_stats32(fbd);
	phy_stats = &fbd->hw_stats.phy;

	spin_lock(&fbd->hw_stats.lock);
	fec_stats->corrected_blocks.total =
		phy_stats->fec.corrected_blocks.value;
	fec_stats->uncorrectable_blocks.total =
		phy_stats->fec.uncorrectable_blocks.value;
	spin_unlock(&fbd->hw_stats.lock);
}

static void
fbnic_get_eth_phy_stats(struct net_device *netdev,
			struct ethtool_eth_phy_stats *eth_phy_stats)
{
	struct fbnic_net *fbn = netdev_priv(netdev);
	struct fbnic_phy_stats *phy_stats;
	struct fbnic_dev *fbd = fbn->fbd;
	u64 total = 0;
	int i;

	fbnic_get_hw_stats32(fbd);
	phy_stats = &fbd->hw_stats.phy;

	spin_lock(&fbd->hw_stats.lock);
	for (i = 0; i < FBNIC_PCS_MAX_LANES; i++)
		total += phy_stats->pcs.SymbolErrorDuringCarrier.lanes[i].value;

	eth_phy_stats->SymbolErrorDuringCarrier = total;
	spin_unlock(&fbd->hw_stats.lock);
}

static void
fbnic_get_eth_mac_stats(struct net_device *netdev,
			struct ethtool_eth_mac_stats *eth_mac_stats)
@@ -1761,6 +1817,7 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
	.set_coalesce			= fbnic_set_coalesce,
	.get_ringparam			= fbnic_get_ringparam,
	.set_ringparam			= fbnic_set_ringparam,
	.get_pause_stats		= fbnic_get_pause_stats,
	.get_pauseparam			= fbnic_phylink_get_pauseparam,
	.set_pauseparam			= fbnic_phylink_set_pauseparam,
	.get_strings			= fbnic_get_strings,
@@ -1782,7 +1839,9 @@ static const struct ethtool_ops fbnic_ethtool_ops = {
	.get_ts_info			= fbnic_get_ts_info,
	.get_ts_stats			= fbnic_get_ts_stats,
	.get_link_ksettings		= fbnic_phylink_ethtool_ksettings_get,
	.get_fec_stats			= fbnic_get_fec_stats,
	.get_fecparam			= fbnic_phylink_get_fecparam,
	.get_eth_phy_stats		= fbnic_get_eth_phy_stats,
	.get_eth_mac_stats		= fbnic_get_eth_mac_stats,
	.get_eth_ctrl_stats		= fbnic_get_eth_ctrl_stats,
	.get_rmon_stats			= fbnic_get_rmon_stats,
+58 −8
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) Meta Platforms, Inc. and affiliates. */

#include <linux/rtnetlink.h>

#include "fbnic.h"

static void fbnic_hw_stat_rst32(struct fbnic_dev *fbd, u32 reg,
@@ -421,9 +423,9 @@ static void fbnic_get_hw_rxq_stats32(struct fbnic_dev *fbd,
void fbnic_get_hw_q_stats(struct fbnic_dev *fbd,
			  struct fbnic_hw_q_stats *hw_q)
{
	spin_lock(&fbd->hw_stats_lock);
	spin_lock(&fbd->hw_stats.lock);
	fbnic_get_hw_rxq_stats32(fbd, hw_q);
	spin_unlock(&fbd->hw_stats_lock);
	spin_unlock(&fbd->hw_stats.lock);
}

static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd,
@@ -510,20 +512,68 @@ static void fbnic_get_pcie_stats_asic64(struct fbnic_dev *fbd,
			   &pcie->ob_rd_no_np_cred);
}

static void fbnic_reset_phy_stats(struct fbnic_dev *fbd,
				  struct fbnic_phy_stats *phy_stats)
{
	const struct fbnic_mac *mac = fbd->mac;

	mac->get_fec_stats(fbd, true, &phy_stats->fec);
	mac->get_pcs_stats(fbd, true, &phy_stats->pcs);
}

static void fbnic_get_phy_stats32(struct fbnic_dev *fbd,
				  struct fbnic_phy_stats *phy_stats)
{
	const struct fbnic_mac *mac = fbd->mac;

	mac->get_fec_stats(fbd, false, &phy_stats->fec);
	mac->get_pcs_stats(fbd, false, &phy_stats->pcs);
}

static void fbnic_reset_hw_mac_stats(struct fbnic_dev *fbd,
				     struct fbnic_mac_stats *mac_stats)
{
	const struct fbnic_mac *mac = fbd->mac;

	mac->get_eth_mac_stats(fbd, true, &mac_stats->eth_mac);
	mac->get_pause_stats(fbd, true, &mac_stats->pause);
	mac->get_eth_ctrl_stats(fbd, true, &mac_stats->eth_ctrl);
	mac->get_rmon_stats(fbd, true, &mac_stats->rmon);
}

void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
{
	spin_lock(&fbd->hw_stats_lock);
	spin_lock(&fbd->hw_stats.lock);
	fbnic_reset_phy_stats(fbd, &fbd->hw_stats.phy);
	fbnic_reset_tmi_stats(fbd, &fbd->hw_stats.tmi);
	fbnic_reset_tti_stats(fbd, &fbd->hw_stats.tti);
	fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc);
	fbnic_reset_rxb_stats(fbd, &fbd->hw_stats.rxb);
	fbnic_reset_hw_rxq_stats(fbd, fbd->hw_stats.hw_q);
	fbnic_reset_pcie_stats_asic(fbd, &fbd->hw_stats.pcie);
	spin_unlock(&fbd->hw_stats_lock);
	spin_unlock(&fbd->hw_stats.lock);

	/* Once registered, the only other access to MAC stats is via the
	 * ethtool API which is protected by the rtnl_lock. The call to
	 * fbnic_reset_hw_stats() during PCI recovery is also protected
	 * by the rtnl_lock hence, we don't need the spinlock to access
	 * the MAC stats.
	 */
	if (fbd->netdev)
		ASSERT_RTNL();
	fbnic_reset_hw_mac_stats(fbd, &fbd->hw_stats.mac);
}

void fbnic_init_hw_stats(struct fbnic_dev *fbd)
{
	spin_lock_init(&fbd->hw_stats.lock);

	fbnic_reset_hw_stats(fbd);
}

static void __fbnic_get_hw_stats32(struct fbnic_dev *fbd)
{
	fbnic_get_phy_stats32(fbd, &fbd->hw_stats.phy);
	fbnic_get_tmi_stats32(fbd, &fbd->hw_stats.tmi);
	fbnic_get_tti_stats32(fbd, &fbd->hw_stats.tti);
	fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc);
@@ -533,19 +583,19 @@ static void __fbnic_get_hw_stats32(struct fbnic_dev *fbd)

void fbnic_get_hw_stats32(struct fbnic_dev *fbd)
{
	spin_lock(&fbd->hw_stats_lock);
	spin_lock(&fbd->hw_stats.lock);
	__fbnic_get_hw_stats32(fbd);
	spin_unlock(&fbd->hw_stats_lock);
	spin_unlock(&fbd->hw_stats.lock);
}

void fbnic_get_hw_stats(struct fbnic_dev *fbd)
{
	spin_lock(&fbd->hw_stats_lock);
	spin_lock(&fbd->hw_stats.lock);
	__fbnic_get_hw_stats32(fbd);

	fbnic_get_tmi_stats(fbd, &fbd->hw_stats.tmi);
	fbnic_get_tti_stats(fbd, &fbd->hw_stats.tti);
	fbnic_get_rxb_stats(fbd, &fbd->hw_stats.rxb);
	fbnic_get_pcie_stats_asic64(fbd, &fbd->hw_stats.pcie);
	spin_unlock(&fbd->hw_stats_lock);
	spin_unlock(&fbd->hw_stats.lock);
}
+28 −0
Original line number Diff line number Diff line
@@ -5,6 +5,7 @@
#define _FBNIC_HW_STATS_H_

#include <linux/ethtool.h>
#include <linux/spinlock.h>

#include "fbnic_csr.h"

@@ -22,6 +23,16 @@ struct fbnic_hw_stat {
	struct fbnic_stat_counter bytes;
};

struct fbnic_fec_stats {
	struct fbnic_stat_counter corrected_blocks, uncorrectable_blocks;
};

struct fbnic_pcs_stats {
	struct {
		struct fbnic_stat_counter lanes[FBNIC_PCS_MAX_LANES];
	} SymbolErrorDuringCarrier;
};

/* Note: not updated by fbnic_get_hw_stats() */
struct fbnic_eth_ctrl_stats {
	struct fbnic_stat_counter MACControlFramesTransmitted;
@@ -39,6 +50,12 @@ struct fbnic_rmon_stats {
	struct fbnic_stat_counter hist_tx[ETHTOOL_RMON_HIST_MAX];
};

/* Note: not updated by fbnic_get_hw_stats() */
struct fbnic_pause_stats {
	struct fbnic_stat_counter tx_pause_frames;
	struct fbnic_stat_counter rx_pause_frames;
};

struct fbnic_eth_mac_stats {
	struct fbnic_stat_counter FramesTransmittedOK;
	struct fbnic_stat_counter FramesReceivedOK;
@@ -55,8 +72,14 @@ struct fbnic_eth_mac_stats {
	struct fbnic_stat_counter FrameTooLongErrors;
};

struct fbnic_phy_stats {
	struct fbnic_fec_stats fec;
	struct fbnic_pcs_stats pcs;
};

struct fbnic_mac_stats {
	struct fbnic_eth_mac_stats eth_mac;
	struct fbnic_pause_stats pause;
	struct fbnic_eth_ctrl_stats eth_ctrl;
	struct fbnic_rmon_stats rmon;
};
@@ -115,6 +138,7 @@ struct fbnic_pcie_stats {
};

struct fbnic_hw_stats {
	struct fbnic_phy_stats phy;
	struct fbnic_mac_stats mac;
	struct fbnic_tmi_stats tmi;
	struct fbnic_tti_stats tti;
@@ -122,11 +146,15 @@ struct fbnic_hw_stats {
	struct fbnic_rxb_stats rxb;
	struct fbnic_hw_q_stats hw_q[FBNIC_MAX_QUEUES];
	struct fbnic_pcie_stats pcie;

	/* Lock protecting the access to hw stats */
	spinlock_t lock;
};

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

void fbnic_reset_hw_stats(struct fbnic_dev *fbd);
void fbnic_init_hw_stats(struct fbnic_dev *fbd);
void fbnic_get_hw_q_stats(struct fbnic_dev *fbd,
			  struct fbnic_hw_q_stats *hw_q);
void fbnic_get_hw_stats32(struct fbnic_dev *fbd);
Loading