linux/drivers/watchdog/shwdt.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * drivers/watchdog/shwdt.c
   4 *
   5 * Watchdog driver for integrated watchdog in the SuperH processors.
   6 *
   7 * Copyright (C) 2001 - 2012  Paul Mundt <lethal@linux-sh.org>
   8 *
   9 * 14-Dec-2001 Matt Domsch <Matt_Domsch@dell.com>
  10 *     Added nowayout module option to override CONFIG_WATCHDOG_NOWAYOUT
  11 *
  12 * 19-Apr-2002 Rob Radez <rob@osinvestor.com>
  13 *     Added expect close support, made emulated timeout runtime changeable
  14 *     general cleanups, add some ioctls
  15 */
  16
  17#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  18
  19#include <linux/module.h>
  20#include <linux/moduleparam.h>
  21#include <linux/platform_device.h>
  22#include <linux/init.h>
  23#include <linux/types.h>
  24#include <linux/spinlock.h>
  25#include <linux/watchdog.h>
  26#include <linux/pm_runtime.h>
  27#include <linux/fs.h>
  28#include <linux/mm.h>
  29#include <linux/slab.h>
  30#include <linux/io.h>
  31#include <linux/clk.h>
  32#include <linux/err.h>
  33#include <asm/watchdog.h>
  34
  35#define DRV_NAME "sh-wdt"
  36
  37/*
  38 * Default clock division ratio is 5.25 msecs. For an additional table of
  39 * values, consult the asm-sh/watchdog.h. Overload this at module load
  40 * time.
  41 *
  42 * In order for this to work reliably we need to have HZ set to 1000 or
  43 * something quite higher than 100 (or we need a proper high-res timer
  44 * implementation that will deal with this properly), otherwise the 10ms
  45 * resolution of a jiffy is enough to trigger the overflow. For things like
  46 * the SH-4 and SH-5, this isn't necessarily that big of a problem, though
  47 * for the SH-2 and SH-3, this isn't recommended unless the WDT is absolutely
  48 * necssary.
  49 *
  50 * As a result of this timing problem, the only modes that are particularly
  51 * feasible are the 4096 and the 2048 divisors, which yield 5.25 and 2.62ms
  52 * overflow periods respectively.
  53 *
  54 * Also, since we can't really expect userspace to be responsive enough
  55 * before the overflow happens, we maintain two separate timers .. One in
  56 * the kernel for clearing out WOVF every 2ms or so (again, this depends on
  57 * HZ == 1000), and another for monitoring userspace writes to the WDT device.
  58 *
  59 * As such, we currently use a configurable heartbeat interval which defaults
  60 * to 30s. In this case, the userspace daemon is only responsible for periodic
  61 * writes to the device before the next heartbeat is scheduled. If the daemon
  62 * misses its deadline, the kernel timer will allow the WDT to overflow.
  63 */
  64static int clock_division_ratio = WTCSR_CKS_4096;
  65#define next_ping_period(cks)   (jiffies + msecs_to_jiffies(cks - 4))
  66
  67#define WATCHDOG_HEARTBEAT 30                   /* 30 sec default heartbeat */
  68static int heartbeat = WATCHDOG_HEARTBEAT;      /* in seconds */
  69static bool nowayout = WATCHDOG_NOWAYOUT;
  70static unsigned long next_heartbeat;
  71
  72struct sh_wdt {
  73        void __iomem            *base;
  74        struct device           *dev;
  75        struct clk              *clk;
  76        spinlock_t              lock;
  77
  78        struct timer_list       timer;
  79};
  80
  81static int sh_wdt_start(struct watchdog_device *wdt_dev)
  82{
  83        struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
  84        unsigned long flags;
  85        u8 csr;
  86
  87        pm_runtime_get_sync(wdt->dev);
  88        clk_enable(wdt->clk);
  89
  90        spin_lock_irqsave(&wdt->lock, flags);
  91
  92        next_heartbeat = jiffies + (heartbeat * HZ);
  93        mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
  94
  95        csr = sh_wdt_read_csr();
  96        csr |= WTCSR_WT | clock_division_ratio;
  97        sh_wdt_write_csr(csr);
  98
  99        sh_wdt_write_cnt(0);
 100
 101        /*
 102         * These processors have a bit of an inconsistent initialization
 103         * process.. starting with SH-3, RSTS was moved to WTCSR, and the
 104         * RSTCSR register was removed.
 105         *
 106         * On the SH-2 however, in addition with bits being in different
 107         * locations, we must deal with RSTCSR outright..
 108         */
 109        csr = sh_wdt_read_csr();
 110        csr |= WTCSR_TME;
 111        csr &= ~WTCSR_RSTS;
 112        sh_wdt_write_csr(csr);
 113
 114#ifdef CONFIG_CPU_SH2
 115        csr = sh_wdt_read_rstcsr();
 116        csr &= ~RSTCSR_RSTS;
 117        sh_wdt_write_rstcsr(csr);
 118#endif
 119        spin_unlock_irqrestore(&wdt->lock, flags);
 120
 121        return 0;
 122}
 123
 124static int sh_wdt_stop(struct watchdog_device *wdt_dev)
 125{
 126        struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 127        unsigned long flags;
 128        u8 csr;
 129
 130        spin_lock_irqsave(&wdt->lock, flags);
 131
 132        del_timer(&wdt->timer);
 133
 134        csr = sh_wdt_read_csr();
 135        csr &= ~WTCSR_TME;
 136        sh_wdt_write_csr(csr);
 137
 138        spin_unlock_irqrestore(&wdt->lock, flags);
 139
 140        clk_disable(wdt->clk);
 141        pm_runtime_put_sync(wdt->dev);
 142
 143        return 0;
 144}
 145
 146static int sh_wdt_keepalive(struct watchdog_device *wdt_dev)
 147{
 148        struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 149        unsigned long flags;
 150
 151        spin_lock_irqsave(&wdt->lock, flags);
 152        next_heartbeat = jiffies + (heartbeat * HZ);
 153        spin_unlock_irqrestore(&wdt->lock, flags);
 154
 155        return 0;
 156}
 157
 158static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t)
 159{
 160        struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev);
 161        unsigned long flags;
 162
 163        if (unlikely(t < 1 || t > 3600)) /* arbitrary upper limit */
 164                return -EINVAL;
 165
 166        spin_lock_irqsave(&wdt->lock, flags);
 167        heartbeat = t;
 168        wdt_dev->timeout = t;
 169        spin_unlock_irqrestore(&wdt->lock, flags);
 170
 171        return 0;
 172}
 173
 174static void sh_wdt_ping(struct timer_list *t)
 175{
 176        struct sh_wdt *wdt = from_timer(wdt, t, timer);
 177        unsigned long flags;
 178
 179        spin_lock_irqsave(&wdt->lock, flags);
 180        if (time_before(jiffies, next_heartbeat)) {
 181                u8 csr;
 182
 183                csr = sh_wdt_read_csr();
 184                csr &= ~WTCSR_IOVF;
 185                sh_wdt_write_csr(csr);
 186
 187                sh_wdt_write_cnt(0);
 188
 189                mod_timer(&wdt->timer, next_ping_period(clock_division_ratio));
 190        } else
 191                dev_warn(wdt->dev, "Heartbeat lost! Will not ping "
 192                         "the watchdog\n");
 193        spin_unlock_irqrestore(&wdt->lock, flags);
 194}
 195
 196static const struct watchdog_info sh_wdt_info = {
 197        .options                = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
 198                                  WDIOF_MAGICCLOSE,
 199        .firmware_version       = 1,
 200        .identity               = "SH WDT",
 201};
 202
 203static const struct watchdog_ops sh_wdt_ops = {
 204        .owner          = THIS_MODULE,
 205        .start          = sh_wdt_start,
 206        .stop           = sh_wdt_stop,
 207        .ping           = sh_wdt_keepalive,
 208        .set_timeout    = sh_wdt_set_heartbeat,
 209};
 210
 211static struct watchdog_device sh_wdt_dev = {
 212        .info   = &sh_wdt_info,
 213        .ops    = &sh_wdt_ops,
 214};
 215
 216static int sh_wdt_probe(struct platform_device *pdev)
 217{
 218        struct sh_wdt *wdt;
 219        int rc;
 220
 221        /*
 222         * As this driver only covers the global watchdog case, reject
 223         * any attempts to register per-CPU watchdogs.
 224         */
 225        if (pdev->id != -1)
 226                return -EINVAL;
 227
 228        wdt = devm_kzalloc(&pdev->dev, sizeof(struct sh_wdt), GFP_KERNEL);
 229        if (unlikely(!wdt))
 230                return -ENOMEM;
 231
 232        wdt->dev = &pdev->dev;
 233
 234        wdt->clk = devm_clk_get(&pdev->dev, NULL);
 235        if (IS_ERR(wdt->clk)) {
 236                /*
 237                 * Clock framework support is optional, continue on
 238                 * anyways if we don't find a matching clock.
 239                 */
 240                wdt->clk = NULL;
 241        }
 242
 243        wdt->base = devm_platform_ioremap_resource(pdev, 0);
 244        if (IS_ERR(wdt->base))
 245                return PTR_ERR(wdt->base);
 246
 247        watchdog_set_nowayout(&sh_wdt_dev, nowayout);
 248        watchdog_set_drvdata(&sh_wdt_dev, wdt);
 249        sh_wdt_dev.parent = &pdev->dev;
 250
 251        spin_lock_init(&wdt->lock);
 252
 253        rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat);
 254        if (unlikely(rc)) {
 255                /* Default timeout if invalid */
 256                sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT);
 257
 258                dev_warn(&pdev->dev,
 259                         "heartbeat value must be 1<=x<=3600, using %d\n",
 260                         sh_wdt_dev.timeout);
 261        }
 262
 263        dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n",
 264                 sh_wdt_dev.timeout, nowayout);
 265
 266        rc = watchdog_register_device(&sh_wdt_dev);
 267        if (unlikely(rc)) {
 268                dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc);
 269                return rc;
 270        }
 271
 272        timer_setup(&wdt->timer, sh_wdt_ping, 0);
 273        wdt->timer.expires      = next_ping_period(clock_division_ratio);
 274
 275        dev_info(&pdev->dev, "initialized.\n");
 276
 277        pm_runtime_enable(&pdev->dev);
 278
 279        return 0;
 280}
 281
 282static int sh_wdt_remove(struct platform_device *pdev)
 283{
 284        watchdog_unregister_device(&sh_wdt_dev);
 285
 286        pm_runtime_disable(&pdev->dev);
 287
 288        return 0;
 289}
 290
 291static void sh_wdt_shutdown(struct platform_device *pdev)
 292{
 293        sh_wdt_stop(&sh_wdt_dev);
 294}
 295
 296static struct platform_driver sh_wdt_driver = {
 297        .driver         = {
 298                .name   = DRV_NAME,
 299        },
 300
 301        .probe          = sh_wdt_probe,
 302        .remove         = sh_wdt_remove,
 303        .shutdown       = sh_wdt_shutdown,
 304};
 305
 306static int __init sh_wdt_init(void)
 307{
 308        if (unlikely(clock_division_ratio < 0x5 ||
 309                     clock_division_ratio > 0x7)) {
 310                clock_division_ratio = WTCSR_CKS_4096;
 311
 312                pr_info("divisor must be 0x5<=x<=0x7, using %d\n",
 313                        clock_division_ratio);
 314        }
 315
 316        return platform_driver_register(&sh_wdt_driver);
 317}
 318
 319static void __exit sh_wdt_exit(void)
 320{
 321        platform_driver_unregister(&sh_wdt_driver);
 322}
 323module_init(sh_wdt_init);
 324module_exit(sh_wdt_exit);
 325
 326MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
 327MODULE_DESCRIPTION("SuperH watchdog driver");
 328MODULE_LICENSE("GPL");
 329MODULE_ALIAS("platform:" DRV_NAME);
 330
 331module_param(clock_division_ratio, int, 0);
 332MODULE_PARM_DESC(clock_division_ratio,
 333        "Clock division ratio. Valid ranges are from 0x5 (1.31ms) "
 334        "to 0x7 (5.25ms). (default=" __MODULE_STRING(WTCSR_CKS_4096) ")");
 335
 336module_param(heartbeat, int, 0);
 337MODULE_PARM_DESC(heartbeat,
 338        "Watchdog heartbeat in seconds. (1 <= heartbeat <= 3600, default="
 339                                __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 340
 341module_param(nowayout, bool, 0);
 342MODULE_PARM_DESC(nowayout,
 343        "Watchdog cannot be stopped once started (default="
 344                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 345