Hi Guenter,

Great thanks for your feedback, will fix them ASAP.
Some feedback and comment inline below :



On 4 May 2015 at 21:42, Guenter Roeck <linux@roeck-us.net> wrote:
On 05/04/2015 05:04 AM, fu.wei@linaro.org wrote:
From: Fu Wei <fu.wei@linaro.org>

Signed-off-by: Fu Wei <fu.wei@linaro.org>

Please fix the subject.

Also, "checkpatch --strict" reports

total: 2 errors, 9 warnings, 20 checks, 700 lines checked

which is a bit on the high side for an explicit review.
Please run it yourself and fix what it reports.

Sorry, I should do that before I sent it, you won't see those in my next version
 

Some more comments inline.

Thanks,
Guenter


---
  drivers/watchdog/Kconfig     |  10 +
  drivers/watchdog/Makefile    |   1 +
  drivers/watchdog/sbsa_gwdt.c | 578 +++++++++++++++++++++++++++++++++++++++++++
  drivers/watchdog/sbsa_gwdt.h |  99 ++++++++
  4 files changed, 688 insertions(+)
  create mode 100644 drivers/watchdog/sbsa_gwdt.c
  create mode 100644 drivers/watchdog/sbsa_gwdt.h

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index e5e7c55..46d6f46 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -152,6 +152,16 @@ config ARM_SP805_WATCHDOG
          ARM Primecell SP805 Watchdog timer. This will reboot your system when
          the timeout is reached.

+config ARM_SBSA_WATCHDOG
+       tristate "ARM SBSA Generic Watchdog"
+       depends on ARM64 && ARM_AMBA
+       select WATCHDOG_CORE
+       help
+         ARM SBSA Generic Watchdog timer. This has two Watchdog Signal(WS0/WS1),
+         will trigger a warnning interrupt(do panic) in the first timeout(WS0);
+         will reboot your system when the second timeout(WS1) is reached.
+         More details: DEN0029B - Server Base System Architecture (SBSA)
+
  config AT91RM9200_WATCHDOG
        tristate "AT91RM9200 watchdog"
        depends on SOC_AT91RM9200 && MFD_SYSCON
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 5c19294..471f1b7c 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -30,6 +30,7 @@ obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o

  # ARM Architecture
  obj-$(CONFIG_ARM_SP805_WATCHDOG) += sp805_wdt.o
+obj-$(CONFIG_ARM_SBSA_WATCHDOG) += sbsa_gwdt.o
  obj-$(CONFIG_AT91RM9200_WATCHDOG) += at91rm9200_wdt.o
  obj-$(CONFIG_AT91SAM9X_WATCHDOG) += at91sam9_wdt.o
  obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c
