Commit df4c5d9a authored by Mohsin Bashir's avatar Mohsin Bashir Committed by Jakub Kicinski
Browse files

eth: fbnic: Fetch PHY stats from device



Add support to fetch PHY stats consisting of PCS and FEC stats from the
device. When reading the stats counters, the lo part is read first, which
latches the hi part to ensure consistent reading of the stats counter.

FEC and PCS stats can wrap depending on the access frequency. To prevent
wrapping, fetch these stats periodically under the service task. Also to
maintain consistency fetch these stats along with other 32b stats under
__fbnic_get_hw_stats32().

Signed-off-by: default avatarMohsin Bashir <mohsin.bashr@gmail.com>
Reviewed-by: default avatarJacob Keller <jacob.e.keller@intel.com>
Link: https://patch.msgid.link/20250825200206.2357713-5-kuba@kernel.org


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent bcf54e5d
Loading
Loading
Loading
Loading
+15 −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) */
+20 −0
Original line number Diff line number Diff line
@@ -512,6 +512,24 @@ 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)
{
@@ -525,6 +543,7 @@ static void fbnic_reset_hw_mac_stats(struct fbnic_dev *fbd,
void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
{
	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);
@@ -553,6 +572,7 @@ void fbnic_init_hw_stats(struct fbnic_dev *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);
+16 −0
Original line number Diff line number Diff line
@@ -23,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;
@@ -56,6 +66,11 @@ 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_eth_ctrl_stats eth_ctrl;
@@ -116,6 +131,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;
+46 −0
Original line number Diff line number Diff line
@@ -631,6 +631,50 @@ static void fbnic_mac_link_up_asic(struct fbnic_dev *fbd,
	wr32(fbd, FBNIC_MAC_COMMAND_CONFIG, cmd_cfg);
}

static void
fbnic_pcs_rsfec_stat_rd32(struct fbnic_dev *fbd, u32 reg, bool reset,
			  struct fbnic_stat_counter *stat)
{
	u32 pcs_rsfec_stat;

	/* The PCS/RFSEC registers are only 16b wide each. So what we will
	 * have after the 64b read is 0x0000xxxx0000xxxx. To make it usable
	 * as a full stat we will shift the upper bits into the lower set of
	 * 0s and then mask off the math at 32b.
	 *
	 * Read ordering must be lower reg followed by upper reg.
	 */
	pcs_rsfec_stat = rd32(fbd, reg) & 0xffff;
	pcs_rsfec_stat |= rd32(fbd, reg + 1) << 16;

	/* RFSEC registers clear themselves upon being read so there is no
	 * need to store the old_reg_value.
	 */
	if (!reset)
		stat->value += pcs_rsfec_stat;
}

static void
fbnic_mac_get_fec_stats(struct fbnic_dev *fbd, bool reset,
			struct fbnic_fec_stats *s)
{
	fbnic_pcs_rsfec_stat_rd32(fbd, FBNIC_RSFEC_CCW_LO(0), reset,
				  &s->corrected_blocks);
	fbnic_pcs_rsfec_stat_rd32(fbd, FBNIC_RSFEC_NCCW_LO(0), reset,
				  &s->uncorrectable_blocks);
}

static void
fbnic_mac_get_pcs_stats(struct fbnic_dev *fbd, bool reset,
			struct fbnic_pcs_stats *s)
{
	int i;

	for (i = 0; i < FBNIC_PCS_MAX_LANES; i++)
		fbnic_pcs_rsfec_stat_rd32(fbd, FBNIC_PCS_SYMBLERR_LO(i), reset,
					  &s->SymbolErrorDuringCarrier.lanes[i]);
}

static void
fbnic_mac_get_eth_mac_stats(struct fbnic_dev *fbd, bool reset,
			    struct fbnic_eth_mac_stats *mac_stats)
@@ -809,6 +853,8 @@ static const struct fbnic_mac fbnic_mac_asic = {
	.pcs_disable = fbnic_pcs_disable_asic,
	.pcs_get_link = fbnic_pcs_get_link_asic,
	.pcs_get_link_event = fbnic_pcs_get_link_event_asic,
	.get_fec_stats = fbnic_mac_get_fec_stats,
	.get_pcs_stats = fbnic_mac_get_pcs_stats,
	.get_eth_mac_stats = fbnic_mac_get_eth_mac_stats,
	.get_eth_ctrl_stats = fbnic_mac_get_eth_ctrl_stats,
	.get_rmon_stats = fbnic_mac_get_rmon_stats,
+4 −0
Original line number Diff line number Diff line
@@ -79,6 +79,10 @@ struct fbnic_mac {
	bool (*pcs_get_link)(struct fbnic_dev *fbd);
	int (*pcs_get_link_event)(struct fbnic_dev *fbd);

	void (*get_fec_stats)(struct fbnic_dev *fbd, bool reset,
			      struct fbnic_fec_stats *fec_stats);
	void (*get_pcs_stats)(struct fbnic_dev *fbd, bool reset,
			      struct fbnic_pcs_stats *pcs_stats);
	void (*get_eth_mac_stats)(struct fbnic_dev *fbd, bool reset,
				  struct fbnic_eth_mac_stats *mac_stats);
	void (*get_eth_ctrl_stats)(struct fbnic_dev *fbd, bool reset,