Commit 8f20a2bf authored by Mohsin Bashir's avatar Mohsin Bashir Committed by Paolo Abeni
Browse files

eth: fbnic: add coverage for hw queue stats



This patch provides support for hardware queue stats and covers
packet errors for RX-DMA engine, RCQ drops and BDQ drops.

The packet errors are also aggregated with the `rx_errors` stats in the
`rtnl_link_stats` as well as with the `hw_drops` in the queue API.

The RCQ and BDQ drops are aggregated with `rx_over_errors` in the
`rtnl_link_stats` as well as with the `hw_drop_overruns` in the queue API.

ethtool -S eth0 | grep -E 'rde'
     rde_0_pkt_err: 0
     rde_0_pkt_cq_drop: 0
     rde_0_pkt_bdq_drop: 0
     ---
     ---
     rde_127_pkt_err: 0
     rde_127_pkt_cq_drop: 0
     rde_127_pkt_bdq_drop: 0

Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarMohsin Bashir <mohsin.bashr@gmail.com>
Reviewed-by: default avatarSimon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250410070859.4160768-3-mohsin.bashr@gmail.com


Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
parent 9f61eb2d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -44,6 +44,15 @@ RPC (Rx parser)
 - ``rpc_out_of_hdr_err``: frames where header was larger than parsable region
 - ``ovr_size_err``: oversized frames

Hardware Queues
~~~~~~~~~~~~~~~

1. RX DMA Engine:

 - ``rde_[i]_pkt_err``: packets with MAC EOP, RPC parser, RXB truncation, or RDE frame truncation errors. These error are flagged in the packet metadata because of cut-through support but the actual drop happens once PCIE/RDE is reached.
 - ``rde_[i]_pkt_cq_drop``: packets dropped because RCQ is full
 - ``rde_[i]_pkt_bdq_drop``: packets dropped because HPQ or PPQ ran out of host buffer

PCIe
~~~~

+12 −0
Original line number Diff line number Diff line
@@ -864,6 +864,12 @@ enum {
#define FBNIC_QUEUE_TWQ1_BAL		0x022		/* 0x088 */
#define FBNIC_QUEUE_TWQ1_BAH		0x023		/* 0x08c */

/* Tx Work Queue Statistics Registers */
#define FBNIC_QUEUE_TWQ0_PKT_CNT	0x062		/* 0x188 */
#define FBNIC_QUEUE_TWQ0_ERR_CNT	0x063		/* 0x18c */
#define FBNIC_QUEUE_TWQ1_PKT_CNT	0x072		/* 0x1c8 */
#define FBNIC_QUEUE_TWQ1_ERR_CNT	0x073		/* 0x1cc */

/* Tx Completion Queue Registers */
#define FBNIC_QUEUE_TCQ_CTL		0x080		/* 0x200 */
#define FBNIC_QUEUE_TCQ_CTL_RESET		CSR_BIT(0)
@@ -953,6 +959,12 @@ enum {
	FBNIC_QUEUE_RDE_CTL1_PAYLD_PACK_RSS	= 2,
};

/* Rx Per CQ Statistics Counters */
#define FBNIC_QUEUE_RDE_PKT_CNT		0x2a2		/* 0xa88 */
#define FBNIC_QUEUE_RDE_PKT_ERR_CNT	0x2a3		/* 0xa8c */
#define FBNIC_QUEUE_RDE_CQ_DROP_CNT	0x2a4		/* 0xa90 */
#define FBNIC_QUEUE_RDE_BDQ_DROP_CNT	0x2a5		/* 0xa94 */

/* Rx Interrupt Manager Registers */
#define FBNIC_QUEUE_RIM_CTL		0x2c0		/* 0xb00 */
#define FBNIC_QUEUE_RIM_CTL_MSIX_MASK		CSR_GENMASK(7, 0)
+48 −7
Original line number Diff line number Diff line
@@ -39,7 +39,20 @@ static const struct fbnic_stat fbnic_gstrings_hw_stats[] = {
};

#define FBNIC_HW_FIXED_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_stats)
#define FBNIC_HW_STATS_LEN	FBNIC_HW_FIXED_STATS_LEN

#define FBNIC_HW_Q_STAT(name, stat) \
	FBNIC_STAT_FIELDS(fbnic_hw_q_stats, name, stat.value)

static const struct fbnic_stat fbnic_gstrings_hw_q_stats[] = {
	FBNIC_HW_Q_STAT("rde_%u_pkt_err", rde_pkt_err),
	FBNIC_HW_Q_STAT("rde_%u_pkt_cq_drop", rde_pkt_cq_drop),
	FBNIC_HW_Q_STAT("rde_%u_pkt_bdq_drop", rde_pkt_bdq_drop),
};

#define FBNIC_HW_Q_STATS_LEN ARRAY_SIZE(fbnic_gstrings_hw_q_stats)
#define FBNIC_HW_STATS_LEN \
	(FBNIC_HW_FIXED_STATS_LEN + \
	 FBNIC_HW_Q_STATS_LEN * FBNIC_MAX_QUEUES)

static void
fbnic_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
@@ -300,29 +313,57 @@ fbnic_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring,

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

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

		for (idx = 0; idx < FBNIC_MAX_QUEUES; idx++) {
			stat = fbnic_gstrings_hw_q_stats;

			for (i = 0; i < FBNIC_HW_Q_STATS_LEN; i++, stat++)
				ethtool_sprintf(&data, stat->string, idx);
		}
		break;
	}
}