new file mode 100644
index 0000000..feee069
--- /dev/null
+++ b/drivers/watchdog/sbsa_gwdt.c
@@ -0,0 +1,578 @@
+/*
+ * SBSA(Server Base System Architecture) Generic Watchdog driver
+ *
+ * Copyright (c) 2015, Linaro Ltd.
+ * Author: Fu Wei <fu.wei@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * Note: This SBSA Generic watchdog driver is compatible with
+ *       the pretimeout concept of Linux kernel.
+ *       But timeout and pretimeout are set by the different REGs.
+ *       The first watch period is set by writing WCV directly,
+ *       that can support more than 10s timeout with the system counter
+ *       at 400MHz.
+ *       And the second watch period is set by WOR which will be loaded
+ *       automatically by hardware, when WS0 is triggered.
+ *       More details: DEN0029B - Server Base System Architecture (SBSA)
+ *
+ * Kernel/API:                         P---------| pretimeout
+ *               |-------------------------------T timeout
+ * SBSA GWDT:                          P--WOR---WS1 pretimeout
+ *               |-------WCV----------WS0~~~~~~~~T timeout
+ */
+
+#include <asm/arch_timer.h>
+
+#include <linux/acpi.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/watchdog.h>
+
+#include "sbsa_gwdt.h"
+
+/* For the second watch period,
+ * the timeout value comes from WOR(a 32bit wide. register).
+ * This gives a maximum watch period of around 10s
+ * at a maximum system counter frequency.
+ *
+ * The System Counter shall run at maximum of 400MHz.
+ * (Server Base System Architecture ARM-DEN-0029 Version 2.3)
+ */
+#define DEFAULT_TIMEOUT                15 /* seconds, the 1st + 2nd watch period*/
+#define DEFAULT_PRETIMEOUT     5 /* seconds, the 2nd watch period*/
+
+/*store the System Counter clock frequency, in Hz.*/
+static u32 sbsa_gwdt_rate;
+
+static unsigned int timeout = 0;
+module_param(timeout, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(timeout,
+       "Watchdog timeout in seconds. (>=0, default="
+       __MODULE_STRING(DEFAULT_TIMEOUT) ")");
+
+static unsigned int max_timeout = UINT_MAX;
+module_param(max_timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(max_timeout,
+       "Watchdog max timeout in seconds. (>=0, default="
+       __MODULE_STRING(UINT_MAX) ")");
+
+static unsigned int pretimeout = 0;
+module_param(pretimeout, uint, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(pretimeout,
+       "Watchdog pretimeout in seconds. (>=0, default="
+       __MODULE_STRING(DEFAULT_PRETIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, S_IRUGO);
+MODULE_PARM_DESC(nowayout,
+       "Watchdog cannot be stopped once started (default="
+       __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+/*
+ * Architected system timer support.
+ */
+static void sbsa_gwdt_cf_write(unsigned int reg, u32 val,
+                               struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       writel_relaxed(val, device_data->control_base + reg);
+}
+
+static void sbsa_gwdt_rf_write(unsigned int reg, u32 val,
+                               struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       writel_relaxed(val, device_data->refresh_base + reg);
+}
+
+static u32 sbsa_gwdt_cf_read(unsigned int reg, struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       return readl_relaxed(device_data->control_base + reg);
+}
+
+static u32 sbsa_gwdt_rf_read(unsigned int reg, struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       return readl_relaxed(device_data->refresh_base + reg);
+}
+
+/*
+ * help founctions for accessing 64bit WCV register
+ * mutex_lock must be called prior to calling this function.
+ */
+static  u64 sbsa_gwdt_get_wcv(struct watchdog_device *wdd)
+{
+       u32 wcv_lo, wcv_hi;
+
+       wcv_lo = sbsa_gwdt_cf_read(SBSA_GWDT_WCV_LO, wdd);
+       wcv_hi = sbsa_gwdt_cf_read(SBSA_GWDT_WCV_HI, wdd);
+
+       return (((u64)wcv_hi << 32) | wcv_lo);
+}
+
+void  sbsa_gwdt_set_wcv(struct watchdog_device *wdd, u64 value)
+{
+       u32 wcv_lo, wcv_hi;
+       wcv_lo = (u32)(value & U32_MAX);
+       wcv_hi = (u32)((value >> 32) & U32_MAX);

Those typecasts are unnecessary.

will fix it , Thanks
 

+
+       sbsa_gwdt_cf_write(SBSA_GWDT_WCV_LO, wcv_lo, wdd);
+       sbsa_gwdt_cf_write(SBSA_GWDT_WCV_HI, wcv_hi, wdd);
+
+       if (sbsa_gwdt_get_wcv(wdd) != value)
+               pr_err("sbsa_gwdt: set wcv fail!\n");
+
A function which can have an error should return an error code, not void.

OK , will fix it ,Thanks :-)
 

+       return;
+}
+
+void  reload_timeout_to_wcv(struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       u64 cntvct, wcv;
+       /* refresh the wcv */
+       cntvct = arch_counter_get_cntvct();
+       wcv = cntvct + (wdd->timeout - gwdt->pretimeout) * sbsa_gwdt_rate;
+       sbsa_gwdt_set_wcv(wdd, wcv);
+
+       return;
+}
+/* Use the following function to set the limit of timeout
+ * after updating pretimeout */
+void  sbsa_gwdt_set_timeout_limits(struct sbsa_gwdt *gwdt)
+{
+       struct watchdog_device *wdd = &gwdt->wdd;
+       unsigned int first_period_max = (U64_MAX / sbsa_gwdt_rate);
+
+       wdd->min_timeout = gwdt->pretimeout + 1;
+       wdd->max_timeout = min((gwdt->pretimeout + first_period_max),

Please no unnecessary ( ).

yes, you are right , will fix it
 

+                               max_timeout);
+
+       return;
+}
+
+/* Use the following function to check if a pretimeout value is invalid */
+static inline bool watchdog_pretimeout_invalid(struct sbsa_gwdt *gwdt,
+                                           unsigned int t)
+{
+       return ((gwdt->max_pretimeout != 0) && (t > gwdt->max_pretimeout));

Please no unnecessary ( ).

yes, will fix it
 

+}
+
+static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
+                                unsigned int timeout)
+{
+       if (watchdog_timeout_invalid(wdd, timeout)) {
+               pr_err("sbsa_gwdt: timeout %d is out of range(%d~%d), unchanged\n",
+                       timeout, wdd->min_timeout, wdd->max_timeout);
+               return -EINVAL;
+       }

The watchdog core already checks if the timeout range is valid.
No need to check it again.

yes, sorry,  will delete this check here. :-)
 

+       wdd->timeout = timeout;
+       /* refresh the wcv */
+       reload_timeout_to_wcv(wdd);
+
+       return 0;
+}
+
+static int sbsa_gwdt_set_pretimeout(struct watchdog_device *wdd,
+                                    unsigned int pretimeout)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       u32 wor;
+
+       if (watchdog_pretimeout_invalid(gwdt, pretimeout)) {
+               pr_err("sbsa_gwdt: pretimeout %d is out of range(0~%d),skip\n",
+                       pretimeout, gwdt->max_pretimeout);
+               return -EINVAL;
+       }

Same here.

sorry, this is for pretimeout , it's different.
 


+       gwdt->pretimeout = pretimeout;
+       sbsa_gwdt_set_timeout_limits(gwdt);
+
+       /* refresh the WOR, that will cause an explicit watchdog refresh */
+       wor = pretimeout * sbsa_gwdt_rate;
+       sbsa_gwdt_cf_write(SBSA_GWDT_WOR, wor, wdd);
+
+       return 0;
+}
+
+static unsigned int sbsa_gwdt_get_timeleft(struct watchdog_device *wdd)
+{
+       u64 timeleft = sbsa_gwdt_get_wcv(wdd) - arch_counter_get_cntvct();
+
+       return (unsigned int)(timeleft / sbsa_gwdt_rate);
+}
+
+static int sbsa_gwdt_start(struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       u32 status;
+       int ret;
+
+       ret = sbsa_gwdt_set_timeout(wdd, wdd->timeout);
+       if (ret)
+               return ret;
+
+       mutex_lock(&device_data->lock);
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+       status |= SBSA_GWDT_WCS_EN;
+       /* writing WCS will cause an explicit watchdog refresh */
+       sbsa_gwdt_cf_write(SBSA_GWDT_WCS, status, wdd);
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+       mutex_unlock(&device_data->lock);
+
+       /* Check if the watchdog was enabled */
+       if (!(status & SBSA_GWDT_WCS_EN))
+               return -EACCES;
+
EACCES is "permission denied". This is not the case here.


+       return 0;
+}
+
+static int sbsa_gwdt_stop(struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       u32 status;
+
+       mutex_lock(&device_data->lock);
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+       status &= ~SBSA_GWDT_WCS_EN;
+       /* writing WCS will cause an explicit watchdog refresh */
+       sbsa_gwdt_cf_write(SBSA_GWDT_WCS, status, wdd);
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+       mutex_unlock(&device_data->lock);
+
+       /* Check if the watchdog was disabled */
+       if (status & SBSA_GWDT_WCS_EN)
+               return -EACCES;

Same as above.

For these two, maybe EPERM?
 


+
+       return 0;
+}
+
+static int sbsa_gwdt_keepalive(struct watchdog_device *wdd)
+{
+       struct sbsa_gwdt *gwdt = to_sbsa_gwdt(wdd);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+
+       mutex_lock(&device_data->lock);
+       /* Writing WRR for an explicit watchdog refresh
+        * You can write anyting(like 0xc0ffee)
+        */
+       sbsa_gwdt_rf_write(SBSA_GWDT_WRR, 0xc0ffee, wdd);
+       mutex_unlock(&device_data->lock);
+
+       reload_timeout_to_wcv(wdd);
+       return 0;
+}
+
+static long sbsa_gwdt_ioctl(struct watchdog_device *wdd, unsigned int cmd,
+                               unsigned long arg)
+{
+       struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
+       void __user *argp = (void __user *)arg;
+       int ret = -ENOIOCTLCMD;
+       unsigned int __user *p = argp;
+       unsigned int new_value;
+
+       /* FIXME: what else do we need here?? */
+       switch (cmd) {
+       case WDIOC_SETPRETIMEOUT:
+               if (get_user(new_value, p))
+                       return -EFAULT;
+               ret = sbsa_gwdt_set_pretimeout(wdd, new_value);
+               break;
+       case WDIOC_GETPRETIMEOUT:
+               ret = put_user(gwdt->pretimeout, (unsigned int __user *)arg);
+               break;
+       }
+
+       return ret;
+}
+
+static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id)
+{
+       struct sbsa_gwdt *gwdt = (struct sbsa_gwdt *)dev_id;
+       struct watchdog_device *wdd = &gwdt->wdd;
+       u32 status;
+       unsigned int left;
+
+       pr_debug("SBSA Watchdog: in %s\n", __func__);
+
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+
+       if (status & SBSA_GWDT_WCS_WS0) {
+               pr_crit("SBSA Watchdog WS0 is triggered\n");
+               left = sbsa_gwdt_get_timeleft(wdd);
+               pr_crit("please try to feed the dog in %ds!\n", left);
+
Pleae no unnecessary noise.


yes, will simplify it
 
Really, what do you expect the user to do here ? To be online,
watch the kernel log, and do something frantic ?

:-) , that is the legacy code from first version, should be delete or simplifed.
 

+               /* FIXME:anything we can do here? */
+               panic("SBSA Watchdog pre-timeout");

Isn't this a pretimeout ?

yes,  in kernel documentaion:
----------------------------------
Pretimeouts:

Some watchdog timers can be set to have a trigger go off before the
actual time they will reset the system.  This can be done with an NMI,
interrupt, or other mechanism.  This allows Linux to record useful
information (like panic information and kernel coredumps) before it
resets.
---------------------------------
So I think it makes sense to do a panic here,  and if the platform supprot kexec/kdump,
it will be trigger automatically

any suggestion?
 


+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct watchdog_info sbsa_gwdt_info = {
+       .identity       = "SBSA Generic Watchdog",
+       .options        = WDIOF_SETTIMEOUT |
+                       WDIOF_KEEPALIVEPING |
+                       WDIOF_MAGICCLOSE |
+                       WDIOF_PRETIMEOUT |
+                       WDIOF_CARDRESET,
+};
+
+static struct watchdog_ops sbsa_gwdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = sbsa_gwdt_start,
+       .stop           = sbsa_gwdt_stop,
+       .ping           = sbsa_gwdt_keepalive,
+       .set_timeout    = sbsa_gwdt_set_timeout,
+       .ioctl          = sbsa_gwdt_ioctl,
+       .get_timeleft   = sbsa_gwdt_get_timeleft,
+};
+
+
+static int sbsa_gwdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+
+       struct sbsa_gwdt *gwdt;
+       struct sbsa_gwdt_device_data *device_data;
+
+       struct watchdog_device *wdd;
+
+       struct resource *res;
+       void *rf_base, *cf_base;
+       int irq;
+       u32 status, flags;
+       u32 w_iidr, idr;
+
+       int ret = 0;
+
+       /*
+        * Try to determine the frequency from the cp15 interface
+        */
+       sbsa_gwdt_rate = arch_timer_get_cntfrq();
+       /* Check the system counter frequency. */
+       if (!sbsa_gwdt_rate)
+               dev_err(dev, "System Counter frequency not available\n");
+
+       gwdt = devm_kzalloc(dev, sizeof(*gwdt), GFP_KERNEL);
+       if (!gwdt)
+               return -ENOMEM;
+
+       wdd = &gwdt->wdd;
+       wdd->parent = dev;
+       device_data = &gwdt->device_data;
+       mutex_init(&device_data->lock);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "refresh_frame");
+       rf_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(rf_base))
+               return PTR_ERR(rf_base);
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                                          "control_frame");
+       cf_base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(rf_base))
+               return PTR_ERR(rf_base);
+
+       irq = platform_get_irq_byname(pdev, "ws0");
+       if (IS_ERR(irq)) {
+               dev_err(dev, "required ws0 interrupt missing\n");
+               return PTR_ERR(irq);
+       }
+
+       res = platform_get_resource_byname(pdev, IORESOURCE_IRQ, "ws0");
+       if (!res)
+               dev_warn(dev, "ws0 interrupt flags missing, ignore\n");
+       else
+               flags = res->flags;
+
Not really sure why you get ws0 twice. Why don't you just use
platform_get_resource_byname() and use it to get the irq number as well ?

