diff options
author | Hans de Goede <hdegoede@redhat.com> | 2012-05-22 05:40:26 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2012-05-30 01:55:17 -0400 |
commit | 7a87982420e5e126bfefeb42232d1fd92052794e (patch) | |
tree | 3a02096895fdd8b9c1e1903e0b578ba90ae25437 /drivers/watchdog/watchdog_dev.c | |
parent | 3dfd6218da4cb9d0eae596581a08de9959aa2b1f (diff) |
watchdog: watchdog_dev: Rewrite wrapper code
Rewrite and extend the wrapper code so that we can easily introduce
locking (this to be able to prevent potential multithreading issues).
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog/watchdog_dev.c')
-rw-r--r-- | drivers/watchdog/watchdog_dev.c | 170 |
1 files changed, 130 insertions, 40 deletions
diff --git a/drivers/watchdog/watchdog_dev.c b/drivers/watchdog/watchdog_dev.c index 55191cccf026..76d2572fed25 100644 --- a/drivers/watchdog/watchdog_dev.c +++ b/drivers/watchdog/watchdog_dev.c | |||
@@ -61,13 +61,18 @@ static struct watchdog_device *old_wdd; | |||
61 | 61 | ||
62 | static int watchdog_ping(struct watchdog_device *wddev) | 62 | static int watchdog_ping(struct watchdog_device *wddev) |
63 | { | 63 | { |
64 | if (watchdog_active(wddev)) { | 64 | int err = 0; |
65 | if (wddev->ops->ping) | 65 | |
66 | return wddev->ops->ping(wddev); /* ping the watchdog */ | 66 | if (!watchdog_active(wddev)) |
67 | else | 67 | goto out_ping; |
68 | return wddev->ops->start(wddev); /* restart watchdog */ | 68 | |
69 | } | 69 | if (wddev->ops->ping) |
70 | return 0; | 70 | err = wddev->ops->ping(wddev); /* ping the watchdog */ |
71 | else | ||
72 | err = wddev->ops->start(wddev); /* restart watchdog */ | ||
73 | |||
74 | out_ping: | ||
75 | return err; | ||
71 | } | 76 | } |
72 | 77 | ||
73 | /* | 78 | /* |
@@ -81,16 +86,17 @@ static int watchdog_ping(struct watchdog_device *wddev) | |||
81 | 86 | ||
82 | static int watchdog_start(struct watchdog_device *wddev) | 87 | static int watchdog_start(struct watchdog_device *wddev) |
83 | { | 88 | { |
84 | int err; | 89 | int err = 0; |
85 | 90 | ||
86 | if (!watchdog_active(wddev)) { | 91 | if (watchdog_active(wddev)) |
87 | err = wddev->ops->start(wddev); | 92 | goto out_start; |
88 | if (err < 0) | ||
89 | return err; | ||
90 | 93 | ||
94 | err = wddev->ops->start(wddev); | ||
95 | if (err == 0) | ||
91 | set_bit(WDOG_ACTIVE, &wddev->status); | 96 | set_bit(WDOG_ACTIVE, &wddev->status); |
92 | } | 97 | |
93 | return 0; | 98 | out_start: |
99 | return err; | ||
94 | } | 100 | } |
95 | 101 | ||
96 | /* | 102 | /* |
@@ -105,21 +111,111 @@ static int watchdog_start(struct watchdog_device *wddev) | |||
105 | 111 | ||
106 | static int watchdog_stop(struct watchdog_device *wddev) | 112 | static int watchdog_stop(struct watchdog_device *wddev) |
107 | { | 113 | { |
108 | int err = -EBUSY; | 114 | int err = 0; |
115 | |||
116 | if (!watchdog_active(wddev)) | ||
117 | goto out_stop; | ||
109 | 118 | ||
110 | if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) { | 119 | if (test_bit(WDOG_NO_WAY_OUT, &wddev->status)) { |
111 | dev_info(wddev->dev, "nowayout prevents watchdog being stopped!\n"); | 120 | dev_info(wddev->dev, "nowayout prevents watchdog being stopped!\n"); |
112 | return err; | 121 | err = -EBUSY; |
122 | goto out_stop; | ||
113 | } | 123 | } |
114 | 124 | ||
115 | if (watchdog_active(wddev)) { | 125 | err = wddev->ops->stop(wddev); |
116 | err = wddev->ops->stop(wddev); | 126 | if (err == 0) |
117 | if (err < 0) | ||
118 | return err; | ||
119 | |||
120 | clear_bit(WDOG_ACTIVE, &wddev->status); | 127 | clear_bit(WDOG_ACTIVE, &wddev->status); |
121 | } | 128 | |
122 | return 0; | 129 | out_stop: |
130 | return err; | ||
131 | } | ||
132 | |||
133 | /* | ||
134 | * watchdog_get_status: wrapper to get the watchdog status | ||
135 | * @wddev: the watchdog device to get the status from | ||
136 | * @status: the status of the watchdog device | ||
137 | * | ||
138 | * Get the watchdog's status flags. | ||
139 | */ | ||
140 | |||
141 | static int watchdog_get_status(struct watchdog_device *wddev, | ||
142 | unsigned int *status) | ||
143 | { | ||
144 | int err = 0; | ||
145 | |||
146 | *status = 0; | ||
147 | if (!wddev->ops->status) | ||
148 | return -EOPNOTSUPP; | ||
149 | |||
150 | *status = wddev->ops->status(wddev); | ||
151 | |||
152 | return err; | ||
153 | } | ||
154 | |||
155 | /* | ||
156 | * watchdog_set_timeout: set the watchdog timer timeout | ||
157 | * @wddev: the watchdog device to set the timeout for | ||
158 | * @timeout: timeout to set in seconds | ||
159 | */ | ||
160 | |||
161 | static int watchdog_set_timeout(struct watchdog_device *wddev, | ||
162 | unsigned int timeout) | ||
163 | { | ||
164 | int err; | ||
165 | |||
166 | if ((wddev->ops->set_timeout == NULL) || | ||
167 | !(wddev->info->options & WDIOF_SETTIMEOUT)) | ||
168 | return -EOPNOTSUPP; | ||
169 | |||
170 | if ((wddev->max_timeout != 0) && | ||
171 | (timeout < wddev->min_timeout || timeout > wddev->max_timeout)) | ||
172 | return -EINVAL; | ||
173 | |||
174 | err = wddev->ops->set_timeout(wddev, timeout); | ||
175 | |||
176 | return err; | ||
177 | } | ||
178 | |||
179 | /* | ||
180 | * watchdog_get_timeleft: wrapper to get the time left before a reboot | ||
181 | * @wddev: the watchdog device to get the remaining time from | ||
182 | * @timeleft: the time that's left | ||
183 | * | ||
184 | * Get the time before a watchdog will reboot (if not pinged). | ||
185 | */ | ||
186 | |||
187 | static int watchdog_get_timeleft(struct watchdog_device *wddev, | ||
188 | unsigned int *timeleft) | ||
189 | { | ||
190 | int err = 0; | ||
191 | |||
192 | *timeleft = 0; | ||
193 | if (!wddev->ops->get_timeleft) | ||
194 | return -EOPNOTSUPP; | ||
195 | |||
196 | *timeleft = wddev->ops->get_timeleft(wddev); | ||
197 | |||
198 | return err; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * watchdog_ioctl_op: call the watchdog drivers ioctl op if defined | ||
203 | * @wddev: the watchdog device to do the ioctl on | ||
204 | * @cmd: watchdog command | ||
205 | * @arg: argument pointer | ||
206 | */ | ||
207 | |||
208 | static int watchdog_ioctl_op(struct watchdog_device *wddev, unsigned int cmd, | ||
209 | unsigned long arg) | ||
210 | { | ||
211 | int err; | ||
212 | |||
213 | if (!wddev->ops->ioctl) | ||
214 | return -ENOIOCTLCMD; | ||
215 | |||
216 | err = wddev->ops->ioctl(wddev, cmd, arg); | ||
217 | |||
218 | return err; | ||
123 | } | 219 | } |
124 | 220 | ||
125 | /* | 221 | /* |
@@ -183,18 +279,18 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, | |||
183 | unsigned int val; | 279 | unsigned int val; |
184 | int err; | 280 | int err; |
185 | 281 | ||
186 | if (wdd->ops->ioctl) { | 282 | err = watchdog_ioctl_op(wdd, cmd, arg); |
187 | err = wdd->ops->ioctl(wdd, cmd, arg); | 283 | if (err != -ENOIOCTLCMD) |
188 | if (err != -ENOIOCTLCMD) | 284 | return err; |
189 | return err; | ||
190 | } | ||
191 | 285 | ||
192 | switch (cmd) { | 286 | switch (cmd) { |
193 | case WDIOC_GETSUPPORT: | 287 | case WDIOC_GETSUPPORT: |
194 | return copy_to_user(argp, wdd->info, | 288 | return copy_to_user(argp, wdd->info, |
195 | sizeof(struct watchdog_info)) ? -EFAULT : 0; | 289 | sizeof(struct watchdog_info)) ? -EFAULT : 0; |
196 | case WDIOC_GETSTATUS: | 290 | case WDIOC_GETSTATUS: |
197 | val = wdd->ops->status ? wdd->ops->status(wdd) : 0; | 291 | err = watchdog_get_status(wdd, &val); |
292 | if (err) | ||
293 | return err; | ||
198 | return put_user(val, p); | 294 | return put_user(val, p); |
199 | case WDIOC_GETBOOTSTATUS: | 295 | case WDIOC_GETBOOTSTATUS: |
200 | return put_user(wdd->bootstatus, p); | 296 | return put_user(wdd->bootstatus, p); |
@@ -218,15 +314,9 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, | |||
218 | watchdog_ping(wdd); | 314 | watchdog_ping(wdd); |
219 | return 0; | 315 | return 0; |
220 | case WDIOC_SETTIMEOUT: | 316 | case WDIOC_SETTIMEOUT: |
221 | if ((wdd->ops->set_timeout == NULL) || | ||
222 | !(wdd->info->options & WDIOF_SETTIMEOUT)) | ||
223 | return -EOPNOTSUPP; | ||
224 | if (get_user(val, p)) | 317 | if (get_user(val, p)) |
225 | return -EFAULT; | 318 | return -EFAULT; |
226 | if ((wdd->max_timeout != 0) && | 319 | err = watchdog_set_timeout(wdd, val); |
227 | (val < wdd->min_timeout || val > wdd->max_timeout)) | ||
228 | return -EINVAL; | ||
229 | err = wdd->ops->set_timeout(wdd, val); | ||
230 | if (err < 0) | 320 | if (err < 0) |
231 | return err; | 321 | return err; |
232 | /* If the watchdog is active then we send a keepalive ping | 322 | /* If the watchdog is active then we send a keepalive ping |
@@ -240,10 +330,10 @@ static long watchdog_ioctl(struct file *file, unsigned int cmd, | |||
240 | return -EOPNOTSUPP; | 330 | return -EOPNOTSUPP; |
241 | return put_user(wdd->timeout, p); | 331 | return put_user(wdd->timeout, p); |
242 | case WDIOC_GETTIMELEFT: | 332 | case WDIOC_GETTIMELEFT: |
243 | if (!wdd->ops->get_timeleft) | 333 | err = watchdog_get_timeleft(wdd, &val); |
244 | return -EOPNOTSUPP; | 334 | if (err) |
245 | 335 | return err; | |
246 | return put_user(wdd->ops->get_timeleft(wdd), p); | 336 | return put_user(val, p); |
247 | default: | 337 | default: |
248 | return -ENOTTY; | 338 | return -ENOTTY; |
249 | } | 339 | } |