Commit 550ee90a authored by MD Danish Anwar's avatar MD Danish Anwar Committed by Jakub Kicinski
Browse files

net: ti: icssg-prueth: Add support for PA Stats



Add support for dumping PA stats registers via ethtool.
Firmware maintained stats are stored at PA Stats registers.
Also modify emac_get_strings() API to use ethtool_puts().

This commit also maintains consistency between miig_stats and pa_stats by
- renaming the array icssg_all_stats to icssg_all_miig_stats
- renaming the structure icssg_stats to icssg_miig_stats
- renaming ICSSG_STATS() to ICSSG_MIIG_STATS()
- changing order of stats related data structures and arrays so that data
  structures of a certain stats type is clubbed together.

Signed-off-by: default avatarMD Danish Anwar <danishanwar@ti.com>
Link: https://patch.msgid.link/20240822122652.1071801-3-danishanwar@ti.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent be91edc8
Loading
Loading
Loading
Loading
+10 −9
Original line number Diff line number Diff line
@@ -83,13 +83,11 @@ static void emac_get_strings(struct net_device *ndev, u32 stringset, u8 *data)

	switch (stringset) {
	case ETH_SS_STATS:
		for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
			if (!icssg_all_stats[i].standard_stats) {
				memcpy(p, icssg_all_stats[i].name,
				       ETH_GSTRING_LEN);
				p += ETH_GSTRING_LEN;
			}
		}
		for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
			if (!icssg_all_miig_stats[i].standard_stats)
				ethtool_puts(&p, icssg_all_miig_stats[i].name);
		for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
			ethtool_puts(&p, icssg_all_pa_stats[i].name);
		break;
	default:
		break;
@@ -104,9 +102,12 @@ static void emac_get_ethtool_stats(struct net_device *ndev,

	emac_update_hardware_stats(emac);

	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
		if (!icssg_all_stats[i].standard_stats)
	for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++)
		if (!icssg_all_miig_stats[i].standard_stats)
			*(data++) = emac->stats[i];

	for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++)
		*(data++) = emac->pa_stats[i];
}

