From: Andrew LaMarche Date: Mon, 31 Mar 2025 17:00:28 +0000 (+0000) Subject: octeon: force pcs reset to fix qca833x traffic X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fpull%2F18385%2Fhead;p=thirdparty%2Fopenwrt.git octeon: force pcs reset to fix qca833x traffic There is a known bug with qca833x switches where they fail to pass traffic without first resetting the PCS. U-Boot already has this fix, though it uses a much newer networking stack from Marvell. This commit backports the fix for OpenWrt. References: - https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L197-L225 - https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L701-L737 Signed-off-by: Andrew LaMarche Link: https://github.com/openwrt/openwrt/pull/18385 Signed-off-by: Robert Marko --- diff --git a/target/linux/octeon/patches-6.6/702-qca833x-force-pcs-reset.patch b/target/linux/octeon/patches-6.6/702-qca833x-force-pcs-reset.patch new file mode 100644 index 00000000000..ed405e88c09 --- /dev/null +++ b/target/linux/octeon/patches-6.6/702-qca833x-force-pcs-reset.patch @@ -0,0 +1,123 @@ +From: Andrew LaMarche +Date: Mon, 31 Mar 2025 13:00:00 +0000 +Subject: [PATCH] octeon: force pcs reset + +QCA833x devices misbehave with SGMII until a PCS reset is triggered. U-boot has +a newer vendor GPL dump that contains logic to reset the PCS. This patch +backports that functionality so that Octeon devices with QCA833{4/7} switchs +pass traffic between the switch and CPU. + +References: +- https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L197-L225 +- https://github.com/u-boot/u-boot/blob/master/arch/mips/mach-octeon/cvmx-helper-sgmii.c#L701-L737 + +Signed-off-by: Andrew LaMarche +--- a/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c ++++ b/arch/mips/cavium-octeon/executive/cvmx-helper-sgmii.c +@@ -125,6 +125,17 @@ static int __cvmx_helper_sgmii_hardware_ + return 0; + } + ++static int __cvmx_helper_need_g15618(void) ++{ ++ if (cvmx_sysinfo_get()->board_type == CVMX_BOARD_TYPE_SIM || ++ OCTEON_IS_MODEL(OCTEON_CN63XX) || ++ OCTEON_IS_MODEL(OCTEON_CN66XX_PASS1_X) || ++ OCTEON_IS_MODEL(OCTEON_CN68XX)) ++ return 1; ++ else ++ return 0; ++} ++ + /** + * Initialize the SERTES link for the first time or after a loss + * of link. +@@ -172,6 +183,39 @@ static int __cvmx_helper_sgmii_hardware_ + cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), + control_reg.u64); + ++ /* Force a PCS reset by powering down the PCS interface ++ * This is needed to deal with broken Qualcomm/Atheros PHYs and switches ++ * which never recover if PCS is not power cycled. The alternative ++ * is to power cycle or hardware reset the Qualcomm devices whenever ++ * SGMII is initialized. ++ * ++ * This is needed for the QCA8033 PHYs as well as the QCA833X switches ++ * to work. The QCA8337 switch has additional SGMII problems and is ++ * best avoided if at all possible. Failure to power cycle PCS prevents ++ * any traffic from flowing between Octeon and Qualcomm devices if there ++ * is a warm reset. Even a software reset to the Qualcomm device will ++ * not work. ++ * ++ * Note that this problem has been reported between Qualcomm and other ++ * vendor's processors as well so this problem is not unique to ++ * Qualcomm and Octeon. ++ * ++ * Power cycling PCS doesn't hurt anything with non-Qualcomm devices ++ * other than adding a 25ms delay during initialization. ++ */ ++ control_reg.s.pwr_dn = 1; ++ cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), ++ control_reg.u64); ++ cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); ++ ++ if (cvmx_sysinfo_get()->board_type != CVMX_BOARD_TYPE_SIM) ++ /* 25ms should be enough, 10ms is too short */ ++ mdelay(25); ++ ++ control_reg.s.pwr_dn = 0; ++ cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), ++ control_reg.u64); ++ + /* + * Wait for PCS*_MR*_STATUS_REG[AN_CPT] to be set, indicating + * that sgmii autonegotiation is complete. In MAC mode this +@@ -507,9 +551,47 @@ union cvmx_helper_link_info __cvmx_helpe + int __cvmx_helper_sgmii_link_set(int ipd_port, + union cvmx_helper_link_info link_info) + { ++ union cvmx_pcsx_mrx_control_reg control_reg; + int interface = cvmx_helper_get_interface_num(ipd_port); + int index = cvmx_helper_get_interface_index_num(ipd_port); +- __cvmx_helper_sgmii_hardware_init_link(interface, index); ++ ++ /* For some devices, i.e. the Qualcomm QCA8337 switch we need to power ++ * down the PCS interface when the link goes down and power it back ++ * up when the link returns. ++ */ ++ if (link_info.s.link_up || !__cvmx_helper_need_g15618()) { ++ __cvmx_helper_sgmii_hardware_init_link(interface, index); ++ } else { ++ union cvmx_pcsx_miscx_ctl_reg pcsx_miscx_ctl_reg; ++ ++ pcsx_miscx_ctl_reg.u64 = cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); ++ ++ /* Disable autonegotiation when MAC mode is enabled or ++ * autonegotiation is disabled. ++ */ ++ control_reg.u64 = cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); ++ if (pcsx_miscx_ctl_reg.s.mac_phy == 0 || ++ !cvmx_read_csr(CVMX_PCSX_ANX_RESULTS_REG(index, interface))) { ++ ++ control_reg.s.an_en = 0; ++ control_reg.s.spdmsb = 1; ++ control_reg.s.spdlsb = 0; ++ control_reg.s.dup = 1; ++ ++ } ++ cvmx_write_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface), ++ control_reg.u64); ++ cvmx_read_csr(CVMX_PCSX_MRX_CONTROL_REG(index, interface)); ++ /* ++ * Use GMXENO to force the link down it will get ++ * reenabled later... ++ */ ++ pcsx_miscx_ctl_reg.s.gmxeno = 1; ++ cvmx_write_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface), ++ pcsx_miscx_ctl_reg.u64); ++ cvmx_read_csr(CVMX_PCSX_MISCX_CTL_REG(index, interface)); ++ return 0; ++ } + return __cvmx_helper_sgmii_hardware_init_link_speed(interface, index, + link_info); + }