Thread (24 messages) flat view 24 messages, 5 authors, 25d ago

Re: [PATCH net-next v20 09/10] net: dsa: mt7530: generalize and move common function to lib module

From: sashiko-bot@kernel.org
Date: 2026-08-18 09:03:28

Thank you for your contribution! Sashiko AI review found 8 potential issue(s) to consider:
- [High] Unsafe conversion of atomic command register triggers into multiple sequential Read-Modify-Write (RMW) operations.
- [High] Hardware staging registers for FDB and VLAN data will retain stale or garbage bits due to the switch from full-register overwrites to field-based RMWs.
- [High] `mt7530_port_enable()` incorrectly applies `PCR_MATRIX_MASK` to an unshifted port matrix value, isolating the port and dropping all traffic.
- [High] Missing `reg_fields` initialization for `ID_EN7528` leads to a NULL pointer dereference during port mirroring.
- [High] mt7530_lib_port_bridge_flags() disables MAC address learning when it is supposed to be enabled, and vice versa.
- [High] mt7530_lib_fdb_read() swaps the last two bytes of the MAC address when reading FDB entries.
- [High] Unchecked regmap_field_read() failures lead to the use of uninitialized stack variables, potentially leaking stack memory to userspace or corrupting hardware state.
- [Medium] `mt7530_lib_mib_reset()` inadvertently disables the hardware MIB counters for octets and breaks the flush sequence by writing 0 instead of 1.
--
--- Patch [9]: [PATCH net-next v20 09/10] net: dsa: mt7530: generalize and move common function to lib module ---
commit 302309065c4dc5c4e0f17f164c9e39732602b582
Author: Christian Marangi [off-list ref]

net: dsa: mt7530: generalize and move common function to lib module

