Netdev List
 help / color / mirror / Atom feed
* [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool
@ 2026-06-14 20:52 Eric Joyner
  2026-06-14 20:52 ` [PATCH net-next v5 1/5] ionic: Fix check in ionic_get_link_ext_stats Eric Joyner
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:52 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

The primary aim of this patchset is to support the reporting of new port
statistics (and one old one) that firmware sends to the driver; these
include general FEC codeword stats and the FEC histogram. A scheme for
these extra stats is introduced in order to prevent devices that don't
support these new statistics from unconditionally setting them or
reporting them in ethtool.

---
v5:
Address new Sashiko AI comments and previous feedback
patch 2:
- Remove additional unused enums that were only used by struct
  ionic_port_pb_stats
- Change IONIC_STAT_INVALID to use (~0ULL) instead of ((__le64)-1) to
  avoid sparse warnings (and moved to patch 3)
patch 4:
- Change ethtool link_down_events count to use firmware-derived value;
  handle overflow and set count to zero on driver load and resets. Finally
  drop the driver-calculated value and ethtool general stat counter and
  only report count in the ethtool extended link stat structure.
patch 5:
- Add check for NULL port_info in .get_fec_stats() callback in order to
  prevent a potential NULL pointer dereference, similar to other ethtool
  callbacks.

v4:
- A big addition is a new scheme where the driver will only report the
  new statistics supported by firmware if the firmware sets the statistic
  value to something that isn't invalid; more details in patch 3, and this
  is used in patch 5 to prevent FEC stats from being unconditionally
  reported on devices/firmware versions that don't support these stats.
- The link_down_count from firmware mentioned in v2 was moved back to an
  entry in the general ethtool statistics; the existing driver-calculated
  value for the ethtool ext link is more appropriate due to the firmware
  value being a small size and not resetting between driver loads.
- Add netdev_err_once() call recommended by Sashiko for ethtool handler
- Drop devcmd retry logic patch from previous versions for now;
  explicitly include Brett's patch from another patchset to fix the
  ionic_get_link_ext_stats() PF/VF check

v3:
Address issues mostly found by Sashiko:
- Fix potential return of uninitialized variable in __ionic_dev_cmd_wait()
- Fix bounds of wait in __ionic_dev_cmd_wait() to prevent function from
  giving up prematurely now that the wait period has changed
- Add NULL check to ionic_get_link_ext_stats(), following the example set by
  ionic_get_link_ksettings()
- Add missing le16_to_cpu() when copying link_down_count from firmware

v2:
- Add missing cpu_to_le64() to FEC histogram stat assignment
- Remove unused pb_stats field that's replaced by the new FEC/extra stats
- Replace ethtool ext link stat with firmware stat instead of adding
  the firmware stat to general ethtool statistics; remove old driver
  calculated stat
- Add explanation for what EAGAIN return value could be used for in
  commit message

Brett Creeley (1):
  ionic: Fix check in ionic_get_link_ext_stats

Eric Joyner (4):
  ionic: Update ionic_if.h with new extra port stats
  ionic: Report "rx_bits_phy" stat to ethtool
  ionic: Get "link_down_count" ext link stat from firmware
  ionic: Add .get_fec_stats ethtool handler

 .../net/ethernet/pensando/ionic/ionic_dev.c   |  10 ++
 .../net/ethernet/pensando/ionic/ionic_dev.h   |   6 +
 .../ethernet/pensando/ionic/ionic_ethtool.c   | 104 +++++++++++++++++-
 .../net/ethernet/pensando/ionic/ionic_if.h    |  64 ++---------
 .../net/ethernet/pensando/ionic/ionic_lif.c   |   4 +-
 .../net/ethernet/pensando/ionic/ionic_lif.h   |   1 -
 .../net/ethernet/pensando/ionic/ionic_main.c  |   8 ++
 .../net/ethernet/pensando/ionic/ionic_stats.c |  65 ++++++++++-
 .../net/ethernet/pensando/ionic/ionic_stats.h |   2 +
 9 files changed, 206 insertions(+), 58 deletions(-)


base-commit: 93790c374b9d77f3db15786d7d432872d92751cf
-- 
2.17.1


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH net-next v5 1/5] ionic: Fix check in ionic_get_link_ext_stats
  2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
@ 2026-06-14 20:52 ` Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 2/5] ionic: Update ionic_if.h with new extra port stats Eric Joyner
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:52 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