yes, I did this before, but some suggestion said it is better to use platform_get_irq. so I am doing this way now
but we can discuss more about this , and will check it again
 
Sure, that may not for for devicetree based initialization, but then you
won't have flags available anyway, and always printing that warning
on devicetree based systems isn't very useful either.

yes, you are right, will fix it, or maybe pr_debug
 


+       device_data->refresh_base = rf_base;
+       device_data->control_base = cf_base;
+       device_data->irq = irq;
+       device_data->flags = flags;
+
+       ret = devm_request_irq(dev, irq, sbsa_gwdt_interrupt,
+                            IRQF_TIMER, pdev->name, gwdt);
+       if (ret) {
+               dev_err(dev, "unable to request IRQ %d, disabling device\n",
+                       irq);
+               return ret;
+       }
+
+       /* get device information from refresh/control frame */
+       w_iidr = sbsa_gwdt_rf_read(SBSA_GWDT_W_IIDR, &gwdt->wdd);
+       idr = sbsa_gwdt_rf_read(SBSA_GWDT_IDR, &gwdt->wdd);
+       dev_info(dev, "W_IIDR %x  IDR %x in RF.\n", w_iidr, idr);
+
+       /* update device information to device_data for future use*/
+       device_data->info.pid = SBSA_GWDT_W_IIDR_PID(w_iidr);
+       device_data->info.arch_ver = SBSA_GWDT_W_IIDR_ARCH_VER(w_iidr);
+       device_data->info.revision = SBSA_GWDT_W_IIDR_REV(w_iidr);
+       device_data->info.vid_bank = SBSA_GWDT_W_IIDR_VID_BANK(w_iidr);
+       device_data->info.vid = SBSA_GWDT_W_IIDR_VID(w_iidr);
+
+       wdd->info = &sbsa_gwdt_info;
+       wdd->ops = &sbsa_gwdt_ops;
+
+       watchdog_set_drvdata(wdd, gwdt);
+
+       status = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+
+       if (status & SBSA_GWDT_WCS_WS1) {
+               dev_warn(dev, "System was reseted by SBSA Watchdog, WCS %x\n",
+                        status);
+               wdd->bootstatus |= WDIOF_CARDRESET;
+               gwdt->wcv_dump = sbsa_gwdt_get_wcv(wdd);
+       }
+
+       watchdog_set_nowayout(wdd, nowayout);
+
+       gwdt->max_pretimeout = min((U32_MAX / sbsa_gwdt_rate),
+                                  (max_timeout - 1));

