From 98c2f0b42eead51282fa722f4aedccd2987e0374 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 16 Oct 2025 23:08:37 -0700 Subject: [PATCH 1/6] net: docs: add missing features that can have stats While trying to figure out ethtool -I | --include-statistics, I noticed some docs got missed when implementing commit 0e9c127729be ("ethtool: add interface to read Tx hardware timestamping statistics"). Fix up the docs to match the kernel code, and while there, sort them in alphabetical order. Reviewed-by: Jacob Keller Reviewed-by: Rahul Rameshbabu Reviewed-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: Jesse Brandeburg Reviewed-by: Paul Menzel Reviewed-by: Aleksandr Loktionov Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-8-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- Documentation/networking/statistics.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Documentation/networking/statistics.rst b/Documentation/networking/statistics.rst index 518284e287b0..66b0ef941457 100644 --- a/Documentation/networking/statistics.rst +++ b/Documentation/networking/statistics.rst @@ -184,9 +184,11 @@ Protocol-related statistics can be requested in get commands by setting the `ETHTOOL_FLAG_STATS` flag in `ETHTOOL_A_HEADER_FLAGS`. Currently statistics are supported in the following commands: - - `ETHTOOL_MSG_PAUSE_GET` - `ETHTOOL_MSG_FEC_GET` + - `ETHTOOL_MSG_LINKSTATE_GET` - `ETHTOOL_MSG_MM_GET` + - `ETHTOOL_MSG_PAUSE_GET` + - `ETHTOOL_MSG_TSINFO_GET` debugfs ------- From 20ae87514ad5159f821951761fc7362bceeca265 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 16 Oct 2025 23:08:38 -0700 Subject: [PATCH 2/6] ice: implement ethtool standard stats Add support for MAC/pause/RMON stats. This enables reporting hardware statistics in a common way via: ethtool -S eth0 --all-groups and ethtool --include-statistics --show-pause eth0 While doing so, add support for one new stat, receive length error (RLEC), which is extremely unlikely to happen since most L2 frames have a type/length field specifying a "type", and raw ethernet frames aren't used much any longer. NOTE: I didn't implement Ctrl aka control frame stats because the hardware doesn't seem to implement support. Reviewed-by: Marcin Szycik Reviewed-by: Jacob Keller Reviewed-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: Jesse Brandeburg Tested-by: Rinitha S Reviewed-by: Aleksandr Loktionov Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-9-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 78 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_main.c | 3 + drivers/net/ethernet/intel/ice/ice_type.h | 1 + 3 files changed, 82 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index dc131779d426..d1ec7e6f12bf 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -4661,6 +4661,81 @@ static void ice_get_fec_stats(struct net_device *netdev, pi->lport, err); } +static void ice_get_eth_mac_stats(struct net_device *netdev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_hw_port_stats *ps = &pf->stats; + + mac_stats->FramesTransmittedOK = ps->eth.tx_unicast + + ps->eth.tx_multicast + + ps->eth.tx_broadcast; + mac_stats->FramesReceivedOK = ps->eth.rx_unicast + + ps->eth.rx_multicast + + ps->eth.rx_broadcast; + mac_stats->FrameCheckSequenceErrors = ps->crc_errors; + mac_stats->OctetsTransmittedOK = ps->eth.tx_bytes; + mac_stats->OctetsReceivedOK = ps->eth.rx_bytes; + mac_stats->MulticastFramesXmittedOK = ps->eth.tx_multicast; + mac_stats->BroadcastFramesXmittedOK = ps->eth.tx_broadcast; + mac_stats->MulticastFramesReceivedOK = ps->eth.rx_multicast; + mac_stats->BroadcastFramesReceivedOK = ps->eth.rx_broadcast; + mac_stats->InRangeLengthErrors = ps->rx_len_errors; + mac_stats->FrameTooLongErrors = ps->rx_oversize; +} + +static void ice_get_pause_stats(struct net_device *netdev, + struct ethtool_pause_stats *pause_stats) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_hw_port_stats *ps = &pf->stats; + + pause_stats->tx_pause_frames = ps->link_xon_tx + ps->link_xoff_tx; + pause_stats->rx_pause_frames = ps->link_xon_rx + ps->link_xoff_rx; +} + +static const struct ethtool_rmon_hist_range ice_rmon_ranges[] = { + { 0, 64 }, + { 65, 127 }, + { 128, 255 }, + { 256, 511 }, + { 512, 1023 }, + { 1024, 1522 }, + { 1523, 9522 }, + {} +}; + +static void ice_get_rmon_stats(struct net_device *netdev, + struct ethtool_rmon_stats *rmon, + const struct ethtool_rmon_hist_range **ranges) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_hw_port_stats *ps = &pf->stats; + + rmon->undersize_pkts = ps->rx_undersize; + rmon->oversize_pkts = ps->rx_oversize; + rmon->fragments = ps->rx_fragments; + rmon->jabbers = ps->rx_jabber; + + rmon->hist[0] = ps->rx_size_64; + rmon->hist[1] = ps->rx_size_127; + rmon->hist[2] = ps->rx_size_255; + rmon->hist[3] = ps->rx_size_511; + rmon->hist[4] = ps->rx_size_1023; + rmon->hist[5] = ps->rx_size_1522; + rmon->hist[6] = ps->rx_size_big; + + rmon->hist_tx[0] = ps->tx_size_64; + rmon->hist_tx[1] = ps->tx_size_127; + rmon->hist_tx[2] = ps->tx_size_255; + rmon->hist_tx[3] = ps->tx_size_511; + rmon->hist_tx[4] = ps->tx_size_1023; + rmon->hist_tx[5] = ps->tx_size_1522; + rmon->hist_tx[6] = ps->tx_size_big; + + *ranges = ice_rmon_ranges; +} + #define ICE_ETHTOOL_PFR (ETH_RESET_IRQ | ETH_RESET_DMA | \ ETH_RESET_FILTER | ETH_RESET_OFFLOAD) @@ -4744,6 +4819,9 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings, .get_fec_stats = ice_get_fec_stats, + .get_eth_mac_stats = ice_get_eth_mac_stats, + .get_pause_stats = ice_get_pause_stats, + .get_rmon_stats = ice_get_rmon_stats, .get_drvinfo = ice_get_drvinfo, .get_regs_len = ice_get_regs_len, .get_regs = ice_get_regs, diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 86f5859e88ef..3d5615caf6d1 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -7138,6 +7138,9 @@ void ice_update_pf_stats(struct ice_pf *pf) &prev_ps->mac_remote_faults, &cur_ps->mac_remote_faults); + ice_stat_update32(hw, GLPRT_RLEC(port), pf->stat_prev_loaded, + &prev_ps->rx_len_errors, &cur_ps->rx_len_errors); + ice_stat_update32(hw, GLPRT_RUC(port), pf->stat_prev_loaded, &prev_ps->rx_undersize, &cur_ps->rx_undersize); diff --git a/drivers/net/ethernet/intel/ice/ice_type.h b/drivers/net/ethernet/intel/ice/ice_type.h index b0a1b67071c5..6a2ec8389a8f 100644 --- a/drivers/net/ethernet/intel/ice/ice_type.h +++ b/drivers/net/ethernet/intel/ice/ice_type.h @@ -1063,6 +1063,7 @@ struct ice_hw_port_stats { u64 error_bytes; /* errbc */ u64 mac_local_faults; /* mlfc */ u64 mac_remote_faults; /* mrfc */ + u64 rx_len_errors; /* rlec */ u64 link_xon_rx; /* lxonrxc */ u64 link_xoff_rx; /* lxoffrxc */ u64 link_xon_tx; /* lxontxc */ From 4368d5fe02f6d2cf36bb3b261a7ca25a2dd9a3ca Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 16 Oct 2025 23:08:39 -0700 Subject: [PATCH 3/6] ice: add tracking of good transmit timestamps As a pre-requisite to implementing timestamp statistics, start tracking successful PTP timestamps. There already existed a trace event, but add a counter as well so it can be displayed by the next patch. Good count is a u64 as it is much more likely to be incremented. The existing error stats are all u32 as before, and are less likely so will wrap less. Reviewed-by: Jacob Keller Reviewed-by: Jakub Kicinski Reviewed-by: Simon Horman Signed-off-by: Jesse Brandeburg Tested-by: Rinitha S Reviewed-by: Aleksandr Loktionov Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-10-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_ptp.c | 9 +++++++++ drivers/net/ethernet/intel/ice/ice_ptp.h | 2 ++ 2 files changed, 11 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index fb0f6365a6d6..4f50e952bfb5 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -500,6 +500,9 @@ void ice_ptp_complete_tx_single_tstamp(struct ice_ptp_tx *tx) if (tstamp) { shhwtstamps.hwtstamp = ns_to_ktime(tstamp); ice_trace(tx_tstamp_complete, skb, idx); + + /* Count the number of Tx timestamps that succeeded */ + pf->ptp.tx_hwtstamp_good++; } skb_tstamp_tx(skb, &shhwtstamps); @@ -558,6 +561,7 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) { struct ice_ptp_port *ptp_port; unsigned long flags; + u32 tstamp_good = 0; struct ice_pf *pf; struct ice_hw *hw; u64 tstamp_ready; @@ -658,11 +662,16 @@ static void ice_ptp_process_tx_tstamp(struct ice_ptp_tx *tx) if (tstamp) { shhwtstamps.hwtstamp = ns_to_ktime(tstamp); ice_trace(tx_tstamp_complete, skb, idx); + + /* Count the number of Tx timestamps that succeeded */ + tstamp_good++; } skb_tstamp_tx(skb, &shhwtstamps); dev_kfree_skb_any(skb); } + + pf->ptp.tx_hwtstamp_good += tstamp_good; } /** diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.h b/drivers/net/ethernet/intel/ice/ice_ptp.h index 137f2070a2d9..27016aac4f1e 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.h +++ b/drivers/net/ethernet/intel/ice/ice_ptp.h @@ -237,6 +237,7 @@ struct ice_ptp_pin_desc { * @clock: pointer to registered PTP clock device * @tstamp_config: hardware timestamping configuration * @reset_time: kernel time after clock stop on reset + * @tx_hwtstamp_good: number of completed Tx timestamp requests * @tx_hwtstamp_skipped: number of Tx time stamp requests skipped * @tx_hwtstamp_timeouts: number of Tx skbs discarded with no time stamp * @tx_hwtstamp_flushed: number of Tx skbs flushed due to interface closed @@ -261,6 +262,7 @@ struct ice_ptp { struct ptp_clock *clock; struct kernel_hwtstamp_config tstamp_config; u64 reset_time; + u64 tx_hwtstamp_good; u32 tx_hwtstamp_skipped; u32 tx_hwtstamp_timeouts; u32 tx_hwtstamp_flushed; From 71462475d0020b4001066d5b591ab09ea143002d Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 16 Oct 2025 23:08:40 -0700 Subject: [PATCH 4/6] ice: implement transmit hardware timestamp statistics The kernel now has common statistics for transmit timestamps, so implement them in the ice driver. use via ethtool -I -T eth0 Reviewed-by: Jacob Keller Reviewed-by: Jakub Kicinski Reviewed-by: Hariprasad Kelam Reviewed-by: Simon Horman Signed-off-by: Jesse Brandeburg Tested-by: Rinitha S Reviewed-by: Aleksandr Loktionov Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-11-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index d1ec7e6f12bf..75492a720c68 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -4736,6 +4736,23 @@ static void ice_get_rmon_stats(struct net_device *netdev, *ranges = ice_rmon_ranges; } +/* ice_get_ts_stats - provide timestamping stats + * @netdev: the netdevice pointer from ethtool + * @ts_stats: the ethtool data structure to fill in + */ +static void ice_get_ts_stats(struct net_device *netdev, + struct ethtool_ts_stats *ts_stats) +{ + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_ptp *ptp = &pf->ptp; + + ts_stats->pkts = ptp->tx_hwtstamp_good; + ts_stats->err = ptp->tx_hwtstamp_skipped + + ptp->tx_hwtstamp_flushed + + ptp->tx_hwtstamp_discarded; + ts_stats->lost = ptp->tx_hwtstamp_timeouts; +} + #define ICE_ETHTOOL_PFR (ETH_RESET_IRQ | ETH_RESET_DMA | \ ETH_RESET_FILTER | ETH_RESET_OFFLOAD) @@ -4822,6 +4839,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .get_eth_mac_stats = ice_get_eth_mac_stats, .get_pause_stats = ice_get_pause_stats, .get_rmon_stats = ice_get_rmon_stats, + .get_ts_stats = ice_get_ts_stats, .get_drvinfo = ice_get_drvinfo, .get_regs_len = ice_get_regs_len, .get_regs = ice_get_regs, From a308ea9721122d632d1ce2af4cec1c008aff512a Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Thu, 16 Oct 2025 23:08:41 -0700 Subject: [PATCH 5/6] ice: refactor to use helpers Use the ice_netdev_to_pf() helper in more places and remove a bunch of boilerplate code. Not every instance could be replaced due to use of the netdev_priv() output or the vsi variable within a bunch of functions. Signed-off-by: Jesse Brandeburg Reviewed-by: Simon Horman Reviewed-by: Przemek Kitszel Reviewed-by: Aleksandr Loktionov Tested-by: Rinitha S Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-12-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/ice/ice_ethtool.c | 48 ++++++------------- .../net/ethernet/intel/ice/ice_flex_pipe.c | 8 +--- drivers/net/ethernet/intel/ice/ice_lag.c | 3 +- drivers/net/ethernet/intel/ice/ice_main.c | 10 ++-- drivers/net/ethernet/intel/ice/ice_ptp.c | 6 +-- drivers/net/ethernet/intel/ice/ice_sriov.c | 3 +- 6 files changed, 24 insertions(+), 54 deletions(-) diff --git a/drivers/net/ethernet/intel/ice/ice_ethtool.c b/drivers/net/ethernet/intel/ice/ice_ethtool.c index 75492a720c68..cb34d4675a78 100644 --- a/drivers/net/ethernet/intel/ice/ice_ethtool.c +++ b/drivers/net/ethernet/intel/ice/ice_ethtool.c @@ -794,8 +794,7 @@ static int ice_get_extended_regs(struct net_device *netdev, void *p) static void ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_hw *hw = &pf->hw; u32 *regs_buf = (u32 *)p; unsigned int i; @@ -810,8 +809,7 @@ ice_get_regs(struct net_device *netdev, struct ethtool_regs *regs, void *p) static u32 ice_get_msglevel(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); #ifndef CONFIG_DYNAMIC_DEBUG if (pf->hw.debug_mask) @@ -824,8 +822,7 @@ static u32 ice_get_msglevel(struct net_device *netdev) static void ice_set_msglevel(struct net_device *netdev, u32 data) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); #ifndef CONFIG_DYNAMIC_DEBUG if (ICE_DBG_USER & data) @@ -840,16 +837,14 @@ static void ice_set_msglevel(struct net_device *netdev, u32 data) static void ice_get_link_ext_stats(struct net_device *netdev, struct ethtool_link_ext_stats *stats) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); stats->link_down_events = pf->link_down_events; } static int ice_get_eeprom_len(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); return (int)pf->hw.flash.flash_size; } @@ -858,9 +853,7 @@ static int ice_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom, u8 *bytes) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_hw *hw = &pf->hw; struct device *dev; int ret; @@ -959,8 +952,7 @@ static u64 ice_link_test(struct net_device *netdev) */ static u64 ice_eeprom_test(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); netdev_info(netdev, "EEPROM test\n"); return !!(ice_nvm_validate_checksum(&pf->hw)); @@ -1274,9 +1266,8 @@ static int ice_lbtest_receive_frames(struct ice_rx_ring *rx_ring) */ static u64 ice_loopback_test(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *orig_vsi = np->vsi, *test_vsi; - struct ice_pf *pf = orig_vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); + struct ice_vsi *test_vsi; u8 *tx_frame __free(kfree) = NULL; u8 broadcast[ETH_ALEN], ret = 0; int num_frames, valid_frames; @@ -1365,8 +1356,7 @@ static u64 ice_loopback_test(struct net_device *netdev) */ static u64 ice_intr_test(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); u16 swic_old = pf->sw_int_count; netdev_info(netdev, "interrupt test\n"); @@ -1394,9 +1384,8 @@ static void ice_self_test(struct net_device *netdev, struct ethtool_test *eth_test, u64 *data) { - struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = ice_netdev_to_pf(netdev); bool if_running = netif_running(netdev); - struct ice_pf *pf = np->vsi->back; struct device *dev; dev = ice_pf_to_dev(pf); @@ -1720,9 +1709,7 @@ static int ice_nway_reset(struct net_device *netdev) */ static u32 ice_get_priv_flags(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); u32 i, ret_flags = 0; for (i = 0; i < ICE_PRIV_FLAG_ARRAY_SIZE; i++) { @@ -4417,9 +4404,7 @@ static int ice_get_module_info(struct net_device *netdev, struct ethtool_modinfo *modinfo) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_hw *hw = &pf->hw; u8 sff8472_comp = 0; u8 sff8472_swap = 0; @@ -4491,12 +4476,10 @@ static int ice_get_module_eeprom(struct net_device *netdev, struct ethtool_eeprom *ee, u8 *data) { - struct ice_netdev_priv *np = netdev_priv(netdev); + struct ice_pf *pf = ice_netdev_to_pf(netdev); #define SFF_READ_BLOCK_SIZE 8 u8 value[SFF_READ_BLOCK_SIZE] = { 0 }; u8 addr = ICE_I2C_EEPROM_DEV_ADDR; - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; struct ice_hw *hw = &pf->hw; bool is_sfp = false; unsigned int i, j; @@ -4774,8 +4757,7 @@ static void ice_get_ts_stats(struct net_device *netdev, */ static int ice_ethtool_reset(struct net_device *dev, u32 *flags) { - struct ice_netdev_priv *np = netdev_priv(dev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(dev); enum ice_reset_req reset; switch (*flags) { diff --git a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c index 363ae79a3620..06b8786ae3ab 100644 --- a/drivers/net/ethernet/intel/ice/ice_flex_pipe.c +++ b/drivers/net/ethernet/intel/ice/ice_flex_pipe.c @@ -574,9 +574,7 @@ ice_destroy_tunnel(struct ice_hw *hw, u16 index, enum ice_tunnel_type type, int ice_udp_tunnel_set_port(struct net_device *netdev, unsigned int table, unsigned int idx, struct udp_tunnel_info *ti) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); enum ice_tunnel_type tnl_type; int status; u16 index; @@ -598,9 +596,7 @@ int ice_udp_tunnel_set_port(struct net_device *netdev, unsigned int table, int ice_udp_tunnel_unset_port(struct net_device *netdev, unsigned int table, unsigned int idx, struct udp_tunnel_info *ti) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); enum ice_tunnel_type tnl_type; int status; diff --git a/drivers/net/ethernet/intel/ice/ice_lag.c b/drivers/net/ethernet/intel/ice/ice_lag.c index aebf8e08a297..d2576d606e10 100644 --- a/drivers/net/ethernet/intel/ice/ice_lag.c +++ b/drivers/net/ethernet/intel/ice/ice_lag.c @@ -2177,8 +2177,7 @@ static void ice_lag_chk_disabled_bond(struct ice_lag *lag, void *ptr) */ static void ice_lag_disable_sriov_bond(struct ice_lag *lag) { - struct ice_netdev_priv *np = netdev_priv(lag->netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(lag->netdev); ice_clear_feature_support(pf, ICE_F_SRIOV_LAG); ice_clear_feature_support(pf, ICE_F_SRIOV_AA_LAG); diff --git a/drivers/net/ethernet/intel/ice/ice_main.c b/drivers/net/ethernet/intel/ice/ice_main.c index 3d5615caf6d1..ca95b8800bb3 100644 --- a/drivers/net/ethernet/intel/ice/ice_main.c +++ b/drivers/net/ethernet/intel/ice/ice_main.c @@ -8074,9 +8074,7 @@ static int ice_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq, struct net_device *dev, u32 filter_mask, int nlflags) { - struct ice_netdev_priv *np = netdev_priv(dev); - struct ice_vsi *vsi = np->vsi; - struct ice_pf *pf = vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(dev); u16 bmode; bmode = pf->first_sw->bridge_mode; @@ -8146,8 +8144,7 @@ ice_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 __always_unused flags, struct netlink_ext_ack __always_unused *extack) { - struct ice_netdev_priv *np = netdev_priv(dev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(dev); struct nlattr *attr, *br_spec; struct ice_hw *hw = &pf->hw; struct ice_sw *pf_sw; @@ -9581,8 +9578,7 @@ ice_indr_setup_tc_cb(struct net_device *netdev, struct Qdisc *sch, */ int ice_open(struct net_device *netdev) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); if (ice_is_reset_in_progress(pf->state)) { netdev_err(netdev, "can't open net device while reset is in progress"); diff --git a/drivers/net/ethernet/intel/ice/ice_ptp.c b/drivers/net/ethernet/intel/ice/ice_ptp.c index 4f50e952bfb5..985b3e79b312 100644 --- a/drivers/net/ethernet/intel/ice/ice_ptp.c +++ b/drivers/net/ethernet/intel/ice/ice_ptp.c @@ -2215,8 +2215,7 @@ static int ice_ptp_getcrosststamp(struct ptp_clock_info *info, int ice_ptp_hwtstamp_get(struct net_device *netdev, struct kernel_hwtstamp_config *config) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); if (pf->ptp.state != ICE_PTP_READY) return -EIO; @@ -2287,8 +2286,7 @@ int ice_ptp_hwtstamp_set(struct net_device *netdev, struct kernel_hwtstamp_config *config, struct netlink_ext_ack *extack) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); int err; if (pf->ptp.state != ICE_PTP_READY) diff --git a/drivers/net/ethernet/intel/ice/ice_sriov.c b/drivers/net/ethernet/intel/ice/ice_sriov.c index 843e82fd3bf9..6b1126ddb561 100644 --- a/drivers/net/ethernet/intel/ice/ice_sriov.c +++ b/drivers/net/ethernet/intel/ice/ice_sriov.c @@ -1190,8 +1190,7 @@ ice_vf_lan_overflow_event(struct ice_pf *pf, struct ice_rq_event_info *event) */ int ice_set_vf_spoofchk(struct net_device *netdev, int vf_id, bool ena) { - struct ice_netdev_priv *np = netdev_priv(netdev); - struct ice_pf *pf = np->vsi->back; + struct ice_pf *pf = ice_netdev_to_pf(netdev); struct ice_vsi *vf_vsi; struct device *dev; struct ice_vf *vf; From 3c7bf5af2196087f394f9099b53e37569636b259 Mon Sep 17 00:00:00 2001 From: Vitaly Lifshits Date: Thu, 16 Oct 2025 23:08:43 -0700 Subject: [PATCH 6/6] e1000e: Introduce private flag to disable K1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The K1 state reduces power consumption on ICH family network controllers during idle periods, similarly to L1 state on PCI Express NICs. Therefore, it is recommended and enabled by default. However, on some systems it has been observed to have adverse side effects, such as packet loss. It has been established through debug that the problem may be due to firmware misconfiguration of specific systems, interoperability with certain link partners, or marginal electrical conditions of specific units. These problems typically cannot be fixed in the field, and generic workarounds to resolve the side effects on all systems, while keeping K1 enabled, were found infeasible. Therefore, add the option for users to globally disable K1 idle state on the adapter. Additionally, disable K1 by default for MTL and later platforms, due to issues reported with the current configuration. Link: https://lore.kernel.org/intel-wired-lan/CAMqyJG3LVqfgqMcTxeaPur_Jq0oQH7GgdxRuVtRX_6TTH2mX5Q@mail.gmail.com/ Link: https://lore.kernel.org/intel-wired-lan/20250626153544.1853d106@onyx.my.domain/ Link: https://lore.kernel.org/intel-wired-lan/Z_z9EjcKtwHCQcZR@mail-itl/ Link: https://github.com/QubesOS/qubes-issues/issues/9896 Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/2115393 Signed-off-by: Vitaly Lifshits Reviewed-by: Timo Teräs Tested-by: Timo Teräs Reviewed-by: Aleksandr Loktionov Reviewed-by: Dima Ruinskiy Tested-by: Avraham Koren Signed-off-by: Jacob Keller Link: https://patch.msgid.link/20251016-jk-iwl-next-2025-10-15-v2-14-ff3a390d9fc6@intel.com Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/intel/e1000e/e1000.h | 1 + drivers/net/ethernet/intel/e1000e/ethtool.c | 45 ++++++++++++++++++--- drivers/net/ethernet/intel/e1000e/ich8lan.c | 41 ++++++++++--------- drivers/net/ethernet/intel/e1000e/netdev.c | 3 ++ 4 files changed, 67 insertions(+), 23 deletions(-) diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h index 018e61aea787..aa08f397988e 100644 --- a/drivers/net/ethernet/intel/e1000e/e1000.h +++ b/drivers/net/ethernet/intel/e1000e/e1000.h @@ -461,6 +461,7 @@ s32 e1000e_get_base_timinca(struct e1000_adapter *adapter, u32 *timinca); #define FLAG2_CHECK_RX_HWTSTAMP BIT(13) #define FLAG2_CHECK_SYSTIM_OVERFLOW BIT(14) #define FLAG2_ENABLE_S0IX_FLOWS BIT(15) +#define FLAG2_DISABLE_K1 BIT(16) #define E1000_RX_DESC_PS(R, i) \ (&(((union e1000_rx_desc_packet_split *)((R).desc))[i])) diff --git a/drivers/net/ethernet/intel/e1000e/ethtool.c b/drivers/net/ethernet/intel/e1000e/ethtool.c index 8e40bb50a01e..cee57a2149ab 100644 --- a/drivers/net/ethernet/intel/e1000e/ethtool.c +++ b/drivers/net/ethernet/intel/e1000e/ethtool.c @@ -26,6 +26,8 @@ struct e1000_stats { static const char e1000e_priv_flags_strings[][ETH_GSTRING_LEN] = { #define E1000E_PRIV_FLAGS_S0IX_ENABLED BIT(0) "s0ix-enabled", +#define E1000E_PRIV_FLAGS_DISABLE_K1 BIT(1) + "disable-k1", }; #define E1000E_PRIV_FLAGS_STR_LEN ARRAY_SIZE(e1000e_priv_flags_strings) @@ -2301,26 +2303,59 @@ static u32 e1000e_get_priv_flags(struct net_device *netdev) if (adapter->flags2 & FLAG2_ENABLE_S0IX_FLOWS) priv_flags |= E1000E_PRIV_FLAGS_S0IX_ENABLED; + if (adapter->flags2 & FLAG2_DISABLE_K1) + priv_flags |= E1000E_PRIV_FLAGS_DISABLE_K1; + return priv_flags; } static int e1000e_set_priv_flags(struct net_device *netdev, u32 priv_flags) { struct e1000_adapter *adapter = netdev_priv(netdev); + struct e1000_hw *hw = &adapter->hw; unsigned int flags2 = adapter->flags2; + unsigned int changed; + + flags2 &= ~(FLAG2_ENABLE_S0IX_FLOWS | FLAG2_DISABLE_K1); - flags2 &= ~FLAG2_ENABLE_S0IX_FLOWS; if (priv_flags & E1000E_PRIV_FLAGS_S0IX_ENABLED) { - struct e1000_hw *hw = &adapter->hw; - - if (hw->mac.type < e1000_pch_cnp) + if (hw->mac.type < e1000_pch_cnp) { + e_err("S0ix is not supported on this device\n"); return -EINVAL; + } + flags2 |= FLAG2_ENABLE_S0IX_FLOWS; } - if (flags2 != adapter->flags2) + if (priv_flags & E1000E_PRIV_FLAGS_DISABLE_K1) { + if (hw->mac.type < e1000_ich8lan) { + e_err("Disabling K1 is not supported on this device\n"); + return -EINVAL; + } + + flags2 |= FLAG2_DISABLE_K1; + } + + changed = adapter->flags2 ^ flags2; + if (changed) adapter->flags2 = flags2; + if (changed & FLAG2_DISABLE_K1) { + /* reset the hardware to apply the changes */ + while (test_and_set_bit(__E1000_RESETTING, + &adapter->state)) + usleep_range(1000, 2000); + + if (netif_running(adapter->netdev)) { + e1000e_down(adapter, true); + e1000e_up(adapter); + } else { + e1000e_reset(adapter); + } + + clear_bit(__E1000_RESETTING, &adapter->state); + } + return 0; } diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index df4e7d781cb1..0ff8688ac3b8 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -286,21 +286,26 @@ static void e1000_toggle_lanphypc_pch_lpt(struct e1000_hw *hw) } /** - * e1000_reconfigure_k1_exit_timeout - reconfigure K1 exit timeout to - * align to MTP and later platform requirements. + * e1000_reconfigure_k1_params - reconfigure Kumeran K1 parameters. * @hw: pointer to the HW structure * + * By default K1 is enabled after MAC reset, so this function only + * disables it. + * * Context: PHY semaphore must be held by caller. * Return: 0 on success, negative on failure */ -static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw) +static s32 e1000_reconfigure_k1_params(struct e1000_hw *hw) { u16 phy_timeout; u32 fextnvm12; s32 ret_val; - if (hw->mac.type < e1000_pch_mtp) + if (hw->mac.type < e1000_pch_mtp) { + if (hw->adapter->flags2 & FLAG2_DISABLE_K1) + return e1000_configure_k1_ich8lan(hw, false); return 0; + } /* Change Kumeran K1 power down state from P0s to P1 */ fextnvm12 = er32(FEXTNVM12); @@ -310,6 +315,8 @@ static s32 e1000_reconfigure_k1_exit_timeout(struct e1000_hw *hw) /* Wait for the interface the settle */ usleep_range(1000, 1100); + if (hw->adapter->flags2 & FLAG2_DISABLE_K1) + return e1000_configure_k1_ich8lan(hw, false); /* Change K1 exit timeout */ ret_val = e1e_rphy_locked(hw, I217_PHY_TIMEOUTS_REG, @@ -373,8 +380,8 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) /* At this point the PHY might be inaccessible so don't * propagate the failure */ - if (e1000_reconfigure_k1_exit_timeout(hw)) - e_dbg("Failed to reconfigure K1 exit timeout\n"); + if (e1000_reconfigure_k1_params(hw)) + e_dbg("Failed to reconfigure K1 parameters\n"); fallthrough; case e1000_pch_lpt: @@ -473,10 +480,10 @@ static s32 e1000_init_phy_workarounds_pchlan(struct e1000_hw *hw) if (hw->mac.type >= e1000_pch_mtp) { ret_val = hw->phy.ops.acquire(hw); if (ret_val) { - e_err("Failed to reconfigure K1 exit timeout\n"); + e_err("Failed to reconfigure K1 parameters\n"); goto out; } - ret_val = e1000_reconfigure_k1_exit_timeout(hw); + ret_val = e1000_reconfigure_k1_params(hw); hw->phy.ops.release(hw); } } @@ -4948,17 +4955,15 @@ static s32 e1000_init_hw_ich8lan(struct e1000_hw *hw) u16 i; e1000_initialize_hw_bits_ich8lan(hw); - if (hw->mac.type >= e1000_pch_mtp) { - ret_val = hw->phy.ops.acquire(hw); - if (ret_val) - return ret_val; + ret_val = hw->phy.ops.acquire(hw); + if (ret_val) + return ret_val; - ret_val = e1000_reconfigure_k1_exit_timeout(hw); - hw->phy.ops.release(hw); - if (ret_val) { - e_dbg("Error failed to reconfigure K1 exit timeout\n"); - return ret_val; - } + ret_val = e1000_reconfigure_k1_params(hw); + hw->phy.ops.release(hw); + if (ret_val) { + e_dbg("Error failed to reconfigure K1 parameters\n"); + return ret_val; } /* Initialize identification LED */ diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c index 201322dac233..116f3c92b5bc 100644 --- a/drivers/net/ethernet/intel/e1000e/netdev.c +++ b/drivers/net/ethernet/intel/e1000e/netdev.c @@ -7675,6 +7675,9 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* init PTP hardware clock */ e1000e_ptp_init(adapter); + if (hw->mac.type >= e1000_pch_mtp) + adapter->flags2 |= FLAG2_DISABLE_K1; + /* reset the hardware with the new settings */ e1000e_reset(adapter);