From: Brett Creeley <brett.creeley@amd.com>

The current check will fail if SR-IOV is not initialized for the
physical function; this is because is_physfn is 0 if sriov_init() isn't
run or fails. Change the check that prevents getting the link down count
to use is_virtfn instead so that VFs don't get this functionality, which
was the original intent.

Fixes: 132b4ebfa090 ("ionic: add support for ethtool extended stat link_down_count")
Signed-off-by: Brett Creeley <brett.creeley@amd.com>
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index 78a802eb159f..6069fa460913 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -116,8 +116,15 @@ static void ionic_get_link_ext_stats(struct net_device *netdev,
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
 
-	if (lif->ionic->pdev->is_physfn)
-		stats->link_down_events = lif->link_down_count;
+	if (lif->ionic->pdev->is_virtfn)
+		return;
+
+	if (!lif->ionic->idev.port_info) {
+		netdev_err_once(netdev, "port_info not initialized\n");
+		return;
+	}
+
+	stats->link_down_events = lif->link_down_count;
 }
 
 static int ionic_get_link_ksettings(struct net_device *netdev,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next v5 2/5] ionic: Update ionic_if.h with new extra port stats
  2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
  2026-06-14 20:52 ` [PATCH net-next v5 1/5] ionic: Fix check in ionic_get_link_ext_stats Eric Joyner
@ 2026-06-14 20:53 ` Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 3/5] ionic: Report "rx_bits_phy" stat to ethtool Eric Joyner
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

Add a new structure to report additional statistics from the firmware to
struct ionic_port_info. This new struct currently only contains FEC
related statistics, but any new port-level statistics collected by the
firmware would go into it.

The new structure is located in the same area as the unused
ionic_port_pb_stats structure, so this patch also removes that and its
supporting enumerations since they was never used in this driver.

