3e67ba2bb193a43aaeabe9db8e977ffc9a92bb2d
[openwrt.git] / target / linux / brcm47xx / patches-3.6 / 544-watchdog-bcm47xx_wdt.c-add-hard-timer.patch
1 --- a/drivers/watchdog/bcm47xx_wdt.c
2 +++ b/drivers/watchdog/bcm47xx_wdt.c
3 @@ -31,6 +31,7 @@
4  
5  #define WDT_DEFAULT_TIME       30      /* seconds */
6  #define WDT_SOFTTIMER_MAX      3600    /* seconds */
7 +#define WDT_SOFTTIMER_THRESHOLD        60      /* seconds */
8  
9  static int timeout = WDT_DEFAULT_TIME;
10  static bool nowayout = WATCHDOG_NOWAYOUT;
11 @@ -52,6 +53,53 @@ static inline struct bcm47xx_wdt *bcm47x
12         return container_of(wdd, struct bcm47xx_wdt, wdd);
13  }
14  
15 +static int bcm47xx_wdt_hard_keepalive(struct watchdog_device *wdd)
16 +{
17 +       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
18 +
19 +       wdt->timer_set_ms(wdt, wdd->timeout * 1000);
20 +
21 +       return 0;
22 +}
23 +
24 +static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd)
25 +{
26 +       return 0;
27 +}
28 +
29 +static int bcm47xx_wdt_hard_stop(struct watchdog_device *wdd)
30 +{
31 +       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
32 +
33 +       wdt->timer_set(wdt, 0);
34 +
35 +       return 0;
36 +}
37 +
38 +static int bcm47xx_wdt_hard_set_timeout(struct watchdog_device *wdd,
39 +                                       unsigned int new_time)
40 +{
41 +       struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd);
42 +       u32 max_timer = wdt->max_timer_ms;
43 +
44 +       if (new_time < 1 || new_time > max_timer / 1000) {
45 +               pr_warn("timeout value must be 1<=x<=%d, using %d\n",
46 +                       max_timer / 1000, new_time);
47 +               return -EINVAL;
48 +       }
49 +
50 +       wdd->timeout = new_time;
51 +       return 0;
52 +}
53 +
54 +static struct watchdog_ops bcm47xx_wdt_hard_ops = {
55 +       .owner          = THIS_MODULE,
56 +       .start          = bcm47xx_wdt_hard_start,
57 +       .stop           = bcm47xx_wdt_hard_stop,
58 +       .ping           = bcm47xx_wdt_hard_keepalive,
59 +       .set_timeout    = bcm47xx_wdt_hard_set_timeout,
60 +};
61 +
62  static void bcm47xx_wdt_soft_timer_tick(unsigned long data)
63  {
64         struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data;
65 @@ -136,15 +184,22 @@ static struct watchdog_ops bcm47xx_wdt_s
66  static int __devinit bcm47xx_wdt_probe(struct platform_device *pdev)
67  {
68         int ret;
69 +       bool soft;
70         struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev);
71  
72         if (!wdt)
73                 return -ENXIO;
74  
75 -       setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
76 -                   (long unsigned int)wdt);
77 +       soft = wdt->max_timer_ms < WDT_SOFTTIMER_THRESHOLD * 1000;
78 +
79 +       if (soft) {
80 +               wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
81 +               setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick,
82 +                           (long unsigned int)wdt);
83 +       } else {
84 +               wdt->wdd.ops = &bcm47xx_wdt_hard_ops;
85 +       }
86  
87 -       wdt->wdd.ops = &bcm47xx_wdt_soft_ops;
88         wdt->wdd.info = &bcm47xx_wdt_info;
89         wdt->wdd.timeout = WDT_DEFAULT_TIME;
90         ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout);
91 @@ -162,14 +217,16 @@ static int __devinit bcm47xx_wdt_probe(s
92         if (ret)
93                 goto err_notifier;
94  
95 -       pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n",
96 -               timeout, nowayout ? ", nowayout" : "");
97 +       dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
98 +               timeout, nowayout ? ", nowayout" : "",
99 +               soft ? ", Software Timer" : "");
100         return 0;
101  
102  err_notifier:
103         unregister_reboot_notifier(&wdt->notifier);
104  err_timer:
105 -       del_timer_sync(&wdt->soft_timer);
106 +       if (soft)
107 +               del_timer_sync(&wdt->soft_timer);
108  
109         return ret;
110  }
111 --- a/include/linux/bcm47xx_wdt.h
112 +++ b/include/linux/bcm47xx_wdt.h
113 @@ -10,6 +10,7 @@
114  struct bcm47xx_wdt {
115         u32 (*timer_set)(struct bcm47xx_wdt *, u32);
116         u32 (*timer_set_ms)(struct bcm47xx_wdt *, u32);
117 +       u32 max_timer_ms;
118  
119         void *driver_data;
120