From patchwork Sat Jun 20 17:33:46 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 215013 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id DADF8C433E2 for ; Sat, 20 Jun 2020 17:35:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B115D2404E for ; Sat, 20 Jun 2020 17:35:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ioJCILsk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728126AbgFTRfH (ORCPT ); Sat, 20 Jun 2020 13:35:07 -0400 Received: from mail-oi1-f194.google.com ([209.85.167.194]:36342 "EHLO mail-oi1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728349AbgFTRfF (ORCPT ); Sat, 20 Jun 2020 13:35:05 -0400 Received: by mail-oi1-f194.google.com with SMTP id a137so11587118oii.3 for ; Sat, 20 Jun 2020 10:35:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=HOVBYX09s4vb3dCiShBG4NSsb19cgNGL44yivBt9AqQ=; b=ioJCILskKb7oD4HN+oRp0Xb7bCKYZgLEUbxjkk+m9AMKBg7srdQhlvulVDHO8I0ATQ VAolcNgU5Zj9svSjp6saOjl+sn0XNXkNk9ObjJCUP+II3W6pLEatemkwcwyU9eNLCcut ZhLyStdZtq4/ESsc/K/xd1m0xwVgB5Os9sPTYSYHrxwUNSrfjKsqsOb/ikUZ50J8vj3c 09XOuTlbV9KJ84Uf+WB91Pewqjf5iVWnQQe49VjTzVeLDDEbEQfnNmlDO2h4Mc36HS2L mc6XwSDtA/ljrBb6flI+O7SLzBsHnSoo+GD97UPqhIPvbAs4M1U4Bxtd6bLH1UiOcOmI 25bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=HOVBYX09s4vb3dCiShBG4NSsb19cgNGL44yivBt9AqQ=; b=pZqi8bXQ4YfTYV1C/nuzOSo1qP8C6a/8/A06wgNm/llqZfm3Pxy6kXo0snbdM3mlx8 M0Iv7c2xNVE6Euf+7kXpWaGY4nThnc1NTbX3+D21WrP5obIxynUz8/MQl85mFJYU09Fw 1bZturHKvAmeiBRBgMOO6hH8SpZn+vPdw/koU9FP7evGEgKwS9vNzUcTLwEm5l2aJLki F5S2c3Ff6tt7JzsVTjCq4lGOVQ4sR7+Y4Jk86M7OI5v4qssgdESnq5yjefvVEh+mTMSs XicEnsu6jwvIMw3gUAWvVCgWjH0Jrs+QH3ISeg/BOOQypdLBRS2KWizF1raZpyD0I0Zc 1sQw== X-Gm-Message-State: AOAM530dSAdjW3Iy2ij4ZOysqIJxJkad8RTBrw0tFnyU7ZuVWm/jSosZ KadYOLKOMmtzIsY5YEyEJ+goxR4= X-Google-Smtp-Source: ABdhPJzJ/aOvpOMypiS7YmUOUcr7cGrxm74otNl6GSmSwuphL4reMsApF68JVR3YLlZVALQSCF8KdA== X-Received: by 2002:a05:6808:c2:: with SMTP id t2mr7599544oic.44.1592674442594; Sat, 20 Jun 2020 10:34:02 -0700 (PDT) Received: from serve.minyard.net ([47.184.146.204]) by smtp.gmail.com with ESMTPSA id y206sm2128230ooa.32.2020.06.20.10.34.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 20 Jun 2020 10:34:01 -0700 (PDT) Received: from t560.minyard.net (unknown [IPv6:2001:470:b8f6:1b:f17b:b355:b0a4:2592]) by serve.minyard.net (Postfix) with ESMTPA id 68241180171; Sat, 20 Jun 2020 17:34:00 +0000 (UTC) From: minyard@acm.org To: Guenter Roeck , Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org, Gabriele Paoloni , Corey Minyard Subject: [PATCH 1/6] watchdog: Allow a driver to use milliseconds instead of seconds Date: Sat, 20 Jun 2020 12:33:46 -0500 Message-Id: <20200620173351.18752-2-minyard@acm.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200620173351.18752-1-minyard@acm.org> References: <20200620173351.18752-1-minyard@acm.org> Sender: linux-watchdog-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-watchdog@vger.kernel.org From: Corey Minyard If the WDIOF_MSECTIMER is set, then all the timeouts in the watchdog structure are expected to be in milliseconds. Add the flag and the various conversions. This should have no effect on existing drivers. Signed-off-by: Corey Minyard --- drivers/watchdog/watchdog_core.c | 30 +++++++++++++------- drivers/watchdog/watchdog_dev.c | 47 ++++++++++++++++++++++++++------ include/linux/watchdog.h | 29 +++++++++++++++----- include/uapi/linux/watchdog.h | 1 + 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index 423844757812..b54451a9a336 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -116,17 +116,17 @@ int watchdog_init_timeout(struct watchdog_device *wdd, { const char *dev_str = wdd->parent ? dev_name(wdd->parent) : (const char *)wdd->info->identity; - unsigned int t = 0; int ret = 0; watchdog_check_min_max_timeout(wdd); /* check the driver supplied value (likely a module parameter) first */ if (timeout_parm) { - if (!watchdog_timeout_invalid(wdd, timeout_parm)) { - wdd->timeout = timeout_parm; - return 0; - } + if (wdd->info->options & WDIOF_MSECTIMER) { + if (!_watchdog_timeout_invalid(wdd, timeout_parm)) + goto set_timeout; + } else if (!watchdog_timeout_invalid(wdd, timeout_parm)) + goto set_timeout; pr_err("%s: driver supplied timeout (%u) out of range\n", dev_str, timeout_parm); ret = -EINVAL; @@ -134,12 +134,18 @@ int watchdog_init_timeout(struct watchdog_device *wdd, /* try to get the timeout_sec property */ if (dev && dev->of_node && - of_property_read_u32(dev->of_node, "timeout-sec", &t) == 0) { - if (t && !watchdog_timeout_invalid(wdd, t)) { - wdd->timeout = t; - return 0; + of_property_read_u32(dev->of_node, "timeout-sec", + &timeout_parm) == 0) { + if (timeout_parm && + !watchdog_timeout_invalid(wdd, timeout_parm)) { + if (!(wdd->info->options & WDIOF_MSECTIMER)) + /* Convert to msecs if not already so. */ + timeout_parm *= 1000; + goto set_timeout; } - pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, t); + + pr_err("%s: DT supplied timeout (%u) out of range\n", dev_str, + timeout_parm); ret = -EINVAL; } @@ -148,6 +154,10 @@ int watchdog_init_timeout(struct watchdog_device *wdd, wdd->timeout); return ret; + +set_timeout: + wdd->timeout = timeout_parm; + return 0; } EXPORT_SYMBOL_GPL(watchdog_init_timeout); diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 7e4cd34a8c20..480460b89c16 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -99,7 +99,11 @@ static inline bool watchdog_need_worker(struct watchdog_device *wdd) { /* All variables in milli-seconds */ unsigned int hm = wdd->max_hw_heartbeat_ms; - unsigned int t = wdd->timeout * 1000; + unsigned int t = wdd->timeout; + + if (!(wdd->info->options & WDIOF_MSECTIMER)) + /* Convert to msecs if not already so. */ + t *= 1000; /* * A worker to generate heartbeat requests is needed if all of the @@ -121,12 +125,16 @@ static inline bool watchdog_need_worker(struct watchdog_device *wdd) static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd) { struct watchdog_core_data *wd_data = wdd->wd_data; - unsigned int timeout_ms = wdd->timeout * 1000; + unsigned int timeout_ms = wdd->timeout; ktime_t keepalive_interval; ktime_t last_heartbeat, latest_heartbeat; ktime_t virt_timeout; unsigned int hw_heartbeat_ms; + if (!(wdd->info->options & WDIOF_MSECTIMER)) + /* Convert to msecs if not already so. */ + timeout_ms *= 1000; + if (watchdog_active(wdd)) virt_timeout = ktime_add(wd_data->last_keepalive, ms_to_ktime(timeout_ms)); @@ -137,7 +145,7 @@ static ktime_t watchdog_next_keepalive(struct watchdog_device *wdd) keepalive_interval = ms_to_ktime(hw_heartbeat_ms / 2); /* - * To ensure that the watchdog times out wdd->timeout seconds + * To ensure that the watchdog times out wdd->timeout seconds/msecs * after the most recent ping from userspace, the last * worker ping has to come in hw_heartbeat_ms before this timeout. */ @@ -382,6 +390,8 @@ static int watchdog_set_timeout(struct watchdog_device *wdd, if (watchdog_timeout_invalid(wdd, timeout)) return -EINVAL; + if (wdd->info->options & WDIOF_MSECTIMER) + timeout *= 1000; if (wdd->ops->set_timeout) { err = wdd->ops->set_timeout(wdd, timeout); } else { @@ -413,6 +423,8 @@ static int watchdog_set_pretimeout(struct watchdog_device *wdd, if (watchdog_pretimeout_invalid(wdd, timeout)) return -EINVAL; + if (wdd->info->options & WDIOF_MSECTIMER) + timeout *= 1000; if (wdd->ops->set_pretimeout) err = wdd->ops->set_pretimeout(wdd, timeout); else @@ -440,6 +452,8 @@ static int watchdog_get_timeleft(struct watchdog_device *wdd, return -EOPNOTSUPP; *timeleft = wdd->ops->get_timeleft(wdd); + if (wdd->info->options & WDIOF_MSECTIMER) + *timeleft /= 1000; return 0; } @@ -508,8 +522,11 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, mutex_lock(&wd_data->lock); status = watchdog_get_timeleft(wdd, &val); mutex_unlock(&wd_data->lock); - if (!status) + if (!status) { + if (wdd->info->options & WDIOF_MSECTIMER) + val /= 1000; status = sprintf(buf, "%u\n", val); + } return status; } @@ -519,8 +536,12 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); + unsigned int t = wdd->timeout; + + if (wdd->info->options & WDIOF_MSECTIMER) + t /= 1000; - return sprintf(buf, "%u\n", wdd->timeout); + return sprintf(buf, "%u\n", t); } static DEVICE_ATTR_RO(timeout); @@ -528,8 +549,12 @@ static ssize_t pretimeout_show(struct device *dev, struct device_attribute *attr, char *buf) { struct watchdog_device *wdd = dev_get_drvdata(dev); + unsigned int t = wdd->pretimeout; - return sprintf(buf, "%u\n", wdd->pretimeout); + if (wdd->info->options & WDIOF_MSECTIMER) + t /= 1000; + + return sprintf(buf, "%u\n", t); } static DEVICE_ATTR_RO(pretimeout); @@ -783,7 +808,10 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, err = -EOPNOTSUPP; break; } - err = put_user(wdd->timeout, p); + val = wdd->timeout; + if (wdd->info->options & WDIOF_MSECTIMER) + val /= 1000; + err = put_user(val, p); break; case WDIOC_GETTIMELEFT: err = watchdog_get_timeleft(wdd, &val); @@ -799,7 +827,10 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, err = watchdog_set_pretimeout(wdd, val); break; case WDIOC_GETPRETIMEOUT: - err = put_user(wdd->pretimeout, p); + val = wdd->pretimeout; + if (wdd->info->options & WDIOF_MSECTIMER) + val /= 1000; + err = put_user(val, p); break; default: err = -ENOTTY; diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index 1464ce6ffa31..49bfaf986b37 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -55,7 +55,9 @@ struct watchdog_ops { long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long); }; -/** struct watchdog_device - The structure that defines a watchdog device +/** struct watchdog_device - The structure that defines a watchdog device. + * Unless otherwise specified, all timeouts are in seconds unless + * WDIOF_MSECTIMER is set, then they are in milliseconds. * * @id: The watchdog's ID. (Allocated by watchdog_register_device) * @parent: The parent bus device @@ -65,10 +67,10 @@ struct watchdog_ops { * @ops: Pointer to the list of watchdog operations. * @gov: Pointer to watchdog pretimeout governor. * @bootstatus: Status of the watchdog device at boot. - * @timeout: The watchdog devices timeout value (in seconds). + * @timeout: The watchdog devices timeout value. * @pretimeout: The watchdog devices pre_timeout value. - * @min_timeout:The watchdog devices minimum timeout value (in seconds). - * @max_timeout:The watchdog devices maximum timeout value (in seconds) + * @min_timeout:The watchdog devices minimum timeout value. + * @max_timeout:The watchdog devices maximum timeout value * as configurable from user space. Only relevant if * max_hw_heartbeat_ms is not provided. * @min_hw_heartbeat_ms: @@ -156,6 +158,17 @@ static inline void watchdog_stop_on_unregister(struct watchdog_device *wdd) set_bit(WDOG_STOP_ON_UNREGISTER, &wdd->status); } +/* + * Use the following function to check if a timeout value is + * internally consistent with the range parameters. t is in milliseconds. + */ +static inline bool _watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t) +{ + return t < wdd->min_timeout || + (!wdd->max_hw_heartbeat_ms && wdd->max_timeout && + t > wdd->max_timeout); +} + /* Use the following function to check if a timeout value is invalid */ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t) { @@ -170,9 +183,11 @@ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigne * is configured, and the requested value is larger than the * configured maximum timeout. */ - return t > UINT_MAX / 1000 || t < wdd->min_timeout || - (!wdd->max_hw_heartbeat_ms && wdd->max_timeout && - t > wdd->max_timeout); + if (t > UINT_MAX / 1000) + return true; + if (wdd->info->options & WDIOF_MSECTIMER) + t *= 1000; + return _watchdog_timeout_invalid(wdd, t); } /* Use the following function to check if a pretimeout value is invalid */ diff --git a/include/uapi/linux/watchdog.h b/include/uapi/linux/watchdog.h index b15cde5c9054..feb3bcc46993 100644 --- a/include/uapi/linux/watchdog.h +++ b/include/uapi/linux/watchdog.h @@ -48,6 +48,7 @@ struct watchdog_info { #define WDIOF_PRETIMEOUT 0x0200 /* Pretimeout (in seconds), get/set */ #define WDIOF_ALARMONLY 0x0400 /* Watchdog triggers a management or other external alarm not a reboot */ +#define WDIOF_MSECTIMER 0x0800 /* Driver can use milliseconds for timeouts */ #define WDIOF_KEEPALIVEPING 0x8000 /* Keep alive ping reply */ #define WDIOS_DISABLECARD 0x0001 /* Turn off the watchdog timer */ From patchwork Sat Jun 20 17:33:48 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 215014 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 69AB3C433DF for ; Sat, 20 Jun 2020 17:35:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 49AF724060 for ; Sat, 20 Jun 2020 17:35:07 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="sIXqVXcl" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728256AbgFTRfE (ORCPT ); Sat, 20 Jun 2020 13:35:04 -0400 Received: from mail-oi1-f193.google.com ([209.85.167.193]:36340 "EHLO mail-oi1-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728191AbgFTRfD (ORCPT ); Sat, 20 Jun 2020 13:35:03 -0400 Received: by mail-oi1-f193.google.com with SMTP id a137so11587106oii.3 for ; Sat, 20 Jun 2020 10:35:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=jIos/cHbqrurStkzPZEPZkdct3JfDCiT1Al2g34v7+M=; b=sIXqVXclo+4Ck3UmWBwJpEjM7CkUr955y0iqifo5W1GC5s72/oIvM5vc2HLkkTI6xK mBgv8FPt6kP79GSevYV+5BLsIKgX185uFW7S1rRckhLqfuqjA8aXSBtS5QIByCirrdIt bDIH29yncc4MfCglZPBmLmEzi4dBLN1eYLI+yFeO78/d21bu8oK5aZuYP7EIL/ldJV+z J5FLX6V2NAKPUEtKiFPYzvt+IaNgdMOqNpkGEhL2d/Qnocy/LEibPZ2cZejTu1m1sc3Y BPCtTRNlXuT9pBT91sQz3ag7vT9VtYjxtK3k3mFrwSBV65t0ps6wiyad54WMA2TARidp zp1A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=jIos/cHbqrurStkzPZEPZkdct3JfDCiT1Al2g34v7+M=; b=Hd5K9tRm0NYAp9YtQgTWt38RDY/nFI0ib60SDiHsPHxOAtYzR9uUd3Mn/PNkr5ZFhl bGbU1gRcH4KqWHZbIP5wa20B3Q0xxzA0hX+tbiRnILM2h1p1To81f9sFqfWUbtD8j5mg Vy5xhSLqcDgyiKRVdo/n1iewx+nXNPoqL7yEt6P9GyAw1MOyYzttdSh1BhMfgCkTpa5U bv/aapfJRfMqM2/X8hmhOr2oA/rdCJoFzbLsanQfcBbzZJYIYuTdddTz4sZa9dzRcjhi PbhGfTmf/D3lO1/dnrujST4pvDb9MZgCrMF0U9wPYO1r5xHr/ukOoyXct1QmXbFqcM5c 27XA== X-Gm-Message-State: AOAM531/mBDaivvh6/pBz5CTAuQguPGv7i+fE2s4Fi4di98jNwjxmFr6 3YrSxO2cX5Ne+rvZ1qhHAFaQL4w= X-Google-Smtp-Source: ABdhPJyMI9Agja2ULN/bm4Egbo2YH898dHbUAjVl/L/cn90eadqH8UlZmHFsy5vR/qOhQi/NwX5q/Q== X-Received: by 2002:aca:d956:: with SMTP id q83mr7020231oig.78.1592674442133; Sat, 20 Jun 2020 10:34:02 -0700 (PDT) Received: from serve.minyard.net ([47.184.146.204]) by smtp.gmail.com with ESMTPSA id w10sm2167357oon.40.2020.06.20.10.34.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 20 Jun 2020 10:34:01 -0700 (PDT) Received: from t560.minyard.net (unknown [IPv6:2001:470:b8f6:1b:f17b:b355:b0a4:2592]) by serve.minyard.net (Postfix) with ESMTPA id 9377818054B; Sat, 20 Jun 2020 17:34:00 +0000 (UTC) From: minyard@acm.org To: Guenter Roeck , Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org, Gabriele Paoloni , Corey Minyard Subject: [PATCH 3/6] watchdog: Add millisecond precision device attributes Date: Sat, 20 Jun 2020 12:33:48 -0500 Message-Id: <20200620173351.18752-4-minyard@acm.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200620173351.18752-1-minyard@acm.org> References: <20200620173351.18752-1-minyard@acm.org> Sender: linux-watchdog-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-watchdog@vger.kernel.org From: Corey Minyard Add timeleft_ms, timeout_ms, and pretimeout_ms that print microsecond values. Signed-off-by: Corey Minyard --- drivers/watchdog/watchdog_dev.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index eca13ce1dc91..b82049896204 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -562,6 +562,21 @@ static ssize_t bootstatus_show(struct device *dev, } static DEVICE_ATTR_RO(bootstatus); +/* + * If _ms is in the attribute name, return milliseconds, otherwise + * return seconds. + */ +static unsigned int conv_time_to_attr_display(struct watchdog_device *wdd, + struct device_attribute *attr, + unsigned int val) +{ + bool in_msec = false; + + if (strstr(attr->attr.name, "_ms")) + in_msec = true; + return watchdog_timeout_toexternal(wdd, in_msec, val); +} + static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -575,11 +590,12 @@ static ssize_t timeleft_show(struct device *dev, struct device_attribute *attr, mutex_unlock(&wd_data->lock); if (!status) status = sprintf(buf, "%u\n", - watchdog_timeout_toexternal(wdd, false, val)); + conv_time_to_attr_display(wdd, attr, val)); return status; } static DEVICE_ATTR_RO(timeleft); +static DEVICE_ATTR(timeleft_ms, 0444, timeleft_show, NULL); static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -587,9 +603,10 @@ static ssize_t timeout_show(struct device *dev, struct device_attribute *attr, struct watchdog_device *wdd = dev_get_drvdata(dev); return sprintf(buf, "%u\n", - watchdog_timeout_toexternal(wdd, false, wdd->timeout)); + conv_time_to_attr_display(wdd, attr, wdd->timeout)); } static DEVICE_ATTR_RO(timeout); +static DEVICE_ATTR(timeout_ms, 0444, timeout_show, NULL); static ssize_t pretimeout_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -597,10 +614,10 @@ static ssize_t pretimeout_show(struct device *dev, struct watchdog_device *wdd = dev_get_drvdata(dev); return sprintf(buf, "%u\n", - watchdog_timeout_toexternal(wdd, false, - wdd->pretimeout)); + conv_time_to_attr_display(wdd, attr, wdd->pretimeout)); } static DEVICE_ATTR_RO(pretimeout); +static DEVICE_ATTR(pretimeout_ms, 0444, pretimeout_show, NULL); static ssize_t identity_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -677,8 +694,11 @@ static struct attribute *wdt_attrs[] = { &dev_attr_state.attr, &dev_attr_identity.attr, &dev_attr_timeout.attr, + &dev_attr_timeout_ms.attr, &dev_attr_pretimeout.attr, + &dev_attr_pretimeout_ms.attr, &dev_attr_timeleft.attr, + &dev_attr_timeleft_ms.attr, &dev_attr_bootstatus.attr, &dev_attr_status.attr, &dev_attr_nowayout.attr, From patchwork Sat Jun 20 17:33:49 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Corey Minyard X-Patchwork-Id: 215012 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-9.6 required=3.0 tests=DKIM_INVALID,DKIM_SIGNED, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_PATCH, MAILING_LIST_MULTI, SIGNED_OFF_BY, SPF_HELO_NONE, SPF_PASS, USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8E558C433E4 for ; Sat, 20 Jun 2020 17:35:08 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 68CBC2405C for ; Sat, 20 Jun 2020 17:35:08 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=fail reason="signature verification failed" (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="gEb7CAlA" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728355AbgFTRfH (ORCPT ); Sat, 20 Jun 2020 13:35:07 -0400 Received: from mail-oi1-f194.google.com ([209.85.167.194]:46804 "EHLO mail-oi1-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728191AbgFTRfG (ORCPT ); Sat, 20 Jun 2020 13:35:06 -0400 Received: by mail-oi1-f194.google.com with SMTP id 25so11545623oiy.13 for ; Sat, 20 Jun 2020 10:35:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=hz8GqE3JxF+NFjEiQfFD110wPSsNpDnROS/GHJzNG6w=; b=gEb7CAlAMt8j5b2PDqsBqbi4s2llZ0Cjca7ToGkekUhyLRRNIPwiTKTRLTVB7RZgaQ YRaAIJhiYqe8uJyxBD+qeP2vjW+vzvo/AHv8mNVvF6ImYxx3pQTyvOA9iPeTU/MPZB4W bLesGENar78NZLmleSheB/atz/d5nfS+cGzTV8C3TOtrwq7GNOHRJc4yF6o0Uxkw333f 3u6Mxk2B9G50FTRqa2dNTR3sa41QU3Tvhml65MAHggQeAWzcBtrafVzJ9GYXsF6b1Uho uwUGJWH+Y49QPF995bYwQsIWRZOO+nQIS3I9b6Er25cZeWsmw7lOzsh77Vyyn4SURTEr WFKw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:from:to:cc:subject:date:message-id :in-reply-to:references; bh=hz8GqE3JxF+NFjEiQfFD110wPSsNpDnROS/GHJzNG6w=; b=NtMUaROleW7c9CuVZqBVi3sW3Liz9ryrelHhJo3S7hzTQc6f5WSYnTxidSRq5mN+jN d52Whb2/f2Dm37t7k536ySD4zK9xWl9+lQk4vvxkWKrwQZ4V2aLJxzGRBZhBGgdffcua ybRvHecuTcevJxAMtsk2fNYH8u3iiXTKlYHyXtQBDxioQDyV2/IfDcZrOflCCuX/GtR9 qDo0lASZ5hioBZZTA8LWjimk+RFjiGp2qunj2mSb0vSFv1Su4ql6j6JCfHn5Ywu1e+tF vuiyxO39X1myxP5Y9Tvd7i6cpx2L3zUw0sbREOnDbedNLeRkK/ikPGTfP9tLTTZU9xzE nOHA== X-Gm-Message-State: AOAM532LPoAqOmCAK4yEVv3t5zBiYuLBXPcZOdcHL+07Kd5qIAL4BvWs 0tetZ4MnbjRUQxOkAJxQSw== X-Google-Smtp-Source: ABdhPJxGwM0r7OnhgY1rekJ7pKdQbFs5eU4T5HFVMVsaLm9lm0Xi1i2vtT8F47XPUnplqISCIzuE6w== X-Received: by 2002:aca:603:: with SMTP id 3mr6845193oig.89.1592674443946; Sat, 20 Jun 2020 10:34:03 -0700 (PDT) Received: from serve.minyard.net (serve.minyard.net. [2001:470:b8f6:1b::1]) by smtp.gmail.com with ESMTPSA id q85sm1994205oic.23.2020.06.20.10.34.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 20 Jun 2020 10:34:02 -0700 (PDT) Received: from t560.minyard.net (unknown [IPv6:2001:470:b8f6:1b:f17b:b355:b0a4:2592]) by serve.minyard.net (Postfix) with ESMTPA id A04A618054F; Sat, 20 Jun 2020 17:34:00 +0000 (UTC) From: minyard@acm.org To: Guenter Roeck , Wim Van Sebroeck Cc: linux-watchdog@vger.kernel.org, Gabriele Paoloni , Corey Minyard Subject: [PATCH 4/6] watchdog: Add documentation for millisecond interfaces Date: Sat, 20 Jun 2020 12:33:49 -0500 Message-Id: <20200620173351.18752-5-minyard@acm.org> X-Mailer: git-send-email 2.17.1 In-Reply-To: <20200620173351.18752-1-minyard@acm.org> References: <20200620173351.18752-1-minyard@acm.org> Sender: linux-watchdog-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-watchdog@vger.kernel.org From: Corey Minyard Document the new interfaces and semantics of how this works. Signed-off-by: Corey Minyard --- Documentation/watchdog/watchdog-api.rst | 59 +++++++++++++++++++ .../watchdog/watchdog-kernel-api.rst | 30 ++++++---- 2 files changed, 78 insertions(+), 11 deletions(-) diff --git a/Documentation/watchdog/watchdog-api.rst b/Documentation/watchdog/watchdog-api.rst index c6c1e9fa9f73..9f9aa1cd7310 100644 --- a/Documentation/watchdog/watchdog-api.rst +++ b/Documentation/watchdog/watchdog-api.rst @@ -112,6 +112,39 @@ current timeout using the GETTIMEOUT ioctl:: ioctl(fd, WDIOC_GETTIMEOUT, &timeout); printf("The timeout was is %d seconds\n", timeout); +There is also millisecond-level ioctls for setting timeouts in +millisecond values. These will work against a watchdog driver that +only supports seconds, but values will be truncated up on setting and +truncated on fetching. So, for instance: + + int timeout = 44001; + ioctl(fd, WDIOC_SETTIMEOUT_MS, &timeout); + printf("The timeout was set to %d milliseconds\n", timeout); + +If the driver only supports seconds, the timeout will be set to 45 +seconds because it's truncated up. + +Fetching does similar conversions. On a driver that supports +milliseconds, if the current value is 39603 milliseconds: + + ioctl(fd, WDIOC_GETTIMEOUT, &timeout); + printf("The timeout was is %d seconds\n", timeout); + ioctl(fd, WDIOC_GETTIMEOUT_MS, &timeout); + printf("The timeout was is %d milliseconds\n", timeout); + +will print 39 seconds and 39603 milliseconds. + +If a driver supports millisecond level precision, it will have the +WDIOF_MSECTIMER flag set in its option field. Note that does not mean +that the driver has millisecond level accuracy. For instance, a +device might have a 10Hz clock, giving 100ms accuracy. The driver +should set the return timeout for WDIOC_SETTIMEOUT_MS to the actual +setting of the timeout, so you can verify the value. + +It would be nice to have a granularity field, but some devices may not +be linear. So a granularity is not a general thing that could be +done. + Pretimeouts =========== @@ -137,6 +170,16 @@ There is also a get function for getting the pretimeout:: Not all watchdog drivers will support a pretimeout. +Like timeouts, pretimeouts also have millisecond-level ioctls: + + pretimeout = 10000; + ioctl(fd, WDIOC_SETPRETIMEOUT_MS, &pretimeout); + ioctl(fd, WDIOC_GETPRETIMEOUT_NS, &pretimeout); + printf("The pretimeout was is %d milliseconds\n", pretimeout); + +These work just like the timeouts, see that discussion for how +conversions are done. + Get the number of seconds before reboot ======================================= @@ -147,6 +190,14 @@ that returns the number of seconds before reboot:: ioctl(fd, WDIOC_GETTIMELEFT, &timeleft); printf("The timeout was is %d seconds\n", timeleft); +There is also a millisecond-level version: + + ioctl(fd, WDIOC_GETTIMELEFT_MS, &timeleft); + printf("The timeout was is %d milliseconds\n", timeleft); + +If the driver only supports seconds, then the value returns is just +1000 times the seconds value. + Environmental monitoring ======================== @@ -223,6 +274,14 @@ sense. The watchdog saw a keepalive ping since it was last queried. + =============== ======================================== + WDIOF_MSECTIMER Driver can use milliseconds for timeouts + =============== ======================================== + +The driver can do millisecond-level timeouts. The seconds-level +interfaces still work, but setting values in milliseconds can result +in finer granularity. + ================ ======================= WDIOF_SETTIMEOUT Can set/get the timeout ================ ======================= diff --git a/Documentation/watchdog/watchdog-kernel-api.rst b/Documentation/watchdog/watchdog-kernel-api.rst index 068a55ee0d4a..bee60e6ae274 100644 --- a/Documentation/watchdog/watchdog-kernel-api.rst +++ b/Documentation/watchdog/watchdog-kernel-api.rst @@ -80,13 +80,13 @@ It contains following fields: additional information about the watchdog timer itself. (Like it's unique name) * ops: a pointer to the list of watchdog operations that the watchdog supports. * gov: a pointer to the assigned watchdog device pretimeout governor or NULL. -* timeout: the watchdog timer's timeout value (in seconds). +* timeout: the watchdog timer's timeout value. This is the time after which the system will reboot if user space does not send a heartbeat request if WDOG_ACTIVE is set. -* pretimeout: the watchdog timer's pretimeout value (in seconds). -* min_timeout: the watchdog timer's minimum timeout value (in seconds). +* pretimeout: the watchdog timer's pretimeout value. +* min_timeout: the watchdog timer's minimum timeout value. If set, the minimum configurable value for 'timeout'. -* max_timeout: the watchdog timer's maximum timeout value (in seconds), +* max_timeout: the watchdog timer's maximum timeout value, as seen from userspace. If set, the maximum configurable value for 'timeout'. Not used if max_hw_heartbeat_ms is non-zero. * min_hw_heartbeat_ms: Hardware limit for minimum time between heartbeats, @@ -96,7 +96,7 @@ It contains following fields: If set, the infrastructure will send heartbeats to the watchdog driver if 'timeout' is larger than max_hw_heartbeat_ms, unless WDOG_ACTIVE is set and userspace failed to send a heartbeat for at least 'timeout' - seconds. max_hw_heartbeat_ms must be set if a driver does not implement + time. max_hw_heartbeat_ms must be set if a driver does not implement the stop function. * reboot_nb: notifier block that is registered for reboot notifications, for internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core @@ -117,6 +117,13 @@ It contains following fields: * deferred: entry in wtd_deferred_reg_list which is used to register early initialized watchdogs. +The time value used to interact with the device can either be in +seconds or milli-seconds except for min_hw_heartbeat_ms and +max_hw_heartbeat_ms, which are always in milli-seconds. If the driver +sets WDIOF_MSECTIMER in the driver info flags, then the time values +will be in milli-seconds. If it is not set, then the time values will +be in seconds. + The list of watchdog operations is defined as:: struct watchdog_ops { @@ -212,12 +219,13 @@ they are supported. These optional routines/operations are: also take care of checking if pretimeout is still valid and set up the timer accordingly. This can't be done in the core without races, so it is the duty of the driver. -* set_pretimeout: this routine checks and changes the pretimeout value of - the watchdog. It is optional because not all watchdogs support pretimeout - notification. The timeout value is not an absolute time, but the number of - seconds before the actual timeout would happen. It returns 0 on success, - -EINVAL for "parameter out of range" and -EIO for "could not write value to - the watchdog". A value of 0 disables pretimeout notification. +* set_pretimeout: this routine checks and changes the pretimeout value + of the watchdog. It is optional because not all watchdogs support + pretimeout notification. The timeout value is not an absolute time, + but the time before the actual timeout would happen. It returns 0 on + success, -EINVAL for "parameter out of range" and -EIO for "could + not write value to the watchdog". A value of 0 disables pretimeout + notification. (Note: the WDIOF_PRETIMEOUT needs to be set in the options field of the watchdog's info structure).