Please no unnecessary ( ).

yes, will fix it
 

+
+       if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+               u32 timeouts[2];
+               ret = of_property_read_u32_array(pdev->dev.of_node,
+                                                "timeout-sec", timeouts, 2);
+               if (ret && timeout && pretimeout) {
+                       timeout = timeouts[0];
+                       pretimeout = timeouts[1];
+               }
+       }
+       if ((!timeout) || (!pretimeout)) {

Please no unnecessary ( ).

yes, will fix it
 


+               dev_info(dev, "get timeouts from DT or param fail."
+                             "Use DEFAULT.\n");
+               timeout = DEFAULT_TIMEOUT;
+               pretimeout = DEFAULT_PRETIMEOUT;
+       }
+
+       sbsa_gwdt_set_pretimeout(wdd, pretimeout);
+       sbsa_gwdt_set_timeout(wdd, timeout);
+
+       platform_set_drvdata(pdev, gwdt);
+       ret = watchdog_register_device(wdd);
+       if (ret)
+               return ret;
+
+       /* Check if watchdog is already enabled */
+       if (status & SBSA_GWDT_WCS_EN) {
+               dev_warn(dev, "already enabled!\n");
+               sbsa_gwdt_keepalive(wdd);
+       }
+
+       dev_info(dev, "registered with %ds timeout, %ds pretimeout\n",
+                wdd->timeout, gwdt->pretimeout);
+
+       return 0;
+}
+
+static void sbsa_gwdt_shutdown(struct platform_device *pdev)
+{
+       struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
+
+       sbsa_gwdt_stop(&gwdt->wdd);
+}
+
+static int sbsa_gwdt_remove(struct platform_device *pdev)
+{
+       struct sbsa_gwdt *gwdt = platform_get_drvdata(pdev);
+       struct watchdog_device *wdd = &gwdt->wdd;
+       int ret = 0;
+
+       if (!nowayout)
+               ret = sbsa_gwdt_stop(wdd);
+       watchdog_unregister_device(wdd);
+
+       return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+/* Disable watchdog if it is active during suspend */
+static int sbsa_gwdt_suspend(struct device *dev)
+{
+       struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
+       struct sbsa_gwdt_device_data *device_data = &gwdt->device_data;
+       struct watchdog_device *wdd = &gwdt->wdd;
+
+       mutex_lock(&device_data->lock);
+       gwdt->pm_status_store = sbsa_gwdt_cf_read(SBSA_GWDT_WCS, wdd);
+       mutex_unlock(&device_data->lock);
+
+       if (gwdt->pm_status_store & SBSA_GWDT_WCS_EN)
+               return sbsa_gwdt_stop(wdd);
+
+       return 0;
+}
+
+/* Enable watchdog and configure it if necessary */
+static int sbsa_gwdt_resume(struct device *dev)
+{
+       struct sbsa_gwdt *gwdt = dev_get_drvdata(dev);
+       struct watchdog_device *wdd = &gwdt->wdd;
+
+       /*
+        * If watchdog was stopped before suspend be sure it gets disabled
+        * again, for the case BIOS has enabled it during resume
+        */
+       if (gwdt->pm_status_store & SBSA_GWDT_WCS_EN)
+               return sbsa_gwdt_start(wdd);
+       else
+               return sbsa_gwdt_stop(wdd);
+}
+#endif
+
+#if IS_BUILTIN(CONFIG_OF)
+static const struct of_device_id sbsa_gwdt_of_match[] = {
+       { .compatible = "arm,sbsa-gwdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, sbsa_gwdt_of_match);
+#endif
+
+static struct dev_pm_ops sbsa_gwdt_pm_ops = {
+       SET_SYSTEM_SLEEP_PM_OPS(sbsa_gwdt_suspend, sbsa_gwdt_resume)
+};
+
+static struct platform_driver sbsa_gwdt_driver = {
+       .driver = {
+               .name = "sbsa-gwdt",
+               .pm = &sbsa_gwdt_pm_ops,
+               .of_match_table = sbsa_gwdt_of_match,
+       },
+       .probe = sbsa_gwdt_probe,
+       .remove = sbsa_gwdt_remove,
+       .shutdown = sbsa_gwdt_shutdown,
+};
+
+module_platform_driver(sbsa_gwdt_driver);
+
+MODULE_DESCRIPTION("SBSA Generic Watchdog Driver");
+MODULE_AUTHOR("Fu Wei <fu.wei@linaro.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/sbsa_gwdt.h b/drivers/watchdog/sbsa_gwdt.h
new file mode 100644
index 0000000..5dc8ace
--- /dev/null
+++ b/drivers/watchdog/sbsa_gwdt.h
@@ -0,0 +1,99 @@
+/*
+ * SBSA(Server Base System Architecture) Generic Watchdog driver definitions
+ *
+ * Copyright (c) 2015, Linaro Ltd.
+ * Author: Fu Wei <fu.wei@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 2 as published
+ * by the Free Software Foundation.
+ */
+
+#ifndef _SBSA_GENERIC_WATCHDOG_H_
+#define _SBSA_GENERIC_WATCHDOG_H_
+
+/* SBSA Generic Watchdog register definitions */
+/* refresh frame */
+#define SBSA_GWDT_WRR                          (0x000)
+
+/* control frame */
+#define SBSA_GWDT_WCS                          (0x000)
+#define SBSA_GWDT_WOR                          (0x008)
+#define SBSA_GWDT_WCV_LO                       (0x010)
+#define SBSA_GWDT_WCV_HI                       (0x014)
+
+/* refresh/control frame */
+#define SBSA_GWDT_W_IIDR                       (0xfcc)
+#define SBSA_GWDT_IDR                          (0xfd0)

All those ( ) are unnecessary.

for this define, I hope we can keep () to prevent someone use these uncarefully in some case,
but it is also my habit to make define, will check it later
 


+
+/* Watchdog Control and Status Register */
+#define SBSA_GWDT_WCS_EN                       (1 << 0)
+#define SBSA_GWDT_WCS_WS0                      (1 << 1)
+#define SBSA_GWDT_WCS_WS1                      (1 << 2)
+
+/* Watchdog Interface Identification Register */
+#define SBSA_GWDT_W_IIDR_PID(x)                        ((x >> 20) & 0xfff)
+#define SBSA_GWDT_W_IIDR_ARCH_VER(x)           ((x >> 16) & 0xf)
+#define SBSA_GWDT_W_IIDR_REV(x)                        ((x >> 12) & 0xf)
+#define SBSA_GWDT_W_IIDR_IMPLEMENTER(x)                (x & 0xfff)
+#define SBSA_GWDT_W_IIDR_VID_BANK(x)           ((x >> 8) & 0xf)
+#define SBSA_GWDT_W_IIDR_VID(x)                        (x & 0x7f)
+
+/* Watchdog Identification Register */
+#define SBSA_GWDT_IDR_W_PIDR2                  (0xfe8)
+#define SBSA_GWDT_IDR_W_PIDR2_ARCH_VER(x)      ((x >> 4) & 0xf)
+
+/**
+ * struct sbsa_gwdt_info - SBSA Generic Watchdog device hardware information
+ * @pid:       GWDT ProductID
+ * @arch_ver:  GWDT architecture version
+ * @revision:  GWDT revision number
+ * @vid_bank:  GWDT The JEP106 continuation code of the implementer
+ * @vid:       GWDT The JEP106 identity code of the implementer
+ * @refresh_pa: the watchdog refresh frame(PA)
+ * @control_pa: the watchdog control frame(PA)
+ */
+struct sbsa_gwdt_info {
+       unsigned int    pid;
+       unsigned int    arch_ver;
+       unsigned int    revision;
+       unsigned int    vid_bank;
+       unsigned int    vid;
+       void            *refresh_pa;
+       void            *control_pa;
+};
+
+/**
+ * struct sbsa_gwdt_device_data - Internal representation of the SBSA GWDT
+ * @refresh_base:      VA of the watchdog refresh frame
+ * @control_base:      VA of the watchdog control frame
+ * @irq:               Watchdog Timer GSIV (WS0)
+ * @flags:             Watchdog Timer Flags
+ * @dev:               Pointer to kernel device structure
+ * @info:              SBSA Generic Watchdog info structure
+ * @lock:              GWDT mutex
+ */
+struct sbsa_gwdt_device_data {
+       void __iomem            *refresh_base;
+       void __iomem            *control_base;
+       int                     irq;
+       u32                     flags;
+       struct device           *dev;
+       struct sbsa_gwdt_info   info;
+       struct mutex            lock;
+};
+
+struct sbsa_gwdt {
+       struct sbsa_gwdt_device_data    device_data;
+       struct watchdog_device          wdd;
+       unsigned int                    pretimeout; /* seconds */
+       unsigned int                    max_pretimeout;
+       u64                             wcv_dump;
+#ifdef CONFIG_PM_SLEEP
+       u8                              pm_status_store;
+#endif
+};
+
+#define to_sbsa_gwdt(e) container_of(e, struct sbsa_gwdt, wdd)
+
+#endif /* _SBSA_GENERIC_WATCHDOG_H_ */





--
Best regards,

Fu Wei
Software Engineer
Red Hat Software (Beijing) Co.,Ltd.Shanghai Branch
Ph: +86 21 61221326(direct)
Ph: +86 186 2020 4684 (mobile)
Room 1512, Regus One Corporate Avenue,Level 15,
One Corporate Avenue,222 Hubin Road,Huangpu District,
Shanghai,China 200021