* [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes
@ 2026-10-22 15:58 Yongzhao Chen
2026-10-22 16:03 ` netdev-bot+sinfo
2026-10-26 16:21 ` netdev-bot+sashiko
0 siblings, 2 replies; 3+ messages in thread
From: Yongzhao Chen @ 2026-10-22 15:58 UTC (permalink / raw)
To: netdev
Cc: Christian Marangi, Andrew Lunn, Vladimir Oltean, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
Russell King, Florian Fainelli, linux-kernel, Ziyang Huang
The MTU update pauses enabled ports 0 and 6 and then unconditionally
enables their MACs. This can undo a phylink link-down decision. Phylink
callbacks also run without RTNL and can enable a MAC during the update.
Changing MAX_FRAME_SIZE with a CPU MAC running can stop the switch from
sending packets until reset, as described in commit 386228c694bf.
Serialize the MTU transaction and PORT_STATUS writers with a dedicated
mutex. Save and restore the MAC bits, abort before the frame-size write
on detected snapshot or pause errors, and restore every touched port.
Mask partial status values before passing them to the regmap callback.
Return the result of the frame-size write even if a later port restore
fails: DSA does not roll back the switch's frame size when the CPU MTU
callback returns an error. Record successful frame-size writes and skip
requests for the same value. DSA invokes the callback for every CPU port,
so a second invocation must not reject an already committed global value.
Retain failed status writes and retry them every second, because a
fixed-link port may receive no further link-up callback. Merge newer port
decisions into the pending target, and recover pending writes on ports 0
and 6 before changing the frame size again. Disable and drain retries for
suspend, shutdown and removal, with managed cleanup on probe failure.
Fixes: 386228c694bf ("net: dsa: qca8k: reset cpu port on MTU change")
Assisted-by: LLM
Signed-off-by: Yongzhao Chen <yongzhao.derek@gmail.com>
---
v7:
- Address Sashiko's review of v6 [1]:
- Mask cached PORT_STATUS values for partial writes. The qca8k regmap
callbacks do not mask their value argument.
- Track the successfully committed global frame size and return success
for repeated requests. This covers DSA invoking the MTU callback for
both CPU ports, including a pending restore failure after the first
callback. Initialize the record from the setup write and update it
only when a frame-size write succeeds.
- The tests now use the actual Ethernet RMW callback and DSA CPU-port
iteration, which the v6 fixtures did not model correctly.
v6: https://lore.kernel.org/netdev/20261019173716.198475-1-yongzhao.derek@gmail.com/
v5: https://lore.kernel.org/netdev/20261015104550.43169-1-yongzhao.derek@gmail.com/
This remains the standalone net fix for existing ports 0 and 6. Internal
CPU support stays in the separate net-next series. The pre-existing NULL
PHY dereference noted in the review is outside this change.
The affected arm64 objects build with W=1, with CONFIG_PM_SLEEP enabled
and disabled. A userspace harness compiled the driver, Ethernet RMW and
DSA MTU functions with mocked transport, topology, netdev and workqueue
boundaries. It covered single and dual CPU ports, both traversal orders,
MTU growth and shrink, failed initial writes, duplicate callbacks, later
MTU changes, retries, callback interleavings and lifecycle handling.
The sent v6 and six deliberately broken variants fail the checks.
This revision has not been tested on hardware or with kernel lockdep.
The net base can still swallow MDIO write errors. The retry and committed
frame-size record handle only errors reported by the register API; they
cannot detect a write that falsely reports success or guarantee recovery
from a write whose completion is unknown.
Merge note: net-next has changed qca8k_port_set_status() to use
regmap_assign_bits(). This patch replaces that function body with the
serialized status-update helper, so that hunk needs manual resolution
when propagating the net fix to net-next.
[1] https://lore.kernel.org/netdev/179265824122.3135.15072303811434404600@kernel.org/
drivers/net/dsa/qca/qca8k-8xxx.c | 33 ++++++-
drivers/net/dsa/qca/qca8k-common.c | 150 ++++++++++++++++++++++++-----
drivers/net/dsa/qca/qca8k.h | 15 +++
3 files changed, 174 insertions(+), 24 deletions(-)
diff --git a/drivers/net/dsa/qca/qca8k-8xxx.c b/drivers/net/dsa/qca/qca8k-8xxx.c
index 4c928983b..f9ae0fe67 100644
--- a/drivers/net/dsa/qca/qca8k-8xxx.c
+++ b/drivers/net/dsa/qca/qca8k-8xxx.c
@@ -1483,7 +1483,9 @@ qca8k_phylink_mac_link_up(struct phylink_config *config,
reg |= QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
- qca8k_write(priv, QCA8K_REG_PORT_STATUS(port), reg);
+ mutex_lock(&priv->port_status_lock);
+ qca8k_port_status_update(priv, port, U32_MAX, reg);
+ mutex_unlock(&priv->port_status_lock);
}
static struct qca8k_pcs *pcs_to_qca8k_pcs(struct phylink_pcs *pcs)
@@ -1995,6 +1997,7 @@ qca8k_setup(struct dsa_switch *ds)
/* Setup our port MTUs to match power on defaults */
ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, ETH_FRAME_LEN + ETH_FCS_LEN);
+ priv->max_frame_size = ret ? 0 : ETH_FRAME_LEN + ETH_FCS_LEN;
if (ret)
dev_warn(priv->dev, "failed setting MTU settings");
@@ -2055,6 +2058,13 @@ static const struct dsa_switch_ops qca8k_switch_ops = {
.connect_tag_protocol = qca8k_connect_tag_protocol,
};
+static void qca8k_port_status_stop(void *data)
+{
+ struct qca8k_priv *priv = data;
+
+ disable_delayed_work_sync(&priv->port_status_work);
+}
+
static int
qca8k_sw_probe(struct mdio_device *mdiodev)
{
@@ -2116,6 +2126,11 @@ 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_lock);
+ INIT_DELAYED_WORK(&priv->port_status_work, qca8k_port_status_work);
+ ret = devm_add_action_or_reset(priv->dev, qca8k_port_status_stop, priv);
+ if (ret)
+ return ret;
dev_set_drvdata(&mdiodev->dev, priv);
return dsa_register_switch(priv->ds);
@@ -2130,6 +2145,7 @@ qca8k_sw_remove(struct mdio_device *mdiodev)
if (!priv)
return;
+ qca8k_port_status_stop(priv);
for (i = 0; i < QCA8K_NUM_PORTS; i++)
qca8k_port_set_status(priv, i, 0);
@@ -2143,6 +2159,7 @@ static void qca8k_sw_shutdown(struct mdio_device *mdiodev)
if (!priv)
return;
+ qca8k_port_status_stop(priv);
dsa_switch_shutdown(priv->ds);
dev_set_drvdata(&mdiodev->dev, NULL);
@@ -2165,13 +2182,24 @@ qca8k_set_pm(struct qca8k_priv *priv, int enable)
}
}
+static void qca8k_port_status_start(struct qca8k_priv *priv)
+{
+ enable_delayed_work(&priv->port_status_work);
+ schedule_delayed_work(&priv->port_status_work, 0);
+}
+
static int qca8k_suspend(struct device *dev)
{
struct qca8k_priv *priv = dev_get_drvdata(dev);
+ int ret;
+ qca8k_port_status_stop(priv);
qca8k_set_pm(priv, 0);
+ ret = dsa_switch_suspend(priv->ds);
+ if (ret)
+ qca8k_port_status_start(priv);
- return dsa_switch_suspend(priv->ds);
+ return ret;
}
static int qca8k_resume(struct device *dev)
@@ -2179,6 +2207,7 @@ static int qca8k_resume(struct device *dev)
struct qca8k_priv *priv = dev_get_drvdata(dev);
qca8k_set_pm(priv, 1);
+ qca8k_port_status_start(priv);
return dsa_switch_resume(priv->ds);
}
diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
index 13005f10e..d9db5e579 100644
--- a/drivers/net/dsa/qca/qca8k-common.c
+++ b/drivers/net/dsa/qca/qca8k-common.c
@@ -463,7 +463,7 @@ int qca8k_mib_init(struct qca8k_priv *priv)
return ret;
}
-void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
+static u32 qca8k_port_status_mask(int port)
{
u32 mask = QCA8K_PORT_STATUS_TXMAC | QCA8K_PORT_STATUS_RXMAC;
@@ -471,10 +471,77 @@ void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
if (port > 0 && port < 6)
mask |= QCA8K_PORT_STATUS_LINK_AUTO;
- if (enable)
- regmap_set_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
+ return mask;
+}
+
+static int qca8k_port_status_restore(struct qca8k_priv *priv, int port)
+{
+ u32 mask = priv->port_status_mask[port];
+ int ret;
+
+ lockdep_assert_held(&priv->port_status_lock);
+
+ if (!mask)
+ return 0;
+
+ if (mask == U32_MAX)
+ ret = qca8k_write(priv, QCA8K_REG_PORT_STATUS(port),
+ priv->port_status_value[port]);
else
- regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(port), mask);
+ ret = regmap_update_bits(priv->regmap,
+ QCA8K_REG_PORT_STATUS(port), mask,
+ priv->port_status_value[port] & mask);
+ if (ret) {
+ dev_err_ratelimited(priv->dev,
+ "failed to restore port %d status: %d\n",
+ port, ret);
+ schedule_delayed_work(&priv->port_status_work, HZ);
+ } else {
+ priv->port_status_mask[port] = 0;
+ }
+
+ return ret;
+}
+
+void qca8k_port_status_update(struct qca8k_priv *priv, int port,
+ u32 mask, u32 val)
+{
+ lockdep_assert_held(&priv->port_status_lock);
+
+ /* A newer decision supersedes pending bits, even if it fails too. */
+ priv->port_status_value[port] &= ~mask;
+ priv->port_status_value[port] |= val & mask;
+ priv->port_status_mask[port] |= mask;
+ qca8k_port_status_restore(priv, port);
+}
+
+void qca8k_port_status_work(struct work_struct *work)
+{
+ struct qca8k_priv *priv = container_of(to_delayed_work(work),
+ struct qca8k_priv,
+ port_status_work);
+ int port;
+
+ mutex_lock(&priv->port_status_lock);
+ for (port = 0; port < QCA8K_NUM_PORTS; port++)
+ qca8k_port_status_restore(priv, port);
+ mutex_unlock(&priv->port_status_lock);
+}
+
+static void __qca8k_port_set_status(struct qca8k_priv *priv, int port,
+ int enable)
+{
+ u32 mask = qca8k_port_status_mask(port);
+
+ lockdep_assert_held(&priv->port_status_lock);
+ qca8k_port_status_update(priv, port, mask, enable ? mask : 0);
+}
+
+void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable)
+{
+ mutex_lock(&priv->port_status_lock);
+ __qca8k_port_set_status(priv, port, enable);
+ mutex_unlock(&priv->port_status_lock);
}
void qca8k_get_strings(struct dsa_switch *ds, int port, u32 stringset,
@@ -751,8 +818,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_lock);
+ __qca8k_port_set_status(priv, port, 1);
priv->port_enabled_map |= BIT(port);
+ mutex_unlock(&priv->port_status_lock);
if (dsa_is_user_port(ds, port))
phy_support_asym_pause(phy);
@@ -764,14 +833,19 @@ 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_lock);
+ __qca8k_port_set_status(priv, port, 0);
priv->port_enabled_map &= ~BIT(port);
+ mutex_unlock(&priv->port_status_lock);
}
int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
{
+ u32 frame_size = new_mtu + ETH_HLEN + ETH_FCS_LEN;
+ u32 status[QCA8K_NUM_PORTS] = { 0 };
struct qca8k_priv *priv = ds->priv;
- int ret;
+ unsigned long ports, stopped = 0;
+ int 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
@@ -782,27 +856,59 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
if (!dsa_is_cpu_port(ds, port))
return 0;
- /* 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.
+ /* To change MAX_FRAME_SIZE, pause enabled ports 0 and 6.
+ * Serialize with phylink and restore the saved MAC state.
*/
- if (priv->port_enabled_map & BIT(0))
- qca8k_port_set_status(priv, 0, 0);
+ mutex_lock(&priv->port_status_lock);
+
+ /* DSA calls us for every CPU port, but the frame size is global. */
+ if (priv->max_frame_size == frame_size) {
+ ret = 0;
+ goto unlock;
+ }
- if (priv->port_enabled_map & BIT(6))
- qca8k_port_set_status(priv, 6, 0);
+ ports = BIT(0) | BIT(6);
- /* Include L2 header / FCS length */
- ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, new_mtu +
- ETH_HLEN + ETH_FCS_LEN);
+ /* Do not mistake a failed restore for a new link-down decision. */
+ for_each_set_bit(i, &ports, QCA8K_NUM_PORTS) {
+ ret = qca8k_port_status_restore(priv, i);
+ if (ret)
+ goto unlock;
+ }
+
+ ports &= priv->port_enabled_map;
+ for_each_set_bit(i, &ports, QCA8K_NUM_PORTS) {
+ ret = regmap_read(priv->regmap, QCA8K_REG_PORT_STATUS(i),
+ &status[i]);
+ if (ret)
+ goto unlock;
+ }
+
+ for_each_set_bit(i, &ports, QCA8K_NUM_PORTS) {
+ u32 mask = qca8k_port_status_mask(i);
+
+ if (!(status[i] & mask))
+ continue;
+
+ __set_bit(i, &stopped);
+ ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(i),
+ mask);
+ if (ret)
+ goto restore;
+ }
- if (priv->port_enabled_map & BIT(0))
- qca8k_port_set_status(priv, 0, 1);
+ ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, frame_size);
+ if (!ret)
+ priv->max_frame_size = frame_size;
- if (priv->port_enabled_map & BIT(6))
- qca8k_port_set_status(priv, 6, 1);
+restore:
+ /* A failed restore must not reject a committed frame size. */
+ for_each_set_bit(i, &stopped, QCA8K_NUM_PORTS)
+ qca8k_port_status_update(priv, i, qca8k_port_status_mask(i),
+ status[i]);
+unlock:
+ mutex_unlock(&priv->port_status_lock);
return ret;
}
diff --git a/drivers/net/dsa/qca/qca8k.h b/drivers/net/dsa/qca/qca8k.h
index 956338893..f4ab46475 100644
--- a/drivers/net/dsa/qca/qca8k.h
+++ b/drivers/net/dsa/qca/qca8k.h
@@ -10,6 +10,7 @@
#include <linux/delay.h>
#include <linux/regmap.h>
+#include <linux/workqueue.h>
#include <linux/gpio/consumer.h>
#include <linux/leds.h>
#include <linux/dsa/tag_qca.h>
@@ -459,6 +460,17 @@ struct qca8k_priv {
struct mii_bus *internal_mdio_bus;
struct dsa_switch *ds;
struct mutex reg_mutex;
+ /* Serializes writes to QCA8K_REG_PORT_STATUS and the MTU update. Taken
+ * from phylink MAC callbacks: do not access a PHY or call into phylink
+ * with it held.
+ */
+ struct mutex port_status_lock;
+ /* Committed frame size, 0 if unknown; protected by port_status_lock. */
+ u32 max_frame_size;
+ struct delayed_work port_status_work;
+ /* Nonzero masks mark pending writes; protected by port_status_lock. */
+ u32 port_status_mask[QCA8K_NUM_PORTS];
+ u32 port_status_value[QCA8K_NUM_PORTS];
struct device *dev;
struct gpio_desc *reset_gpio;
struct net_device *mgmt_conduit; /* Track if mdio/mib Ethernet is available */
@@ -502,6 +514,9 @@ static inline u32 qca8k_port_to_phy(int port)
extern const struct qca8k_mib_desc ar8327_mib[];
extern const struct regmap_access_table qca8k_readable_table;
int qca8k_mib_init(struct qca8k_priv *priv);
+void qca8k_port_status_work(struct work_struct *work);
+void qca8k_port_status_update(struct qca8k_priv *priv, int port,
+ u32 mask, u32 val);
void qca8k_port_set_status(struct qca8k_priv *priv, int port, int enable);
int qca8k_read_switch_id(struct qca8k_priv *priv);
base-commit: 78731b46967e3e7102b5cd5062bef185f3404b5c
--
2.43.0
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes
2026-10-22 15:58 [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes Yongzhao Chen
@ 2026-10-22 16:03 ` netdev-bot+sinfo
2026-10-26 16:21 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sinfo @ 2026-10-22 16:03 UTC (permalink / raw)
To: Yongzhao Chen
Cc: netdev, Christian Marangi, Andrew Lunn, Vladimir Oltean,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Simon Horman, Russell King, Florian Fainelli, linux-kernel,
Ziyang Huang
Hi!
This is an automated message. This series looks like a fix, but its
commit messages seem to be missing some information:
- How the issue was discovered, e.g. hit in production, hit during
development, syzbot report, manual code inspection, LLM or static
analysis tool scan.
Please do not repost the series just to address the above. Instead,
reply to this email with the missing information, so that reviewers
can take it into account. If the series needs another revision for
other reasons, please include the information in the commit messages
then.
The evaluation is done by an LLM so it may be wrong, if you think
that is the case please reply and explain.
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes
2026-10-22 15:58 [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes Yongzhao Chen
2026-10-22 16:03 ` netdev-bot+sinfo
@ 2026-10-26 16:21 ` netdev-bot+sashiko
1 sibling, 0 replies; 3+ messages in thread
From: netdev-bot+sashiko @ 2026-10-26 16:21 UTC (permalink / raw)
To: yongzhao.derek
Cc: netdev, ansuelsmth, andrew, olteanv, davem, edumazet, kuba,
pabeni, horms, linux, florian.fainelli, linux-kernel, hzyitc
Thank you for your contribution! Sashiko AI review found 1 potential
issue(s) to consider.
Critical: 0 · High: 0 · Medium: 1 · Low: 0
If you believe none of the issues are legitimate, please reply to each
issue of Medium severity or higher and explain why the AI is wrong.
If any of them are legitimate and you plan to respin, please let patchwork
know by including "pw-bot: cr" as a separate line at the end of your reply
(one such reply per series is enough).
- [Medium] In qca8k_port_change_mtu()
(drivers/net/dsa/qca/qca8k-common.c), the decision to pause a CPU MAC…
--
net: dsa: qca8k: preserve port state across MTU changes
This patch adds a dedicated mutex that serializes the MTU update with all
PORT_STATUS writers. During the update, the MAC bits of the enabled CPU
ports are saved and restored instead of being forced back on afterwards.
Failed status writes are recorded and retried from a delayed work, and the
committed MAX_FRAME_SIZE is tracked so a duplicate call for the same value
returns early.
> diff --git a/drivers/net/dsa/qca/qca8k-common.c b/drivers/net/dsa/qca/qca8k-common.c
> index 13005f10edb7d..d9db5e57928ee 100644
> --- a/drivers/net/dsa/qca/qca8k-common.c
> +++ b/drivers/net/dsa/qca/qca8k-common.c
[ ... ]
> @@ -782,27 +856,59 @@ int qca8k_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
> if (!dsa_is_cpu_port(ds, port))
> return 0;
>
> - /* 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.
> + /* To change MAX_FRAME_SIZE, pause enabled ports 0 and 6.
> + * Serialize with phylink and restore the saved MAC state.
> */
> - if (priv->port_enabled_map & BIT(0))
> - qca8k_port_set_status(priv, 0, 0);
> + mutex_lock(&priv->port_status_lock);
[ ... ]
> + ports &= priv->port_enabled_map;
> + for_each_set_bit(i, &ports, QCA8K_NUM_PORTS) {
> + ret = regmap_read(priv->regmap, QCA8K_REG_PORT_STATUS(i),
> + &status[i]);
> + if (ret)
> + goto unlock;
> + }
> +
> + for_each_set_bit(i, &ports, QCA8K_NUM_PORTS) {
> + u32 mask = qca8k_port_status_mask(i);
> +
> + if (!(status[i] & mask))
> + continue;
[Severity: Medium]
Can a concurrent register reader corrupt the status[] snapshot here and
make this skip the pause?
qca8k_regmap_config in qca8k-8xxx.c has:
.disable_locking = true, /* Locking is handled by qca8k read/write */
So regmap_read() goes through _regmap_bus_read() and takes no regmap lock.
The register address is formatted into the shared map->work_buf, and
qca8k_bulk_read() reads it back from there:
u32 reg = *(u16 *)reg_buf;
The value is parsed from the shared work_val only after the transport has
released mdio_lock:
drivers/base/regmap/regmap.c:_regmap_bus_read() {
...
ret = _regmap_raw_read(map, reg, work_val, map->format.val_bytes, false);
if (ret == 0)
*val = map->format.parse_val(work_val);
...
}
port_status_lock does not cover readers such as qca8k_pcs_get_state().
Phylink calls it from its resolve worker without RTNL, and it is polled
because qca8k_setup_pcs() sets pcs.poll = true. The LED hw_control_get
path is another reader that takes no lock.
For example, with port 0 enabled and port 6 in in-band mode after a
link_down:
CPU1 (RTNL held)
qca8k_port_change_mtu()
regmap_read(QCA8K_REG_PORT_STATUS(0))
CPU2
phylink_resolve()
qca8k_pcs_get_state(port 6)
qca8k_read(priv, QCA8K_REG_PORT_STATUS(port), ®)
Suppose port 6's address or value lands in work_buf before port 0's value
is parsed. Then status[0] would have no TXMAC/RXMAC bits, the continue
above would skip port 0, and this write would run with the port 0 MAC
still enabled:
> + __set_bit(i, &stopped);
> + ret = regmap_clear_bits(priv->regmap, QCA8K_REG_PORT_STATUS(i),
> + mask);
> + if (ret)
> + goto restore;
> + }
>
> - if (priv->port_enabled_map & BIT(0))
> - qca8k_port_set_status(priv, 0, 1);
> + ret = qca8k_write(priv, QCA8K_MAX_FRAME_SIZE, frame_size);
Commit 386228c694bf says this state stops the switch from sending packets
until reset.
The shared work_buf race itself predates this patch. However, the old pause
was an unconditional regmap_clear_bits(), which goes through
qca8k_regmap_update_bits() and does not use work_buf. So it could not be
skipped this way.
The window is small, but should the pause avoid depending on this unlocked
read? One option would be to clear the MAC bits of the enabled CPU ports
unconditionally, as before.
> + if (!ret)
> + priv->max_frame_size = frame_size;
[ ... ]
--
Sashiko AI review · https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20261022155837.760-1-yongzhao.derek%40gmail.com
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-10-26 16:21 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-22 15:58 [PATCH net v7] net: dsa: qca8k: preserve port state across MTU changes Yongzhao Chen
2026-10-22 16:03 ` netdev-bot+sinfo
2026-10-26 16:21 ` netdev-bot+sashiko
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®