diff options
| author | Jakub Kicinski <kuba@kernel.org> | 2026-06-16 04:15:12 +0300 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-06-16 04:15:12 +0300 |
| commit | 987257c49bfb59ccf94bb30f41edc92ea0d6f739 (patch) | |
| tree | 309d4805775f46c3767037ff07118c5aad8c5900 | |
| parent | 195900546305644b5570dcd615e30be3abe86185 (diff) | |
| parent | 3277e605ac01fd11d0a7c6c68c617547ba66c87f (diff) | |
| download | linux-987257c49bfb59ccf94bb30f41edc92ea0d6f739.tar.xz | |
Merge branch 'ionic-expose-more-port-stats-to-ethtool'
Eric Joyner says:
====================
ionic: Expose more port stats to ethtool [part]
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. 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.
====================
Link: https://patch.msgid.link/20260614205303.48088-1-eric.joyner@amd.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_dev.c | 10 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_dev.h | 6 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 27 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_if.h | 64 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_lif.c | 4 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_lif.h | 1 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_main.c | 8 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_stats.c | 65 | ||||
| -rw-r--r-- | drivers/net/ethernet/pensando/ionic/ionic_stats.h | 2 |
9 files changed, 129 insertions, 58 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 35566f97eaea..db90e39a1442 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h +++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h @@ -184,6 +184,10 @@ 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; + bool link_down_count_init; + u16 link_down_count_last; + u32 link_down_count_total; struct ionic_devinfo dev_info; }; @@ -394,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 78a802eb159f..c4ab4b5caa0a 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c @@ -115,9 +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 (ionic->pdev->is_virtfn) + return; + + if (!ionic->idev.port_info) { + netdev_err_once(netdev, "port_info not initialized\n"); + return; + } + + 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; - if (lif->ionic->pdev->is_physfn) - stats->link_down_events = lif->link_down_count; + 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_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; }; /* 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 3c5200e2fdb7..6e6f3ed07271 100644 --- a/drivers/net/ethernet/pensando/ionic/ionic_main.c +++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c @@ -731,6 +731,14 @@ 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)); + + 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); 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) { \ |
