Commit f82dedf812ecdf0c19c6c240e85a4a487ab62016
Committed by
Wim Van Sebroeck
1 parent
5434a04db9
Exists in
master
and in
20 other branches
watchdog: bcm47xx_wdt.c: use platform device
Instead of accessing the function to set the watchdog timer directly, register a platform driver the platform could register to use this watchdog driver. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Showing 2 changed files with 87 additions and 78 deletions Side-by-side Diff
drivers/watchdog/bcm47xx_wdt.c
... | ... | @@ -3,6 +3,7 @@ |
3 | 3 | * |
4 | 4 | * Copyright (C) 2008 Aleksandar Radovanovic <biblbroks@sezampro.rs> |
5 | 5 | * Copyright (C) 2009 Matthieu CASTET <castet.matthieu@free.fr> |
6 | + * Copyright (C) 2012-2013 Hauke Mehrtens <hauke@hauke-m.de> | |
6 | 7 | * |
7 | 8 | * This program is free software; you can redistribute it and/or |
8 | 9 | * modify it under the terms of the GNU General Public License |
9 | 10 | |
10 | 11 | |
... | ... | @@ -12,19 +13,19 @@ |
12 | 13 | |
13 | 14 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
14 | 15 | |
16 | +#include <linux/bcm47xx_wdt.h> | |
15 | 17 | #include <linux/bitops.h> |
16 | 18 | #include <linux/errno.h> |
17 | 19 | #include <linux/init.h> |
18 | 20 | #include <linux/kernel.h> |
19 | 21 | #include <linux/module.h> |
20 | 22 | #include <linux/moduleparam.h> |
23 | +#include <linux/platform_device.h> | |
21 | 24 | #include <linux/reboot.h> |
22 | 25 | #include <linux/types.h> |
23 | 26 | #include <linux/watchdog.h> |
24 | 27 | #include <linux/timer.h> |
25 | 28 | #include <linux/jiffies.h> |
26 | -#include <linux/ssb/ssb_embedded.h> | |
27 | -#include <asm/mach-bcm47xx/bcm47xx.h> | |
28 | 29 | |
29 | 30 | #define DRV_NAME "bcm47xx_wdt" |
30 | 31 | |
31 | 32 | |
32 | 33 | |
33 | 34 | |
34 | 35 | |
... | ... | @@ -43,48 +44,19 @@ |
43 | 44 | "Watchdog cannot be stopped once started (default=" |
44 | 45 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
45 | 46 | |
46 | -static struct timer_list wdt_timer; | |
47 | -static atomic_t ticks; | |
48 | - | |
49 | -static inline void bcm47xx_wdt_hw_start(void) | |
47 | +static inline struct bcm47xx_wdt *bcm47xx_wdt_get(struct watchdog_device *wdd) | |
50 | 48 | { |
51 | - /* this is 2,5s on 100Mhz clock and 2s on 133 Mhz */ | |
52 | - switch (bcm47xx_bus_type) { | |
53 | -#ifdef CONFIG_BCM47XX_SSB | |
54 | - case BCM47XX_BUS_TYPE_SSB: | |
55 | - ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0xfffffff); | |
56 | - break; | |
57 | -#endif | |
58 | -#ifdef CONFIG_BCM47XX_BCMA | |
59 | - case BCM47XX_BUS_TYPE_BCMA: | |
60 | - bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, | |
61 | - 0xfffffff); | |
62 | - break; | |
63 | -#endif | |
64 | - } | |
49 | + return container_of(wdd, struct bcm47xx_wdt, wdd); | |
65 | 50 | } |
66 | 51 | |
67 | -static inline int bcm47xx_wdt_hw_stop(void) | |
52 | +static void bcm47xx_timer_tick(unsigned long data) | |
68 | 53 | { |
69 | - switch (bcm47xx_bus_type) { | |
70 | -#ifdef CONFIG_BCM47XX_SSB | |
71 | - case BCM47XX_BUS_TYPE_SSB: | |
72 | - return ssb_watchdog_timer_set(&bcm47xx_bus.ssb, 0); | |
73 | -#endif | |
74 | -#ifdef CONFIG_BCM47XX_BCMA | |
75 | - case BCM47XX_BUS_TYPE_BCMA: | |
76 | - bcma_chipco_watchdog_timer_set(&bcm47xx_bus.bcma.bus.drv_cc, 0); | |
77 | - return 0; | |
78 | -#endif | |
79 | - } | |
80 | - return -EINVAL; | |
81 | -} | |
54 | + struct bcm47xx_wdt *wdt = (struct bcm47xx_wdt *)data; | |
55 | + u32 next_tick = min(wdt->wdd.timeout * 1000, wdt->max_timer_ms); | |
82 | 56 | |
83 | -static void bcm47xx_timer_tick(unsigned long unused) | |
84 | -{ | |
85 | - if (!atomic_dec_and_test(&ticks)) { | |
86 | - bcm47xx_wdt_hw_start(); | |
87 | - mod_timer(&wdt_timer, jiffies + HZ); | |
57 | + if (!atomic_dec_and_test(&wdt->soft_ticks)) { | |
58 | + wdt->timer_set_ms(wdt, next_tick); | |
59 | + mod_timer(&wdt->soft_timer, jiffies + HZ); | |
88 | 60 | } else { |
89 | 61 | pr_crit("Watchdog will fire soon!!!\n"); |
90 | 62 | } |
91 | 63 | |
92 | 64 | |
93 | 65 | |
94 | 66 | |
95 | 67 | |
96 | 68 | |
97 | 69 | |
98 | 70 | |
... | ... | @@ -92,34 +64,43 @@ |
92 | 64 | |
93 | 65 | static int bcm47xx_wdt_keepalive(struct watchdog_device *wdd) |
94 | 66 | { |
95 | - atomic_set(&ticks, wdt_time); | |
67 | + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); | |
96 | 68 | |
69 | + atomic_set(&wdt->soft_ticks, wdd->timeout); | |
70 | + | |
97 | 71 | return 0; |
98 | 72 | } |
99 | 73 | |
100 | 74 | static int bcm47xx_wdt_start(struct watchdog_device *wdd) |
101 | 75 | { |
102 | - bcm47xx_wdt_pet(); | |
103 | - bcm47xx_timer_tick(0); | |
76 | + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); | |
104 | 77 | |
78 | + bcm47xx_wdt_keepalive(wdd); | |
79 | + bcm47xx_timer_tick((unsigned long)wdt); | |
80 | + | |
105 | 81 | return 0; |
106 | 82 | } |
107 | 83 | |
108 | 84 | static int bcm47xx_wdt_stop(struct watchdog_device *wdd) |
109 | 85 | { |
110 | - del_timer_sync(&wdt_timer); | |
111 | - bcm47xx_wdt_hw_stop(); | |
86 | + struct bcm47xx_wdt *wdt = bcm47xx_wdt_get(wdd); | |
112 | 87 | |
88 | + del_timer_sync(&wdt->soft_timer); | |
89 | + wdt->timer_set(wdt, 0); | |
90 | + | |
113 | 91 | return 0; |
114 | 92 | } |
115 | 93 | |
116 | 94 | static int bcm47xx_wdt_set_timeout(struct watchdog_device *wdd, |
117 | 95 | unsigned int new_time) |
118 | 96 | { |
119 | - if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | |
97 | + if (new_time < 1 || new_time > WDT_MAX_TIME) { | |
98 | + pr_warn("timeout value must be 1<=x<=%d, using %d\n", | |
99 | + WDT_MAX_TIME, new_time); | |
120 | 100 | return -EINVAL; |
101 | + } | |
121 | 102 | |
122 | - wdt_time = new_time; | |
103 | + wdd->timeout = new_time; | |
123 | 104 | return 0; |
124 | 105 | } |
125 | 106 | |
126 | 107 | |
... | ... | @@ -133,8 +114,11 @@ |
133 | 114 | static int bcm47xx_wdt_notify_sys(struct notifier_block *this, |
134 | 115 | unsigned long code, void *unused) |
135 | 116 | { |
117 | + struct bcm47xx_wdt *wdt; | |
118 | + | |
119 | + wdt = container_of(this, struct bcm47xx_wdt, notifier); | |
136 | 120 | if (code == SYS_DOWN || code == SYS_HALT) |
137 | - bcm47xx_wdt_stop(); | |
121 | + wdt->wdd.ops->stop(&wdt->wdd); | |
138 | 122 | return NOTIFY_DONE; |
139 | 123 | } |
140 | 124 | |
141 | 125 | |
142 | 126 | |
143 | 127 | |
144 | 128 | |
145 | 129 | |
146 | 130 | |
147 | 131 | |
148 | 132 | |
149 | 133 | |
150 | 134 | |
151 | 135 | |
152 | 136 | |
153 | 137 | |
154 | 138 | |
... | ... | @@ -146,57 +130,73 @@ |
146 | 130 | .set_timeout = bcm47xx_wdt_set_timeout, |
147 | 131 | }; |
148 | 132 | |
149 | -static struct watchdog_device bcm47xx_wdt_wdd = { | |
150 | - .info = &bcm47xx_wdt_info, | |
151 | - .ops = &bcm47xx_wdt_ops, | |
152 | -}; | |
153 | - | |
154 | -static struct notifier_block bcm47xx_wdt_notifier = { | |
155 | - .notifier_call = bcm47xx_wdt_notify_sys, | |
156 | -}; | |
157 | - | |
158 | -static int __init bcm47xx_wdt_init(void) | |
133 | +static int bcm47xx_wdt_probe(struct platform_device *pdev) | |
159 | 134 | { |
160 | 135 | int ret; |
136 | + struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); | |
161 | 137 | |
162 | - if (bcm47xx_wdt_hw_stop() < 0) | |
163 | - return -ENODEV; | |
138 | + if (!wdt) | |
139 | + return -ENXIO; | |
164 | 140 | |
165 | - setup_timer(&wdt_timer, bcm47xx_timer_tick, 0L); | |
141 | + setup_timer(&wdt->soft_timer, bcm47xx_timer_tick, | |
142 | + (long unsigned int)wdt); | |
166 | 143 | |
167 | - if (bcm47xx_wdt_settimeout(wdt_time)) { | |
168 | - bcm47xx_wdt_settimeout(WDT_DEFAULT_TIME); | |
169 | - pr_info("wdt_time value must be 0 < wdt_time < %d, using %d\n", | |
170 | - (WDT_MAX_TIME + 1), wdt_time); | |
171 | - } | |
172 | - watchdog_set_nowayout(&bcm47xx_wdt_wdd, nowayout); | |
144 | + wdt->wdd.ops = &bcm47xx_wdt_ops; | |
145 | + wdt->wdd.info = &bcm47xx_wdt_info; | |
146 | + wdt->wdd.timeout = WDT_DEFAULT_TIME; | |
147 | + ret = wdt->wdd.ops->set_timeout(&wdt->wdd, timeout); | |
148 | + if (ret) | |
149 | + goto err_timer; | |
150 | + watchdog_set_nowayout(&wdt->wdd, nowayout); | |
173 | 151 | |
174 | - ret = register_reboot_notifier(&bcm47xx_wdt_notifier); | |
152 | + wdt->notifier.notifier_call = &bcm47xx_wdt_notify_sys; | |
153 | + | |
154 | + ret = register_reboot_notifier(&wdt->notifier); | |
175 | 155 | if (ret) |
176 | - return ret; | |
156 | + goto err_timer; | |
177 | 157 | |
178 | - ret = watchdog_register_device(&bcm47xx_wdt_wdd); | |
179 | - if (ret) { | |
180 | - unregister_reboot_notifier(&bcm47xx_wdt_notifier); | |
181 | - return ret; | |
182 | - } | |
158 | + ret = watchdog_register_device(&wdt->wdd); | |
159 | + if (ret) | |
160 | + goto err_notifier; | |
183 | 161 | |
184 | 162 | pr_info("BCM47xx Watchdog Timer enabled (%d seconds%s)\n", |
185 | 163 | wdt_time, nowayout ? ", nowayout" : ""); |
186 | 164 | return 0; |
165 | + | |
166 | +err_notifier: | |
167 | + unregister_reboot_notifier(&wdt->notifier); | |
168 | +err_timer: | |
169 | + del_timer_sync(&wdt->soft_timer); | |
170 | + | |
171 | + return ret; | |
187 | 172 | } |
188 | 173 | |
189 | -static void __exit bcm47xx_wdt_exit(void) | |
174 | +static int bcm47xx_wdt_remove(struct platform_device *pdev) | |
190 | 175 | { |
191 | - watchdog_unregister_device(&bcm47xx_wdt_wdd); | |
176 | + struct bcm47xx_wdt *wdt = dev_get_platdata(&pdev->dev); | |
192 | 177 | |
193 | - unregister_reboot_notifier(&bcm47xx_wdt_notifier); | |
178 | + if (!wdt) | |
179 | + return -ENXIO; | |
180 | + | |
181 | + watchdog_unregister_device(&wdt->wdd); | |
182 | + unregister_reboot_notifier(&wdt->notifier); | |
183 | + | |
184 | + return 0; | |
194 | 185 | } |
195 | 186 | |
196 | -module_init(bcm47xx_wdt_init); | |
197 | -module_exit(bcm47xx_wdt_exit); | |
187 | +static struct platform_driver bcm47xx_wdt_driver = { | |
188 | + .driver = { | |
189 | + .owner = THIS_MODULE, | |
190 | + .name = "bcm47xx-wdt", | |
191 | + }, | |
192 | + .probe = bcm47xx_wdt_probe, | |
193 | + .remove = bcm47xx_wdt_remove, | |
194 | +}; | |
198 | 195 | |
196 | +module_platform_driver(bcm47xx_wdt_driver); | |
197 | + | |
199 | 198 | MODULE_AUTHOR("Aleksandar Radovanovic"); |
199 | +MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>"); | |
200 | 200 | MODULE_DESCRIPTION("Watchdog driver for Broadcom BCM47xx"); |
201 | 201 | MODULE_LICENSE("GPL"); |
include/linux/bcm47xx_wdt.h
1 | 1 | #ifndef LINUX_BCM47XX_WDT_H_ |
2 | 2 | #define LINUX_BCM47XX_WDT_H_ |
3 | 3 | |
4 | +#include <linux/notifier.h> | |
5 | +#include <linux/timer.h> | |
4 | 6 | #include <linux/types.h> |
7 | +#include <linux/watchdog.h> | |
5 | 8 | |
6 | 9 | |
7 | 10 | struct bcm47xx_wdt { |
... | ... | @@ -10,6 +13,12 @@ |
10 | 13 | u32 max_timer_ms; |
11 | 14 | |
12 | 15 | void *driver_data; |
16 | + | |
17 | + struct watchdog_device wdd; | |
18 | + struct notifier_block notifier; | |
19 | + | |
20 | + struct timer_list soft_timer; | |
21 | + atomic_t soft_ticks; | |
13 | 22 | }; |
14 | 23 | |
15 | 24 | static inline void *bcm47xx_wdt_get_drvdata(struct bcm47xx_wdt *wdt) |