[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.