Finally, to indicate firmware support for the new structure, introduce a
new device capability that the driver can use to see if the attached
device supports reporting these extra stats.

Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 .../net/ethernet/pensando/ionic/ionic_if.h    | 64 ++++---------------
 1 file changed, 11 insertions(+), 53 deletions(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h
index 23d6e2b4791e..0a201422d0c5 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_if.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h
@@ -273,10 +273,12 @@ union ionic_drv_identity {
  * enum ionic_dev_capability - Device capabilities
  * @IONIC_DEV_CAP_VF_CTRL:     Device supports VF ctrl operations
  * @IONIC_DEV_CAP_DISC_CMB:    Device supports CMB discovery operations
+ * @IONIC_DEV_CAP_EXTRA_STATS: Device supports extra stats schema
  */
 enum ionic_dev_capability {
 	IONIC_DEV_CAP_VF_CTRL        = BIT(0),
 	IONIC_DEV_CAP_DISC_CMB       = BIT(1),
+	IONIC_DEV_CAP_EXTRA_STATS    = BIT(4),
 };
 
 /**
@@ -2329,7 +2331,7 @@ struct ionic_qos_identify_comp {
 /* Capri max supported, should be renamed. */
 #define IONIC_QOS_CLASS_MAX		7
 #define IONIC_QOS_PCP_MAX		8
-#define IONIC_QOS_CLASS_NAME_SZ	32
+#define IONIC_QOS_CLASS_NAME_SZ		32
 #define IONIC_QOS_DSCP_MAX		64
 #define IONIC_QOS_ALL_PCP		0xFF
 #define IONIC_DSCP_BLOCK_SIZE		8
@@ -2855,54 +2857,12 @@ struct ionic_mgmt_port_stats {
 	__le64 frames_tx_pause;
 };
 
-enum ionic_pb_buffer_drop_stats {
-	IONIC_BUFFER_INTRINSIC_DROP = 0,
-	IONIC_BUFFER_DISCARDED,
-	IONIC_BUFFER_ADMITTED,
-	IONIC_BUFFER_OUT_OF_CELLS_DROP,
-	IONIC_BUFFER_OUT_OF_CELLS_DROP_2,
-	IONIC_BUFFER_OUT_OF_CREDIT_DROP,
-	IONIC_BUFFER_TRUNCATION_DROP,
-	IONIC_BUFFER_PORT_DISABLED_DROP,
-	IONIC_BUFFER_COPY_TO_CPU_TAIL_DROP,
-	IONIC_BUFFER_SPAN_TAIL_DROP,
-	IONIC_BUFFER_MIN_SIZE_VIOLATION_DROP,
-	IONIC_BUFFER_ENQUEUE_ERROR_DROP,
-	IONIC_BUFFER_INVALID_PORT_DROP,
-	IONIC_BUFFER_INVALID_OUTPUT_QUEUE_DROP,
-	IONIC_BUFFER_DROP_MAX,
-};
-
-enum ionic_oflow_drop_stats {
-	IONIC_OFLOW_OCCUPANCY_DROP,
-	IONIC_OFLOW_EMERGENCY_STOP_DROP,
-	IONIC_OFLOW_WRITE_BUFFER_ACK_FILL_UP_DROP,
-	IONIC_OFLOW_WRITE_BUFFER_ACK_FULL_DROP,
-	IONIC_OFLOW_WRITE_BUFFER_FULL_DROP,
-	IONIC_OFLOW_CONTROL_FIFO_FULL_DROP,
-	IONIC_OFLOW_DROP_MAX,
-};
-
-/* struct ionic_port_pb_stats - packet buffers system stats
- * uses ionic_pb_buffer_drop_stats for drop_counts[]
- */
-struct ionic_port_pb_stats {
-	__le64 sop_count_in;
-	__le64 eop_count_in;
-	__le64 sop_count_out;
-	__le64 eop_count_out;
-	__le64 drop_counts[IONIC_BUFFER_DROP_MAX];
-	__le64 input_queue_buffer_occupancy[IONIC_QOS_TC_MAX];
-	__le64 input_queue_port_monitor[IONIC_QOS_TC_MAX];
-	__le64 output_queue_port_monitor[IONIC_QOS_TC_MAX];
-	__le64 oflow_drop_counts[IONIC_OFLOW_DROP_MAX];
-	__le64 input_queue_good_pkts_in[IONIC_QOS_TC_MAX];
-	__le64 input_queue_good_pkts_out[IONIC_QOS_TC_MAX];
-	__le64 input_queue_err_pkts_in[IONIC_QOS_TC_MAX];
-	__le64 input_queue_fifo_depth[IONIC_QOS_TC_MAX];
-	__le64 input_queue_max_fifo_depth[IONIC_QOS_TC_MAX];
-	__le64 input_queue_peak_occupancy[IONIC_QOS_TC_MAX];
-	__le64 output_queue_buffer_occupancy[IONIC_QOS_TC_MAX];
+struct ionic_port_extra_stats {
+	__le64 rsfec_correctable_blocks;
+	__le64 rsfec_uncorrectable_blocks;
+	__le64 fec_corrected_bits_total;
+	__le64 rx_bits_phy;
+	__le64 fec_codeword_error_bin[16];
 };
 
 /**
@@ -2950,7 +2910,7 @@ union ionic_port_identity {
  * @sprom_page2:     Extended Transceiver sprom, page 2
  * @sprom_page17:    Extended Transceiver sprom, page 17
  * @rsvd:            reserved byte(s)
- * @pb_stats:        uplink pb drop stats
+ * @extra_stats:     Extra port statistics data
  */
 struct ionic_port_info {
 	union ionic_port_config config;
@@ -2968,9 +2928,7 @@ struct ionic_port_info {
 		};
 	};
 	u8     rsvd[376];
-
-	/* pb_stats must start at 2k offset */
-	struct ionic_port_pb_stats  pb_stats;
+	struct ionic_port_extra_stats extra_stats;
 };
 
 /*
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next v5 3/5] ionic: Report "rx_bits_phy" stat to ethtool
  2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
  2026-06-14 20:52 ` [PATCH net-next v5 1/5] ionic: Fix check in ionic_get_link_ext_stats Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 2/5] ionic: Update ionic_if.h with new extra port stats Eric Joyner
@ 2026-06-14 20:53 ` Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 4/5] ionic: Get "link_down_count" ext link stat from firmware Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 5/5] ionic: Add .get_fec_stats ethtool handler Eric Joyner
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

This stat contains the number of total bits that the PHY has received;
it's useful for BER calculations. Add it to the ethtool stats output.

However, since this is one of the new "extra port stats", it's reported
in a different manner than the existing port stats and only
conditionally added to the ethtool stats output list: both the
DEV_CAP_EXTRA_STATS capability must be supported by the firmware, and
the firmware must set the value of the statistic to something other than
IONIC_STAT_INVALID.

To help support this scheme, the extra port stats region is initialized to
0xff's/IONIC_STAT_INVALID by the driver, to ensure the statistics that
the driver knows about but the firmware does not are still invalid
to the driver.

Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 .../net/ethernet/pensando/ionic/ionic_dev.h   |  1 +
 .../net/ethernet/pensando/ionic/ionic_main.c  |  6 ++
 .../net/ethernet/pensando/ionic/ionic_stats.c | 65 ++++++++++++++++++-
 .../net/ethernet/pensando/ionic/ionic_stats.h |  2 +
 4 files changed, 73 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
index 35566f97eaea..5f677bcbaf02 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
@@ -184,6 +184,7 @@ struct ionic_dev {
 	u32 port_info_sz;
 	struct ionic_port_info *port_info;
 	dma_addr_t port_info_pa;
+	struct ionic_port_extra_stats port_extra_stats_cache;
 
 	struct ionic_devinfo dev_info;
 };
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 3c5200e2fdb7..306d9d160e17 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -731,6 +731,12 @@ int ionic_port_init(struct ionic *ionic)
 			return -ENOMEM;
 	}
 
+	/* If the driver knows about more "extra stats" than the firmware,
+	 * make sure these stats are marked as invalid.
+	 */
+	memset(&idev->port_info->extra_stats, 0xff,
+	       sizeof(idev->port_info->extra_stats));
+
 	sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
 
 	mutex_lock(&ionic->dev_cmd_lock);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.c b/drivers/net/ethernet/pensando/ionic/ionic_stats.c
index 0107599a9dd4..428d5cca930f 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_stats.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.c
@@ -167,6 +167,7 @@ static const struct ionic_stat_desc ionic_rx_stats_desc[] = {
 #define IONIC_NUM_PORT_STATS ARRAY_SIZE(ionic_port_stats_desc)
 #define IONIC_NUM_TX_STATS ARRAY_SIZE(ionic_tx_stats_desc)
 #define IONIC_NUM_RX_STATS ARRAY_SIZE(ionic_rx_stats_desc)
+#define IONIC_NUM_EXTRA_PORT_STATS	1
 
 #define MAX_Q(lif)   ((lif)->netdev->real_num_tx_queues)
 
@@ -232,6 +233,33 @@ static void ionic_get_lif_stats(struct ionic_lif *lif,
 	stats->hw_tx_aborted_errors = ns.tx_aborted_errors;
 }
 
+static u32 ionic_extra_port_stats_get_count(struct ionic_lif *lif)
+{
+	struct ionic_dev *idev = &lif->ionic->idev;
+	struct ionic_port_extra_stats *pes_cache;
+	u32 count = 0;
+
+	if (!(lif->ionic->ident.dev.capabilities &
+	      cpu_to_le64(IONIC_DEV_CAP_EXTRA_STATS)))
+		return count;
+
+	pes_cache = &idev->port_extra_stats_cache;
+	/* Treat all of the extra port stats as invalid in subsequent calls if
+	 * port_info isn't set; otherwise cache a valid snapshot for them.
+	 */
+	if (!idev->port_info) {
+		memset(pes_cache, 0xff, sizeof(*pes_cache));
+		return count;
+	}
+
+	*pes_cache = idev->port_info->extra_stats;
+
+	if (pes_cache->rx_bits_phy != IONIC_STAT_INVALID)
+		count++;
+
+	return count;
+}
+
 static u64 ionic_sw_stats_get_count(struct ionic_lif *lif)
 {
 	u64 total = 0, tx_queues = MAX_Q(lif), rx_queues = MAX_Q(lif);
@@ -243,7 +271,7 @@ static u64 ionic_sw_stats_get_count(struct ionic_lif *lif)
 		rx_queues += 1;
 
 	total += IONIC_NUM_LIF_STATS;
-	total += IONIC_NUM_PORT_STATS;
+	total += IONIC_NUM_PORT_STATS + ionic_extra_port_stats_get_count(lif);
 
 	total += tx_queues * IONIC_NUM_TX_STATS;
 	total += rx_queues * IONIC_NUM_RX_STATS;
@@ -271,6 +299,20 @@ static void ionic_sw_stats_get_rx_strings(struct ionic_lif *lif, u8 **buf,
 				ionic_rx_stats_desc[i].name);
 }
 
+static void ionic_extra_port_stats_get_strings(struct ionic_lif *lif, u8 **buf)
+{
+	struct ionic_port_extra_stats *pes_cache;
+
+	if (!(lif->ionic->ident.dev.capabilities &
+	    cpu_to_le64(IONIC_DEV_CAP_EXTRA_STATS)))
+		return;
+
+	pes_cache = &lif->ionic->idev.port_extra_stats_cache;
+
+	if (pes_cache->rx_bits_phy != IONIC_STAT_INVALID)
+		ethtool_puts(buf, "rx_bits_phy");
+}
+
 static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf)
 {
 	int i, q_num;
@@ -280,6 +322,7 @@ static void ionic_sw_stats_get_strings(struct ionic_lif *lif, u8 **buf)
 
 	for (i = 0; i < IONIC_NUM_PORT_STATS; i++)
 		ethtool_puts(buf, ionic_port_stats_desc[i].name);
+	ionic_extra_port_stats_get_strings(lif, buf);
 
 	for (q_num = 0; q_num < MAX_Q(lif); q_num++)
 		ionic_sw_stats_get_tx_strings(lif, buf, q_num);
@@ -322,6 +365,25 @@ static void ionic_sw_stats_get_rxq_values(struct ionic_lif *lif, u64 **buf,
 	}
 }
 
+static void ionic_extra_port_stats_get_values(struct ionic_lif *lif, u64 **buf)
+{
+	struct ionic_port_extra_stats *pes_cache;
+
+	if (!(lif->ionic->ident.dev.capabilities &
+	      cpu_to_le64(IONIC_DEV_CAP_EXTRA_STATS)))
+		return;
+
+	/* The number of statistics added to @buf here must equal
+	 * ionic_extra_port_stats_get_count().
+	 */
+	pes_cache = &lif->ionic->idev.port_extra_stats_cache;
+
+	if (pes_cache->rx_bits_phy != IONIC_STAT_INVALID) {
+		**buf = le64_to_cpu(pes_cache->rx_bits_phy);
+		(*buf)++;
+	}
+}
+
 static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf)
 {
 	struct ionic_port_stats *port_stats;
@@ -341,6 +403,7 @@ static void ionic_sw_stats_get_values(struct ionic_lif *lif, u64 **buf)
 					     &ionic_port_stats_desc[i]);
 		(*buf)++;
 	}
+	ionic_extra_port_stats_get_values(lif, buf);
 
 	for (q_num = 0; q_num < MAX_Q(lif); q_num++)
 		ionic_sw_stats_get_txq_values(lif, buf, q_num);
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_stats.h b/drivers/net/ethernet/pensando/ionic/ionic_stats.h
index 2a725834f792..7ed935868e84 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_stats.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_stats.h
@@ -4,6 +4,8 @@
 #ifndef _IONIC_STATS_H_
 #define _IONIC_STATS_H_
 
+#define IONIC_STAT_INVALID	(cpu_to_le64(~0ULL))
+
 #define IONIC_STAT_TO_OFFSET(type, stat_name) (offsetof(type, stat_name))
 
 #define IONIC_STAT_DESC(type, stat_name) { \
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next v5 4/5] ionic: Get "link_down_count" ext link stat from firmware
  2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
                   ` (2 preceding siblings ...)
  2026-06-14 20:53 ` [PATCH net-next v5 3/5] ionic: Report "rx_bits_phy" stat to ethtool Eric Joyner
@ 2026-06-14 20:53 ` Eric Joyner
  2026-06-14 20:53 ` [PATCH net-next v5 5/5] ionic: Add .get_fec_stats ethtool handler Eric Joyner
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

The number of times that link has gone down at the port level is tracked
by the firmware and sent to the driver via regular DMA writes to an
instance of struct ionic_port_status in the driver's memory.

