diff options
-rw-r--r-- | drivers/watchdog/bcm47xx_wdt.c | 69 |
1 files changed, 63 insertions, 6 deletions
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c index e3bfe25a71ef..b4021a2b459b 100644 --- a/drivers/watchdog/bcm47xx_wdt.c +++ b/drivers/watchdog/bcm47xx_wdt.c | |||
@@ -31,6 +31,7 @@ | |||
31 | 31 | ||
32 | #define WDT_DEFAULT_TIME 30 /* seconds */ | 32 | #define WDT_DEFAULT_TIME 30 /* seconds */ |
33 | #define WDT_SOFTTIMER_MAX 255 /* seconds */ | 33 | #define WDT_SOFTTIMER_MAX 255 /* seconds */ |
34 | #define WDT_SOFTTIMER_THRESHOLD 60 /* seconds */ | ||
34 | 35 | ||
35 | static int timeout = WDT_DEFAULT_TIME; | 36 | static int timeout = WDT_DEFAULT_TIME; |
36 | static bool nowayout = WATCHDOG_NOWAYOUT; | 37 | static bool nowayout = WATCHDOG_NOWAYOUT; |
@@ -49,6 +50,53 @@ static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd) | |||
49 | return container_of(wdd, struct bcm47xx_wdt, wdd); | 50 | return container_of(wdd, struct bcm47xx_wdt, wdd); |
50 | } | 51 | } |
51 | 52 | ||
53 | static 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 | |||
62 | static int bcm47xx_wdt_hard_start(struct watchdog_device *wdd) | ||
63 | { | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static 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 | |||
76 | static 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 | |||
92 | static 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 | |||
52 | static void bcm47xx_wdt_soft_timer_tick(unsigned long data) | 100 | static void bcm47xx_wdt_soft_timer_tick(unsigned long data) |
53 | { | 101 | { |
54 | struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data; | 102 | struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data; |
@@ -133,15 +181,22 @@ static struct watchdog_ops bcm47xx_wdt_soft_ops = { | |||
133 | static int bcm47xx_wdt_probe(struct platform_device *pdev) | 181 | static int bcm47xx_wdt_probe(struct platform_device *pdev) |
134 | { | 182 | { |
135 | int ret; | 183 | int ret; |
184 | bool soft; | ||
136 | struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); | 185 | struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); |
137 | 186 | ||
138 | if (!wdt) | 187 | if (!wdt) |
139 | return -ENXIO; | 188 | return -ENXIO; |
140 | 189 | ||
141 | setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick, | 190 | soft = wdt->max_timer_ms < WDT_SOFTTIMER_THRESHOLD * 1000; |
142 | (long unsigned int)wdt); | 191 | |
192 | if (soft) { | ||
193 | wdt->wdd.ops = &bcm47xx_wdt_soft_ops; | ||
194 | setup_timer(&wdt->soft_timer, bcm47xx_wdt_soft_timer_tick, | ||
195 | (long unsigned int)wdt); | ||
196 | } else { | ||
197 | wdt->wdd.ops = &bcm47xx_wdt_hard_ops; | ||
198 | } | ||
143 | 199 | ||
144 | wdt->wdd.ops = &bcm47xx_wdt_soft_ops; | ||
145 | wdt->wdd.info = &bcm47xx_wdt_info; | 200 | wdt->wdd.info = &bcm47xx_wdt_info; |
146 | wdt->wdd.timeout = WDT_DEFAULT_TIME; | 201 | wdt->wdd.timeout = WDT_DEFAULT_TIME; |
147 | ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); | 202 | ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); |
@@ -159,14 +214,16 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev) | |||
159 | if (ret) | 214 | if (ret) |
160 | goto err_notifier; | 215 | goto err_notifier; |
161 | 216 | ||
162 | pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", | 217 | dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n", |
163 | timeout, nowayout ? ", nowayout" : ""); | 218 | timeout, nowayout ? ", nowayout" : "", |
219 | soft ? ", Software Timer" : ""); | ||
164 | return 0; | 220 | return 0; |
165 | 221 | ||
166 | err_notifier: | 222 | err_notifier: |
167 | unregister_reboot_notifier(&wdt->notifier); | 223 | unregister_reboot_notifier(&wdt->notifier); |
168 | err_timer: | 224 | err_timer: |
169 | del_timer_sync(&wdt->soft_timer); | 225 | if (soft) |
226 | del_timer_sync(&wdt->soft_timer); | ||
170 | 227 | ||
171 | return ret; | 228 | return ret; |
172 | } | 229 | } |