From: Yongzhao Chen <yongzhao.derek@gmail.com>
To: netdev@vger.kernel.org
Cc: andrew@lunn.ch, olteanv@gmail.com, ansuelsmth@gmail.com,
hkallweit1@gmail.com, linux@armlinux.org.uk,
florian.fainelli@broadcom.com, jonas.gorski@gmail.com,
woojung.huh@microchip.com, UNGLinuxDriver@microchip.com,
hzyitc@outlook.com, kuba@kernel.org, pabeni@redhat.com,
horms@kernel.org, Yongzhao Chen <yongzhao.derek@gmail.com>
Subject: [RFC PATCH net-next v2 3/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes
Date: Tue, 22 Sep 2026 22:26:51 +0200 [thread overview]
Message-ID: <20260922202653.1153-4-yongzhao.derek@gmail.com> (raw)
In-Reply-To: <20260922202653.1153-1-yongzhao.derek@gmail.com>
The global maximum frame size must be changed with CPU MACs disabled.
The old sequence only handled ports 0 and 6, leaving an internal PHY CPU
port enabled while the register was updated.
Include enabled internal CPU ports in the pause. Serialize the whole MTU
update with port enable/disable and phylink link-up/down callbacks, so a
link-up cannot re-enable a CPU MAC during the frame-size write. Read and
restore each port's original TXMAC/RXMAC bits instead of enabling both
unconditionally; a link-down port remains down and LINK_AUTO is preserved.
Abort before updating the frame size if a status read or MAC pause fails,
attempt to restore any port already touched, and report a restore error
when the frame-size write itself succeeded.
Keep the existing treatment of ports 0 and 6, including when either is a
user port.
Assisted-by: LLM
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
---
drivers/net/dsa/qca/qca8k-8xxx.c | 3 ++
drivers/net/dsa/qca/qca8k-common.c | 79 ++++++++++++++++++++++++------
drivers/net/dsa/qca/qca8k.h | 2 +
3 files changed, 69 insertions(+), 15 deletions(-)
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 17704cb53..787f30495 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1486,7 +1486,9 @@ qca8k_phylink_mac_link_up(struct phylink_config *config,
reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
+ mutex_lock(&priv->port_status_mutex);
qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
+ mutex_unlock(&priv->port_status_mutex);
}
static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs)
@@ -2119,6 +2121,7 @@ qca8k_sw_probe(struct mdio_device *mdiodev)
priv->ds->ops = &qca8k_switch_ops;
priv->ds->phylink_mac_ops = &qca8k_phylink_mac_ops;
mutex_init(&priv->reg_mutex);
+ mutex_init(&priv->port_status_mutex);
dev_set_drvdata(&mdiodev->dev, priv);
return dsa_register_switch(priv->ds);
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 13005f10e..a584ddf72 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->port_status_mutex);
+ qca8k_port_set_status_locked(priv, port, enable);
+ mutex_unlock(&priv->port_status_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->port_status_mutex);
+ qca8k_port_set_status_locked(priv, port, 1);
priv->port_enabled_map |= BIT(port);
+ mutex_unlock(&priv->port_status_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->port_status_mutex);
+ qca8k_port_set_status_locked(priv, port, 0);
priv->port_enabled_map &= ~BIT(port);
+ mutex_unlock(&priv->port_status_mutex);
}
int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
struct qca8k_priv *priv = ds->priv;
- int ret;
+ u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
+ u32 status[QCA8K_NUM_PORTS] = { 0 };
+ u32 ports;
+ u32 stopped = 0;
+ int ret, restore_ret, i;
/* 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->port_status_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->port_status_mutex);
return ret;
}
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 956338893..6cb060204 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -459,6 +459,8 @@ struct qca8k_priv {
struct mii_bus *internal_mdio_bus;
struct dsa_switch *ds;
struct mutex reg_mutex;
+ /* Serializes port MAC state changes with global MTU updates. */
+ struct mutex port_status_mutex;
struct device *dev;
struct gpio_desc *reset_gpio;
struct net_device *mgmt_conduit; /* Track if mdio/mib Ethernet is available */
--
2.43.0
next prev parent reply other threads:[~2026-09-22 20:27 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-22 20:26 [RFC PATCH net-next v2 0/5] net: dsa: qca8k: add a QCA8337 CPU PHY consumer Yongzhao Chen
2026-09-22 20:26 ` [RFC PATCH net-next v2 1/5] net: dsa: pass PHY flags when connecting shared ports Yongzhao Chen
2026-09-22 21:49 ` Florian Fainelli
2026-09-22 20:26 ` [RFC PATCH net-next v2 2/5] net: dsa: qca8k: support an internal PHY as the CPU port Yongzhao Chen
2026-09-22 20:26 ` Yongzhao Chen [this message]
2026-09-22 20:58 ` [RFC PATCH net-next v2 3/5] net: dsa: qca8k: serialize CPU MAC pause during MTU changes Andrew Lunn
2026-09-23 21:57 ` Yongzhao Chen
2026-09-22 20:26 ` [RFC PATCH net-next v2 4/5] net: dsa: qca8k: flag QCA8337 internal CPU PHYs for SmartSpeed Yongzhao Chen
2026-09-22 21:00 ` Andrew Lunn
2026-09-23 21:57 ` Yongzhao Chen
2026-09-22 20:26 ` [RFC PATCH net-next v2 5/5] net: phy: qca83xx: disable SmartSpeed before resetting CPU PHYs Yongzhao Chen
2026-09-22 21:06 ` Andrew Lunn
2026-09-23 21:57 ` Yongzhao Chen
2026-09-24 12:30 ` Andrew Lunn
2026-09-24 23:48 ` Yongzhao Chen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260922202653.1153-4-yongzhao.derek@gmail.com \
--to=yongzhao.derek@gmail.com \
--cc=UNGLinuxDriver@microchip.com \
--cc=andrew@lunn.ch \
--cc=ansuelsmth@gmail.com \
--cc=florian.fainelli@broadcom.com \
--cc=hkallweit1@gmail.com \
--cc=horms@kernel.org \
--cc=hzyitc@outlook.com \
--cc=jonas.gorski@gmail.com \
--cc=kuba@kernel.org \
--cc=linux@armlinux.org.uk \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=pabeni@redhat.com \
--cc=woojung.huh@microchip.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox