Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'intel-wired-lan-driver-updates-2026-04-20-ice'

Jacob Keller says:

====================
Intel Wired LAN Driver Updates 2026-04-20 (ice)

Since this is a set of related fixes for just the ice driver, Jake provides
the following description for the series:

We recently ran into a nasty corner case issue with a customer operating
E825C cards seeing some strange behavior with missing Tx timestamps. During
the course of debugging. This series contains a few fixes found during this
debugging process.

The primary issue discovered in the investigation is a misconfiguration of
the E825C PHY timestamp interrupt register, PHY_REG_TS_INT_CONFIG. This
register is responsible for programming the Tx timestamp behavior of a PHY
port. The driver programs two values here: a threshold for when to
interrupt and whether the interrupt is enabled.

The threshold value is used by hardware to determine when to trigger a Tx
timestamp interrupt. The interrupt cause for the port is raised when the
number of outstanding timestamps in the PHY port timestamp memory meets the
threshold. The interrupt cause is not cleared until the number of
outstanding timestamps drops *below* the threshold.

It is considered a misconfiguration if the threshold is programmed to 0. If
the interrupt is enabled while the threshold is zero, hardware will raise
the interrupt cause at the next time it checks. Once raised, the interrupt
cause for the port will never lower, since you cannot have fewer than zero
outstanding timestamps.

Worse, the timestamp status for the port will remain high even if the
PHY_REG_TS_INT_CONFIG is reprogrammed with a new threshold. The PHY is a
separate hardware block from the MAC, and thus the interrupt status for the
port will remain high even if you reset the device MAC with a PF reset,
CORE reset, or GLOBAL reset.

PHY ports are connected together into quads. Each quad muxes the PHY
interrupt status for the 4 ports on the quad together before connecting
that to the MACs miscellaneous interrupt vector. As a result, if a single
PHY port in the quad is stuck, no timestamp interrupts will be generated
for any timestamp on any port on that quad.

The ice driver never directly writes a value of 0 for the threshold.
Indeed, the desired behavior is to set the threshold to 1, so that
interrupts are generated as soon as a single timestamp is captured.
Unfortunately, it turns out that for the E825C PHY, programming the
threshold and enable bit in the same write may cause a race in the PHY
timestamp block. The PHY may "see" the interrupt as enabled first before it
sees the threshold value. If the previous threshold value is zero (such as
when the register is initialized to zero at a cold power on), the hardware
may race with programming the threshold and set the PHY interrupt status to
high as described above.

The first patch in this series corrects that programming order, ensuring
that the threshold is always written first in a separate transaction from
enabling the interrupt bit. Additionally, an explicit check against writing
a 0 is added to make it clear to future readers that writing 0 to the
threshold while enabling the interrupt is not safe.

The PHY timestamp block does not reset with the MAC, and seems to only
reset during cold power on. This makes recovery from the faulty
configuration difficult. To address this, perform an explicit reset of the
PHY PTP block during initialization. This is achieved by writing the
PHY_REG_GLOBAL register. This performs a PHY soft reset, which completely
resets the timestamp block. This includes clearing the timestamp memory,
the PHY timestamp interrupt status, and the PHY PTP counter. A soft reset
of all ports on the device is done as part of ice_ptp_init_phc() during
early initialization of the PTP functionality by the PTP clock owner, prior
to programming each PHY. The ice_ptp_init_phc() function is called at
driver init and during reinitialization after all forms of device reset.
This ensures that the driver begins operation at a clean slate, rather than
carrying over the stale and potentially buggy configuration of a previous
driver.

While attempting to root cause the issue with the PHY timestamp interrupt,
we also discovered that the driver incorrectly assumes that it is operating
on E822 hardware when reading the PHY timestamp memory status registers in
a few places. This includes the check at the end of the interrupt handler,
as well as the check done inside the PTP auxiliary function. This prevented
the driver from detecting waiting timestamps on ports other than the first
two.

Finally, the ice_ptp_read_tx_hwstamp_status_eth56g() function was
discovered to only read the timestamp interrupt status value from the first
quad due to mistaking the port index for a PHY quad index. This resulted in
reporting the timestamp status for the second quad as identical to the
first quad instead of properly reporting its value. This is a minor fix
since the function currently is only used for diagnostic purposes and does
not impact driver decision logic.
====================

