* [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer
@ 2026-09-23 21:58 Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 1/5] net: dsa: pass PHY flags when connecting shared ports Yongzhao Chen
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Florian Fainelli, Jonas Gorski, Andrew Lunn, Vladimir Oltean,
Woojung Huh, UNGLinuxDriver, Christian Marangi, Heiner Kallweit,
Russell King, linux-doc, linux-kernel, linux-arm-msm,
Ziyang Huang
The qca83xx PHY driver is already in net-next. This series allows
passing PHY flags on DSA shared ports and adds support for a QCA8337
internal CPU PHY. It implements CPU port selection, serializes MAC state
across global MTU updates, and proposes disabling SmartSpeed prior to
CPU PHY resets.
The first patch extends the DSA core interface; the qca8k patches
provide its concrete user. No board-name matching or board-specific DT
properties are introduced.
The minimal topology uses a single CPU link: a conduit PHY connects over
MDI to QCA8337 PHY4 on switch port 5, with each endpoint having its own
phy-handle. A reduced devicetree fixture based on Redmi AX5400 wiring
passed dtc and validation against the complete net-next schema set. This
is a binding fixture rather than a bootable board description. Because
the pinned base tree lacks the IPQ5018 Ethernet MAC driver and RA74
board support, this series has not been boot-tested on RA74 under pure
net-next.
On one RA74 board, diagnostic boot logs showed PHY4 advertising
1000BASE-T full duplex after generic config_aneg() succeeded, but a
later read found the advertisement missing. No intervening write was
found through the instrumented Clause 22 BMCR/CTRL1000 path; other paths
were not excluded. The exact trigger remains unknown. Clearing
SmartSpeed before the initial reset preserved the 1 Gb/s internal link
during the tested boot sequence. Runtime testing did not establish
late-peer causality, a broken pair, or successful fallback to 100 Mb/s.
Two scope questions remain for this RFC:
1. Internal CPU port selection currently falls back to ports 1 through 5
only on QCA8337. Dedicated ports 0 and 6 retain priority on all
models, including mixed CPU port descriptions. AR8327 documentation
describes per-port headers and destination bitmaps, but I have not
established its internal CPU link behavior. Should this fallback
remain limited to QCA8337, or can maintainers confirm the same support
for QCA8327?
2. The proposed SmartSpeed policy applies to QCA8337 internal CPU PHYs.
SmartSpeed is the hardware downshift feature, so disabling it removes
that fallback behavior. Current hardware evidence is limited to PHY4
on a single RA74 board. Is the internal CPU link role sufficient
justification for this policy, or should the quirk be scoped more
narrowly?
Changes since v2:
- Patch 2 uses reg_mutex across the MTU pause, frame-size write, and
state restoration. Variable declarations now follow reverse
Christmas-tree order. This patch precedes topology support so MTU
protection is in place when internal CPU ports become available.
- Patch 3 adds internal CPU port fallback while retaining port 0 and 6
priority, leaving QCA8327 support as an explicit RFC question.
- Patch 4 masks the revision before setting the CPU PHY flag, clarifies
SmartSpeed downshift behavior, and drops the delayed-conduit causal
claim.
- Patch 5 clarifies reset and config_aneg ordering along with hardware
evidence limits, keeping generic config_aneg.
This series depends on the separate net patch "net: dsa: qca8k:
propagate MDIO errors":
https://lore.kernel.org/netdev/20260923215748.1336-1-yongzhao.derek@gmail.com/
Testing:
Fault injection against the actual MDIO/PHY functions and kernel polling
macros covered busy-read errors, timeouts and successful transactions.
The old polling code reproduced false success on read error; the fixed
path blocked SmartSpeed writes and initial/resume resets. Tests with
mocked hardware also covered flag scope, CPU-port selection and
MDIO-to-MTU error handling.
The changed qca8k-8xxx.o built with W=1 for x86_64 and ARM64 under
allyesconfig and allmodconfig, with no compiler diagnostics. Unchanged
qca8k-common.o and MTU locking retain the earlier build and concurrency
test results. Hardware tests used downstream RA74 firmware. This
revision has no full kernel image/modules build, pure net-next RA74 boot
or hardware lockdep run.
Original RFC:
https://lore.kernel.org/netdev/20260919085406.1395-1-yongzhao.derek@gmail.com/
v2:
https://lore.kernel.org/netdev/20260922202653.1153-1-yongzhao.derek@gmail.com/
Base: net-next 8830e65ed46de41f849eefb8ba227d4852c460f6.
Local prerequisite: 3ba847ea54227f704ee3b04f95d4b52d4e22d483.
Yongzhao Chen (4):
net: dsa: pass PHY flags when connecting shared ports
net: dsa: qca8k: serialize CPU MAC pause during MTU changes
net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed
net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs
Ziyang Huang (1):
net: dsa: qca8k: support QCA8337 internal PHY CPU links
Documentation/networking/dsa/dsa.rst | 2 +
MAINTAINERS | 1 +
drivers/net/dsa/bcm_sf2.c | 4 ++
drivers/net/dsa/microchip/ksz8.c | 4 ++
drivers/net/dsa/qca/qca8k-8xxx.c | 39 +++++++++-----
drivers/net/dsa/qca/qca8k-common.c | 79 ++++++++++++++++++++++------
drivers/net/phy/qcom/qca83xx.c | 32 +++++++++--
include/linux/qca83xx.h | 11 ++++
net/dsa/port.c | 6 ++-
9 files changed, 145 insertions(+), 33 deletions(-)
create mode 100644 include/linux/qca83xx.h
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next v3 1/5] net: dsa: pass PHY flags when connecting shared ports
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
@ 2026-09-23 21:58 ` Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 2/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes Yongzhao Chen
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
Florian Fainelli, Jonas Gorski, Andrew Lunn, Vladimir Oltean,
Woojung Huh, UNGLinuxDriver, Russell King, linux-doc,
linux-kernel, Ziyang Huang
DSA calls get_phy_flags() for user ports, but passes zero when connecting
CPU or DSA port PHYs. Pass the callback result before PHY initialization
for shared ports too. Drivers without the callback still pass zero.
Keep bcm_sf2 and ksz88xx shared-port flags at zero, preserving their
existing behavior. Document the extended callback scope.
This lets qca8k pass revision information and a SmartSpeed quirk to an
internal PHY used as a CPU link. The remaining patches supply that user.
Assisted-by: LLM
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
Documentation/networking/dsa/dsa.rst | 2 ++
drivers/net/dsa/bcm_sf2.c | 4 ++++
drivers/net/dsa/microchip/ksz8.c | 4 ++++
net/dsa/port.c | 6 +++++-
4 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/Documentation/networking/dsa/dsa.rst b/Documentation/networking/dsa/dsa.rst
index 7edfdd555..647f952e3 100644
--- a/Documentation/networking/dsa/dsa.rst
+++ b/Documentation/networking/dsa/dsa.rst
@@ -668,6 +668,8 @@ PHY devices and link management
on its own (e.g.: coming from switch memory mapped registers), this function
should return a 32-bit bitmask of "flags" that is private between the switch
driver and the Ethernet PHY driver in ``drivers/net/phy/\*``.
+ It is called when connecting PHYs for user, CPU and DSA ports. Drivers
+ should return zero for ports that do not need switch-specific PHY flags.
- ``phy_read``: Function invoked by the DSA user MDIO bus when attempting to read
the switch port MDIO registers. If unavailable, return 0xffff for each read.
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index 9e5713015..f516fc396 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -709,6 +709,10 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
{
struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
+ /* Shared ports previously received no PHY flags. */
+ if (!dsa_is_user_port(ds, port))
+ return 0;
+
/* The BCM7xxx PHY driver expects to find the integrated PHY revision
* in bits 15:8 and the patch level in bits 7:0 which is exactly what
* the REG_PHY_REVISION register layout is.
diff --git a/drivers/net/dsa/microchip/ksz8.c b/drivers/net/dsa/microchip/ksz8.c
index d74981320..be8861a7a 100644
--- a/drivers/net/dsa/microchip/ksz8.c
+++ b/drivers/net/dsa/microchip/ksz8.c
@@ -3076,6 +3076,10 @@ static u32 ksz88xx_get_phy_flags(struct dsa_switch *ds, int port)
{
struct ksz_device *dev = ds->priv;
+ /* Shared ports previously received no PHY flags. */
+ if (!dsa_is_user_port(ds, port))
+ return 0;
+
switch (dev->chip_id) {
case KSZ88X3_CHIP_ID:
/* Silicon Errata Sheet (DS80000830A):
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 1f5536c0d..4db7e6f9c 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -1666,6 +1666,7 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp)
{
struct dsa_switch *ds = dp->ds;
struct device_node *port_dn = dp->dn;
+ u32 phy_flags = 0;
int err;
dp->pl_config.dev = ds->dev;
@@ -1675,7 +1676,10 @@ static int dsa_shared_port_phylink_register(struct dsa_port *dp)
if (err)
return err;
- err = phylink_of_phy_connect(dp->pl, port_dn, 0);
+ if (ds->ops->get_phy_flags)
+ phy_flags = ds->ops->get_phy_flags(ds, dp->index);
+
+ err = phylink_of_phy_connect(dp->pl, port_dn, phy_flags);
if (err && err != -ENODEV) {
pr_err("could not attach to PHY: %d\n", err);
goto err_phy_connect;
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next v3 2/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 1/5] net: dsa: pass PHY flags when connecting shared ports Yongzhao Chen
@ 2026-09-23 21:58 ` Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 3/5] net: dsa: qca8k: support QCA8337 internal PHY CPU links Yongzhao Chen
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, Andrew Lunn, Vladimir Oltean,
Christian Marangi, Russell King, linux-kernel, Ziyang Huang
The global maximum frame size must be updated with CPU MACs disabled.
The previous logic only paused ports 0 and 6, leaving an internal PHY
CPU port enabled while modifying the register.
Include enabled internal CPU ports in the pause sequence. Use the
existing reg_mutex to serialize the MTU update against port enable, port
disable, and phylink link-up and link-down transitions. Read and restore
each port's original TXMAC and RXMAC bits, ensuring ports that were down
remain down and preserving LINK_AUTO. Retain existing handling for ports
0 and 6.
Abort before updating the frame size if reading port status or pausing
the MAC fails. Attempt to restore all ports already modified, and report
any restoration failures even if an earlier error occurred.
The standalone qca8k MDIO error-propagation fix is a prerequisite for
this series; that error-handling bug predates this locking change.
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
Assisted-by: LLM
---
drivers/net/dsa/qca/qca8k-8xxx.c | 2 +
drivers/net/dsa/qca/qca8k-common.c | 79 ++++++++++++++++++++++++------
2 files changed, 66 insertions(+), 15 deletions(-)
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index f9e2eb0b9..d8564001c 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1488,7 +1488,9 @@ qca8k_phylink_mac_link_up(struct phylink_config *config,
reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
+ mutex_lock(&priv->reg_mutex);
qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
+ mutex_unlock(&priv->reg_mutex);
}
static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs)
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 13005f10e..6b32bdd75 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -463,7 +463,8 @@ int qca8k_mib_init(struct qca8k_priv *priv)
return ret;
}
-void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
+static void qca8k_port_set_status_locked(struct qca8k_priv *priv, int port,
+ int enable)
{
u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
@@ -477,6 +478,13 @@ void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
}
+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
+{
+ mutex_lock(&priv->reg_mutex);
+ qca8k_port_set_status_locked(priv, port, enable);
+ mutex_unlock(&priv->reg_mutex);
+}
+
void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset,
uint8_t *data)
{
@@ -751,8 +759,10 @@ int qca8k_port_enable(struct dsa_switch *ds, int port,
{
struct qca8k_priv *priv = ds->priv;
- qca8k_port_set_status(priv, port, 1);
+ mutex_lock(&priv->reg_mutex);
+ qca8k_port_set_status_locked(priv, port, 1);
priv->port_enabled_map |= BIT(port);
+ mutex_unlock(&priv->reg_mutex);
if (dsa_is_user_port(ds, port))
phy_support_asym_pause(phy);
@@ -764,14 +774,20 @@ void qca8k_port_disable(struct dsa_switch *ds, int port)
{
struct qca8k_priv *priv = ds->priv;
- qca8k_port_set_status(priv, port, 0);
+ mutex_lock(&priv->reg_mutex);
+ qca8k_port_set_status_locked(priv, port, 0);
priv->port_enabled_map &= ~BIT(port);
+ mutex_unlock(&priv->reg_mutex);
}
int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
struct qca8k_priv *priv = ds->priv;
- int ret;
+ u32 status[QCA8K_NUM_PORTS] = { 0 };
+ int ret, restore_ret, i;
+ u32 stopped = 0;
+ u32 ports;
/* We have only have a general MTU setting.
* DSA always set the CPU port's MTU to the largest MTU of the user
@@ -784,25 +800,58 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
/* To change the MAX_FRAME_SIZE the cpu ports must be off or
* the switch panics.
- * Turn off both cpu ports before applying the new value to prevent
- * this.
+ * Include internal PHY CPU ports as well as the two MAC-only ports.
+ * Toggle only MAC enables, preserving the phylink link-control mode.
*/
- if (priv->port_enabled_map & BIT(0))
- qca8k_port_set_status(priv, 0, 0);
+ ports = BIT(0) | BIT(6);
+ for (i = 1; i < 6; i++)
+ if (dsa_is_cpu_port(ds, i))
+ ports |= BIT(i);
- if (priv->port_enabled_map & BIT(6))
- qca8k_port_set_status(priv, 6, 0);
+ mutex_lock(&priv->reg_mutex);
+ ports &= priv->port_enabled_map;
+
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ if (!(ports & BIT(i)))
+ continue;
+
+ ret = regmap_read(priv->regmap, QCA8K_REG_PORT_STATUS(i),
+ &status[i]);
+ if (ret)
+ goto unlock;
+ }
+
+ for (i = 0; i < QCA8K_NUM_PORTS; i++) {
+ if (!(ports & BIT(i)) || !(status[i] & mask))
+ continue;
+
+ stopped |= BIT(i);
+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(i),
+ mask);
+ if (ret)
+ goto restore;
+ }
/* Include L2 header / FCS length */
ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu +
ETH_HLEN + ETH_FCS_LEN);
- if (priv->port_enabled_map & BIT(0))
- qca8k_port_set_status(priv, 0, 1);
-
- if (priv->port_enabled_map & BIT(6))
- qca8k_port_set_status(priv, 6, 1);
+restore:
+ for (i = 0; i < QCA8K_NUM_PORTS; i++)
+ if (stopped & BIT(i)) {
+ restore_ret = regmap_update_bits(priv->regmap,
+ QCA8K_REG_PORT_STATUS(i),
+ mask, status[i] & mask);
+ if (restore_ret) {
+ dev_err(priv->dev, "failed to restore MAC state on port %d: %d\n",
+ i, restore_ret);
+ if (!ret)
+ ret = restore_ret;
+ }
+ }
+unlock:
+ mutex_unlock(&priv->reg_mutex);
return ret;
}
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next v3 3/5] net: dsa: qca8k: support QCA8337 internal PHY CPU links
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 1/5] net: dsa: pass PHY flags when connecting shared ports Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 2/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes Yongzhao Chen
@ 2026-09-23 21:58 ` Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 5/5] net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs Yongzhao Chen
4 siblings, 0 replies; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, Andrew Lunn, Vladimir Oltean,
Christian Marangi, Russell King, linux-kernel, Ziyang Huang
From: Ziyang Huang <hzyitc@outlook.com>
A PHY-to-PHY CPU link connects the SoC PHY directly to an internal
switch PHY. The QCA8337 supports header mode on these ports, and
existing phylink callbacks already handle their internal interfaces.
Allow QCA8337 CPU port selection to fall back to ports 1 through 5 after
checking the dedicated MAC-only ports. Preserve the preference for CPU
ports 0 and 6 across all switch models, limiting the internal-port
fallback to QCA8337. Support for QCA8327 internal CPU links remains an
open question in this RFC. Include internal CPU PHYs when selecting the
PHY access method, without altering the handling of MAC-only or external
user ports.
This enables a single internal CPU PHY configured with an explicit
phy-handle and phy-mode = "internal". The conduit interface uses its own
PHY on the opposite side of the MDI connection. Existing single-CPU DSA
forwarding uses the selected port for default flooding and membership
without extra routing changes.
Adapted from the OpenWrt PHY-to-PHY CPU link patch, narrowing the MDIO
filter adjustments to preserve handling for external user ports.
[yongzhao: preserve external user-port handling on port 6 and limit
internal CPU PHY support to QCA8337]
Assisted-by: LLM
Signed-off-by: Ziyang Huang <hzyitc@outlook.com>
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index d8564001c..07640ce4a 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1019,7 +1019,8 @@ qca8k_setup_mdio_bus(struct qca8k_priv *priv)
return ret;
}
- if (!dsa_is_user_port(priv->ds, reg))
+ if (!dsa_is_user_port(priv->ds, reg) &&
+ !(reg > 0 && reg < 6 && dsa_is_cpu_port(priv->ds, reg)))
continue;
of_get_phy_mode(port, &mode);
@@ -1095,16 +1096,23 @@ qca8k_setup_mac_pwr_sel(struct qca8k_priv *priv)
static int qca8k_find_cpu_port(struct dsa_switch *ds)
{
struct qca8k_priv *priv = ds->priv;
+ int port;
- /* Find the connected cpu port. Valid port are 0 or 6 */
if (dsa_is_cpu_port(ds, 0))
return 0;
- dev_dbg(priv->dev, "port 0 is not the CPU port. Checking port 6");
-
if (dsa_is_cpu_port(ds, 6))
return 6;
+ /* Internal PHY CPU port selection is currently enabled for QCA8337. */
+ if (priv->switch_id != QCA8K_ID_QCA8337)
+ return -EINVAL;
+
+ /* An internal PHY can provide a PHY-to-PHY CPU link. */
+ for (port = 1; port < 6; port++)
+ if (dsa_is_cpu_port(ds, port))
+ return port;
+
return -EINVAL;
}
@@ -1856,7 +1864,7 @@ qca8k_setup(struct dsa_switch *ds)
cpu_port = qca8k_find_cpu_port(ds);
if (cpu_port < 0) {
- dev_err(priv->dev, "No cpu port configured in both cpu port0 and port6");
+ dev_err(priv->dev, "No CPU port configured");
return cpu_port;
}
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
` (2 preceding siblings ...)
2026-09-23 21:58 ` [RFC PATCH net-next v3 3/5] net: dsa: qca8k: support QCA8337 internal PHY CPU links Yongzhao Chen
@ 2026-09-23 21:58 ` Yongzhao Chen
2026-09-24 2:51 ` Andrew Lunn
2026-09-23 21:58 ` [RFC PATCH net-next v3 5/5] net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs Yongzhao Chen
4 siblings, 1 reply; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, Andrew Lunn, Vladimir Oltean,
Christian Marangi, Heiner Kallweit, Russell King, linux-kernel,
linux-arm-msm, Ziyang Huang
Flag QCA8337 internal PHYs used as CPU links for SmartSpeed suppression.
SmartSpeed is the Qualcomm PHY driver downshift feature configured in
register 0x14. Its enable and bypass-timer bits are cleared by a
subsequent patch prior to software reset.
In a diagnostic boot on one RA74, PHY4 initially advertised 1000BASE-T
full duplex, but a later read showed that advertisement cleared.
Clearing SmartSpeed before the initial reset preserved the 1 Gb/s link
on that board. This observation does not establish the root cause of the
advertisement loss or prove that a delayed conduit PHY caused it.
Define a shared switch-to-PHY flag while preserving the hardware
revision bits consumed by the PHY driver. Mask the revision before
setting the flag to prevent revision values from mistakenly enabling the
quirk on user ports. Only QCA8337 internal CPU ports 1 through 5 receive
this flag. The hardware test covered PHY4 on one RA74; the other ports
and boards selected by this code have not been validated.
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
Assisted-by: LLM
---
MAINTAINERS | 1 +
drivers/net/dsa/qca/qca8k-8xxx.c | 19 ++++++++++---------
drivers/net/phy/qcom/qca83xx.c | 3 +--
include/linux/qca83xx.h | 11 +++++++++++
4 files changed, 23 insertions(+), 11 deletions(-)
create mode 100644 include/linux/qca83xx.h
diff --git a/MAINTAINERS b/MAINTAINERS
index df8ab9b82..fa1da8031 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22336,6 +22336,7 @@ L: netdev@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/net/dsa/qca8k.yaml
F: drivers/net/dsa/qca/qca8k*
+F: include/linux/qca83xx.h
F: net/dsa/tag_qca.c
QUALCOMM ATHEROS QCA7K ETHERNET DRIVER
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 07640ce4a..cd7adb2d9 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -8,6 +8,7 @@
#include <linux/module.h>
#include <linux/phy.h>
+#include <linux/qca83xx.h>
#include <linux/netdevice.h>
#include <linux/bitfield.h>
#include <linux/regmap.h>
@@ -1754,17 +1755,17 @@ qca8k_get_ethtool_stats_eth(struct dsa_switch *ds, int port, u64 *data)
static u32 qca8k_get_phy_flags(struct dsa_switch *ds, int port)
{
struct qca8k_priv *priv = ds->priv;
+ u32 flags;
- /* Communicate to the phy internal driver the switch revision.
- * Based on the switch revision different values needs to be
- * set to the dbg and mmd reg on the phy.
- * The first 2 bit are used to communicate the switch revision
- * to the phy driver.
- */
- if (port > 0 && port < 6)
- return priv->switch_revision;
+ if (port <= 0 || port >= 6)
+ return 0;
- return 0;
+ /* The PHY driver uses the switch revision for analog initialization. */
+ flags = priv->switch_revision & QCA8K_DEVFLAGS_REVISION_MASK;
+ if (priv->switch_id == QCA8K_ID_QCA8337 && dsa_is_cpu_port(ds, port))
+ flags |= QCA8K_DEVFLAGS_NO_SMARTSPEED;
+
+ return flags;
}
static enum dsa_tag_protocol
diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c
index bc70ed8ef..0f484cdfe 100644
--- a/drivers/net/phy/qcom/qca83xx.c
+++ b/drivers/net/phy/qcom/qca83xx.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0+
#include <linux/phy.h>
+#include <linux/qca83xx.h>
#include <linux/module.h>
#include "qcom.h"
@@ -16,8 +17,6 @@
#define QCA8327_B_PHY_ID 0x004dd034
#define QCA8337_PHY_ID 0x004dd036
-#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
-
static struct at803x_hw_stat qca83xx_hw_stats[] = {
{ "phy_idle_errors", 0xa, GENMASK(7, 0), PHY},
{ "phy_receive_errors", 0x15, GENMASK(15, 0), PHY},
diff --git a/include/linux/qca83xx.h b/include/linux/qca83xx.h
new file mode 100644
index 000000000..f90ed80fb
--- /dev/null
+++ b/include/linux/qca83xx.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _LINUX_QCA83XX_H
+#define _LINUX_QCA83XX_H
+
+#include <linux/bits.h>
+
+/* QCA8K switch-to-PHY flags, carried through phy_device::dev_flags. */
+#define QCA8K_DEVFLAGS_REVISION_MASK GENMASK(2, 0)
+#define QCA8K_DEVFLAGS_NO_SMARTSPEED BIT(3)
+
+#endif
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [RFC PATCH net-next v3 5/5] net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
` (3 preceding siblings ...)
2026-09-23 21:58 ` [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed Yongzhao Chen
@ 2026-09-23 21:58 ` Yongzhao Chen
4 siblings, 0 replies; 7+ messages in thread
From: Yongzhao Chen @ 2026-09-23 21:58 UTC (permalink / raw)
To: netdev
Cc: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Florian Fainelli, Andrew Lunn, Vladimir Oltean,
Christian Marangi, Heiner Kallweit, Russell King, linux-kernel,
linux-arm-msm, Ziyang Huang
For flagged QCA8337 CPU PHYs, clear the SmartSpeed enable and
bypass-timer bits before invoking genphy_soft_reset(). The register
update preserves all other bits, and an MDIO read or write error
prevents the reset. Reapply the clear prior to soft reset on system
resume. Unflagged QCA8337 PHYs and QCA8327 retain their standard reset
sequence.
The quirk flag is set on phydev before phy_init_hw() calls soft_reset();
config_init() executes after the reset completes, and generic
config_aneg() remains in use. In the RA74 diagnostic trace, generic
config_aneg() preserved CTRL1000 at 0x0600 and returned success, yet a
later read returned 0x0400. The trace verified that no intervening
writes occurred via the instrumented Clause 22 BMCR and CTRL1000 path,
though it did not isolate the precise timing or cause of the change. A
read value of 0x0400 reflects the advertised capability rather than an
active negotiated link speed.
Disabling SmartSpeed before the initial reset maintained a 1 Gb/s
internal link during the tested RA74 boot sequence. The experiment did
not establish a broken pair condition or a functional fallback to 100
Mb/s. Board support for the RA74 is not included in this series.
Link: https://github.com/openwrt/openwrt/issues/24696
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
Assisted-by: LLM
---
drivers/net/phy/qcom/qca83xx.c | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/qcom/qca83xx.c b/drivers/net/phy/qcom/qca83xx.c
index 0f484cdfe..21ab015f6 100644
--- a/drivers/net/phy/qcom/qca83xx.c
+++ b/drivers/net/phy/qcom/qca83xx.c
@@ -91,6 +91,28 @@ static int qca83xx_probe(struct phy_device *phydev)
return 0;
}
+static int qca8337_disable_smartspeed(struct phy_device *phydev)
+{
+ if (!(phydev->dev_flags & QCA8K_DEVFLAGS_NO_SMARTSPEED))
+ return 0;
+
+ /* SmartSpeed settings take effect at software reset. */
+ return phy_clear_bits(phydev, AT803X_SMART_SPEED,
+ AT803X_SMART_SPEED_ENABLE |
+ AT803X_SMART_SPEED_BYPASS_TIMER);
+}
+
+static int qca8337_soft_reset(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = qca8337_disable_smartspeed(phydev);
+ if (ret)
+ return ret;
+
+ return genphy_soft_reset(phydev);
+}
+
static int qca83xx_config_init(struct phy_device *phydev)
{
u8 switch_revision;
@@ -160,6 +182,11 @@ static int qca83xx_resume(struct phy_device *phydev)
/* Reinit the port, reset values set by suspend */
qca83xx_config_init(phydev);
+ /* Reapply the CPU PHY quirk before the resume reset. */
+ ret = qca8337_disable_smartspeed(phydev);
+ if (ret)
+ return ret;
+
/* Reset the port on port resume */
phy_set_bits(phydev, MII_BMCR, BMCR_RESET | BMCR_ANENABLE);
@@ -218,7 +245,7 @@ static struct phy_driver qca83xx_driver[] = {
.probe = qca83xx_probe,
.flags = PHY_IS_INTERNAL,
.config_init = qca83xx_config_init,
- .soft_reset = genphy_soft_reset,
+ .soft_reset = qca8337_soft_reset,
.get_sset_count = qca83xx_get_sset_count,
.get_strings = qca83xx_get_strings,
.get_stats = qca83xx_get_stats,
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed
2026-09-23 21:58 ` [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed Yongzhao Chen
@ 2026-09-24 2:51 ` Andrew Lunn
0 siblings, 0 replies; 7+ messages in thread
From: Andrew Lunn @ 2026-09-24 2:51 UTC (permalink / raw)
To: Yongzhao Chen
Cc: netdev, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Florian Fainelli, Vladimir Oltean,
Christian Marangi, Heiner Kallweit, Russell King, linux-kernel,
linux-arm-msm, Ziyang Huang
On Wed, Sep 23, 2026 at 11:58:56PM +0200, Yongzhao Chen wrote:
> Flag QCA8337 internal PHYs used as CPU links for SmartSpeed suppression.
> SmartSpeed is the Qualcomm PHY driver downshift feature configured in
> register 0x14.
As far as i can see, nothing configures register 0x14, so this is not
very useful.
Please look at other PHYs which support downshift. There is a tunable
for it. Also, the read_status is expected to return the real speed,
which often is not in BMSR, but in a vendor register.
Is there an errata which covers this?
It would be interesting to know if downshift is broken in general, or
only when used in switch integrated PHYs.
What might be possible here it to look at phydev->is_internal, rather
than add a flag, to differentiate switch internal PHYs and discrete
PHYs.
Andrew
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-09-24 2:51 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 21:58 [RFC PATCH net-next v3 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 1/5] net: dsa: pass PHY flags when connecting shared ports Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 2/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 3/5] net: dsa: qca8k: support QCA8337 internal PHY CPU links Yongzhao Chen
2026-09-23 21:58 ` [RFC PATCH net-next v3 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed Yongzhao Chen
2026-09-24 2:51 ` Andrew Lunn
2026-09-23 21:58 ` [RFC PATCH net-next v3 5/5] net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs Yongzhao Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®