linux/drivers/watchdog/bcm47xx_wdt.c
<<
>>
Prefs
   1/*
   2 *  Watchdog driver for Broadcom BCM47XX
   3 *
   4 *  Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs>
   5 *  Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr>
   6 *  Copyright (C) 2012-2013 Hauke Mehrtens <hauke@hauke-m.de>
   7 *
   8 *  This program is free software; you can redistribute it and/or
   9 *  modify it under the terms of the GNU General Public License
  10 *  as published by the Free Software Foundation; either version
  11 *  2 of the License, or (at your option) any later version.
  12 */
  13
  14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  15
  16#include <linux/bcm47xx_wdt.h>
  17#include <linux/bitops.h>
  18#include <linux/errno.h>
  19#include <linux/init.h>
  20#include <linux/kernel.h>
  21#include <linux/module.h>
  22#include <linux/moduleparam.h>
  23#include <linux/platform_device.h>
  24#include <linux/reboot.h>
  25#include <linux/types.h>
  26#include <linux/watchdog.h>
  27#include <linux/timer.h>
  28#include <linux/jiffies.h>
  29
  30#define DRV_NAME                "bcm47xx_wdt"
  31
  32#define WDT_DEFAULT_TIME        30      /* seconds */
  33#define WDT_SOFTTIMER_MAX       255     /* seconds */
  34#define WDT_SOFTTIMER_THRESHOLD 60      /* seconds */
  35
  36static int timeout = WDT_DEFAULT_TIME;
  37static bool nowayout = WATCHDOG_NOWAYOUT;
  38
  39module_param(timeout, int, 0);
  40MODULE_PARM_DESC(timeout, "Watchdog time in seconds. (default="
  41                                __MODULE_STRING(WDT_DEFAULT_TIME) ")");
  42
  43module_param(nowayout, bool, 0);
  44MODULE_PARM_DESC(nowayout,
  45                "Watchdog cannot be stopped once started (default="
  46                                __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  47
  48static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd)
  49{
  50        return container_of(wdd, struct bcm47xx_wdt, wdd);
  51}
  52
  53static int bcm47xx_wdt_hard_keepalive(struct watchdog_device *wdd)
  54{
  55        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
  56
  57        wdt->timer_set_ms(wdt, wdd->timeout * 1000);
  58
  59        return 0;
  60}
  61
  62static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd)
  63{
  64        return 0;
  65}
  66
  67static int bcm47xx_wdt_hard_stop(struct watchdog_device *wdd)
  68{
  69        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
  70
  71        wdt->timer_set(wdt, 0);
  72
  73        return 0;
  74}
  75
  76static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
  77                                        unsigned int new_time)
  78{
  79        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
  80        u32 max_timer = wdt->max_timer_ms;
  81
  82        if (new_time < 1 || new_time > max_timer / 1000) {
  83                pr_warn("timeout value must be 1<=x<=%d, using %d\n",
  84                        max_timer / 1000, new_time);
  85                return -EINVAL;
  86        }
  87
  88        wdd->timeout = new_time;
  89        return 0;
  90}
  91
  92static struct watchdog_ops bcm47xx_wdt_hard_ops = {
  93        .owner          = THIS_MODULE,
  94        .start          = bcm47xx_wdt_hard_start,
  95        .stop           = bcm47xx_wdt_hard_stop,
  96        .ping           = bcm47xx_wdt_hard_keepalive,
  97        .set_timeout    = bcm47xx_wdt_hard_set_timeout,
  98};
  99
 100static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
 101{
 102        struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
 103        u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms);
 104
 105        if (!atomic_dec_and_test(&wdt->soft_ticks)) {
 106                wdt->timer_set_ms(wdt, next_tick);
 107                mod_timer(&wdt->soft_timer, jiffies + HZ);
 108        } else {
 109                pr_crit("Watchdog will fire soon!!!\n");
 110        }
 111}
 112
 113static int bcm47xx_wdt_soft_keepalive(struct watchdog_device *wdd)
 114{
 115        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
 116
 117        atomic_set(&wdt->soft_ticks, wdd->timeout);
 118
 119        return 0;
 120}
 121
 122static int bcm47xx_wdt_soft_start(struct watchdog_device *wdd)
 123{
 124        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
 125
 126        bcm47xx_wdt_soft_keepalive(wdd);
 127        bcm47xx_wdt_soft_timer_tick((unsigned long)wdt);
 128
 129        return 0;
 130}
 131
 132static int bcm47xx_wdt_soft_stop(struct watchdog_device *wdd)
 133{
 134        struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
 135
 136        del_timer_sync(&wdt->soft_timer);
 137        wdt->timer_set(wdt, 0);
 138
 139        return 0;
 140}
 141
 142static int bcm47xx_wdt_soft_set_timeout(struct watchdog_device *wdd,
 143                                        unsigned int new_time)
 144{
 145        if (new_time < 1 || new_time > WDT_SOFTTIMER_MAX) {
 146                pr_warn("timeout value must be 1<=x<=%d, using %d\n",
 147                        WDT_SOFTTIMER_MAX, new_time);
 148                return -EINVAL;
 149        }
 150
 151        wdd->timeout = new_time;
 152        return 0;
 153}
 154
 155static const struct watchdog_info bcm47xx_wdt_info = {
 156        .identity       = DRV_NAME,
 157        .options        = WDIOF_SETTIMEOUT |
sscode=timeout" class="sre2rs/watchdog/bcn0EPALIVEPSTRING" class="sredog/bcn0EPALIVEPSTROUT |
bcm47xx_wnotify_sy_out(struct  *bcm47xx_wdt *wdt  66
wdt<    = container_of(bcm47xx_wdt, wdt->wdd.stop(&wdt->wdd);
watchdog_ops bcm47xx_wdt_sord_nfo = {
owner          = THIS_MODULE,
start          = bcm47xx_wdt_soft_start,
stop           = bcm47xx_wdt_soft_stop,
        .ping           = bcm47xx_wdt_soft_keepalive,
set_timeout    = bcm47xx_wdt_soft_set_timeout,
bcm47xx_wproblout(struct bool swdtbcm47xx_wdt *wdt = wdt
                return -swdt = wdt->max_timer_ms &l   WDT_SOFTTIMER_THRESHOLD * 1>
swdt) {
wdt->wdd.bcm47xx_wdt_sord_nfo<>
wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
wdt);
wdt->wdd.bcm47xx_wdt_hard_ops);
        wdt->wdd.bcm47xx_wdt_info<>
        wdt->wdd.timeout = WDT_DEFAULT_TIME;
 102     nt wdt->wdd.set_timeout(&wdt->wdd, timeout);
 103        if (     /a>     gotoa>,  105     ct sde=nowayout" class="srede=watchdf">sde=nowayout(&wdt->wdd, nowayout);

        wdt->bcm47xx_wnotify_sy_out);

 109     nt wdt-> 110        if (             gotoa>,  112
        watchdregister_og_devtop(&wdt->wdd);
        if (             gotoa>,  116
 117        &quBCMbcm4 ot;WatchdTt_ti enablarteng  secondsng &#sng &#s)7;d\n",
             >, timeout, nowayout< ?a>) &qu, f">nowayd\n") &qud\n",
                swdt) &qu, S">swaredTt_tid\n") &qud\n");
        retu1>
 121
 122<>,         wdt-> 124<>,         if (swdt
                del_timer_sync(&wdt->soft_timer);

        retunt  129< >);

static int bcm47xx_wremoalync(struct         struct bcm47xx_wdt *wdt = 
        if (!wdt
                return -
        watchddnregister_og_device" class="sref">watchddnregister_og_devtop(&wdt->wdd);
     nt wdt->
        retu1>
 142< >);
 143<>);
 144static struct  = {
        . = {
 146                .ownerTHIS_MODULE,
 147             /a>.&quog/bcm4-xx_d\n",
 148     }an>,
 149        .bcm47xx_wproblout,
        .bcm47xx_wremoalync,
 151
 153< = );
 154
 155&quAleksandar Radovano_ded\n");
 156&quHauke Mehrtens/a> &hauke@hauke-m.dea>-&d\n");
 157"Watchdf="dri lat Broadcom BCMbcm4d\n");
&quGPLd\n");

The original LXR s">swaredby the );
LXR communentity<, fh(t experimental driviondby );
lxi@s="ux.noime

lxi.s="ux.no kindly hosteddby );
Redpill L="pro ASity<, providri of L="uxtic cult usiand opera>opti ser_devi since91> 5.