This statistic was never reported in favor of a driver-derived stat, but
doing it in the driver was never necessary since firmware had been
reporting it the whole time. Since it would be more accurate and true to
the description of the statistic to get this count at the PHY level,
replace the driver-calculated statistic with one derived from the
firmware one and remove the driver-calculated one entirely.

The stat reported by the ethtool .get_link_ext_stats() handler is
normalized to 0 on driver load and any device resets that require the
driver to rebuild state while also handling overflows.

Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 .../net/ethernet/pensando/ionic/ionic_dev.c   | 10 +++++++++
 .../net/ethernet/pensando/ionic/ionic_dev.h   |  5 +++++
 .../ethernet/pensando/ionic/ionic_ethtool.c   | 22 ++++++++++++++++---
 .../net/ethernet/pensando/ionic/ionic_lif.c   |  4 +++-
 .../net/ethernet/pensando/ionic/ionic_lif.h   |  1 -
 .../net/ethernet/pensando/ionic/ionic_main.c  |  2 ++
 6 files changed, 39 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
index 3838c4a70766..648d9d24be85 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
@@ -1076,3 +1076,13 @@ bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos)
 
 	return ((pos - tail) & mask) < ((head - tail) & mask);
 }
+
+void ionic_reset_link_down_count(struct ionic_dev *idev)
+{
+	if (!READ_ONCE(idev->link_down_count_init)) {
+		idev->link_down_count_total = 0;
+		idev->link_down_count_last =
+			le16_to_cpu(idev->port_info->status.link_down_count);
+		WRITE_ONCE(idev->link_down_count_init, true);
+	}
+}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
index 5f677bcbaf02..db90e39a1442 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
@@ -185,6 +185,9 @@ struct ionic_dev {
 	struct ionic_port_info *port_info;
 	dma_addr_t port_info_pa;
 	struct ionic_port_extra_stats port_extra_stats_cache;
+	bool link_down_count_init;
+	u16 link_down_count_last;
+	u32 link_down_count_total;
 
 	struct ionic_devinfo dev_info;
 };
