net: pse-pd: si3474: validate the channels of a PI

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: a2317231df ("net: pse-pd: Add Si3474 PSE controller driver")
Signed-off-by: Piotr Kubik <piotr@kubik.pl>
Reviewed-by: Kory Maincent <kory.maincent@bootlin.com>
Link: https://patch.msgid.link/20261019162453.1244120-3-piotr@kubik.pl
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Piotr Kubik 2026-10-19 18:24:53 +02:00 committed by Jakub Kicinski
parent b530456be7
commit 110eb80832

View File

@ -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;