[PATCH v3 2/6] watchdog: wdt-uclass: report effective timeout in start print
Juuso Rinta <[email protected]>
| Newsgroups | org.u-boot-project.lists.u-boot |
|---|---|
| Message-ID | <[email protected]> |
The wdt_start() function may be called with a timeout greater than the hardware-supported maximum. This in turn can result in a bogus print, for example, if the device clamps the timeout to 10s but wdt_start() is called with a 60s timeout: Started <watchdog@> with servicing every 1000ms (60s timeout) Add a max_timeout_ms field to uclass-plat data, so drivers can set the hardware-limited max timeout value there during probing. For drivers that support this feature, the wdt_start() function clamps the timeout_ms value before calling ops->start() and the startup print now shows both the actual and requested timeouts, e.g. Started <watchdog@> with servicing every 1000ms (10s timeout, requested 60s) The timeout comparison is done in whole seconds to avoid noise from sub-second rounding. The value defaults to 0. For drivers that do not support this feature, the resulting print remains the same as before. Signed-off-by: Juuso Rinta <[email protected]> --- drivers/watchdog/wdt-uclass.c | 23 +++++++++++++++++++++-- include/wdt.h | 11 +++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c index cce874dc000..418f1023a85 100644 --- a/drivers/watchdog/wdt-uclass.c +++ b/drivers/watchdog/wdt-uclass.c @@ -119,15 +119,23 @@ int initr_watchdog(void) int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { const struct wdt_ops *ops = device_get_ops(dev); + struct wdt_uc_plat *plat = dev_get_uclass_plat(dev); + u64 req_timeout_ms = timeout_ms; int ret; if (!ops->start) return -ENOSYS; + /* Clamp to max timeout if reported by driver */ + if (plat->max_timeout_ms && timeout_ms > plat->max_timeout_ms) + timeout_ms = plat->max_timeout_ms; ret = ops->start(dev, timeout_ms, flags); if (ret == 0) { struct wdt_priv *priv = dev_get_uclass_priv(dev); char svc_str[16]; + char req_str[32]; + u32 req_s = lldiv(req_timeout_ms, 1000); + u32 tout_s = lldiv(timeout_ms, 1000); svc_str[0] = '\0'; if (IS_ENABLED(CONFIG_WATCHDOG)) { @@ -144,9 +152,19 @@ int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) } priv->running = true; - printf("WDT: Started %s with%s servicing %s (%ds timeout)\n", + + /* + * If the requested timeout was clamped, note the value + * when it differs at whole-second resolution. Sub-second + * rounding is ignored to avoid noise. + */ + req_str[0] = '\0'; + if (req_s != tout_s) + snprintf(req_str, sizeof(req_str), ", requested %ds", req_s); + + printf("WDT: Started %s with%s servicing %s (%ds timeout%s)\n", dev->name, IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out", - svc_str, (u32)lldiv(timeout_ms, 1000)); + svc_str, tout_s, req_str); } return ret; @@ -269,4 +287,5 @@ UCLASS_DRIVER(wdt) = { .flags = DM_UC_FLAG_SEQ_ALIAS, .pre_probe = wdt_pre_probe, .per_device_auto = sizeof(struct wdt_priv), + .per_device_plat_auto = sizeof(struct wdt_uc_plat), }; diff --git a/include/wdt.h b/include/wdt.h index 1ef656585c4..db1faa321b3 100644 --- a/include/wdt.h +++ b/include/wdt.h @@ -74,6 +74,17 @@ int wdt_reset(struct udevice *dev); */ int wdt_expire_now(struct udevice *dev, ulong flags); +/** + * struct wdt_uc_plat - uclass platform data for a watchdog device + * + * @max_timeout_ms: Maximum timeout (in ms) that the hardware can honour. + * A driver should set this typically at probe time. Default value 0 + * means no limit set by the driver. + */ +struct wdt_uc_plat { + u32 max_timeout_ms; +}; + /* * struct wdt_ops - Driver model wdt operations * -- 2.39.2