mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
net: stmmac: propagate PTP init failures in __stmmac_open() and stmmac_resume()
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(), stopping the DMA engines when PTP setup fails. In stmmac_resume(), re-initialise timestamping only when the PTP clock was registered before suspend, re-apply the platform clock rate configuration, and stop the DMA engines if re-initialisation fails. While at it, factor the hardware timestamping capability check into a stmmac_check_timestamp_cap() helper and apply it to the hwtstamp get path and the ethtool ts_info path. stmmac_setup_ptp() now enables the PTP reference clock and runs the platform ptp_clk_freq_config() callback before validating the resulting clock rate; if no valid rate is available, it disables the clock and returns success without registering the PTP clock. This keeps the interface operational on platforms with PTP-capable silicon but an unconfigured PTP clock, where timestamping cannot be enabled: instead of failing, the driver proceeds without setting up timestamping. Extend the timestamping gate on the set path (which keeps testing the core's basic/advanced timestamping capability) and the devlink registration with the PTP reference clock rate requirement. 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(). Reviewed-by: Maxime Chevallier <maxime.chevallier@bootlin.com> Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com> Link: https://patch.msgid.link/20260914-stmmac-ptp-error-propagate-v5-1-81149897e65d@oss.qualcomm.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
a0afc297a0
commit
8181678a92
|
|
@ -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,11 @@ 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)
|
||||
{
|
||||
return priv->dma_cap.time_stamp || priv->dma_cap.atime_stamp;
|
||||
}
|
||||
|
||||
static inline bool stmmac_xdp_is_enabled(struct stmmac_priv *priv)
|
||||
{
|
||||
return !!priv->xdp_prog;
|
||||
|
|
|
|||
|
|
@ -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 |
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -866,11 +867,6 @@ static int stmmac_init_tstamp_counter(struct stmmac_priv *priv,
|
|||
{
|
||||
struct timespec64 now;
|
||||
|
||||
if (!priv->plat->clk_ptp_rate) {
|
||||
netdev_err(priv->dev, "Invalid PTP clock rate");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
stmmac_config_hw_tstamping(priv, priv->ptpaddr, systime_flags);
|
||||
priv->systime_flags = systime_flags;
|
||||
|
||||
|
|
@ -885,26 +881,37 @@ static int stmmac_init_tstamp_counter(struct stmmac_priv *priv,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int stmmac_init_ptp_clk_freq(struct stmmac_priv *priv)
|
||||
{
|
||||
if (priv->plat->ptp_clk_freq_config)
|
||||
priv->plat->ptp_clk_freq_config(priv);
|
||||
|
||||
if (!priv->plat->clk_ptp_rate) {
|
||||
netdev_info(priv->dev, "PTP clock rate not configured\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* stmmac_init_timestamping - initialise timestamping
|
||||
* @priv: driver private structure
|
||||
* Description: this is to verify if the HW supports the PTPv1 or PTPv2.
|
||||
* This is done by looking at the HW cap. register.
|
||||
* This function also registers the ptp driver.
|
||||
*
|
||||
* Description: initialise the hardware timestamping counter, reset the
|
||||
* timestamping configuration and derive the advanced timestamping flags from
|
||||
* the HW capabilities. The caller must have ensured a valid PTP reference
|
||||
* clock rate (see stmmac_init_ptp_clk_freq()); the configured state is valid
|
||||
* as long as the interface is open and not suspended, and this function is
|
||||
* re-run on resume.
|
||||
*
|
||||
* Return: 0 on success, a negative errno otherwise.
|
||||
*/
|
||||
static int stmmac_init_timestamping(struct stmmac_priv *priv)
|
||||
{
|
||||
bool xmac = dwmac_is_xmac(priv->plat->core_type);
|
||||
int ret;
|
||||
|
||||
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 +944,48 @@ 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);
|
||||
if (stmmac_init_ptp_clk_freq(priv)) {
|
||||
clk_disable_unprepare(priv->plat->clk_ptp_ref);
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 +4192,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);
|
||||
|
||||
|
|
@ -4191,7 +4224,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;
|
||||
}
|
||||
|
||||
|
|
@ -7764,8 +7800,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) || !priv->plat->clk_ptp_rate)
|
||||
return 0;
|
||||
|
||||
priv->devlink = devlink_alloc(&stmmac_devlink_ops, sizeof(*dl_priv),
|
||||
|
|
@ -8370,14 +8405,19 @@ 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) {
|
||||
if (stmmac_init_ptp_clk_freq(priv))
|
||||
goto init_coalesce;
|
||||
|
||||
ret = stmmac_init_timestamping(priv);
|
||||
if (ret)
|
||||
goto error_stop_dma;
|
||||
}
|
||||
|
||||
init_coalesce:
|
||||
stmmac_init_coalesce(priv);
|
||||
phylink_rx_clk_stop_block(priv->phylink);
|
||||
stmmac_set_rx_mode(ndev);
|
||||
|
|
@ -8400,6 +8440,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);
|
||||
|
||||
|
|
|
|||
|
|
@ -970,7 +970,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)
|
||||
|
|
@ -995,6 +996,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,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user