This commit moves common functions for the MT7530 switch into a separate
library module to prepare for Airoha support. It refactors register
accesses to use the regmap reg_field API instead of raw read/writes. A
new library struct is introduced to house the shared dependencies and
register fields.
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/dsa/mt7530-lib.c b/drivers/net/dsa/mt7530-lib.c
new file mode 100644
index 0000000000000..01ed941efc892
--- /dev/null
+++ b/drivers/net/dsa/mt7530-lib.c
@@ -0,0 +1,1106 @@
[ ... ]
+void mt7530_lib_mib_reset(struct mt7530_lib_priv *priv)
+{
+	regmap_field_write(priv->fields[MT7530_CCR_MIB_ENABLE], 0);
+	regmap_field_write(priv->fields[MT7530_CCR_RX_OCT_CNT_GOOD], 0);
+	regmap_field_write(priv->fields[MT7530_CCR_RX_OCT_CNT_BAD], 0);
+	regmap_field_write(priv->fields[MT7530_CCR_TX_OCT_CNT_GOOD], 0);
+	regmap_field_write(priv->fields[MT7530_CCR_TX_OCT_CNT_BAD], 0);
[Severity: Medium]
Does this correctly clear the counters? The original code wrote a 1 to flush
and clear the counters. Writing 0 to a write-1-to-clear field might fail to
reset them.

[ ... ]
+int mt7530_lib_fdb_cmd(struct mt7530_lib_priv *priv, enum mt7530_fdb_cmd cmd,
+		       u32 mat, u32 *rsp)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_field_write(priv->fields[MT7530_ATC_MAT], mat);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(priv->fields[MT7530_ATC_CMD], cmd);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(priv->fields[MT7530_ATC_BUSY], 1);
[Severity: High]
Can splitting the FDB command execution into multiple read-modify-writes
corrupt the MAC table operations? The previous implementation constructed the
32-bit value and wrote it atomically, preventing intermediate hardware states.

[ ... ]
+static void mt7530_lib_fdb_write(struct mt7530_lib_priv *priv, u16 vid,
+				 u8 port_mask, const u8 *mac,
+				 u8 aging, u8 type)
+{
+	regmap_field_write(priv->fields[MT7530_ATWD_CVID], vid);
+	regmap_field_write(priv->fields[MT7530_ATWD_IVL], 1);
[Severity: High]
Could this approach leak uninitialized or stale data into the FDB table?
Writing fields individually performs a read-modify-write, preserving undefined
bits from prior operations, whereas the old code explicitly cleared
unspecified bits by writing fully initialized arrays directly.

[ ... ]
+void mt7530_lib_fdb_read(struct mt7530_lib_priv *priv, struct mt7530_fdb *fdb)
+{
+	u32 val;
+
+	regmap_field_read(priv->fields[MT7530_ATRD_CVID], &val);
+	fdb->vid = val;
[Severity: High]
If regmap_field_read fails, could we end up assigning uninitialized stack
memory from val to the fdb fields? This might leak kernel stack data to
userspace during an FDB dump.

[ ... ]
+int mt7530_lib_port_mirror_add(struct mt7530_lib_priv *priv, int port,
+			       struct dsa_mall_mirror_tc_entry *mirror,
+			       bool ingress, struct netlink_ext_ack *extack)
+{
+	int monitor_port;
+	u32 val;
+
+	/* Check for existent entry */
+	if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
+		return -EEXIST;
+
+	regmap_field_read(priv->fields[MT7530_MIRROR_EN], &val);
[Severity: High]
Is it possible for priv->fields to lack an initialization here? The
ID_EN7528 entry in mt753x_table appears to be missing its reg_fields
setup, which could lead to a NULL pointer dereference.

[Severity: High]
Could a failure in regmap_field_read leave val and monitor_port
uninitialized? Using these uninitialized values in the subsequent condition
might cause unpredictable branch behavior.

[ ... ]
+int mt7530_lib_port_bridge_flags(struct mt7530_lib_priv *priv, int port,
+				 struct switchdev_brport_flags flags,
+				 struct netlink_ext_ack *extack)
+{
+	struct dsa_switch *ds = priv->ds;
+
+	if (flags.mask & BR_LEARNING)
+		regmap_fields_write(priv->fields[MT7530_PSC_SA_DIR],
+				    port, !!(flags.val & BR_LEARNING));
[Severity: High]
Does this invert the learning logic? The hardware bit SA_DIS disables
learning, so passing the boolean value of BR_LEARNING directly might
disable learning when it is supposed to be enabled, and vice versa.

[ ... ]
+static int mt7530_vlan_cmd(struct mt7530_lib_priv *priv, enum mt7530_vlan_cmd cmd,
+			   u16 vid)
+{
+	u32 val;
+	int ret;
+
+	ret = regmap_field_write(priv->fields[MT7530_VTCR_FUNC], cmd);
+	if (ret)
+		return ret;
+
+	ret = regmap_field_write(priv->fields[MT7530_VTCR_VID], vid);
[Severity: High]
Will breaking this command register access into multiple read-modify-write
operations cause issues with the hardware state machine? The original code
wrote the entire VTCR register in a single atomic operation.

[ ... ]
+static void mt7530_hw_vlan_add(struct mt7530_lib_priv *priv,
+			       struct mt7530_hw_vlan_entry *entry)
+{
+	struct dsa_port *dp = dsa_to_port(priv->ds, entry->port);
+	u8 new_members;
+	u32 val;
+
+	new_members = entry->old_members | BIT(entry->port);
+
+	/* Validate the entry with independent learning, create egress tag per
+	 * VLAN and joining the port as one of the port members.
+	 */
+	regmap_field_write(priv->fields[MT7530_VAWD_IVL_MAC], 1);
[Severity: High]
Might this leave stale or garbage bits in the VAWD1 register? The original
logic performed a full 32-bit register overwrite, explicitly clearing
unspecified bits like EG_CON. Using sequential regmap_field_write operations
performs read-modify-writes, which retains any previous unmapped bits.
quoted hunk ↗ jump to hunk
diff --git a/drivers/net/dsa/mt7530.c b/drivers/net/dsa/mt7530.c
index d01772cfe3a2d..f313a7a7bfef1 100644
--- a/drivers/net/dsa/mt7530.c
+++ b/drivers/net/dsa/mt7530.c
[ ... ]
quoted hunk ↗ jump to hunk
@@ -24,10 +24,159 @@
 #include <net/pkt_cls.h>
 
 #include "mt7530.h"
+#include "mt7530-lib.h"
 
 #define MT7530_STATS_POLL_INTERVAL	(1 * HZ)
 #define MT7530_STATS_RATE_LIMIT		(HZ / 10)
 
+static const struct mt7530_reg_field mt753x_fields[] = {
[ ... ]
+	{ MT7530_ATRD_ENT_STATUS, REG_FIELD(MT7530_ATRD, 2, 3), },
+	{ MT7530_ATRD_MAC_BYTE_5, REG_FIELD(MT7530_TSRA2, 24, 31), },
+	{ MT7530_ATRD_MAC_BYTE_4, REG_FIELD(MT7530_TSRA2, 16, 23), },
[Severity: High]
Are the bit ranges for MAC_BYTE_4 and MAC_BYTE_5 swapped here? The original
logic mapped MAC_BYTE_4 to bits 24-31 and MAC_BYTE_5 to bits 16-23 in the
TSRA2 register, causing corrupted MAC addresses on FDB read.

[ ... ]
quoted hunk ↗ jump to hunk
@@ -1373,7 +1141,7 @@ mt7530_port_enable(struct dsa_switch *ds, int port,
 	if (dsa_port_is_user(dp)) {
 		struct dsa_port *cpu_dp = dp->cpu_dp;
 
-		priv->ports[port].pm |= PCR_MATRIX(BIT(cpu_dp->index));
+		priv->ports[port].pm |= BIT(cpu_dp->index);
 	}
 	priv->ports[port].enable = true;
 	mt7530_rmw(priv, MT7530_PCR_P(port), PCR_MATRIX_MASK,
 		   priv->ports[port].pm);
[Severity: High]
Does this effectively isolate the port by dropping all traffic? The bitmask
in pm is now constructed without the PCR_MATRIX() shift, but it is passed
directly into mt7530_rmw() where PCR_MATRIX_MASK is applied. Since the
unshifted bits fall outside the mask, this will write zero to the matrix
field.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260817082034.20326-1-ansuelsmth@gmail.com?part=9
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help