static void fbnic_report_hw_stats(const struct fbnic_stat *stat,
				  const void *base, int len, u64 **data)
{
	while (len--) {
		u8 *curr = (u8 *)base + stat->offset;

		**data = *(u64 *)curr;

		stat++;
		(*data)++;
	}
}

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;
	struct fbnic_dev *fbd = fbn->fbd;
	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);
	spin_lock(&fbd->hw_stats_lock);
	fbnic_report_hw_stats(fbnic_gstrings_hw_stats, &fbd->hw_stats,
			      FBNIC_HW_FIXED_STATS_LEN, &data);

	for (i  = 0; i < FBNIC_MAX_QUEUES; i++) {
		const struct fbnic_hw_q_stats *hw_q = &fbd->hw_stats.hw_q[i];

		fbnic_report_hw_stats(fbnic_gstrings_hw_q_stats, hw_q,
				      FBNIC_HW_Q_STATS_LEN, &data);
	}
	spin_unlock(&fbd->hw_stats_lock);
}

static int fbnic_get_sset_count(struct net_device *dev, int sset)
+50 −0
Original line number Diff line number Diff line
@@ -117,6 +117,54 @@ static void fbnic_get_rpc_stats32(struct fbnic_dev *fbd,
			   &rpc->ovr_size_err);
}

static void fbnic_reset_hw_rxq_stats(struct fbnic_dev *fbd,
				     struct fbnic_hw_q_stats *hw_q)
{
	int i;

	for (i = 0; i < fbd->max_num_queues; i++, hw_q++) {
		u32 base = FBNIC_QUEUE(i);

		fbnic_hw_stat_rst32(fbd,
				    base + FBNIC_QUEUE_RDE_PKT_ERR_CNT,
				    &hw_q->rde_pkt_err);
		fbnic_hw_stat_rst32(fbd,
				    base + FBNIC_QUEUE_RDE_CQ_DROP_CNT,
				    &hw_q->rde_pkt_cq_drop);
		fbnic_hw_stat_rst32(fbd,
				    base + FBNIC_QUEUE_RDE_BDQ_DROP_CNT,
				    &hw_q->rde_pkt_bdq_drop);
	}
}

static void fbnic_get_hw_rxq_stats32(struct fbnic_dev *fbd,
				     struct fbnic_hw_q_stats *hw_q)
{
	int i;

	for (i = 0; i < fbd->max_num_queues; i++, hw_q++) {
		u32 base = FBNIC_QUEUE(i);

		fbnic_hw_stat_rd32(fbd,
				   base + FBNIC_QUEUE_RDE_PKT_ERR_CNT,
				   &hw_q->rde_pkt_err);
		fbnic_hw_stat_rd32(fbd,
				   base + FBNIC_QUEUE_RDE_CQ_DROP_CNT,
				   &hw_q->rde_pkt_cq_drop);
		fbnic_hw_stat_rd32(fbd,
				   base + FBNIC_QUEUE_RDE_BDQ_DROP_CNT,
				   &hw_q->rde_pkt_bdq_drop);
	}
}

void fbnic_get_hw_q_stats(struct fbnic_dev *fbd,
			  struct fbnic_hw_q_stats *hw_q)
{
	spin_lock(&fbd->hw_stats_lock);
	fbnic_get_hw_rxq_stats32(fbd, hw_q);
	spin_unlock(&fbd->hw_stats_lock);
}

static void fbnic_reset_pcie_stats_asic(struct fbnic_dev *fbd,
					struct fbnic_pcie_stats *pcie)
{
@@ -205,6 +253,7 @@ void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
{
	spin_lock(&fbd->hw_stats_lock);
	fbnic_reset_rpc_stats(fbd, &fbd->hw_stats.rpc);
	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);
}
@@ -212,6 +261,7 @@ void fbnic_reset_hw_stats(struct fbnic_dev *fbd)
static void __fbnic_get_hw_stats32(struct fbnic_dev *fbd)
{
	fbnic_get_rpc_stats32(fbd, &fbd->hw_stats.rpc);
	fbnic_get_hw_rxq_stats32(fbd, fbd->hw_stats.hw_q);
}

void fbnic_get_hw_stats32(struct fbnic_dev *fbd)
+9 −0
Original line number Diff line number Diff line
@@ -43,6 +43,12 @@ struct fbnic_rpc_stats {
	struct fbnic_stat_counter tcp_opt_err, out_of_hdr_err, ovr_size_err;
};

struct fbnic_hw_q_stats {
	struct fbnic_stat_counter rde_pkt_err;
	struct fbnic_stat_counter rde_pkt_cq_drop;
	struct fbnic_stat_counter rde_pkt_bdq_drop;
};

struct fbnic_pcie_stats {
	struct fbnic_stat_counter ob_rd_tlp, ob_rd_dword;
	struct fbnic_stat_counter ob_wr_tlp, ob_wr_dword;
@@ -56,12 +62,15 @@ struct fbnic_pcie_stats {
struct fbnic_hw_stats {
	struct fbnic_mac_stats mac;
	struct fbnic_rpc_stats rpc;
	struct fbnic_hw_q_stats hw_q[FBNIC_MAX_QUEUES];
	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_q_stats(struct fbnic_dev *fbd,
			  struct fbnic_hw_q_stats *hw_q);
void fbnic_get_hw_stats32(struct fbnic_dev *fbd);
void fbnic_get_hw_stats(struct fbnic_dev *fbd);

Loading