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

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.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent be91edc8
......@@ -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,
......
......@@ -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)
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment