[PATCH net-next 2/5] net: phy: broadcom: use timestamped MDIO writes in gettimex64

From: James Clark

Date: Fri Oct 09 2026 - 10:38:28 EST


Use __phy_write_sts() to obtain tighter system timestamp bounds in
gettimex64 by timestamping completion of the write that triggers
capture of the PHC time.

The PHY captures its time a short delay after the end of the write.
End-to-end measurements show that the delay is small, within the
measurement accuracy of a few tenths of a microsecond.

This patch does not try to fix the error handling in the existing
framesync code, which ignores MDIO write errors.

Signed-off-by: James Clark <jjc@xxxxxxxxxx>
Assisted-by: LLM
---
Does Broadcom know the delay from the end of the MDIO write to the
framesync capture in the BCM54210PE? If so, I can add compensation
for it.

drivers/net/phy/bcm-phy-lib.c | 25 +++++++++++++++++++++++++
drivers/net/phy/bcm-phy-lib.h | 7 +++++++
drivers/net/phy/bcm-phy-ptp.c | 27 +++++++++++++++++++++------
3 files changed, 53 insertions(+), 6 deletions(-)

diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index b64beade8dd..022f5e5e6ce 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -42,6 +42,31 @@ int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val)
}
EXPORT_SYMBOL_GPL(bcm_phy_write_exp);

+static int __bcm_phy_write_exp_sts(struct phy_device *phydev, u16 reg, u16 val,
+ struct ptp_system_timestamp *sts)
+{
+ int rc;
+
+ rc = __phy_write(phydev, MII_BCM54XX_EXP_SEL, reg);
+ if (rc < 0)
+ return rc;
+
+ return __phy_write_sts(phydev, MII_BCM54XX_EXP_DATA, val, sts);
+}
+
+int bcm_phy_write_exp_sts(struct phy_device *phydev, u16 reg, u16 val,
+ struct ptp_system_timestamp *sts)
+{
+ int rc;
+
+ phy_lock_mdio_bus(phydev);
+ rc = __bcm_phy_write_exp_sts(phydev, reg, val, sts);
+ phy_unlock_mdio_bus(phydev);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(bcm_phy_write_exp_sts);
+
int __bcm_phy_read_exp(struct phy_device *phydev, u16 reg)
{
int val;
diff --git a/drivers/net/phy/bcm-phy-lib.h b/drivers/net/phy/bcm-phy-lib.h
index bba94ce9619..365cb3d1c32 100644
--- a/drivers/net/phy/bcm-phy-lib.h
+++ b/drivers/net/phy/bcm-phy-lib.h
@@ -34,6 +34,8 @@ int __bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
int __bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
int __bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set);
int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
+int bcm_phy_write_exp_sts(struct phy_device *phydev, u16 reg, u16 val,
+ struct ptp_system_timestamp *sts);
int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
int bcm_phy_modify_exp(struct phy_device *phydev, u16 reg, u16 mask, u16 set);

@@ -48,6 +50,11 @@ static inline int bcm_phy_read_exp_sel(struct phy_device *phydev, u16 reg)
return bcm_phy_read_exp(phydev, reg | MII_BCM54XX_EXP_SEL_ER);
}

+static inline bool bcm_phy_supports_write_exp_sts(struct phy_device *phydev)
+{
+ return phy_supports_write_sts(phydev);
+}
+
int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val);
int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum);

diff --git a/drivers/net/phy/bcm-phy-ptp.c b/drivers/net/phy/bcm-phy-ptp.c
index 65d609ed69f..2d8b377010b 100644
--- a/drivers/net/phy/bcm-phy-ptp.c
+++ b/drivers/net/phy/bcm-phy-ptp.c
@@ -214,22 +214,34 @@ static void bcm_ptp_framesync(struct phy_device *phydev, u16 ctrl)
bcm_phy_write_exp(phydev, NSE_CTRL, ctrl | NSE_CPU_FRAMESYNC);
}

+static int bcm_ptp_framesync_sts(struct phy_device *phydev, u16 ctrl,
+ struct ptp_system_timestamp *sts)
+{
+ return bcm_phy_write_exp_sts(phydev, NSE_CTRL,
+ ctrl | NSE_CPU_FRAMESYNC, sts);
+}
+
static int bcm_ptp_framesync_ts(struct phy_device *phydev,
struct ptp_system_timestamp *sts,
struct timespec64 *ts,
u16 orig_ctrl)
{
u16 ctrl, reg;
- int i;
+ int i, err = 0;

ctrl = bcm_ptp_framesync_disable(phydev, orig_ctrl);

- ptp_read_system_prets(sts);
-
/* trigger framesync + capture */
- bcm_ptp_framesync(phydev, ctrl | NSE_CAPTURE_EN);
-
- ptp_read_system_postts(sts);
+ if (sts && bcm_phy_supports_write_exp_sts(phydev)) {
+ /* cannot ignore error since sts may be uninitialized,
+ * but still poll for any triggered capture
+ */
+ err = bcm_ptp_framesync_sts(phydev, ctrl | NSE_CAPTURE_EN, sts);
+ } else {
+ ptp_read_system_prets(sts);
+ bcm_ptp_framesync(phydev, ctrl | NSE_CAPTURE_EN);
+ ptp_read_system_postts(sts);
+ }

/* poll for FSYNC interrupt from TS capture */
for (i = 0; i < 10; i++) {
@@ -242,6 +254,9 @@ static int bcm_ptp_framesync_ts(struct phy_device *phydev,

bcm_ptp_framesync_restore(phydev, orig_ctrl);

+ if (err)
+ return err;
+
return reg & INTC_FSYNC ? 0 : -ETIMEDOUT;
}

--
2.56.0