5b0b9a8a40c7047fb540f17fa2dd8d1bff6069e8
[openwrt/svn-archive/archive.git] / target / linux / brcm47xx / patches-3.8 / 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 255 /* seconds */
7 +#define WDT_SOFTTIMER_THRESHOLD 60 /* seconds */
8
9 static int timeout = WDT_DEFAULT_TIME;
10 static bool nowayout = WATCHDOG_NOWAYOUT;
11 @@ -49,6 +50,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 @@ -133,15 +181,22 @@ static struct watchdog_ops bcm47xx_wdt_s
66 static int 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 @@ -159,14 +214,16 @@ static int bcm47xx_wdt_probe(struct plat
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 }