From: James Clark <jjc@jclark.com>
To: "David S. Miller" <davem@davemloft.net>,
"Eric Dumazet" <edumazet@kernel.org>,
"Jakub Kicinski" <kuba@kernel.org>,
"Paolo Abeni" <pabeni@redhat.com>,
"Andrew Lunn" <andrew+netdev@lunn.ch>,
"Heiner Kallweit" <hkallweit1@gmail.com>,
"Richard Cochran" <richardcochran@gmail.com>,
"Florian Fainelli" <florian.fainelli@broadcom.com>,
"Doug Berger" <opendmb@gmail.com>,
"Nicolai Buchwitz" <nb@tipi-net.de>,
"Théo Lebrun" <theo.lebrun@bootlin.com>
Cc: Andrew Lunn <andrew@lunn.ch>,
Russell King <linux@armlinux.org.uk>,
Conor Dooley <conor.dooley@microchip.com>,
Broadcom internal kernel review list
<bcm-kernel-feedback-list@broadcom.com>,
Thomas Gleixner <tglx@kernel.org>,
John Stultz <jstultz@google.com>, Stephen Boyd <sboyd@kernel.org>,
Miroslav Lichvar <mlichvar@redhat.com>,
Vladimir Oltean <olteanv@gmail.com>,
Hubert Feurstein <h.feurstein@gmail.com>,
netdev@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH net-next v2 4/6] net: phy: broadcom: use timestamped MDIO writes in gettimex64
Date: Sun, 18 Oct 2026 17:02:55 +0700 [thread overview]
Message-ID: <20261018100257.566267-5-jjc@jclark.com> (raw)
In-Reply-To: <20261018100257.566267-1-jjc@jclark.com>
When the MDIO bus provides the write_sts operation, 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 last MDC edge of the
write. This delay is not documented. The correctness of gettimex64
requires that the event delay passed to __phy_write_sts() is an upper
bound on the actual delay.
The upper bound BCM_FRAMESYNC_CAPTURE_NS was established by measurements
performed on a Raspberry Pi CM4. The same PPS signal was wired both to
the SYNC_OUT pin connected to the PHY's PHC and to GPIO pin 18. Two
programs were run simultaneously. One used polling of GPIO registers to
estimate the system time of each pulse. The other waited for the extts
event for each pulse, and then performed a PTP_SYS_OFFSET_EXTENDED
ioctl. Combining these gives a PHC/system time pair for each pulse. The
system time of the PHC reading in each PTP_SYS_OFFSET_EXTENDED sample
was estimated by interpolating between the PHC/system time pairs of the
pulses on either side of it. Over about 30,000 samples, every estimate
was at least 285 ns after the lower system time bound of the sample.
The write cannot complete before the lower bound, so the delay can be no
more than the gap from the lower bound to the capture.
However, the polling brackets are about 150 ns wide. Compensating for
polling error by considering neighbouring pulses gives an upper bound of
at most 330 ns; BCM_FRAMESYNC_CAPTURE_NS uses this rounded up to 350 ns,
which also covers a possible variation of 8 ns in the delay,
corresponding to one period of the PHY's 125 MHz clock.
This assumes that the delay is a property of the PHY, so that it applies
equally with other MDIO buses. Changing the MDC period between 100 and
400 ns changed the delay by less than 10 ns. Measurements on a Raspberry
Pi CM5, where the same PHY is on the RP1's macb, are consistent with the
CM4 measurements. But there the GPIO is polled across PCIe, so the
polling brackets are wider.
gettimex64 can now return -EBUSY if the clock is stepped during the
write, as gettimex64 already can in other drivers, such as mvpp2 and
ionic.
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@jclark.com>
Assisted-by: LLM
---
Changes in v2:
- Take into account the PHY's capture delay, with a bound of 350 ns
found by measurement
- Say that gettimex64 can now return -EBUSY if the clock is stepped
during the write
- Say that the tighter bounds need a bus driver with write_sts
(Sashiko)
Does Broadcom know the BCM54210PE's capture delay, from the end of the
MDIO write to the framesync capture? If so, I can use it in place of
the 350 ns bound found by measurement.
drivers/net/phy/bcm-phy-lib.c | 27 +++++++++++++++++++++++++++
drivers/net/phy/bcm-phy-lib.h | 7 +++++++
drivers/net/phy/bcm-phy-ptp.c | 33 +++++++++++++++++++++++++++------
3 files changed, 61 insertions(+), 6 deletions(-)
diff --git a/drivers/net/phy/bcm-phy-lib.c b/drivers/net/phy/bcm-phy-lib.c
index b64beade8dd..5f8813d01a8 100644
--- a/drivers/net/phy/bcm-phy-lib.c
+++ b/drivers/net/phy/bcm-phy-lib.c
@@ -42,6 +42,33 @@ 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,
+ u32 event_delay_ns,
+ 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,
+ event_delay_ns, sts);
+}
+
+int bcm_phy_write_exp_sts(struct phy_device *phydev, u16 reg, u16 val,
+ u32 event_delay_ns, struct ptp_system_timestamp *sts)
+{
+ int rc;
+
+ phy_lock_mdio_bus(phydev);
+ rc = __bcm_phy_write_exp_sts(phydev, reg, val, event_delay_ns, 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..08ab59fb9b8 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,
+ u32 event_delay_ns, 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..61593dd2dbc 100644
--- a/drivers/net/phy/bcm-phy-ptp.c
+++ b/drivers/net/phy/bcm-phy-ptp.c
@@ -161,6 +161,11 @@ struct bcm_ptp_capture {
#define BCM_MAX_PULSE_8NS ((1U << 9) - 1)
#define BCM_MAX_PERIOD_8NS ((1U << 30) - 1)
+/* Allowed for the PHY to capture its time after the last MDC edge of
+ * the framesync write.
+ */
+#define BCM_FRAMESYNC_CAPTURE_NS 350
+
#define BRCM_PHY_MODEL(phydev) \
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
@@ -214,22 +219,35 @@ 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,
+ BCM_FRAMESYNC_CAPTURE_NS, 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 +260,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
next prev parent reply other threads:[~2026-10-18 10:03 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-18 10:02 [PATCH net-next v2 0/6] net: mdio: add timestamped MDIO writes for PHY gettimex64 James Clark
2026-10-18 10:02 ` [PATCH net-next v2 1/6] timekeeping: add ktime_scale_raw_ns() James Clark
2026-10-18 10:02 ` [PATCH net-next v2 2/6] ptp: add functions to adjust system timestamps James Clark
2026-10-18 10:02 ` [PATCH net-next v2 3/6] net: mdio: add timestamped write operation James Clark
2026-10-19 10:34 ` netdev-bot+sashiko
2026-10-18 10:02 ` James Clark [this message]
2026-10-19 10:34 ` [PATCH net-next v2 4/6] net: phy: broadcom: use timestamped MDIO writes in gettimex64 netdev-bot+sashiko
2026-10-18 10:02 ` [PATCH net-next v2 5/6] net: macb: implement timestamped MDIO writes James Clark
2026-10-18 10:02 ` [PATCH net-next v2 6/6] net: mdio: bcm-unimac: " James Clark
2026-10-19 10:34 ` netdev-bot+sashiko
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261018100257.566267-5-jjc@jclark.com \
--to=jjc@jclark.com \
--cc=andrew+netdev@lunn.ch \
--cc=andrew@lunn.ch \
--cc=bcm-kernel-feedback-list@broadcom.com \
--cc=conor.dooley@microchip.com \
--cc=davem@davemloft.net \
--cc=edumazet@kernel.org \
--cc=florian.fainelli@broadcom.com \
--cc=h.feurstein@gmail.com \
--cc=hkallweit1@gmail.com \
--cc=jstultz@google.com \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux@armlinux.org.uk \
--cc=mlichvar@redhat.com \
--cc=nb@tipi-net.de \
--cc=netdev@vger.kernel.org \
--cc=olteanv@gmail.com \
--cc=opendmb@gmail.com \
--cc=pabeni@redhat.com \
--cc=richardcochran@gmail.com \
--cc=sboyd@kernel.org \
--cc=tglx@kernel.org \
--cc=theo.lebrun@bootlin.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox