aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2012-05-22 05:40:26 -0400
committerWim Van Sebroeck <wim@iguana.be>2012-05-30 01:55:17 -0400
commit7a87982420e5e126bfefeb42232d1fd92052794e (patch)
tree3a02096895fdd8b9c1e1903e0b578ba90ae25437 /drivers/watchdog
parent3dfd6218da4cb9d0eae596581a08de9959aa2b1f (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')
-rw-r--r--drivers/watchdog/watchdog_dev.c170
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
62static int watchdog_ping(struct watchdog_device *wddev) 62static 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
74out_ping:
75 return err;
71} 76}
72 77
73/* 78/*
@@ -81,16 +86,17 @@ static int watchdog_ping(struct watchdog_device *wddev)
81 86
82static int watchdog_start(struct watchdog_device *wddev) 87static 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; 98out_start:
99 return err;
94} 100}
95 101
96/* 102/*
@@ -105,21 +111,111 @@ static int watchdog_start(struct watchdog_device *wddev)
105 111
106static int watchdog_stop(struct watchdog_device *wddev) 112static 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; 129out_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
141static 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
161static 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
187static 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
208static 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 }