diff mbox series

[net-next,v5,2/2] net: ti: icssg-prueth: Add support for PA Stats

Message ID 20240814092033.2984734-3-danishanwar@ti.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Add support for ICSSG PA_STATS | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 7 this patch: 7
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 7 this patch: 7
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 7 this patch: 7
netdev/checkpatch warning WARNING: line length of 91 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc fail Errors and warnings before: 0 this patch: 5
netdev/source_inline success Was 0 now: 0

Commit Message

MD Danish Anwar Aug. 14, 2024, 9:20 a.m. UTC
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().

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 17 +++++-----
 drivers/net/ethernet/ti/icssg/icssg_prueth.c  |  6 ++++
 drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  5 ++-
 drivers/net/ethernet/ti/icssg/icssg_stats.c   | 19 +++++++++--
 drivers/net/ethernet/ti/icssg/icssg_stats.h   | 32 +++++++++++++++++++
 5 files changed, 67 insertions(+), 12 deletions(-)

Comments

Dan Carpenter Aug. 15, 2024, 11:28 a.m. UTC | #1
On Wed, Aug 14, 2024 at 02:50:33PM +0530, MD Danish Anwar wrote:
> 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().
> 
> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
> ---
>  drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 17 +++++-----
>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  |  6 ++++
>  drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  5 ++-
>  drivers/net/ethernet/ti/icssg/icssg_stats.c   | 19 +++++++++--
>  drivers/net/ethernet/ti/icssg/icssg_stats.h   | 32 +++++++++++++++++++
>  5 files changed, 67 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> index 5688f054cec5..51bb509d37c7 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
> @@ -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_stats); i++)
> +			if (!icssg_all_stats[i].standard_stats)
> +				ethtool_puts(&p, icssg_all_stats[i].name);
> +		for (i = 0; i < ICSSG_NUM_PA_STATS; i++)

It would probably be better to use ARRAY_SIZE(icssg_all_pa_stats) so that it's
consistent with the loop right before.

