From 8218be96aff2075b3f10d2a0636ccd0f63472fa7 Mon Sep 17 00:00:00 2001 From: Revanth Kumar Uppala Date: Thu, 4 Sep 2025 06:46:16 +0000 Subject: [PATCH] r8126: Fix PCIe completion timeouts During PTP operation, abnormal interrupt handling could stall internal transactions, leading to delayed BAR register reads and PCIe completion timeout errors. This patch adjusts the PTP interrupt mechanism to eliminate the stall and reduce latency. Bug 4755448 Change-Id: Id7fa3fbcac33ba89b3635d86a15932ac95f7e4bd Signed-off-by: Revanth Kumar Uppala Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/3446108 Reviewed-by: Brad Griffis GVS: buildbot_gerritrpt Reviewed-by: Shobek Attupurath --- drivers/net/ethernet/realtek/r8126/r8126.h | 2 + drivers/net/ethernet/realtek/r8126/r8126_n.c | 44 ++++++++++------- .../net/ethernet/realtek/r8126/r8126_ptp.c | 49 +++++++++---------- .../net/ethernet/realtek/r8126/r8126_ptp.h | 2 +- 4 files changed, 53 insertions(+), 44 deletions(-) diff --git a/drivers/net/ethernet/realtek/r8126/r8126.h b/drivers/net/ethernet/realtek/r8126/r8126.h index 83b851ee..ef028d11 100644 --- a/drivers/net/ethernet/realtek/r8126/r8126.h +++ b/drivers/net/ethernet/realtek/r8126/r8126.h @@ -1584,6 +1584,7 @@ enum RTL8126_registers { PTP_Time_SHIFTER_S_8125 = 0x6856, PPS_RISE_TIME_NS_8125 = 0x68A0, PPS_RISE_TIME_S_8125 = 0x68A4, + PTP_DUMMY_REG = 0XC070, PTP_EGRESS_TIME_BASE_NS_8125 = 0XCF20, PTP_EGRESS_TIME_BASE_S_8125 = 0XCF24, PTP_CTL = 0xE400, @@ -2760,6 +2761,7 @@ struct rtl8126_private { u16 MacMcuPageSize; u64 hw_mcu_patch_code_ver; u64 bin_mcu_patch_code_ver; + u8 hw_has_mac_mcu_patch_code; u8 HwSuppTcamVer; diff --git a/drivers/net/ethernet/realtek/r8126/r8126_n.c b/drivers/net/ethernet/realtek/r8126/r8126_n.c index 2bd5e53a..5458c468 100644 --- a/drivers/net/ethernet/realtek/r8126/r8126_n.c +++ b/drivers/net/ethernet/realtek/r8126/r8126_n.c @@ -1021,6 +1021,7 @@ static int proc_get_driver_variable(struct seq_file *m, void *v) seq_printf(m, "HwIcVerUnknown\t0x%x\n", tp->HwIcVerUnknown); seq_printf(m, "NotWrRamCodeToMicroP\t0x%x\n", tp->NotWrRamCodeToMicroP); seq_printf(m, "NotWrMcuPatchCode\t0x%x\n", tp->NotWrMcuPatchCode); + seq_printf(m, "hw_has_mac_mcu_patch_code\t0x%x\n", tp->hw_has_mac_mcu_patch_code); seq_printf(m, "HwHasWrRamCodeToMicroP\t0x%x\n", tp->HwHasWrRamCodeToMicroP); seq_printf(m, "sw_ram_code_ver\t0x%x\n", tp->sw_ram_code_ver); seq_printf(m, "hw_ram_code_ver\t0x%x\n", tp->hw_ram_code_ver); @@ -1745,6 +1746,7 @@ static int proc_get_driver_variable(char *page, char **start, "HwIcVerUnknown\t0x%x\n" "NotWrRamCodeToMicroP\t0x%x\n" "NotWrMcuPatchCode\t0x%x\n" + "hw_has_mac_mcu_patch_code\t0x%x\n" "HwHasWrRamCodeToMicroP\t0x%x\n" "sw_ram_code_ver\t0x%x\n" "hw_ram_code_ver\t0x%x\n" @@ -1872,6 +1874,7 @@ static int proc_get_driver_variable(char *page, char **start, tp->HwIcVerUnknown, tp->NotWrRamCodeToMicroP, tp->NotWrMcuPatchCode, + tp->hw_has_mac_mcu_patch_code, tp->HwHasWrRamCodeToMicroP, tp->sw_ram_code_ver, tp->hw_ram_code_ver, @@ -2969,9 +2972,11 @@ static ssize_t testmode_show(struct device *dev, struct net_device *netdev = to_net_dev(dev); struct rtl8126_private *tp = netdev_priv(netdev); - sprintf(buf, "%u\n", tp->testmode); - - return strlen(buf); +#if LINUX_VERSION_CODE < KERNEL_VERSION(5,4,103) + return sprintf(buf, "%u\n", tp->testmode); +#else + return sysfs_emit(buf, "%u\n", tp->testmode); +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(5,4,103) */ } static ssize_t testmode_store(struct device *dev, @@ -4057,8 +4062,7 @@ static bool rtl8126_vec_2_tx_q_num( struct rtl8126_private *tp, u32 messageId, - u32 *qnum -) + u32 *qnum) { u32 whichQ = 0xffffffff; bool rc = false; @@ -4109,8 +4113,7 @@ static bool rtl8126_vec_2_rx_q_num( struct rtl8126_private *tp, u32 messageId, - u32 *qnum -) + u32 *qnum) { u32 whichQ = 0xffffffff; bool rc = false; @@ -6957,6 +6960,9 @@ rtl8126_wait_phy_ups_resume(struct net_device *dev, u16 PhyState) static void rtl8126_set_mcu_d3_stack(struct rtl8126_private *tp) { + if (!tp->hw_has_mac_mcu_patch_code) + return; + switch (tp->mcfg) { case CFG_METHOD_2: rtl8126_mac_ocp_write(tp, 0xD018, 0xD116); @@ -7216,8 +7222,8 @@ rtl8126_set_mac_mcu_8126a_2(struct net_device *dev) rtl8126_mac_ocp_write(tp, 0xFC26, 0x8000); - //rtl8126_mac_ocp_write(tp, 0xFC28, 0x00FE); - //rtl8126_mac_ocp_write(tp, 0xFC2A, 0x4A14); + rtl8126_mac_ocp_write(tp, 0xFC28, 0x00FE); + rtl8126_mac_ocp_write(tp, 0xFC2A, 0x4A14); rtl8126_mac_ocp_write(tp, 0xFC2C, 0x2360); rtl8126_mac_ocp_write(tp, 0xFC2E, 0x14A4); rtl8126_mac_ocp_write(tp, 0xFC30, 0x415E); @@ -7225,7 +7231,7 @@ rtl8126_set_mac_mcu_8126a_2(struct net_device *dev) rtl8126_mac_ocp_write(tp, 0xFC34, 0x4280); rtl8126_mac_ocp_write(tp, 0xFC36, 0x234A); - rtl8126_mac_ocp_write(tp, 0xFC48, 0x00FC); + rtl8126_mac_ocp_write(tp, 0xFC48, 0x00FF); } static void @@ -7281,8 +7287,8 @@ rtl8126_set_mac_mcu_8126a_3(struct net_device *dev) rtl8126_mac_ocp_write(tp, 0xFC26, 0x8000); - //rtl8126_mac_ocp_write(tp, 0xFC28, 0x00FE); - //rtl8126_mac_ocp_write(tp, 0xFC2A, 0x55DE); + rtl8126_mac_ocp_write(tp, 0xFC28, 0x00FE); + rtl8126_mac_ocp_write(tp, 0xFC2A, 0x55DE); rtl8126_mac_ocp_write(tp, 0xFC2C, 0x14A4); rtl8126_mac_ocp_write(tp, 0xFC2E, 0x4176); rtl8126_mac_ocp_write(tp, 0xFC30, 0x41FC); @@ -7292,7 +7298,7 @@ rtl8126_set_mac_mcu_8126a_3(struct net_device *dev) //rtl8126_mac_ocp_write(tp, 0xFC38, 0x2382); rtl8126_mac_ocp_write(tp, 0xFC3A, 0x234A); - rtl8126_mac_ocp_write(tp, 0xFC48, 0x023C); + rtl8126_mac_ocp_write(tp, 0xFC48, 0x023F); } static void @@ -7300,6 +7306,8 @@ rtl8126_hw_mac_mcu_config(struct net_device *dev) { struct rtl8126_private *tp = netdev_priv(dev); + tp->hw_has_mac_mcu_patch_code = FALSE; + if (tp->NotWrMcuPatchCode == TRUE) return; @@ -7315,7 +7323,11 @@ rtl8126_hw_mac_mcu_config(struct net_device *dev) case CFG_METHOD_3: rtl8126_set_mac_mcu_8126a_3(dev); break; + default: + return; } + + tp->hw_has_mac_mcu_patch_code = TRUE; } #endif @@ -7351,6 +7363,8 @@ static void rtl8126_apply_firmware(struct rtl8126_private *tp) tp->sw_ram_code_ver = tp->hw_ram_code_ver; tp->HwHasWrRamCodeToMicroP = TRUE; + tp->hw_has_mac_mcu_patch_code = TRUE; + r8126_spin_unlock(&tp->phy_lock, flags); } } @@ -16374,10 +16388,6 @@ static void rtl8126_shutdown(struct pci_dev *pdev) tp->wol_enabled = WOL_DISABLED; rtl8126_close(dev); - - if (netif_running(dev)) - netif_device_detach(dev); - rtl8126_disable_msi(pdev, tp); rtnl_unlock(); diff --git a/drivers/net/ethernet/realtek/r8126/r8126_ptp.c b/drivers/net/ethernet/realtek/r8126/r8126_ptp.c index 9c74eb1d..df4d1327 100644 --- a/drivers/net/ethernet/realtek/r8126/r8126_ptp.c +++ b/drivers/net/ethernet/realtek/r8126/r8126_ptp.c @@ -560,8 +560,6 @@ static void rtl8126_ptp_tx_hwtstamp(struct rtl8126_private *tp) struct skb_shared_hwtstamps shhwtstamps = { 0 }; struct timespec64 ts64; - rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR); - rtl8126_ptp_egresstime(tp, &ts64); /* Upper 32 bits contain s, lower 32 bits contain ns. */ @@ -592,31 +590,28 @@ static void rtl8126_ptp_tx_work(struct work_struct *work) if (!tp->ptp_tx_skb) return; + rtnl_lock(); + if (rtl8126_mac_ocp_read(tp, PTP_DUMMY_REG) & TX_TS_INTR) { + tx_intr = true; + rtl8126_mac_ocp_write(tp, PTP_DUMMY_REG, TX_TS_INTR); + } else + tx_intr = false; + rtnl_unlock(); + if (time_is_before_jiffies(tp->ptp_tx_start + RTL8126_PTP_TX_TIMEOUT)) { dev_kfree_skb_any(tp->ptp_tx_skb); tp->ptp_tx_skb = NULL; clear_bit_unlock(__RTL8126_PTP_TX_IN_PROGRESS, &tp->state); tp->tx_hwtstamp_timeouts++; - /* Clear the tx valid bit in TSYNCTXCTL register to enable - * interrupt - */ - r8126_spin_lock(&tp->phy_lock, flags); - rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, TX_TX_INTR); - r8126_spin_unlock(&tp->phy_lock, flags); return; } - r8126_spin_lock(&tp->phy_lock, flags); - if (rtl8126_mdio_direct_read_phy_ocp(tp, PTP_INSR) & TX_TX_INTR) { - tx_intr = true; + if (tx_intr) { + r8126_spin_lock(&tp->phy_lock, flags); rtl8126_ptp_tx_hwtstamp(tp); + r8126_spin_unlock(&tp->phy_lock, flags); } else { - tx_intr = false; - } - r8126_spin_unlock(&tp->phy_lock, flags); - - if (!tx_intr) { /* reschedule to check later */ schedule_work(&tp->ptp_tx_work); } @@ -626,26 +621,28 @@ static int rtl8126_hwtstamp_enable(struct rtl8126_private *tp, bool enable) { unsigned long flags; + ASSERT_RTNL(); + r8126_spin_lock(&tp->phy_lock, flags); + /* trx timestamp interrupt disable */ + rtl8126_clear_eth_phy_ocp_bit(tp, PTP_INER, RX_TS_INTR | TX_TS_INTR); + + //clear ptp isr + rtl8126_mac_ocp_write(tp, PTP_DUMMY_REG, 0xffff); + if (enable) { - //trx timestamp interrupt enable - rtl8126_set_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3); + //tx timestamp interrupt enable + rtl8126_set_eth_phy_ocp_bit(tp, PTP_INER, TX_TS_INTR); - //set isr clear mode - rtl8126_set_eth_phy_ocp_bit(tp, PTP_GEN_CFG, BIT_0); - - //clear ptp isr - rtl8126_mdio_direct_write_phy_ocp(tp, PTP_INSR, 0xFFFF); + //set isr clear mode to read clear + rtl8126_clear_eth_phy_ocp_bit(tp, PTP_GEN_CFG, BIT_0); //enable ptp rtl8126_ptp_enable_config(tp); //rtl8126_set_local_time(tp); } else { - /* trx timestamp interrupt disable */ - rtl8126_clear_eth_phy_ocp_bit(tp, PTP_INER, BIT_2 | BIT_3); - /* disable ptp */ rtl8126_clear_eth_phy_ocp_bit(tp, PTP_SYNCE_CTL, BIT_0); rtl8126_clear_eth_phy_ocp_bit(tp, PTP_CTL, BIT_0); diff --git a/drivers/net/ethernet/realtek/r8126/r8126_ptp.h b/drivers/net/ethernet/realtek/r8126/r8126_ptp.h index 62366dd6..d9fb256e 100644 --- a/drivers/net/ethernet/realtek/r8126/r8126_ptp.h +++ b/drivers/net/ethernet/realtek/r8126/r8126_ptp.h @@ -94,7 +94,7 @@ enum PTP_INSR_TYPE { EVENT_CAP_INTR = (1 << 0), TRIG_GEN_INTR = (1 << 1), RX_TS_INTR = (1 << 2), - TX_TX_INTR = (1 << 3), + TX_TS_INTR = (1 << 3), }; enum PTP_TRX_TS_STA_REG {