[openwrt/openwrt] octeon: force pcs reset to fix qca833x traffic

LEDE Commits lede-commits at lists.infradead.org
Wed Apr 2 01:04:56 PDT 2025


robimarko pushed a commit to openwrt/openwrt.git, branch main:
https://git.openwrt.org/ce1991cd6466e12fc3c018e5729572b52d4e20fd

commit ce1991cd6466e12fc3c018e5729572b52d4e20fd
Author: Andrew LaMarche <andrewjlamarche at gmail.com>
AuthorDate: Mon Mar 31 17:00:28 2025 +0000

    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 <andrewjlamarche at gmail.com>
    Link: https://github.com/openwrt/openwrt/pull/18385
    Signed-off-by: Robert Marko <robimarko at gmail.com>
---
 .../patches-6.6/702-qca833x-force-pcs-reset.patch  | 123 +++++++++++++++++++++
 1 file changed, 123 insertions(+)

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 0000000000..ed405e88c0
--- /dev/null
+++ b/target/linux/octeon/patches-6.6/702-qca833x-force-pcs-reset.patch
@@ -0,0 +1,123 @@
+From: Andrew LaMarche <andrewjlamarche at gmail.com>
+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 <andrewjlamarche at gmail.com>
+--- 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);
+ }




More information about the lede-commits mailing list