[PATCH net 2/2] net: pse-pd: si3474: validate the channels of a PI

From: Piotr Kubik

Date: Mon Oct 19 2026 - 12:35:53 EST


si3474_get_of_channels() accepted channel 8, one past the last channel.
The driver then accessed channel 4 instead: quad 1, channel index 0.

It also accepted a 4-pair PI whose two channels are not a channel pair
of one quad. The chip forms a 4-pair port only from channels 0+1 or 2+3
of a quad (2P/4P mode bit in POWER_ALLOCATION, PORT_REMAP default), and
the driver sends every register access of a PI to the quad of its first
channel, so such a PI enabled and measured the wrong channels.

Reject both at probe.

Discovered by an AI code review agent; no shipped device tree triggers
it. Validated and tested on an SDG-9000 board (MediaTek MT7988A, two
Si3474) with Linux 6.18 and a modified device tree: one chip with a
channel at reg 8, the other with a 4-pair PI on channels 1 and 2. The
driver now rejects both at probe, and the unmodified device tree still
probes all eight PIs. No kernel selftest covers PSE hardware.

Fixes: a2317231df4b ("net: pse-pd: Add Si3474 PSE controller driver")
Signed-off-by: Piotr Kubik <piotr@xxxxxxxx>
---
drivers/net/pse-pd/si3474.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/net/pse-pd/si3474.c b/drivers/net/pse-pd/si3474.c
index 99e96f6bdefc..2f18714c95f1 100644
--- a/drivers/net/pse-pd/si3474.c
+++ b/drivers/net/pse-pd/si3474.c
@@ -250,9 +250,9 @@ static int si3474_get_of_channels(struct si3474_priv *priv)
"Failed to read channel reg property\n");
return ret;
}
- if (chan_id > SI3474_MAX_CHANS) {
+ if (chan_id >= SI3474_MAX_CHANS) {
dev_err(&priv->client[0]->dev,
- "Incorrect channel number: %d\n", chan_id);
+ "Incorrect channel number: %u\n", chan_id);
return -EINVAL;
}

@@ -267,6 +267,16 @@ static int si3474_get_of_channels(struct si3474_priv *priv)
pi->np);
return -EINVAL;
}
+
+ /* The 2P/4P mode bit pairs channels 0+1 and 2+3 of a quad */
+ if (pairset_found &&
+ (priv->pi[pi_no].chan[0] ^ 1) != priv->pi[pi_no].chan[1]) {
+ dev_err(&priv->client[0]->dev,
+ "PI %pOF: channels %u and %u are not a channel pair\n",
+ pi->np, priv->pi[pi_no].chan[0],
+ priv->pi[pi_no].chan[1]);
+ return -EINVAL;
+ }
}

return 0;
--
2.55.0