[PATCH net v4] net: stmmac: propagate PTP init failures in __stmmac_open() and stmmac_resume()
Lorenzo Bianconi
lorenzo.bianconi at oss.qualcomm.com
Sun Sep 13 01:29:00 PDT 2026
stmmac_setup_ptp() returns void and swallows both PTP setup errors:
the PTP reference clock enable and stmmac_init_timestamping()
failures are logged but never propagated. When they fail, the MAC
system time counter is left in its post-reset, non-running state,
while the driver keeps operating as if timestamping were up.
This matters for TAPRIO/EST qdisc offloading, which derives the EST
base time from the hardware timestamp counter: arming the gate list
against a non-advancing time base would leave the schedule permanently
stuck.
Make stmmac_setup_ptp() return an error code and propagate the
failure in __stmmac_open() and stmmac_resume(), stopping the DMA
engines when PTP setup fails.
While at it, factor the timestamping availability check into a
stmmac_check_timestamp_cap() helper that requires both the hardware
timestamping capability and a valid PTP reference clock rate. This
keeps the interface operational on platforms with PTP-capable
silicon but an unconfigured PTP clock, where timestamping cannot be
enabled: those are treated as PTP-less rather than failing to open
or resume. Apply the helper to the hwtstamp get path and the
ethtool ts_info path, and keep the timestamping gate on the set path
(now also requiring a valid PTP reference clock rate), so all of
them consistently report -EOPNOTSUPP when timestamping is not usable.
Gate the PTP reference clock enable/disable in the platform noirq
suspend/resume callbacks on priv->ptp_enabled, keeping the clock
reference balanced against the new early return in
stmmac_release_ptp().
Fixes: 92ba6888510c ("stmmac: add the support for PTP hw clock driver")
Fixes: 276aae377206 ("net: stmmac: fix system hang caused by eee_ctrl_timer during suspend/resume")
Reviewed-by: Maxime Chevallier <maxime.chevallier at bootlin.com>
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi at oss.qualcomm.com>
---
Changes in v4:
- Drop stmmac_restore_subsecond_increment() and
stmmac_update_subsecond_increment() changes for the moment.
- Add ptp_enabled check in stmmac_pltfr_noirq_suspend() and
stmmac_pltfr_noirq_resume().
- Link to v3: https://lore.kernel.org/r/20260910-stmmac-ptp-error-propagate-v3-1-4f386e8256b6@oss.qualcomm.com
Changes in v3:
- Rebase on top of net main branch.
- Link to v2: https://lore.kernel.org/r/20260907-stmmac-ptp-error-propagate-v2-1-4a2e8e41e860@oss.qualcomm.com
Changes in v2:
- Check clk_ptp_rate value in stmmac_check_timestamp_cap().
- Return error code in stmmac_update_subsecond_increment() and
stmmac_init_tstamp_counter().
- Rely on stmmac_check_timestamp_cap() in stmmac_hwtstamp_set() and
stmmac_hwtstamp_get().
- Link to v1: https://lore.kernel.org/r/20260904-stmmac-ptp-error-propagate-v1-1-80f01b03dafa@oss.qualcomm.com
---
drivers/net/ethernet/stmicro/stmmac/stmmac.h | 13 ++++
.../net/ethernet/stmicro/stmmac/stmmac_ethtool.c | 3 +-
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 72 +++++++++++++++-------
.../net/ethernet/stmicro/stmmac/stmmac_platform.c | 6 +-
4 files changed, 70 insertions(+), 24 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac.h b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
index 7582fca63741..c781cf3441fc 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
@@ -329,6 +329,8 @@ struct stmmac_priv {
struct kernel_hwtstamp_config tstamp_config;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_ops;
+ bool ptp_enabled;
+
unsigned int default_addend;
u32 sub_second_inc;
u32 systime_flags;
@@ -419,6 +421,17 @@ int stmmac_set_clk_tx_rate(void *bsp_priv, struct clk *clk_tx_i,
struct plat_stmmacenet_data *stmmac_plat_dat_alloc(struct device *dev);
+static inline bool stmmac_check_timestamp_cap(struct stmmac_priv *priv)
+{
+ if (!priv->dma_cap.time_stamp && !priv->dma_cap.atime_stamp)
+ return false;
+
+ if (!priv->plat->clk_ptp_rate)
+ return false;
+
+ return true;
+}
+
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
{
return !!priv->xdp_prog;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
index 154cc0c7623d..7758b854700a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_ethtool.c
@@ -1007,8 +1007,7 @@ static int stmmac_get_ts_info(struct net_device *dev,
{
struct stmmac_priv *priv = netdev_priv(dev);
- if ((priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) {
-
+ if (stmmac_check_timestamp_cap(priv)) {
info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 62c3441911e7..9d2c6bf68575 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -653,7 +653,8 @@ static int stmmac_hwtstamp_set(struct net_device *dev,
u32 ts_master_en = 0;
u32 ts_event_en = 0;
- if (!(priv->dma_cap.time_stamp || priv->adv_ts)) {
+ if (!priv->plat->clk_ptp_rate ||
+ !(priv->dma_cap.time_stamp || priv->adv_ts)) {
NL_SET_ERR_MSG_MOD(extack, "No support for HW time stamping");
priv->hwts_tx_en = 0;
priv->hwts_rx_en = 0;
@@ -843,7 +844,7 @@ static int stmmac_hwtstamp_get(struct net_device *dev,
{
struct stmmac_priv *priv = netdev_priv(dev);
- if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp))
+ if (!stmmac_check_timestamp_cap(priv))
return -EOPNOTSUPP;
*config = priv->tstamp_config;
@@ -900,11 +901,6 @@ static int stmmac_init_timestamping(struct stmmac_priv *priv)
if (priv->plat->ptp_clk_freq_config)
priv->plat->ptp_clk_freq_config(priv);
- if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp)) {
- netdev_info(priv->dev, "PTP not supported by HW\n");
- return -EOPNOTSUPP;
- }
-
ret = stmmac_init_tstamp_counter(priv, STMMAC_HWTS_ACTIVE |
PTP_TCR_TSCFUPDT);
if (ret) {
@@ -937,24 +933,43 @@ static int stmmac_init_timestamping(struct stmmac_priv *priv)
return 0;
}
-static void stmmac_setup_ptp(struct stmmac_priv *priv)
+static int stmmac_setup_ptp(struct stmmac_priv *priv)
{
int ret;
+ if (!stmmac_check_timestamp_cap(priv)) {
+ netdev_info(priv->dev, "PTP not supported\n");
+ return 0;
+ }
+
ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
- if (ret < 0)
+ if (ret < 0) {
netdev_warn(priv->dev,
"failed to enable PTP reference clock: %pe\n",
ERR_PTR(ret));
+ return ret;
+ }
- if (stmmac_init_timestamping(priv) == 0)
- stmmac_ptp_register(priv);
+ ret = stmmac_init_timestamping(priv);
+ if (ret) {
+ clk_disable_unprepare(priv->plat->clk_ptp_ref);
+ return ret;
+ }
+
+ stmmac_ptp_register(priv);
+ priv->ptp_enabled = true;
+
+ return 0;
}
static void stmmac_release_ptp(struct stmmac_priv *priv)
{
+ if (!priv->ptp_enabled)
+ return;
+
stmmac_ptp_unregister(priv);
clk_disable_unprepare(priv->plat->clk_ptp_ref);
+ priv->ptp_enabled = false;
}
static void stmmac_legacy_serdes_power_down(struct stmmac_priv *priv)
@@ -4161,10 +4176,12 @@ static int __stmmac_open(struct net_device *dev,
ret = stmmac_hw_setup(dev);
if (ret < 0) {
netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
- goto init_error;
+ return ret;
}
- stmmac_setup_ptp(priv);
+ ret = stmmac_setup_ptp(priv);
+ if (ret)
+ goto ptp_error;
stmmac_init_coalesce(priv);
@@ -4189,7 +4206,10 @@ static int __stmmac_open(struct net_device *dev,
hrtimer_cancel(&priv->dma_conf.tx_queue[chan].txtimer);
stmmac_release_ptp(priv);
-init_error:
+ptp_error:
+ stmmac_stop_all_dma(priv);
+ stmmac_mac_set(priv, priv->ioaddr, false);
+
return ret;
}
@@ -7740,8 +7760,7 @@ static int stmmac_register_devlink(struct stmmac_priv *priv)
/* For now, what is exposed over devlink is only relevant when
* timestamping is available and we have a valid ptp clock rate
*/
- if (!(priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp) ||
- !priv->plat->clk_ptp_rate)
+ if (!stmmac_check_timestamp_cap(priv))
return 0;
priv->devlink = devlink_alloc(&stmmac_devlink_ops, sizeof(*dl_priv),
@@ -8346,13 +8365,14 @@ int stmmac_resume(struct device *dev)
ret = stmmac_hw_setup(ndev);
if (ret < 0) {
netdev_err(priv->dev, "%s: Hw setup failed\n", __func__);
- stmmac_legacy_serdes_power_down(priv);
- mutex_unlock(&priv->lock);
- rtnl_unlock();
- return ret;
+ goto error_unlock;
}
- stmmac_init_timestamping(priv);
+ if (priv->ptp_enabled) {
+ ret = stmmac_init_timestamping(priv);
+ if (ret)
+ goto error_stop_dma;
+ }
stmmac_init_coalesce(priv);
phylink_rx_clk_stop_block(priv->phylink);
@@ -8376,6 +8396,16 @@ int stmmac_resume(struct device *dev)
netif_device_attach(ndev);
return 0;
+
+error_stop_dma:
+ stmmac_stop_all_dma(priv);
+ stmmac_mac_set(priv, priv->ioaddr, false);
+error_unlock:
+ stmmac_legacy_serdes_power_down(priv);
+ mutex_unlock(&priv->lock);
+ rtnl_unlock();
+
+ return ret;
}
EXPORT_SYMBOL_GPL(stmmac_resume);
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 6128ed1bd521..19d481554499 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -959,7 +959,8 @@ static int __maybe_unused stmmac_pltfr_noirq_suspend(struct device *dev)
if (!priv->wolopts) {
/* Disable clock in case of PWM is off */
- clk_disable_unprepare(priv->plat->clk_ptp_ref);
+ if (priv->ptp_enabled)
+ clk_disable_unprepare(priv->plat->clk_ptp_ref);
ret = pm_runtime_force_suspend(dev);
if (ret)
@@ -984,6 +985,9 @@ static int __maybe_unused stmmac_pltfr_noirq_resume(struct device *dev)
if (ret)
return ret;
+ if (!priv->ptp_enabled)
+ return 0;
+
ret = clk_prepare_enable(priv->plat->clk_ptp_ref);
if (ret < 0) {
netdev_warn(priv->dev,
---
base-commit: 6500e89132d5d510c75e1be443455af87267b40e
change-id: 20260904-stmmac-ptp-error-propagate-6c0147b4ce29
Best regards,
--
Lorenzo Bianconi <lorenzo.bianconi at oss.qualcomm.com>
More information about the linux-arm-kernel
mailing list