From patchwork Fri May 15 11:24:48 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Fu Wei Fu X-Patchwork-Id: 48561 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f199.google.com (mail-wi0-f199.google.com [209.85.212.199]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id D267D2121F for ; Fri, 15 May 2015 11:25:50 +0000 (UTC) Received: by wizk4 with SMTP id k4sf33363584wiz.2 for ; Fri, 15 May 2015 04:25:50 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=nvtVo0JHqpv3UCVPSO2b+Fd9aSIXqQf/39XwCdJKKxc=; b=bn+EgJ05VJhxt0Bl1cBlUIDnCfpOXNXFfjlWIJ3xIN6fSOm7IQbo5X+9n8XKoNl4HC FXg8vzJ766weBZZVC/FP6IcMNLqOM2gg3bbbd39Q1lJFn3Y9X+rw2B3HbcmpIGtfmnqS 0LF493XLfGZNLxPtSTcYS2L1wLi45Izh36f+No9b/PemxPo2kB88flMQWYiv5seNk1zv RkXuIE2CQ5yzHqwwdl6AaDdI4sif1ht8LG5CAFb6bjd5FW5elJ5Y3zzPVOi7BNzH5JCl 1YYfByNtEmmiilARbnmEAhGLBqb/iJrseIk2rUtZzCkOtIQQBb97Gsb6afPA+lO+z2Nb uVYw== X-Gm-Message-State: ALoCoQkD1MzVjy+7myIjoAi4JHczraRVoWNhSoY/zRzG2o8m6i3gV8k/v7ccFAmaQYrb0JHyWsx3 X-Received: by 10.112.189.131 with SMTP id gi3mr6673536lbc.6.1431689149935; Fri, 15 May 2015 04:25:49 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.152.8.114 with SMTP id q18ls530143laa.8.gmail; Fri, 15 May 2015 04:25:49 -0700 (PDT) X-Received: by 10.112.185.100 with SMTP id fb4mr6858091lbc.79.1431689149640; Fri, 15 May 2015 04:25:49 -0700 (PDT) Received: from mail-la0-f49.google.com (mail-la0-f49.google.com. [209.85.215.49]) by mx.google.com with ESMTPS id v6si879990lav.62.2015.05.15.04.25.49 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 15 May 2015 04:25:49 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) client-ip=209.85.215.49; Received: by lagr1 with SMTP id r1so33016996lag.0 for ; Fri, 15 May 2015 04:25:49 -0700 (PDT) X-Received: by 10.112.13.6 with SMTP id d6mr6661447lbc.117.1431689149457; Fri, 15 May 2015 04:25:49 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.112.108.230 with SMTP id hn6csp1952920lbb; Fri, 15 May 2015 04:25:48 -0700 (PDT) X-Received: by 10.70.93.69 with SMTP id cs5mr17258367pdb.165.1431689147452; Fri, 15 May 2015 04:25:47 -0700 (PDT) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 11si2185142pda.42.2015.05.15.04.25.46; Fri, 15 May 2015 04:25:47 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of devicetree-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933562AbbEOLZp (ORCPT + 7 others); Fri, 15 May 2015 07:25:45 -0400 Received: from mail-pd0-f171.google.com ([209.85.192.171]:36104 "EHLO mail-pd0-f171.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754359AbbEOLZn (ORCPT ); Fri, 15 May 2015 07:25:43 -0400 Received: by pdfh10 with SMTP id h10so10273631pdf.3 for ; Fri, 15 May 2015 04:25:43 -0700 (PDT) X-Received: by 10.67.3.3 with SMTP id bs3mr17419842pad.51.1431689143131; Fri, 15 May 2015 04:25:43 -0700 (PDT) Received: from localhost.localdomain (li400-65.members.linode.com. [106.187.50.65]) by mx.google.com with ESMTPSA id pp6sm1614811pbb.17.2015.05.15.04.25.33 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 15 May 2015 04:25:42 -0700 (PDT) From: fu.wei@linaro.org To: Suravee.Suthikulpanit@amd.com, linaro-acpi@lists.linaro.org, linux-watchdog@vger.kernel.org, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org Cc: tekkamanninja@gmail.com, graeme.gregory@linaro.org, al.stone@linaro.org, hanjun.guo@linaro.org, timur@codeaurora.org, ashwin.chaugule@linaro.org, arnd@arndb.de, linux@roeck-us.net, vgandhi@codeaurora.org, wim@iguana.be, jcm@redhat.com, leo.duran@amd.com, corbet@lwn.net, Fu Wei Subject: [PATCH 4/6] Watchdog: introdouce "pretimeout" into framework Date: Fri, 15 May 2015 19:24:48 +0800 Message-Id: <1431689090-3125-1-git-send-email-fu.wei@linaro.org> X-Mailer: git-send-email 1.9.1 In-Reply-To: <=fu.wei@linaro.org> References: <=fu.wei@linaro.org> Sender: devicetree-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: devicetree@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: fu.wei@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.49 as permitted sender) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Fu Wei Reasons: (1)kernel already has two watchdog drivers are using "pretimeout": drivers/char/ipmi/ipmi_watchdog.c drivers/watchdog/kempld_wdt.c(but the definition is different) (2)some other dirvers are going to use this: ARM SBSA Generic Watchdog Signed-off-by: Fu Wei --- drivers/watchdog/watchdog_core.c | 66 ++++++++++++++++++++++++++++++++++++++++ drivers/watchdog/watchdog_dev.c | 48 +++++++++++++++++++++++++++++ include/linux/watchdog.h | 19 ++++++++++++ 3 files changed, 133 insertions(+) diff --git a/drivers/watchdog/watchdog_core.c b/drivers/watchdog/watchdog_core.c index cec9b55..6ca9578 100644 --- a/drivers/watchdog/watchdog_core.c +++ b/drivers/watchdog/watchdog_core.c @@ -54,6 +54,14 @@ static void watchdog_check_min_max_timeout(struct watchdog_device *wdd) wdd->min_timeout = 0; wdd->max_timeout = 0; } + if (wdd->min_pretimeout && wdd->min_timeout < wdd->min_pretimeout) { + pr_info("Invalid min timeout, resetting to min pretimeout!\n"); + wdd->min_timeout = wdd->min_pretimeout; + } + if (wdd->max_pretimeout && wdd->max_timeout < wdd->max_pretimeout) { + pr_info("Invalid max timeout, resetting to max pretimeout!\n"); + wdd->max_timeout = wdd->max_pretimeout; + } } /** @@ -98,6 +106,63 @@ int watchdog_init_timeout(struct watchdog_device *wdd, } EXPORT_SYMBOL_GPL(watchdog_init_timeout); +static void watchdog_check_min_max_pretimeout(struct watchdog_device *wdd) +{ + /* + * Check that we have valid min and max pretimeout values, if + * not reset them both to 0 (=not used or unknown) + */ + if (wdd->min_pretimeout > wdd->max_pretimeout) { + pr_info("Invalid min and max pretimeout, resetting to 0!\n"); + wdd->min_pretimeout = 0; + wdd->max_pretimeout = 0; + } +} + +/** + * watchdog_init_pretimeout() - initialize the pretimeout field + * @pretimeout_parm: pretimeout module parameter + * @dev: Device that stores the timeout-sec property + * + * Initialize the pretimeout field of the watchdog_device struct with either + * the pretimeout module parameter (if it is valid value) or the timeout-sec + * property (only if it is a valid value and the timeout_parm is out of bounds). + * If none of them are valid then we keep the old value (which should normally + * be the default pretimeout value. + * + * A zero is returned on success and -EINVAL for failure. + */ +int watchdog_init_pretimeout(struct watchdog_device *wdd, + unsigned int pretimeout_parm, struct device *dev) +{ + int ret = 0; + u32 timeouts[2]; + + watchdog_check_min_max_pretimeout(wdd); + + /* try to get the timeout module parameter first */ + if (!watchdog_pretimeout_invalid(wdd, pretimeout_parm) && + pretimeout_parm) { + wdd->pretimeout = pretimeout_parm; + return ret; + } + if (pretimeout_parm) + ret = -EINVAL; + + /* try to get the timeout_sec property */ + if (!dev || !dev->of_node) + return ret; + ret = of_property_read_u32_array(dev->of_node, + "timeout-sec", timeouts, 2); + if (!watchdog_pretimeout_invalid(wdd, timeouts[1]) && timeouts[1]) + wdd->pretimeout = timeouts[1]; + else + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL_GPL(watchdog_init_pretimeout); + /** * watchdog_register_device() - register a watchdog device * @wdd: watchdog device @@ -119,6 +184,7 @@ int watchdog_register_device(struct watchdog_device *wdd) if (wdd->ops->start == NULL || wdd->ops->stop == NULL) return -EINVAL; + watchdog_check_min_max_pretimeout(wdd); watchdog_check_min_max_timeout(wdd); /* diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 6aaefba..b519257 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c @@ -218,6 +218,38 @@ out_timeout: } /* + * watchdog_set_pretimeout: set the watchdog timer pretimeout + * @wddev: the watchdog device to set the timeout for + * @pretimeout: pretimeout to set in seconds + */ + +static int watchdog_set_pretimeout(struct watchdog_device *wddev, + unsigned int pretimeout) +{ + int err; + + if (!wddev->ops->set_pretimeout || + !(wddev->info->options & WDIOF_PRETIMEOUT)) + return -EOPNOTSUPP; + + if (watchdog_pretimeout_invalid(wddev, pretimeout)) + return -EINVAL; + + mutex_lock(&wddev->lock); + + if (test_bit(WDOG_UNREGISTERED, &wddev->status)) { + err = -ENODEV; + goto out_pretimeout; + } + + err = wddev->ops->set_pretimeout(wddev, pretimeout); + +out_pretimeout: + mutex_unlock(&wddev->lock); + return err; +} + +/* * watchdog_get_timeleft: wrapper to get the time left before a reboot * @wddev: the watchdog device to get the remaining time from * @timeleft: the time that's left @@ -388,6 +420,22 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, if (wdd->timeout == 0) return -EOPNOTSUPP; return put_user(wdd->timeout, p); + case WDIOC_SETPRETIMEOUT: + if (get_user(val, p)) + return -EFAULT; + err = watchdog_set_pretimeout(wdd, val); + if (err < 0) + return err; + /* If the watchdog is active then we send a keepalive ping + * to make sure that the watchdog keep's running (and if + * possible that it takes the new timeout) */ + watchdog_ping(wdd); + /* Fall */ + case WDIOC_GETPRETIMEOUT: + /* timeout == 0 means that we don't use the pretimeout */ + if (wdd->pretimeout == 0) + return -EOPNOTSUPP; + return put_user(wdd->pretimeout, p); case WDIOC_GETTIMELEFT: err = watchdog_get_timeleft(wdd, &val); if (err) diff --git a/include/linux/watchdog.h b/include/linux/watchdog.h index a746bf5..f0a3c5b 100644 --- a/include/linux/watchdog.h +++ b/include/linux/watchdog.h @@ -25,6 +25,7 @@ struct watchdog_device; * @ping: The routine that sends a keepalive ping to the watchdog device. * @status: The routine that shows the status of the watchdog device. * @set_timeout:The routine for setting the watchdog devices timeout value. + * @set_pretimeout:The routine for setting the watchdog devices pretimeout value * @get_timeleft:The routine that get's the time that's left before a reset. * @ref: The ref operation for dyn. allocated watchdog_device structs * @unref: The unref operation for dyn. allocated watchdog_device structs @@ -44,6 +45,7 @@ struct watchdog_ops { int (*ping)(struct watchdog_device *); unsigned int (*status)(struct watchdog_device *); int (*set_timeout)(struct watchdog_device *, unsigned int); + int (*set_pretimeout)(struct watchdog_device *, unsigned int); unsigned int (*get_timeleft)(struct watchdog_device *); void (*ref)(struct watchdog_device *); void (*unref)(struct watchdog_device *); @@ -62,6 +64,9 @@ struct watchdog_ops { * @timeout: The watchdog devices timeout value. * @min_timeout:The watchdog devices minimum timeout value. * @max_timeout:The watchdog devices maximum timeout value. + * @pretimeout: The watchdog devices pretimeout value. + * @min_pretimeout:The watchdog devices minimum pretimeout value. + * @max_pretimeout:The watchdog devices maximum pretimeout value. * @driver-data:Pointer to the drivers private data. * @lock: Lock for watchdog core internal use only. * @status: Field that contains the devices internal status bits. @@ -86,6 +91,9 @@ struct watchdog_device { unsigned int timeout; unsigned int min_timeout; unsigned int max_timeout; + unsigned int pretimeout; + unsigned int min_pretimeout; + unsigned int max_pretimeout; void *driver_data; struct mutex lock; unsigned long status; @@ -120,6 +128,14 @@ static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigne (t < wdd->min_timeout || t > wdd->max_timeout)); } +/* Use the following function to check if a pretimeout value is invalid */ +static inline bool watchdog_pretimeout_invalid(struct watchdog_device *wdd, + unsigned int t) +{ + return ((wdd->max_pretimeout != 0) && + (t < wdd->min_pretimeout || t > wdd->max_pretimeout)); +} + /* Use the following functions to manipulate watchdog driver specific data */ static inline void watchdog_set_drvdata(struct watchdog_device *wdd, void *data) { @@ -134,6 +150,9 @@ static inline void *watchdog_get_drvdata(struct watchdog_device *wdd) /* drivers/watchdog/watchdog_core.c */ extern int watchdog_init_timeout(struct watchdog_device *wdd, unsigned int timeout_parm, struct device *dev); +extern int watchdog_init_pretimeout(struct watchdog_device *wdd, + unsigned int pretimeout_parm, + struct device *dev); extern int watchdog_register_device(struct watchdog_device *); extern void watchdog_unregister_device(struct watchdog_device *);