static int emac_get_ts_info(struct net_device *ndev,
+6 −0
Original line number Diff line number Diff line
@@ -1182,6 +1182,12 @@ static int prueth_probe(struct platform_device *pdev)
		return -ENODEV;
	}

	prueth->pa_stats = syscon_regmap_lookup_by_phandle(np, "ti,pa-stats");
	if (IS_ERR(prueth->pa_stats)) {
		dev_err(dev, "couldn't get ti,pa-stats syscon regmap\n");
		return -ENODEV;
	}

	if (eth0_node) {
		ret = prueth_get_cores(prueth, ICSS_SLICE0, false);
		if (ret)
+7 −2
Original line number Diff line number Diff line
@@ -50,8 +50,10 @@

#define ICSSG_MAX_RFLOWS	8	/* per slice */

#define ICSSG_NUM_PA_STATS	4
#define ICSSG_NUM_MIIG_STATS	60
/* Number of ICSSG related stats */
#define ICSSG_NUM_STATS 60
#define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
#define ICSSG_NUM_STANDARD_STATS 31
#define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)

@@ -190,7 +192,8 @@ struct prueth_emac {
	int port_vlan;

	struct delayed_work stats_work;
	u64 stats[ICSSG_NUM_STATS];
	u64 stats[ICSSG_NUM_MIIG_STATS];
	u64 pa_stats[ICSSG_NUM_PA_STATS];

	/* RX IRQ Coalescing Related */
	struct hrtimer rx_hrtimer;
@@ -230,6 +233,7 @@ struct icssg_firmwares {
 * @registered_netdevs: list of registered netdevs
 * @miig_rt: regmap to mii_g_rt block
 * @mii_rt: regmap to mii_rt block
 * @pa_stats: regmap to pa_stats block
 * @pru_id: ID for each of the PRUs
 * @pdev: pointer to ICSSG platform device
 * @pdata: pointer to platform data for ICSSG driver
@@ -263,6 +267,7 @@ struct prueth {
	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
	struct regmap *miig_rt;
	struct regmap *mii_rt;
	struct regmap *pa_stats;

	enum pruss_pru_id pru_id[PRUSS_NUM_PRUS];
	struct platform_device *pdev;
+22 −9
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@

#define ICSSG_TX_PACKET_OFFSET	0xA0
#define ICSSG_TX_BYTE_OFFSET	0xEC
#define ICSSG_FW_STATS_BASE	0x0248

static u32 stats_base[] = {	0x54c,	/* Slice 0 stats start */
				0xb18,	/* Slice 1 stats start */
@@ -22,24 +23,31 @@ void emac_update_hardware_stats(struct prueth_emac *emac)
	int slice = prueth_emac_slice(emac);
	u32 base = stats_base[slice];
	u32 tx_pkt_cnt = 0;
	u32 val;
	u32 val, reg;
	int i;

	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
	for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
		regmap_read(prueth->miig_rt,
			    base + icssg_all_stats[i].offset,
			    base + icssg_all_miig_stats[i].offset,
			    &val);
		regmap_write(prueth->miig_rt,
			     base + icssg_all_stats[i].offset,
			     base + icssg_all_miig_stats[i].offset,
			     val);

		if (icssg_all_stats[i].offset == ICSSG_TX_PACKET_OFFSET)
		if (icssg_all_miig_stats[i].offset == ICSSG_TX_PACKET_OFFSET)
			tx_pkt_cnt = val;

		emac->stats[i] += val;
		if (icssg_all_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
		if (icssg_all_miig_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
			emac->stats[i] -= tx_pkt_cnt * 8;
	}

	for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) {
		reg = ICSSG_FW_STATS_BASE + icssg_all_pa_stats[i].offset *
		      PRUETH_NUM_MACS + slice * sizeof(u32);
		regmap_read(prueth->pa_stats, reg, &val);
		emac->pa_stats[i] += val;
	}
}

void icssg_stats_work_handler(struct work_struct *work)
@@ -57,9 +65,14 @@ int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
{
	int i;

	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
		if (!strcmp(icssg_all_stats[i].name, stat_name))
			return emac->stats[icssg_all_stats[i].offset / sizeof(u32)];
	for (i = 0; i < ARRAY_SIZE(icssg_all_miig_stats); i++) {
		if (!strcmp(icssg_all_miig_stats[i].name, stat_name))
			return emac->stats[icssg_all_miig_stats[i].offset / sizeof(u32)];
	}

	for (i = 0; i < ARRAY_SIZE(icssg_all_pa_stats); i++) {
		if (!strcmp(icssg_all_pa_stats[i].name, stat_name))
			return emac->pa_stats[icssg_all_pa_stats[i].offset / sizeof(u32)];
	}

	netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
+95 −63
Original line number Diff line number Diff line
@@ -77,82 +77,114 @@ struct miig_stats_regs {
	u32 tx_bytes;
};

#define ICSSG_STATS(field, stats_type)			\
#define ICSSG_MIIG_STATS(field, stats_type)			\
{							\
	#field,						\
	offsetof(struct miig_stats_regs, field),	\
	stats_type					\
}

struct icssg_stats {
struct icssg_miig_stats {
	char name[ETH_GSTRING_LEN];
	u32 offset;
	bool standard_stats;
};

static const struct icssg_stats icssg_all_stats[] = {
static const struct icssg_miig_stats icssg_all_miig_stats[] = {
	/* Rx */
	ICSSG_STATS(rx_packets, true),
	ICSSG_STATS(rx_broadcast_frames, false),
	ICSSG_STATS(rx_multicast_frames, true),
	ICSSG_STATS(rx_crc_errors, true),
	ICSSG_STATS(rx_mii_error_frames, false),
	ICSSG_STATS(rx_odd_nibble_frames, false),
	ICSSG_STATS(rx_frame_max_size, true),
	ICSSG_STATS(rx_max_size_error_frames, false),
	ICSSG_STATS(rx_frame_min_size, true),
	ICSSG_STATS(rx_min_size_error_frames, false),
	ICSSG_STATS(rx_over_errors, true),
	ICSSG_STATS(rx_class0_hits, false),
	ICSSG_STATS(rx_class1_hits, false),
	ICSSG_STATS(rx_class2_hits, false),
	ICSSG_STATS(rx_class3_hits, false),
	ICSSG_STATS(rx_class4_hits, false),
	ICSSG_STATS(rx_class5_hits, false),
	ICSSG_STATS(rx_class6_hits, false),
	ICSSG_STATS(rx_class7_hits, false),
	ICSSG_STATS(rx_class8_hits, false),
	ICSSG_STATS(rx_class9_hits, false),
	ICSSG_STATS(rx_class10_hits, false),
	ICSSG_STATS(rx_class11_hits, false),
	ICSSG_STATS(rx_class12_hits, false),
	ICSSG_STATS(rx_class13_hits, false),
	ICSSG_STATS(rx_class14_hits, false),
	ICSSG_STATS(rx_class15_hits, false),
	ICSSG_STATS(rx_smd_frags, false),
	ICSSG_STATS(rx_bucket1_size, true),
	ICSSG_STATS(rx_bucket2_size, true),
	ICSSG_STATS(rx_bucket3_size, true),
	ICSSG_STATS(rx_bucket4_size, true),
	ICSSG_STATS(rx_64B_frames, true),
	ICSSG_STATS(rx_bucket1_frames, true),
	ICSSG_STATS(rx_bucket2_frames, true),
	ICSSG_STATS(rx_bucket3_frames, true),
	ICSSG_STATS(rx_bucket4_frames, true),
	ICSSG_STATS(rx_bucket5_frames, true),
	ICSSG_STATS(rx_bytes, true),
	ICSSG_STATS(rx_tx_total_bytes, false),
	ICSSG_MIIG_STATS(rx_packets, true),
	ICSSG_MIIG_STATS(rx_broadcast_frames, false),
	ICSSG_MIIG_STATS(rx_multicast_frames, true),
	ICSSG_MIIG_STATS(rx_crc_errors, true),
	ICSSG_MIIG_STATS(rx_mii_error_frames, false),
	ICSSG_MIIG_STATS(rx_odd_nibble_frames, false),
	ICSSG_MIIG_STATS(rx_frame_max_size, true),
	ICSSG_MIIG_STATS(rx_max_size_error_frames, false),
	ICSSG_MIIG_STATS(rx_frame_min_size, true),
	ICSSG_MIIG_STATS(rx_min_size_error_frames, false),
	ICSSG_MIIG_STATS(rx_over_errors, true),
	ICSSG_MIIG_STATS(rx_class0_hits, false),
	ICSSG_MIIG_STATS(rx_class1_hits, false),
	ICSSG_MIIG_STATS(rx_class2_hits, false),
	ICSSG_MIIG_STATS(rx_class3_hits, false),
	ICSSG_MIIG_STATS(rx_class4_hits, false),
	ICSSG_MIIG_STATS(rx_class5_hits, false),
	ICSSG_MIIG_STATS(rx_class6_hits, false),
	ICSSG_MIIG_STATS(rx_class7_hits, false),
	ICSSG_MIIG_STATS(rx_class8_hits, false),
	ICSSG_MIIG_STATS(rx_class9_hits, false),
	ICSSG_MIIG_STATS(rx_class10_hits, false),
	ICSSG_MIIG_STATS(rx_class11_hits, false),
	ICSSG_MIIG_STATS(rx_class12_hits, false),
	ICSSG_MIIG_STATS(rx_class13_hits, false),
	ICSSG_MIIG_STATS(rx_class14_hits, false),
	ICSSG_MIIG_STATS(rx_class15_hits, false),
	ICSSG_MIIG_STATS(rx_smd_frags, false),
	ICSSG_MIIG_STATS(rx_bucket1_size, true),
	ICSSG_MIIG_STATS(rx_bucket2_size, true),
	ICSSG_MIIG_STATS(rx_bucket3_size, true),
	ICSSG_MIIG_STATS(rx_bucket4_size, true),
	ICSSG_MIIG_STATS(rx_64B_frames, true),
	ICSSG_MIIG_STATS(rx_bucket1_frames, true),
	ICSSG_MIIG_STATS(rx_bucket2_frames, true),
	ICSSG_MIIG_STATS(rx_bucket3_frames, true),
	ICSSG_MIIG_STATS(rx_bucket4_frames, true),
	ICSSG_MIIG_STATS(rx_bucket5_frames, true),
	ICSSG_MIIG_STATS(rx_bytes, true),
	ICSSG_MIIG_STATS(rx_tx_total_bytes, false),
	/* Tx */
	ICSSG_STATS(tx_packets, true),
	ICSSG_STATS(tx_broadcast_frames, false),
	ICSSG_STATS(tx_multicast_frames, false),
	ICSSG_STATS(tx_odd_nibble_frames, false),
	ICSSG_STATS(tx_underflow_errors, false),
	ICSSG_STATS(tx_frame_max_size, true),
	ICSSG_STATS(tx_max_size_error_frames, false),
	ICSSG_STATS(tx_frame_min_size, true),
	ICSSG_STATS(tx_min_size_error_frames, false),
	ICSSG_STATS(tx_bucket1_size, true),
	ICSSG_STATS(tx_bucket2_size, true),
	ICSSG_STATS(tx_bucket3_size, true),
	ICSSG_STATS(tx_bucket4_size, true),
	ICSSG_STATS(tx_64B_frames, true),
	ICSSG_STATS(tx_bucket1_frames, true),
	ICSSG_STATS(tx_bucket2_frames, true),
	ICSSG_STATS(tx_bucket3_frames, true),
	ICSSG_STATS(tx_bucket4_frames, true),
	ICSSG_STATS(tx_bucket5_frames, true),
	ICSSG_STATS(tx_bytes, true),
	ICSSG_MIIG_STATS(tx_packets, true),
	ICSSG_MIIG_STATS(tx_broadcast_frames, false),
	ICSSG_MIIG_STATS(tx_multicast_frames, false),
	ICSSG_MIIG_STATS(tx_odd_nibble_frames, false),
	ICSSG_MIIG_STATS(tx_underflow_errors, false),
	ICSSG_MIIG_STATS(tx_frame_max_size, true),
	ICSSG_MIIG_STATS(tx_max_size_error_frames, false),
	ICSSG_MIIG_STATS(tx_frame_min_size, true),
	ICSSG_MIIG_STATS(tx_min_size_error_frames, false),
	ICSSG_MIIG_STATS(tx_bucket1_size, true),
	ICSSG_MIIG_STATS(tx_bucket2_size, true),
	ICSSG_MIIG_STATS(tx_bucket3_size, true),
	ICSSG_MIIG_STATS(tx_bucket4_size, true),
	ICSSG_MIIG_STATS(tx_64B_frames, true),
	ICSSG_MIIG_STATS(tx_bucket1_frames, true),
	ICSSG_MIIG_STATS(tx_bucket2_frames, true),
	ICSSG_MIIG_STATS(tx_bucket3_frames, true),
	ICSSG_MIIG_STATS(tx_bucket4_frames, true),
	ICSSG_MIIG_STATS(tx_bucket5_frames, true),
	ICSSG_MIIG_STATS(tx_bytes, true),
};

/**
 * struct pa_stats_regs - ICSSG Firmware maintained PA Stats register
 * @fw_rx_cnt: Number of valid packets sent by Rx PRU to Host on PSI
 * @fw_tx_cnt: Number of valid packets copied by RTU0 to Tx queues
 * @fw_tx_pre_overflow: Host Egress Q (Pre-emptible) Overflow Counter
 * @fw_tx_exp_overflow: Host Egress Q (Express) Overflow Counter
 */
struct pa_stats_regs {
	u32 fw_rx_cnt;
	u32 fw_tx_cnt;
	u32 fw_tx_pre_overflow;
	u32 fw_tx_exp_overflow;
};

#define ICSSG_PA_STATS(field)			\
{						\
	#field,					\
	offsetof(struct pa_stats_regs, field),	\
}

struct icssg_pa_stats {
	char name[ETH_GSTRING_LEN];
	u32 offset;
};

static const struct icssg_pa_stats icssg_all_pa_stats[] = {
	ICSSG_PA_STATS(fw_rx_cnt),
	ICSSG_PA_STATS(fw_tx_cnt),
	ICSSG_PA_STATS(fw_tx_pre_overflow),
	ICSSG_PA_STATS(fw_tx_exp_overflow),
};

#endif /* __NET_TI_ICSSG_STATS_H */