Link: https://patch.msgid.link/20260420-jk-iwl-net-2026-04-20-ptp-e825c-phy-interrupt-fixes-v1-0-bc2240f42251@intel.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+269 -33
+18 -26
drivers/net/ethernet/intel/ice/ice_ptp.c
··· 2710 2710 bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) 2711 2711 { 2712 2712 struct ice_hw *hw = &pf->hw; 2713 - unsigned int i; 2713 + int ret; 2714 2714 2715 2715 /* Check software indicator */ 2716 2716 switch (pf->ptp.tx_interrupt_mode) { ··· 2731 2731 } 2732 2732 2733 2733 /* Check hardware indicator */ 2734 - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { 2735 - u64 tstamp_ready = 0; 2736 - int err; 2737 - 2738 - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); 2739 - if (err || tstamp_ready) 2740 - return true; 2734 + ret = ice_check_phy_tx_tstamp_ready(hw); 2735 + if (ret < 0) { 2736 + dev_dbg(ice_pf_to_dev(pf), "Unable to read PHY Tx timestamp ready bitmap, err %d\n", 2737 + ret); 2738 + /* Stop triggering IRQs if we're unable to read PHY */ 2739 + return false; 2741 2740 } 2742 2741 2743 - return false; 2742 + /* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps 2743 + * available, 0 if there are no waiting timestamps, and a negative 2744 + * value if there was an error (which we checked for above). 2745 + */ 2746 + return ret > 0; 2744 2747 } 2745 2748 2746 2749 /** ··· 2827 2824 { 2828 2825 struct device *dev = ice_pf_to_dev(pf); 2829 2826 struct ice_hw *hw = &pf->hw; 2830 - bool trigger_oicr = false; 2831 - unsigned int i; 2827 + int ret; 2832 2828 2833 2829 if (!pf->ptp.port.tx.has_ready_bitmap) 2834 2830 return; ··· 2835 2833 if (!ice_pf_src_tmr_owned(pf)) 2836 2834 return; 2837 2835 2838 - for (i = 0; i < ICE_GET_QUAD_NUM(hw->ptp.num_lports); i++) { 2839 - u64 tstamp_ready; 2840 - int err; 2841 - 2842 - err = ice_get_phy_tx_tstamp_ready(&pf->hw, i, &tstamp_ready); 2843 - if (!err && tstamp_ready) { 2844 - trigger_oicr = true; 2845 - break; 2846 - } 2847 - } 2848 - 2849 - if (trigger_oicr) { 2850 - /* Trigger a software interrupt, to ensure this data 2851 - * gets processed. 2852 - */ 2836 + ret = ice_check_phy_tx_tstamp_ready(hw); 2837 + if (ret < 0) { 2838 + dev_dbg(dev, "PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n", 2839 + ret); 2840 + } else if (ret) { 2853 2841 dev_dbg(dev, "PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n"); 2854 2842 2855 2843 wr32(hw, PFINT_OICR, PFINT_OICR_TSYN_TX_M);
+246 -7
drivers/net/ethernet/intel/ice/ice_ptp_hw.c
··· 378 378 */ 379 379 380 380 /** 381 + * ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization 382 + * @hw: pointer to HW struct 383 + * 384 + * Perform E825C-specific PTP hardware clock initialization steps. 385 + * 386 + * Return: 0 on success, or a negative error value on failure. 387 + */ 388 + static int ice_ptp_init_phc_e825c(struct ice_hw *hw) 389 + { 390 + int err; 391 + 392 + /* Soft reset all ports, to ensure everything is at a clean state */ 393 + for (int port = 0; port < hw->ptp.num_lports; port++) { 394 + err = ice_ptp_phy_soft_reset_eth56g(hw, port); 395 + if (err) { 396 + ice_debug(hw, ICE_DBG_PTP, "Failed to soft reset port %d, err %d\n", 397 + port, err); 398 + return err; 399 + } 400 + } 401 + 402 + return 0; 403 + } 404 + 405 + /** 381 406 * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number 382 407 * @hw: pointer to the HW struct 383 408 * @port: destination port ··· 1872 1847 * @ena: enable or disable interrupt 1873 1848 * @threshold: interrupt threshold 1874 1849 * 1850 + * The threshold cannot be 0 while the interrupt is enabled. 1851 + * 1875 1852 * Configure TX timestamp interrupt for the specified port 1876 1853 * 1877 1854 * Return: ··· 1885 1858 int err; 1886 1859 u32 val; 1887 1860 1861 + if (ena && !threshold) 1862 + return -EINVAL; 1863 + 1888 1864 err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); 1889 1865 if (err) 1890 1866 return err; 1891 1867 1868 + val &= ~PHY_TS_INT_CONFIG_ENA_M; 1892 1869 if (ena) { 1893 - val |= PHY_TS_INT_CONFIG_ENA_M; 1894 1870 val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M; 1895 1871 val |= FIELD_PREP(PHY_TS_INT_CONFIG_THRESHOLD_M, threshold); 1896 - } else { 1897 - val &= ~PHY_TS_INT_CONFIG_ENA_M; 1872 + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, 1873 + val); 1874 + if (err) { 1875 + ice_debug(hw, ICE_DBG_PTP, 1876 + "Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", 1877 + port, !!ena, threshold); 1878 + return err; 1879 + } 1880 + val |= PHY_TS_INT_CONFIG_ENA_M; 1898 1881 } 1899 1882 1900 - return ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); 1883 + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, val); 1884 + if (err) { 1885 + ice_debug(hw, ICE_DBG_PTP, 1886 + "Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", 1887 + port, !!ena, threshold); 1888 + return err; 1889 + } 1890 + 1891 + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_TS_INT_CONFIG, &val); 1892 + if (err) { 1893 + ice_debug(hw, ICE_DBG_PTP, 1894 + "Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n", 1895 + port, !!ena, threshold); 1896 + return err; 1897 + } 1898 + 1899 + return 0; 1901 1900 } 1902 1901 1903 1902 /** ··· 2169 2116 } 2170 2117 2171 2118 /** 2119 + * ice_check_phy_tx_tstamp_ready_eth56g - Check Tx memory status for all ports 2120 + * @hw: pointer to the HW struct 2121 + * 2122 + * Check the PHY_REG_TX_MEMORY_STATUS for all ports. A set bit indicates 2123 + * a waiting timestamp. 2124 + * 2125 + * Return: 1 if any port has at least one timestamp ready bit set, 2126 + * 0 otherwise, and a negative error code if unable to read the bitmap. 2127 + */ 2128 + static int ice_check_phy_tx_tstamp_ready_eth56g(struct ice_hw *hw) 2129 + { 2130 + int port; 2131 + 2132 + for (port = 0; port < hw->ptp.num_lports; port++) { 2133 + u64 tstamp_ready; 2134 + int err; 2135 + 2136 + err = ice_get_phy_tx_tstamp_ready(hw, port, &tstamp_ready); 2137 + if (err) 2138 + return err; 2139 + 2140 + if (tstamp_ready) 2141 + return 1; 2142 + } 2143 + 2144 + return 0; 2145 + } 2146 + 2147 + /** 2172 2148 * ice_ptp_read_tx_hwtstamp_status_eth56g - Get TX timestamp status 2173 2149 * @hw: pointer to the HW struct 2174 2150 * @ts_status: the timestamp mask pointer ··· 2219 2137 *ts_status = 0; 2220 2138 2221 2139 for (phy = 0; phy < params->num_phys; phy++) { 2140 + u8 port; 2222 2141 int err; 2223 2142 2224 - err = ice_read_phy_eth56g(hw, phy, PHY_PTP_INT_STATUS, &status); 2143 + /* ice_read_phy_eth56g expects a port index, so use the first 2144 + * port of the PHY 2145 + */ 2146 + port = phy * hw->ptp.ports_per_phy; 2147 + 2148 + err = ice_read_phy_eth56g(hw, port, PHY_PTP_INT_STATUS, &status); 2225 2149 if (err) 2226 2150 return err; 2227 2151 2228 - *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); 2152 + *ts_status |= (status & mask) << port; 2229 2153 } 2230 2154 2231 2155 ice_debug(hw, ICE_DBG_PTP, "PHY interrupt err: %x\n", *ts_status); 2232 2156 2233 2157 return 0; 2158 + } 2159 + 2160 + /** 2161 + * ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G 2162 + * @hw: pointer to the HW structure 2163 + * @port: PHY port number 2164 + * 2165 + * Trigger a soft reset of the ETH56G PHY by toggling the soft reset 2166 + * bit in the PHY global register. The reset sequence consists of: 2167 + * 1. Clearing the soft reset bit 2168 + * 2. Asserting the soft reset bit 2169 + * 3. Clearing the soft reset bit again 2170 + * 2171 + * Short delays are inserted between each step to allow the hardware 2172 + * to settle. This provides a controlled way to reinitialize the PHY 2173 + * without requiring a full device reset. 2174 + * 2175 + * Return: 0 on success, or a negative error code on failure when 2176 + * reading or writing the PHY register. 2177 + */ 2178 + int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port) 2179 + { 2180 + u32 global_val; 2181 + int err; 2182 + 2183 + err = ice_read_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, &global_val); 2184 + if (err) { 2185 + ice_debug(hw, ICE_DBG_PTP, "Failed to read PHY_REG_GLOBAL for port %d, err %d\n", 2186 + port, err); 2187 + return err; 2188 + } 2189 + 2190 + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; 2191 + ice_debug(hw, ICE_DBG_PTP, "Clearing soft reset bit for port %d, val: 0x%x\n", 2192 + port, global_val); 2193 + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); 2194 + if (err) { 2195 + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", 2196 + port, err); 2197 + return err; 2198 + } 2199 + 2200 + usleep_range(5000, 6000); 2201 + 2202 + global_val |= PHY_REG_GLOBAL_SOFT_RESET_M; 2203 + ice_debug(hw, ICE_DBG_PTP, "Set soft reset bit for port %d, val: 0x%x\n", 2204 + port, global_val); 2205 + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); 2206 + if (err) { 2207 + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", 2208 + port, err); 2209 + return err; 2210 + } 2211 + usleep_range(5000, 6000); 2212 + 2213 + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M; 2214 + ice_debug(hw, ICE_DBG_PTP, "Clear soft reset bit for port %d, val: 0x%x\n", 2215 + port, global_val); 2216 + err = ice_write_ptp_reg_eth56g(hw, port, PHY_REG_GLOBAL, global_val); 2217 + if (err) 2218 + ice_debug(hw, ICE_DBG_PTP, "Failed to write PHY_REG_GLOBAL for port %d, err %d\n", 2219 + port, err); 2220 + return err; 2234 2221 } 2235 2222 2236 2223 /** ··· 4354 4203 } 4355 4204 4356 4205 /** 4206 + * ice_check_phy_tx_tstamp_ready_e82x - Check Tx memory status for all quads 4207 + * @hw: pointer to the HW struct 4208 + * 4209 + * Check the Q_REG_TX_MEMORY_STATUS for all quads. A set bit indicates 4210 + * a waiting timestamp. 4211 + * 4212 + * Return: 1 if any quad has at least one timestamp ready bit set, 4213 + * 0 otherwise, and a negative error value if unable to read the bitmap. 4214 + */ 4215 + static int ice_check_phy_tx_tstamp_ready_e82x(struct ice_hw *hw) 4216 + { 4217 + int quad; 4218 + 4219 + for (quad = 0; quad < ICE_GET_QUAD_NUM(hw->ptp.num_lports); quad++) { 4220 + u64 tstamp_ready; 4221 + int err; 4222 + 4223 + err = ice_get_phy_tx_tstamp_ready(hw, quad, &tstamp_ready); 4224 + if (err) 4225 + return err; 4226 + 4227 + if (tstamp_ready) 4228 + return 1; 4229 + } 4230 + 4231 + return 0; 4232 + } 4233 + 4234 + /** 4357 4235 * ice_phy_cfg_intr_e82x - Configure TX timestamp interrupt 4358 4236 * @hw: pointer to the HW struct 4359 4237 * @quad: the timestamp quad ··· 4935 4755 return 0; 4936 4756 } 4937 4757 4758 + /** 4759 + * ice_check_phy_tx_tstamp_ready_e810 - Check Tx memory status register 4760 + * @hw: pointer to the HW struct 4761 + * 4762 + * The E810 devices do not have a Tx memory status register. Note this is 4763 + * intentionally different behavior from ice_get_phy_tx_tstamp_ready_e810 4764 + * which always says that all bits are ready. This function is called in cases 4765 + * where code will trigger interrupts if timestamps are waiting, and should 4766 + * not be called for E810 hardware. 4767 + * 4768 + * Return: 0. 4769 + */ 4770 + static int ice_check_phy_tx_tstamp_ready_e810(struct ice_hw *hw) 4771 + { 4772 + return 0; 4773 + } 4774 + 4938 4775 /* E810 SMA functions 4939 4776 * 4940 4777 * The following functions operate specifically on E810 hardware and are used ··· 5204 5007 *tstamp_ready = rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_H); 5205 5008 *tstamp_ready <<= 32; 5206 5009 *tstamp_ready |= rd32(hw, E830_PRTMAC_TS_TX_MEM_VALID_L); 5010 + } 5011 + 5012 + /** 5013 + * ice_check_phy_tx_tstamp_ready_e830 - Check Tx memory status register 5014 + * @hw: pointer to the HW struct 5015 + * 5016 + * Return: 1 if the device has waiting timestamps, 0 otherwise. 5017 + */ 5018 + static int ice_check_phy_tx_tstamp_ready_e830(struct ice_hw *hw) 5019 + { 5020 + u64 tstamp_ready; 5021 + 5022 + ice_get_phy_tx_tstamp_ready_e830(hw, 0, &tstamp_ready); 5023 + 5024 + return !!tstamp_ready; 5207 5025 } 5208 5026 5209 5027 /** ··· 5776 5564 case ICE_MAC_GENERIC: 5777 5565 return ice_ptp_init_phc_e82x(hw); 5778 5566 case ICE_MAC_GENERIC_3K_E825: 5779 - return 0; 5567 + return ice_ptp_init_phc_e825c(hw); 5780 5568 default: 5781 5569 return -EOPNOTSUPP; 5782 5570 } ··· 5808 5596 case ICE_MAC_GENERIC_3K_E825: 5809 5597 return ice_get_phy_tx_tstamp_ready_eth56g(hw, block, 5810 5598 tstamp_ready); 5599 + default: 5600 + return -EOPNOTSUPP; 5601 + } 5602 + } 5603 + 5604 + /** 5605 + * ice_check_phy_tx_tstamp_ready - Check PHY Tx timestamp memory status 5606 + * @hw: pointer to the HW struct 5607 + * 5608 + * Check the PHY for Tx timestamp memory status on all ports. If you need to 5609 + * see individual timestamp status for each index, use 5610 + * ice_get_phy_tx_tstamp_ready() instead. 5611 + * 5612 + * Return: 1 if any port has timestamps available, 0 if there are no timestamps 5613 + * available, and a negative error code on failure. 5614 + */ 5615 + int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw) 5616 + { 5617 + switch (hw->mac_type) { 5618 + case ICE_MAC_E810: 5619 + return ice_check_phy_tx_tstamp_ready_e810(hw); 5620 + case ICE_MAC_E830: 5621 + return ice_check_phy_tx_tstamp_ready_e830(hw); 5622 + case ICE_MAC_GENERIC: 5623 + return ice_check_phy_tx_tstamp_ready_e82x(hw); 5624 + case ICE_MAC_GENERIC_3K_E825: 5625 + return ice_check_phy_tx_tstamp_ready_eth56g(hw); 5811 5626 default: 5812 5627 return -EOPNOTSUPP; 5813 5628 }
+5
drivers/net/ethernet/intel/ice/ice_ptp_hw.h
··· 300 300 int ice_ptp_init_phc(struct ice_hw *hw); 301 301 void ice_ptp_init_hw(struct ice_hw *hw); 302 302 int ice_get_phy_tx_tstamp_ready(struct ice_hw *hw, u8 block, u64 *tstamp_ready); 303 + int ice_check_phy_tx_tstamp_ready(struct ice_hw *hw); 303 304 int ice_ptp_one_port_cmd(struct ice_hw *hw, u8 configured_port, 304 305 enum ice_ptp_tmr_cmd configured_cmd); 305 306 ··· 375 374 int ice_start_phy_timer_eth56g(struct ice_hw *hw, u8 port); 376 375 int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold); 377 376 int ice_phy_cfg_ptp_1step_eth56g(struct ice_hw *hw, u8 port); 377 + int ice_ptp_phy_soft_reset_eth56g(struct ice_hw *hw, u8 port); 378 378 379 379 #define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL 380 380 #define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL ··· 678 676 #define ICE_P0_GNSS_PRSNT_N BIT(4) 679 677 680 678 /* ETH56G PHY register addresses */ 679 + #define PHY_REG_GLOBAL 0x0 680 + #define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) 681 + 681 682 /* Timestamp PHY incval registers */ 682 683 #define PHY_REG_TIMETUS_L 0x8 683 684 #define PHY_REG_TIMETUS_U 0xC