When an X710 ethernet port with an active ptp daemon (like the ptp4l and phc2sys combo) suddenly loses its link and regains it after a while, the ptp daemon has a hard time to recover synchronization and sometimes entirely fails to do so. The issue seems to be related to a wrongly configured increment while the link is down. This could not be observed with the Intel reference driver. We identified the fix to appear in Intels official ethernet-linux-i40e release version 2.17.4. Include the relevant changes in the kernel version of this driver. Fixes: beb0dff1251d ("i40e: enable PTP") Cc: stable@vger.kernel.org Signed-off-by: Markus Blöchl --- Tested with an X710 at 10G link speed and kernel version 6.12.42. --- drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h | 9 +++ drivers/net/ethernet/intel/i40e/i40e_ptp.c | 68 +++++++++++++++++++++-- drivers/net/ethernet/intel/i40e/i40e_register.h | 9 +++ drivers/net/ethernet/intel/i40e/i40e_type.h | 8 +++ 4 files changed, 89 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h index cc02a85ad42b..ec176e9569ad 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h +++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h @@ -1488,6 +1488,15 @@ enum i40e_aq_link_speed { I40E_LINK_SPEED_25GB = BIT(I40E_LINK_SPEED_25GB_SHIFT), }; +enum i40e_prt_mac_pcs_link_speed { + I40E_PRT_MAC_PCS_LINK_SPEED_UNKNOWN = 0, + I40E_PRT_MAC_PCS_LINK_SPEED_100MB, + I40E_PRT_MAC_PCS_LINK_SPEED_1GB, + I40E_PRT_MAC_PCS_LINK_SPEED_10GB, + I40E_PRT_MAC_PCS_LINK_SPEED_40GB, + I40E_PRT_MAC_PCS_LINK_SPEED_20GB +}; + struct i40e_aqc_module_desc { u8 oui[3]; u8 reserved1; diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c index 33535418178b..ee6927e2c6f8 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c +++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c @@ -847,6 +847,65 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) i40e_ptp_convert_to_hwtstamp(skb_hwtstamps(skb), ns); } +/** + * i40e_ptp_get_link_speed_hw - get the link speed + * @pf: Board private structure + * + * Calculate link speed depending on the link status. + * Return the link speed. + **/ +static enum i40e_aq_link_speed i40e_ptp_get_link_speed_hw(struct i40e_pf *pf) +{ + bool link_up = pf->hw.phy.link_info.link_info & I40E_AQ_LINK_UP; + enum i40e_aq_link_speed link_speed = I40E_LINK_SPEED_UNKNOWN; + struct i40e_hw *hw = &pf->hw; + + if (link_up) { + struct i40e_link_status *hw_link_info = &hw->phy.link_info; + + i40e_aq_get_link_info(hw, true, NULL, NULL); + link_speed = hw_link_info->link_speed; + } else { + enum i40e_prt_mac_link_speed prtmac_linksta; + u64 prtmac_pcs_linksta; + + prtmac_linksta = (rd32(hw, I40E_PRTMAC_LINKSTA(0)) + & I40E_PRTMAC_LINKSTA_MAC_LINK_SPEED_MASK) + >> I40E_PRTMAC_LINKSTA_MAC_LINK_SPEED_SHIFT; + if (prtmac_linksta == I40E_PRT_MAC_LINK_SPEED_40GB) { + link_speed = I40E_LINK_SPEED_40GB; + } else { + i40e_aq_debug_read_register(hw, + I40E_PRTMAC_PCS_LINK_STATUS1(0), + &prtmac_pcs_linksta, + NULL); + + prtmac_pcs_linksta = (prtmac_pcs_linksta + & I40E_PRTMAC_PCS_LINK_STATUS1_LINK_SPEED_MASK) + >> I40E_PRTMAC_PCS_LINK_STATUS1_LINK_SPEED_SHIFT; + + switch (prtmac_pcs_linksta) { + case I40E_PRT_MAC_PCS_LINK_SPEED_100MB: + link_speed = I40E_LINK_SPEED_100MB; + break; + case I40E_PRT_MAC_PCS_LINK_SPEED_1GB: + link_speed = I40E_LINK_SPEED_1GB; + break; + case I40E_PRT_MAC_PCS_LINK_SPEED_10GB: + link_speed = I40E_LINK_SPEED_10GB; + break; + case I40E_PRT_MAC_PCS_LINK_SPEED_20GB: + link_speed = I40E_LINK_SPEED_20GB; + break; + default: + link_speed = I40E_LINK_SPEED_UNKNOWN; + } + } + } + + return link_speed; +} + /** * i40e_ptp_set_increment - Utility function to update clock increment rate * @pf: Board private structure @@ -857,16 +916,14 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index) **/ void i40e_ptp_set_increment(struct i40e_pf *pf) { - struct i40e_link_status *hw_link_info; + enum i40e_aq_link_speed link_speed; struct i40e_hw *hw = &pf->hw; u64 incval; u32 mult; - hw_link_info = &hw->phy.link_info; + link_speed = i40e_ptp_get_link_speed_hw(pf); - i40e_aq_get_link_info(&pf->hw, true, NULL, NULL); - - switch (hw_link_info->link_speed) { + switch (link_speed) { case I40E_LINK_SPEED_10GB: mult = I40E_PTP_10GB_INCVAL_MULT; break; @@ -909,6 +966,7 @@ void i40e_ptp_set_increment(struct i40e_pf *pf) /* Update the base adjustement value. */ WRITE_ONCE(pf->ptp_adj_mult, mult); smp_mb(); /* Force the above update. */ + i40e_ptp_set_1pps_signal_hw(pf); } /** diff --git a/drivers/net/ethernet/intel/i40e/i40e_register.h b/drivers/net/ethernet/intel/i40e/i40e_register.h index 432afbb64201..c4051dbcc297 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_register.h +++ b/drivers/net/ethernet/intel/i40e/i40e_register.h @@ -530,6 +530,15 @@ #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT 0 #define I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_MASK I40E_MASK(0xFFFF, \ I40E_PRTMAC_HSEC_CTL_TX_PAUSE_REFRESH_TIMER_SHIFT) +/* _i=0...3 */ /* Reset: GLOBR */ +#define I40E_PRTMAC_PCS_LINK_STATUS1(_i) (0x0008C200 + ((_i) * 4)) +#define I40E_PRTMAC_PCS_LINK_STATUS1_LINK_SPEED_SHIFT 24 +#define I40E_PRTMAC_PCS_LINK_STATUS1_LINK_SPEED_MASK I40E_MASK(0x7, I40E_PRTMAC_PCS_LINK_STATUS1_LINK_SPEED_SHIFT) +#define I40E_PRTMAC_PCS_LINK_STATUS2 0x0008C220 +/* _i=0...3 */ /* Reset: GLOBR */ +#define I40E_PRTMAC_LINKSTA(_i) (0x001E2420 + ((_i) * 4)) +#define I40E_PRTMAC_LINKSTA_MAC_LINK_SPEED_SHIFT 27 +#define I40E_PRTMAC_LINKSTA_MAC_LINK_SPEED_MASK I40E_MASK(0x7, I40E_PRTMAC_LINKSTA_MAC_LINK_SPEED_SHIFT) #define I40E_GLNVM_FLA 0x000B6108 /* Reset: POR */ #define I40E_GLNVM_FLA_LOCKED_SHIFT 6 #define I40E_GLNVM_FLA_LOCKED_MASK I40E_MASK(0x1, I40E_GLNVM_FLA_LOCKED_SHIFT) diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h index ed8bbdb586da..98c8c5709e5f 100644 --- a/drivers/net/ethernet/intel/i40e/i40e_type.h +++ b/drivers/net/ethernet/intel/i40e/i40e_type.h @@ -115,6 +115,14 @@ enum i40e_queue_type { I40E_QUEUE_TYPE_UNKNOWN }; +enum i40e_prt_mac_link_speed { + I40E_PRT_MAC_LINK_SPEED_100MB = 0, + I40E_PRT_MAC_LINK_SPEED_1GB, + I40E_PRT_MAC_LINK_SPEED_10GB, + I40E_PRT_MAC_LINK_SPEED_40GB, + I40E_PRT_MAC_LINK_SPEED_20GB +}; + struct i40e_link_status { enum i40e_aq_phy_type phy_type; enum i40e_aq_link_speed link_speed; --- base-commit: 8b690556d8fe074b4f9835075050fba3fb180e93 change-id: 20251119-i40e_ptp_link_down-47934f9e155d Best regards, -- Markus Blöchl --