The PTP time of the switch is not preserved when uploading a new static configuration. Work around this hardware oddity by reading its PTP time before a static config upload, and restoring it afterwards.
Static config changes are expected to occur at runtime even in scenarios directly related to PTP, i.e. the Time-Aware Scheduler of the switch is programmed in this way. Signed-off-by: Vladimir Oltean <olte...@gmail.com> --- Changes since RFC: - None. drivers/net/dsa/sja1105/sja1105_main.c | 32 ++++++++++++- drivers/net/dsa/sja1105/sja1105_ptp.c | 66 ++++++++++++++++++-------- drivers/net/dsa/sja1105/sja1105_ptp.h | 25 ++++++++++ drivers/net/dsa/sja1105/sja1105_spi.c | 4 -- 4 files changed, 101 insertions(+), 26 deletions(-) diff --git a/drivers/net/dsa/sja1105/sja1105_main.c b/drivers/net/dsa/sja1105/sja1105_main.c index f7f03d486499..abb22f0a9884 100644 --- a/drivers/net/dsa/sja1105/sja1105_main.c +++ b/drivers/net/dsa/sja1105/sja1105_main.c @@ -1382,8 +1382,13 @@ static void sja1105_bridge_leave(struct dsa_switch *ds, int port, */ static int sja1105_static_config_reload(struct sja1105_private *priv) { + struct ptp_system_timestamp ptp_sts_before; + struct ptp_system_timestamp ptp_sts_after; struct sja1105_mac_config_entry *mac; int speed_mbps[SJA1105_NUM_PORTS]; + s64 t1, t2, t3, t4; + s64 ptpclkval; + s64 t12, t34; int rc, i; mac = priv->static_config.tables[BLK_IDX_MAC_CONFIG].entries; @@ -1398,10 +1403,35 @@ static int sja1105_static_config_reload(struct sja1105_private *priv) mac[i].speed = SJA1105_SPEED_AUTO; } + /* No PTP operations can run right now */ + mutex_lock(&priv->ptp_lock); + + ptpclkval = __sja1105_ptp_gettimex(priv, &ptp_sts_before); + /* Reset switch and send updated static configuration */ rc = sja1105_static_config_upload(priv); if (rc < 0) - goto out; + goto out_unlock_ptp; + + rc = __sja1105_ptp_settime(priv, 0, &ptp_sts_after); + if (rc < 0) + goto out_unlock_ptp; + + t1 = timespec64_to_ns(&ptp_sts_before.pre_ts); + t2 = timespec64_to_ns(&ptp_sts_before.post_ts); + t3 = timespec64_to_ns(&ptp_sts_after.pre_ts); + t4 = timespec64_to_ns(&ptp_sts_after.post_ts); + /* Mid point, corresponds to pre-reset PTPCLKVAL */ + t12 = t1 + (t2 - t1) / 2; + /* Mid point, corresponds to post-reset PTPCLKVAL, aka 0 */ + t34 = t3 + (t4 - t3) / 2; + /* Advance PTPCLKVAL by the time it took since its readout */ + ptpclkval += (t34 - t12); + + __sja1105_ptp_adjtime(priv, ptpclkval); + +out_unlock_ptp: + mutex_unlock(&priv->ptp_lock); /* Configure the CGU (PLLs) for MII and RMII PHYs. * For these interfaces there is no dynamic configuration diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.c b/drivers/net/dsa/sja1105/sja1105_ptp.c index 04693c702b09..a7722c0944fb 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.c +++ b/drivers/net/dsa/sja1105/sja1105_ptp.c @@ -215,17 +215,26 @@ int sja1105_ptp_reset(struct sja1105_private *priv) return rc; } +/* Caller must hold priv->ptp_lock */ +u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) +{ + u64 ticks; + + ticks = sja1105_ptpclkval_read(priv, sts); + + return sja1105_ticks_to_ns(ticks); +} + static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp, struct timespec64 *ts, struct ptp_system_timestamp *sts) { struct sja1105_private *priv = ptp_to_sja1105(ptp); - u64 ticks; mutex_lock(&priv->ptp_lock); - ticks = sja1105_ptpclkval_read(priv, sts); - *ts = ns_to_timespec64(sja1105_ticks_to_ns(ticks)); + *ts = ns_to_timespec64(__sja1105_ptp_gettimex(priv, sts)); mutex_unlock(&priv->ptp_lock); @@ -245,33 +254,42 @@ static int sja1105_ptp_mode_set(struct sja1105_private *priv, } /* Caller must hold priv->ptp_lock */ -static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val) +static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 val, + struct ptp_system_timestamp *ptp_sts) { const struct sja1105_regs *regs = priv->info->regs; return sja1105_spi_send_int(priv, SPI_WRITE, regs->ptpclk, &val, 8, - NULL); + ptp_sts); } /* Write to PTPCLKVAL while PTPCLKADD is 0 */ -static int sja1105_ptp_settime(struct ptp_clock_info *ptp, - const struct timespec64 *ts) +int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts) { - u64 ticks = ns_to_sja1105_ticks(timespec64_to_ns(ts)); - struct sja1105_private *priv = ptp_to_sja1105(ptp); + u64 ticks = ns_to_sja1105_ticks(ns); int rc; - mutex_lock(&priv->ptp_lock); - rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE); if (rc < 0) { dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n"); - goto out; + return rc; } - rc = sja1105_ptpclkval_write(priv, ticks); + return sja1105_ptpclkval_write(priv, ticks, ptp_sts); +} + +static int sja1105_ptp_settime(struct ptp_clock_info *ptp, + const struct timespec64 *ts) +{ + struct sja1105_private *priv = ptp_to_sja1105(ptp); + u64 ns = timespec64_to_ns(ts); + int rc; + + mutex_lock(&priv->ptp_lock); + + rc = __sja1105_ptp_settime(priv, ns, NULL); -out: mutex_unlock(&priv->ptp_lock); return rc; @@ -320,23 +338,29 @@ u64 sja1105_ptpclkval_read(struct sja1105_private *priv, } /* Write to PTPCLKVAL while PTPCLKADD is 1 */ -static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) { - struct sja1105_private *priv = ptp_to_sja1105(ptp); s64 ticks = ns_to_sja1105_ticks(delta); int rc; - mutex_lock(&priv->ptp_lock); - rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE); if (rc < 0) { dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n"); - goto out; + return rc; } - rc = sja1105_ptpclkval_write(priv, ticks); + return sja1105_ptpclkval_write(priv, ticks, NULL); +} + +static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta) +{ + struct sja1105_private *priv = ptp_to_sja1105(ptp); + int rc; + + mutex_lock(&priv->ptp_lock); + + rc = __sja1105_ptp_adjtime(priv, delta); -out: mutex_unlock(&priv->ptp_lock); return rc; diff --git a/drivers/net/dsa/sja1105/sja1105_ptp.h b/drivers/net/dsa/sja1105/sja1105_ptp.h index 80c33e5e4503..c699611e585d 100644 --- a/drivers/net/dsa/sja1105/sja1105_ptp.h +++ b/drivers/net/dsa/sja1105/sja1105_ptp.h @@ -42,6 +42,14 @@ int sja1105_ptp_reset(struct sja1105_private *priv); u64 sja1105_ptpclkval_read(struct sja1105_private *priv, struct ptp_system_timestamp *sts); +u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts); + +int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts); + +int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta); + #else static inline int sja1105_ptp_clock_register(struct sja1105_private *priv) @@ -77,6 +85,23 @@ static inline u64 sja1105_ptpclkval_read(struct sja1105_private *priv, return 0; } +static inline u64 __sja1105_ptp_gettimex(struct sja1105_private *priv, + struct ptp_system_timestamp *sts) +{ + return 0; +} + +static inline int __sja1105_ptp_settime(struct sja1105_private *priv, u64 ns, + struct ptp_system_timestamp *ptp_sts) +{ + return 0; +} + +static inline int __sja1105_ptp_adjtime(struct sja1105_private *priv, s64 delta) +{ + return 0; +} + #define sja1105et_ptp_cmd NULL #define sja1105pqrs_ptp_cmd NULL diff --git a/drivers/net/dsa/sja1105/sja1105_spi.c b/drivers/net/dsa/sja1105/sja1105_spi.c index 26985f1209ad..eae9c9baa189 100644 --- a/drivers/net/dsa/sja1105/sja1105_spi.c +++ b/drivers/net/dsa/sja1105/sja1105_spi.c @@ -496,10 +496,6 @@ int sja1105_static_config_upload(struct sja1105_private *priv) dev_info(dev, "Succeeded after %d tried\n", RETRIES - retries); } - rc = sja1105_ptp_reset(priv); - if (rc < 0) - dev_err(dev, "Failed to reset PTP clock: %d\n", rc); - dev_info(dev, "Reset switch and programmed static config\n"); out: -- 2.17.1