The wdt_start function may be called with a timeout greater
than the hardware-supported maximum. This in turn can result
to bogus print, e.g.
Started <watchdog@> with servicing every 1000ms (60s timeout)

Add a uclass get_timeout operation and helper so drivers can
report the effective timeout. When available, the startup
print now shows both actual and requested timeout values, e.g.
Started <watchdog@> with servicing every 1000ms (10s timeout, requested 60s)

Signed-off-by: Juuso Rinta <[email protected]>
---
 drivers/watchdog/wdt-uclass.c | 35 +++++++++++++++++++++++++++++++++--
 include/wdt.h                 | 22 ++++++++++++++++++++++
 2 files changed, 55 insertions(+), 2 deletions(-)

diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c
index 438833b2245..c9ce5c07afd 100644
--- a/drivers/watchdog/wdt-uclass.c
+++ b/drivers/watchdog/wdt-uclass.c
@@ -116,10 +116,28 @@ int initr_watchdog(void)
        return 0;
 }
 
+int wdt_get_timeout(struct udevice *dev, u64 *timeout_ms)
+{
+       const struct wdt_ops *ops = device_get_ops(dev);
+       u64 tout_val;
+       int ret;
+
+       if (!ops->get_timeout)
+               return -ENOSYS;
+
+       ret = ops->get_timeout(dev, &tout_val);
+       if (ret == 0)
+               *timeout_ms = tout_val;
+
+       return ret;
+}
+
 int wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
 {
        const struct wdt_ops *ops = device_get_ops(dev);
        int ret;
+       u64 effective_timeout = timeout_ms;
+       char requested_timeout[32];
 
        if (!ops->start)
                return -ENOSYS;
@@ -143,9 +161,22 @@ 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",
+
+               /* Get the effective timeout from driver if supported */
+               memset(requested_timeout, 0, 32);
+               if (wdt_get_timeout(dev, &effective_timeout) == 0) {
+                       u32 effective_s = (u32)lldiv(effective_timeout, 1000);
+                       u32 requested_s = (u32)lldiv(timeout_ms, 1000);
+
+                       if (effective_s != requested_s) {
+                               snprintf(requested_timeout, 32, ", requested 
%ds",
+                                        requested_s);
+                       }
+               }
+
+               printf("WDT:   Started %s with%s servicing %s (%ds 
timeout%s)\n",
                       dev->name, IS_ENABLED(CONFIG_WATCHDOG) ? "" : "out",
-                      str, (u32)lldiv(timeout_ms, 1000));
+                      str, (u32)lldiv(effective_timeout, 1000), 
requested_timeout);
        }
 
        return ret;
diff --git a/include/wdt.h b/include/wdt.h
index 1ef656585c4..5c38eba3a5a 100644
--- a/include/wdt.h
+++ b/include/wdt.h
@@ -74,6 +74,19 @@ int wdt_reset(struct udevice *dev);
  */
 int wdt_expire_now(struct udevice *dev, ulong flags);
 
+/*
+ * Get the effective timeout in milliseconds.
+ *
+ * The effective value may differ from the value passed to wdt_start()
+ * if the hardware has rounded and/or clamped it.
+ *
+ * @dev: WDT device
+ * @timeout_ms: A pointer where the effective timeout in milliseconds
+ * is returned to. On error, the value is left unchanged.
+ * @return 0 if OK -ve on error
+ */
+int wdt_get_timeout(struct udevice *dev, u64 *timeout_ms);
+
 /*
  * struct wdt_ops - Driver model wdt operations
  *
@@ -120,6 +133,15 @@ struct wdt_ops {
         * @return 0 if OK -ve on error. May not return.
         */
        int (*expire_now)(struct udevice *dev, ulong flags);
+       /*
+        * Get the effective timeout in milliseconds (optional)
+        *
+        * @dev: WDT device
+        * @timeout_ms: Location to store timeout in milliseconds,
+        * written only on success
+        * @return 0 if OK -ve on error
+        */
+       int (*get_timeout)(struct udevice *dev, u64 *timeout_ms);
 };
 
 int initr_watchdog(void);

-- 
2.39.2

Reply via email to