[PATCH net-next 2/9] ptp: ocp: do not cache EEPROM content after a failed TMC bus hand-back

From: Sagi Maimon

Date: Tue Sep 22 2026 - 10:54:29 EST


adva_x1_bus_release() drops the i2c root adapter lock whatever
adva_x1_mblaze_release() returned. That is deliberate - holding the lock
after the firmware failed to take the segment back would stall every other
user of the controller with no way to recover it - but it means the errno
reaches only the CPLD operation that held the claim, while the next
transfer on that adapter may still be routed to the TMC bus.

ptp_ocp_read_eeprom() is reachable from the unprivileged
DEVLINK_CMD_INFO_GET path and stores what it reads without validating it,
so in that window it can latch whatever answers 0x50/0x58 on the TMC
segment as bp->serial and bp->board_id and then publish them.

Record that the routing is unknown when the hand-back times out and skip
the EEPROM read while it is, rather than caching a value that was never
read from the EEPROMs. A later claim that the firmware grants proves the
handshake is working again and clears it.

This does not fence the at24 and nvmem sysfs paths, which do not go
through the driver; it only stops the driver publishing the result.

Fixes: 3b815e29966f ("ptp: ocp: add TAP CPLD access for ADVA TimeCard X1")
Signed-off-by: Sagi Maimon <maimon.sagi@xxxxxxxxx>
---
drivers/ptp/ptp_ocp.c | 27 +++++++++++++++++++++++++--
1 file changed, 25 insertions(+), 2 deletions(-)

diff --git a/drivers/ptp/ptp_ocp.c b/drivers/ptp/ptp_ocp.c
index 4a58bcc14648..510083dc750a 100644
--- a/drivers/ptp/ptp_ocp.c
+++ b/drivers/ptp/ptp_ocp.c
@@ -448,6 +448,8 @@ struct ptp_ocp {
unsigned int cpld_id_attempts;
/* x1 TAP CPLD present */
bool has_cpld;
+ /* the TMC segment was never handed back; routing is unknown */
+ bool cpld_bus_stuck;
/* EN_CFG_TP issued but not yet REFRESH'd */
bool cpld_in_config_mode;
};
@@ -2022,6 +2024,18 @@ ptp_ocp_read_eeprom(struct ptp_ocp *bp)
if (!bp->i2c_ctrl)
return;

+ /* A hand-back that timed out leaves the controller possibly still
+ * routed to the TMC segment. Reading now would latch whatever
+ * answers 0x50/0x58 there as the serial and board id, and those are
+ * published over the unprivileged devlink info path, so refuse
+ * rather than cache something that was never read from the EEPROMs.
+ */
+ if (READ_ONCE(bp->cpld_bus_stuck)) {
+ dev_dbg(&bp->pdev->dev,
+ "skipping EEPROM read, TMC bus routing unknown\n");
+ return;
+ }
+
tag = NULL;
nvmem = NULL;

@@ -4537,6 +4551,8 @@ static int adva_x1_bus_release(struct ptp_ocp *bp)
return 0;

err = adva_x1_mblaze_release(bp);
+ if (err)
+ WRITE_ONCE(bp->cpld_bus_stuck, true);
bp->cpld_adap = NULL;
kfree(bp->cpld_buf);
bp->cpld_buf = NULL;
@@ -4632,10 +4648,17 @@ static int adva_x1_bus_claim(struct ptp_ocp *bp)
bp->cpld_adap = adap;

ret = adva_x1_mblaze_acquire(bp);
- if (ret)
+ if (ret) {
adva_x1_bus_release(bp); /* keeps the acquire error */
+ return ret;
+ }

- return ret;
+ /* The firmware granted the segment, so it is answering the handshake
+ * again and the routing is known once more.
+ */
+ WRITE_ONCE(bp->cpld_bus_stuck, false);
+
+ return 0;
}

/* Select a mux channel, or deselect all with ch < 0 - the power-on state.
--
2.47.0