> +			ethtool_puts(&p, icssg_all_pa_stats[i].name);
>  		break;
>  	default:
>  		break;
> @@ -100,13 +98,16 @@ static void emac_get_ethtool_stats(struct net_device *ndev,
>  				   struct ethtool_stats *stats, u64 *data)
>  {
>  	struct prueth_emac *emac = netdev_priv(ndev);
> -	int i;
> +	int i, j;
>  
>  	emac_update_hardware_stats(emac);
>  
>  	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
>  		if (!icssg_all_stats[i].standard_stats)
>  			*(data++) = emac->stats[i];
> +
> +	for (j = 0; j < ICSSG_NUM_PA_STATS; j++)
> +		*(data++) = emac->stats[i + j];

Here i is not an iterator.  It's a stand in for ARRAY_SIZE(icssg_all_stats).
It would be more readable to do that directly.

	for (i = 0; i < ICSSG_NUM_PA_STATS; i++)
		*(data++) = emac->stats[ARRAY_SIZE(icssg_all_stats) + i];

To be honest, putting the pa_stats at the end of ->stats would have made sense
if we could have looped over the whole array, but since they have to be treated
differently we should probably just put them into their own ->pa_stats array.

I haven't tested this so maybe I've missed something obvious.

The "all" in "icssg_all_stats" doesn't really make sense anymore btw...

Sorry for being so nit picky on a v5 patch. :(

regards,
dan carpenter
Simon Horman Aug. 15, 2024, 4:01 p.m. UTC | #2
On Wed, Aug 14, 2024 at 02:50:33PM +0530, MD Danish Anwar wrote:

...

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
> index f678d656a3ed..ac2291d22c42 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
> @@ -50,8 +50,10 @@
>  
>  #define ICSSG_MAX_RFLOWS	8	/* per slice */
>  
> +#define ICSSG_NUM_PA_STATS 4
> +#define ICSSG_NUM_MII_G_RT_STATS 60
>  /* Number of ICSSG related stats */
> -#define ICSSG_NUM_STATS 60
> +#define ICSSG_NUM_STATS (ICSSG_NUM_MII_G_RT_STATS + ICSSG_NUM_PA_STATS)
>  #define ICSSG_NUM_STANDARD_STATS 31
>  #define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
>  
> @@ -263,6 +265,7 @@ struct prueth {
>  	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
>  	struct regmap *miig_rt;
>  	struct regmap *mii_rt;
> +	struct regmap *pa_stats;

Please add an entry for pa_stats to the Kernel doc for this structure.

>  
>  	enum pruss_pru_id pru_id[PRUSS_NUM_PRUS];
>  	struct platform_device *pdev;

...

> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
> index 999a4a91276c..e834316092c9 100644
> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
> @@ -77,6 +77,20 @@ struct miig_stats_regs {
>  	u32 tx_bytes;
>  };
>  
> +/**
> + * struct pa_stats_regs - ICSSG Firmware maintained PA Stats register
> + * @u32 fw_rx_cnt: Number of valid packets sent by Rx PRU to Host on PSI
> + * @u32 fw_tx_cnt: Number of valid packets copied by RTU0 to Tx queues
> + * @u32 fw_tx_pre_overflow: Host Egress Q (Pre-emptible) Overflow Counter
> + * @u32 fw_tx_exp_overflow: Host Egress Q (Express) Overflow Counter
> + */

./scripts/kernel-doc -none doesn't seem to like the syntax above.
Perhaps s/u32 // ?

> +struct pa_stats_regs {
> +	u32 fw_rx_cnt;
> +	u32 fw_tx_cnt;
> +	u32 fw_tx_pre_overflow;
> +	u32 fw_tx_exp_overflow;
> +};
> +
>  #define ICSSG_STATS(field, stats_type)			\
>  {							\
>  	#field,						\

...
Anwar, Md Danish Aug. 19, 2024, 7:10 a.m. UTC | #3
On 8/15/2024 9:31 PM, Simon Horman wrote:
> On Wed, Aug 14, 2024 at 02:50:33PM +0530, MD Danish Anwar wrote:
> 
> ...
> 
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> index f678d656a3ed..ac2291d22c42 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
>> @@ -50,8 +50,10 @@
>>  
>>  #define ICSSG_MAX_RFLOWS	8	/* per slice */
>>  
>> +#define ICSSG_NUM_PA_STATS 4
>> +#define ICSSG_NUM_MII_G_RT_STATS 60
>>  /* Number of ICSSG related stats */
>> -#define ICSSG_NUM_STATS 60
>> +#define ICSSG_NUM_STATS (ICSSG_NUM_MII_G_RT_STATS + ICSSG_NUM_PA_STATS)
>>  #define ICSSG_NUM_STANDARD_STATS 31
>>  #define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
>>  
>> @@ -263,6 +265,7 @@ struct prueth {
>>  	struct net_device *registered_netdevs[PRUETH_NUM_MACS];
>>  	struct regmap *miig_rt;
>>  	struct regmap *mii_rt;
>> +	struct regmap *pa_stats;
> 
> Please add an entry for pa_stats to the Kernel doc for this structure.
> 
>>  
>>  	enum pruss_pru_id pru_id[PRUSS_NUM_PRUS];
>>  	struct platform_device *pdev;
> 
> ...
> 
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> index 999a4a91276c..e834316092c9 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
>> @@ -77,6 +77,20 @@ struct miig_stats_regs {
>>  	u32 tx_bytes;
>>  };
>>  
>> +/**
>> + * struct pa_stats_regs - ICSSG Firmware maintained PA Stats register
>> + * @u32 fw_rx_cnt: Number of valid packets sent by Rx PRU to Host on PSI
>> + * @u32 fw_tx_cnt: Number of valid packets copied by RTU0 to Tx queues
>> + * @u32 fw_tx_pre_overflow: Host Egress Q (Pre-emptible) Overflow Counter
>> + * @u32 fw_tx_exp_overflow: Host Egress Q (Express) Overflow Counter
>> + */
> 
> ./scripts/kernel-doc -none doesn't seem to like the syntax above.
> Perhaps s/u32 // ?

Sure, I will drop u32 from comment.

> 
>> +struct pa_stats_regs {
>> +	u32 fw_rx_cnt;
>> +	u32 fw_tx_cnt;
>> +	u32 fw_tx_pre_overflow;
>> +	u32 fw_tx_exp_overflow;
>> +};
>> +
>>  #define ICSSG_STATS(field, stats_type)			\
>>  {							\
>>  	#field,						\
> 
> ...
Anwar, Md Danish Aug. 19, 2024, 7:15 a.m. UTC | #4
On 8/15/2024 4:58 PM, Dan Carpenter wrote:
> On Wed, Aug 14, 2024 at 02:50:33PM +0530, MD Danish Anwar wrote:
>> 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().
>>
>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>> ---
>>  drivers/net/ethernet/ti/icssg/icssg_ethtool.c | 17 +++++-----
>>  drivers/net/ethernet/ti/icssg/icssg_prueth.c  |  6 ++++
>>  drivers/net/ethernet/ti/icssg/icssg_prueth.h  |  5 ++-
>>  drivers/net/ethernet/ti/icssg/icssg_stats.c   | 19 +++++++++--
>>  drivers/net/ethernet/ti/icssg/icssg_stats.h   | 32 +++++++++++++++++++
>>  5 files changed, 67 insertions(+), 12 deletions(-)
>>
>> diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
>> index 5688f054cec5..51bb509d37c7 100644
>> --- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
>> +++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
>> @@ -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_stats); i++)
>> +			if (!icssg_all_stats[i].standard_stats)
>> +				ethtool_puts(&p, icssg_all_stats[i].name);
>> +		for (i = 0; i < ICSSG_NUM_PA_STATS; i++)
> 
> It would probably be better to use ARRAY_SIZE(icssg_all_pa_stats) so that it's
> consistent with the loop right before.

Sure Dan.

> 
>> +			ethtool_puts(&p, icssg_all_pa_stats[i].name);
>>  		break;
>>  	default:
>>  		break;
>> @@ -100,13 +98,16 @@ static void emac_get_ethtool_stats(struct net_device *ndev,
>>  				   struct ethtool_stats *stats, u64 *data)
>>  {
>>  	struct prueth_emac *emac = netdev_priv(ndev);
>> -	int i;
>> +	int i, j;
>>  
>>  	emac_update_hardware_stats(emac);
>>  
>>  	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
>>  		if (!icssg_all_stats[i].standard_stats)
>>  			*(data++) = emac->stats[i];
>> +
>> +	for (j = 0; j < ICSSG_NUM_PA_STATS; j++)
>> +		*(data++) = emac->stats[i + j];
> 
> Here i is not an iterator.  It's a stand in for ARRAY_SIZE(icssg_all_stats).
> It would be more readable to do that directly.
> 
> 	for (i = 0; i < ICSSG_NUM_PA_STATS; i++)
> 		*(data++) = emac->stats[ARRAY_SIZE(icssg_all_stats) + i];
> 
> To be honest, putting the pa_stats at the end of ->stats would have made sense
> if we could have looped over the whole array, but since they have to be treated
> differently we should probably just put them into their own ->pa_stats array.
> 

Sure Dan. It will make more sense to have different array for pa_stats.
I will do this change and update.

> I haven't tested this so maybe I've missed something obvious.
> 
> The "all" in "icssg_all_stats" doesn't really make sense anymore btw...
> 

Correct, the "icssg_all_stats" should be renamed to "icssg_mii_g_rt_stats".

> Sorry for being so nit picky on a v5 patch. :(
> 

It's okay. Thanks for the review. I will address all these comments and
send out a v6.

> regards,
> dan carpenter
>
diff mbox series

Patch

diff --git a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
index 5688f054cec5..51bb509d37c7 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_ethtool.c
@@ -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_stats); i++)
+			if (!icssg_all_stats[i].standard_stats)
+				ethtool_puts(&p, icssg_all_stats[i].name);
+		for (i = 0; i < ICSSG_NUM_PA_STATS; i++)
+			ethtool_puts(&p, icssg_all_pa_stats[i].name);
 		break;
 	default:
 		break;
@@ -100,13 +98,16 @@  static void emac_get_ethtool_stats(struct net_device *ndev,
 				   struct ethtool_stats *stats, u64 *data)
 {
 	struct prueth_emac *emac = netdev_priv(ndev);
-	int i;
+	int i, j;
 
 	emac_update_hardware_stats(emac);
 
 	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++)
 		if (!icssg_all_stats[i].standard_stats)
 			*(data++) = emac->stats[i];
+
+	for (j = 0; j < ICSSG_NUM_PA_STATS; j++)
+		*(data++) = emac->stats[i + j];
 }
 
 static int emac_get_ts_info(struct net_device *ndev,
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.c b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
index 53a3e44b99a2..f623a0f603fc 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.c
@@ -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)
diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index f678d656a3ed..ac2291d22c42 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -50,8 +50,10 @@ 
 
 #define ICSSG_MAX_RFLOWS	8	/* per slice */
 
+#define ICSSG_NUM_PA_STATS 4
+#define ICSSG_NUM_MII_G_RT_STATS 60
 /* Number of ICSSG related stats */
-#define ICSSG_NUM_STATS 60
+#define ICSSG_NUM_STATS (ICSSG_NUM_MII_G_RT_STATS + ICSSG_NUM_PA_STATS)
 #define ICSSG_NUM_STANDARD_STATS 31
 #define ICSSG_NUM_ETHTOOL_STATS (ICSSG_NUM_STATS - ICSSG_NUM_STANDARD_STATS)
 
@@ -263,6 +265,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;
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.c b/drivers/net/ethernet/ti/icssg/icssg_stats.c
index 2fb150c13078..ce6606e4a369 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.c
@@ -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,8 +23,8 @@  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;
-	int i;
+	u32 val, reg;
+	int i, j;
 
 	for (i = 0; i < ARRAY_SIZE(icssg_all_stats); i++) {
 		regmap_read(prueth->miig_rt,
@@ -40,6 +41,13 @@  void emac_update_hardware_stats(struct prueth_emac *emac)
 		if (icssg_all_stats[i].offset == ICSSG_TX_BYTE_OFFSET)
 			emac->stats[i] -= tx_pkt_cnt * 8;
 	}
+
+	for (j = 0; j < ICSSG_NUM_PA_STATS; j++) {
+		reg = ICSSG_FW_STATS_BASE + icssg_all_pa_stats[j].offset *
+		      PRUETH_NUM_MACS + slice * sizeof(u32);
+		regmap_read(prueth->pa_stats, reg, &val);
+		emac->stats[i + j] += val;
+	}
 }
 
 void icssg_stats_work_handler(struct work_struct *work)
@@ -55,13 +63,18 @@  EXPORT_SYMBOL_GPL(icssg_stats_work_handler);
 
 int emac_get_stat_by_name(struct prueth_emac *emac, char *stat_name)
 {
-	int i;
+	int i, j;
 
 	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 (j = 0; j < ICSSG_NUM_PA_STATS; j++) {
+		if (!strcmp(icssg_all_pa_stats[j].name, stat_name))
+			return emac->stats[i + icssg_all_pa_stats[j].offset / sizeof(u32)];
+	}
+
 	netdev_err(emac->ndev, "Invalid stats %s\n", stat_name);
 	return -EINVAL;
 }
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 999a4a91276c..e834316092c9 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -77,6 +77,20 @@  struct miig_stats_regs {
 	u32 tx_bytes;
 };
 
+/**
+ * struct pa_stats_regs - ICSSG Firmware maintained PA Stats register
+ * @u32 fw_rx_cnt: Number of valid packets sent by Rx PRU to Host on PSI
+ * @u32 fw_tx_cnt: Number of valid packets copied by RTU0 to Tx queues
+ * @u32 fw_tx_pre_overflow: Host Egress Q (Pre-emptible) Overflow Counter
+ * @u32 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_STATS(field, stats_type)			\
 {							\
 	#field,						\
@@ -84,12 +98,23 @@  struct miig_stats_regs {
 	stats_type					\
 }
 
+#define ICSSG_PA_STATS(field)			\
+{						\
+	#field,					\
+	offsetof(struct pa_stats_regs, field),	\
+}
+
 struct icssg_stats {
 	char name[ETH_GSTRING_LEN];
 	u32 offset;
 	bool standard_stats;
 };
 
+struct icssg_pa_stats {
+	char name[ETH_GSTRING_LEN];
+	u32 offset;
+};
+
 static const struct icssg_stats icssg_all_stats[] = {
 	/* Rx */
 	ICSSG_STATS(rx_packets, true),
@@ -155,4 +180,11 @@  static const struct icssg_stats icssg_all_stats[] = {
 	ICSSG_STATS(tx_bytes, true),
 };
 
+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 */