@@ -395,4 +398,6 @@ bool ionic_adminq_poke_doorbell(struct ionic_queue *q);
 bool ionic_txq_poke_doorbell(struct ionic_queue *q);
 bool ionic_rxq_poke_doorbell(struct ionic_queue *q);
 
+void ionic_reset_link_down_count(struct ionic_dev *idev);
+
 #endif /* _IONIC_DEV_H_ */
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index 6069fa460913..c4ab4b5caa0a 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -115,16 +115,32 @@ static void ionic_get_link_ext_stats(struct net_device *netdev,
 				     struct ethtool_link_ext_stats *stats)
 {
 	struct ionic_lif *lif = netdev_priv(netdev);
+	struct ionic *ionic = lif->ionic;
+	u64 link_down_count_total;
+	u16 link_down_count_fw;
 
-	if (lif->ionic->pdev->is_virtfn)
+	if (ionic->pdev->is_virtfn)
 		return;
 
-	if (!lif->ionic->idev.port_info) {
+	if (!ionic->idev.port_info) {
 		netdev_err_once(netdev, "port_info not initialized\n");
 		return;
 	}
 
-	stats->link_down_events = lif->link_down_count;
+	link_down_count_fw =
+	    le16_to_cpu(ionic->idev.port_info->status.link_down_count);
+	link_down_count_total = ionic->idev.link_down_count_total +
+				link_down_count_fw -
+				ionic->idev.link_down_count_last;
+
+	/* The firmware counter is only 16 bits and can wraparound */
+	if (link_down_count_fw < ionic->idev.link_down_count_last)
+		link_down_count_total += BIT(16);
+
+	ionic->idev.link_down_count_last = link_down_count_fw;
+	ionic->idev.link_down_count_total = link_down_count_total;
+
+	stats->link_down_events = link_down_count_total;
 }
 
 static int ionic_get_link_ksettings(struct net_device *netdev,
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
index 637e635bbf03..fd3ee9820531 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
@@ -140,6 +140,7 @@ void ionic_lif_deferred_enqueue(struct ionic_lif *lif,
 
 static void ionic_link_status_check(struct ionic_lif *lif)
 {
+	struct ionic_dev *idev = &lif->ionic->idev;
 	struct net_device *netdev = lif->netdev;
 	u16 link_status;
 	bool link_up;
@@ -153,6 +154,8 @@ static void ionic_link_status_check(struct ionic_lif *lif)
 		return;
 	}
 
+	ionic_reset_link_down_count(idev);
+
 	link_status = le16_to_cpu(lif->info->status.link_status);
 	link_up = link_status == IONIC_PORT_OPER_STATUS_UP;
 
@@ -179,7 +182,6 @@ static void ionic_link_status_check(struct ionic_lif *lif)
 		}
 	} else {
 		if (netif_carrier_ok(netdev)) {
-			lif->link_down_count++;
 			netdev_info(netdev, "Link down\n");
 			netif_carrier_off(netdev);
 		}
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
index 8e10f66dc50e..d34692462036 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
@@ -214,7 +214,6 @@ struct ionic_lif {
 	bool registered;
 	bool doorbell_wa;
 	u16 lif_type;
-	unsigned int link_down_count;
 	unsigned int nmcast;
 	unsigned int nucast;
 	unsigned int nvlans;
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
index 306d9d160e17..6e6f3ed07271 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
@@ -737,6 +737,8 @@ int ionic_port_init(struct ionic *ionic)
 	memset(&idev->port_info->extra_stats, 0xff,
 	       sizeof(idev->port_info->extra_stats));
 
+	WRITE_ONCE(idev->link_down_count_init, false);
+
 	sz = min(sizeof(ident->port.config), sizeof(idev->dev_cmd_regs->data));
 
 	mutex_lock(&ionic->dev_cmd_lock);
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* [PATCH net-next v5 5/5] ionic: Add .get_fec_stats ethtool handler
  2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
                   ` (3 preceding siblings ...)
  2026-06-14 20:53 ` [PATCH net-next v5 4/5] ionic: Get "link_down_count" ext link stat from firmware Eric Joyner
@ 2026-06-14 20:53 ` Eric Joyner
  4 siblings, 0 replies; 6+ messages in thread
From: Eric Joyner @ 2026-06-14 20:53 UTC (permalink / raw)
  To: netdev
  Cc: Brett Creeley, Andrew Lunn, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Eric Joyner, Nikhil P . Rao,
	Simon Horman

Reports FEC statistics totals and an 802.3ck FEC histogram. Per-lane
counts currently aren't supported.

The reporting of these statistics is gated by DEV_CAP_EXTRA_STATS and
checks for IONIC_STAT_INVALID, since only the newest devices support
reporting all of these stats. Older devices can only report some of the
statistics or not at all, and so the output will properly exclude those
unsupported statistics.

Assisted-by: Claude:claude-4.6-sonnet
Signed-off-by: Eric Joyner <eric.joyner@amd.com>
---
 .../ethernet/pensando/ionic/ionic_ethtool.c   | 77 +++++++++++++++++++
 1 file changed, 77 insertions(+)

diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
index c4ab4b5caa0a..e88e818667c2 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
@@ -441,6 +441,82 @@ static int ionic_get_fecparam(struct net_device *netdev,
 	return 0;
 }
 
+static const struct ethtool_fec_hist_range ionic_fec_ranges[] = {
+	{ 0, 0},
+	{ 1, 1},
+	{ 2, 2},
+	{ 3, 3},
+	{ 4, 4},
+	{ 5, 5},
+	{ 6, 6},
+	{ 7, 7},
+	{ 8, 8},
+	{ 9, 9},
+	{ 10, 10},
+	{ 11, 11},
+	{ 12, 12},
+	{ 13, 13},
+	{ 14, 14},
+	{ 15, 15},
+	{ 0, 0},
+};
+
+#define IONIC_FEC_STAT(dst, src)			\
+	do {						\
+		if ((src) != IONIC_STAT_INVALID)	\
+			(dst) = le64_to_cpu((src));	\
+	} while (0)
+
+static void
+ionic_fill_fec_hist(const struct ionic_port_extra_stats *port_extra_stats,
+		    struct ethtool_fec_hist *hist)
+{
+	__le64 fec_cw_err_bin;
+	int i;
+
+	if (port_extra_stats->fec_codeword_error_bin[0] == IONIC_STAT_INVALID)
+		return;
+
+	hist->ranges = ionic_fec_ranges;
+	/* All bins in ranges must be set */
+	for (i = 0; i < ARRAY_SIZE(ionic_fec_ranges) - 1; i++) {
+		fec_cw_err_bin = port_extra_stats->fec_codeword_error_bin[i];
+
+		if (fec_cw_err_bin != IONIC_STAT_INVALID)
+			hist->values[i].sum = le64_to_cpu(fec_cw_err_bin);
+		else
+			hist->values[i].sum = 0;
+	}
+}
+
+static void ionic_get_fec_stats(struct net_device *netdev,
+				struct ethtool_fec_stats *fec_stats,
+				struct ethtool_fec_hist *hist)
+{
+	struct ionic_port_extra_stats *port_extra_stats;
+	struct ionic_lif *lif = netdev_priv(netdev);
+
+	if (!(lif->ionic->ident.dev.capabilities &
+	      cpu_to_le64(IONIC_DEV_CAP_EXTRA_STATS)))
+		return;
+
+	if (!lif->ionic->idev.port_info) {
+		netdev_err_once(netdev, "port_info not initialized\n");
+		return;
+	}
+
+	port_extra_stats = &lif->ionic->idev.port_info->extra_stats;
+
+	IONIC_FEC_STAT(fec_stats->corrected_blocks.total,
+		       port_extra_stats->rsfec_correctable_blocks);
+	IONIC_FEC_STAT(fec_stats->uncorrectable_blocks.total,
+		       port_extra_stats->rsfec_uncorrectable_blocks);
+	IONIC_FEC_STAT(fec_stats->corrected_bits.total,
+		       port_extra_stats->fec_corrected_bits_total);
+
+	ionic_fill_fec_hist(port_extra_stats, hist);
+}
+
 static int ionic_set_fecparam(struct net_device *netdev,
 			      struct ethtool_fecparam *fec)
 {
@@ -1177,6 +1253,7 @@ static const struct ethtool_ops ionic_ethtool_ops = {
 	.get_module_eeprom_by_page	= ionic_get_module_eeprom_by_page,
 	.get_pauseparam		= ionic_get_pauseparam,
 	.set_pauseparam		= ionic_set_pauseparam,
+	.get_fec_stats		= ionic_get_fec_stats,
 	.get_fecparam		= ionic_get_fecparam,
 	.set_fecparam		= ionic_set_fecparam,
 	.get_ts_info		= ionic_get_ts_info,
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2026-06-14 20:53 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-06-14 20:52 [PATCH net-next v5 0/5] ionic: Expose more port stats to ethtool Eric Joyner
2026-06-14 20:52 ` [PATCH net-next v5 1/5] ionic: Fix check in ionic_get_link_ext_stats Eric Joyner
2026-06-14 20:53 ` [PATCH net-next v5 2/5] ionic: Update ionic_if.h with new extra port stats Eric Joyner
2026-06-14 20:53 ` [PATCH net-next v5 3/5] ionic: Report "rx_bits_phy" stat to ethtool Eric Joyner
2026-06-14 20:53 ` [PATCH net-next v5 4/5] ionic: Get "link_down_count" ext link stat from firmware Eric Joyner
2026-06-14 20:53 ` [PATCH net-next v5 5/5] ionic: Add .get_fec_stats ethtool handler Eric Joyner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox