[PATCH net 4/5] net: dsa: b53: reject conflicting mirror destinations
From: Florian Fainelli
Date: Tue Oct 27 2026 - 16:40:55 EST
The mirror capture control register selects one destination for all
ingress and egress mirror sources. Adding a rule for a different capture
port currently overwrites that field and silently redirects all existing
mirror rules.
Read the capture control before changing any source masks and reject a
different destination while mirroring is enabled. Return an extack which
describes the hardware limitation, and propagate a failed capture-control
read rather than making the decision from uninitialized data.
Clear the capture-port field when the final source is removed so a later
rule can select a new destination.
Fixes: ed3af5fd08eb ("net: dsa: b53: Add support for port mirroring")
Signed-off-by: Florian Fainelli <florian.fainelli@xxxxxxxxxxxx>
---
drivers/net/dsa/b53/b53_common.c | 29 +++++++++++++++++++----------
1 file changed, 19 insertions(+), 10 deletions(-)
diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 0871a10d8cbc..b8a7b380bac8 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -2543,7 +2543,19 @@ int b53_mirror_add(struct dsa_switch *ds, int port,
struct netlink_ext_ack *extack)
{
struct b53_device *dev = ds->priv;
- u16 reg, loc;
+ u16 reg, loc, cap_ctl;
+ int ret;
+
+ ret = b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, &cap_ctl);
+ if (ret)
+ return ret;
+
+ if ((cap_ctl & MIRROR_EN) &&
+ (cap_ctl & CAP_PORT_MASK) != mirror->to_local_port) {
+ NL_SET_ERR_MSG_MOD(extack,
+ "Only one mirroring destination is supported");
+ return -EOPNOTSUPP;
+ }
if (ingress)
loc = B53_IG_MIR_CTL;
@@ -2554,11 +2566,10 @@ int b53_mirror_add(struct dsa_switch *ds, int port,
reg |= BIT(port);
b53_write16(dev, B53_MGMT_PAGE, loc, reg);
- b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®);
- reg &= ~CAP_PORT_MASK;
- reg |= mirror->to_local_port;
- reg |= MIRROR_EN;
- b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg);
+ cap_ctl &= ~CAP_PORT_MASK;
+ cap_ctl |= mirror->to_local_port;
+ cap_ctl |= MIRROR_EN;
+ b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, cap_ctl);
return 0;
}
@@ -2595,10 +2606,8 @@ void b53_mirror_del(struct dsa_switch *ds, int port,
b53_read16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, ®);
/* Both no longer have ports, let's disable mirroring */
- if (loc_disable && other_loc_disable) {
- reg &= ~MIRROR_EN;
- reg &= ~mirror->to_local_port;
- }
+ if (loc_disable && other_loc_disable)
+ reg &= ~(MIRROR_EN | CAP_PORT_MASK);
b53_write16(dev, B53_MGMT_PAGE, B53_MIR_CAP_CTL, reg);
}
EXPORT_SYMBOL(b53_mirror_del);
--
2.53.0