36
36
#include <linux/errno.h> /* For the -ENODEV/... values */
37
37
#include <linux/fs.h> /* For file operations */
38
38
#include <linux/init.h> /* For __init/__exit/... */
39
- #include <linux/jiffies .h> /* For timeout functions */
39
+ #include <linux/hrtimer .h> /* For hrtimers */
40
40
#include <linux/kernel.h> /* For printk/panic/... */
41
41
#include <linux/kref.h> /* For data references */
42
- #include <linux/kthread.h> /* For kthread_delayed_work */
42
+ #include <linux/kthread.h> /* For kthread_work */
43
43
#include <linux/miscdevice.h> /* For handling misc devices */
44
44
#include <linux/module.h> /* For module stuff/... */
45
45
#include <linux/mutex.h> /* For mutexes */
@@ -67,9 +67,10 @@ struct watchdog_core_data {
67
67
struct cdev cdev ;
68
68
struct watchdog_device * wdd ;
69
69
struct mutex lock ;
70
- unsigned long last_keepalive ;
71
- unsigned long last_hw_keepalive ;
72
- struct kthread_delayed_work work ;
70
+ ktime_t last_keepalive ;
71
+ ktime_t last_hw_keepalive ;
72
+ struct hrtimer timer ;
73
+ struct kthread_work work ;
73
74
unsigned long status ; /* Internal status bits */
74
75
#define _WDOG_DEV_OPEN 0 /* Opened ? */
75
76
#define _WDOG_ALLOW_RELEASE 1 /* Did we receive the magic char ? */
@@ -109,18 +110,19 @@ static inline bool watchdog_need_worker(struct watchdog_device *wdd)
109
110
(t && !watchdog_active (wdd ) && watchdog_hw_running (wdd ));
110
111
}
111
112
112
- static long watchdog_next_keepalive (struct watchdog_device * wdd )
113
+ static ktime_t watchdog_next_keepalive (struct watchdog_device * wdd )
113
114
{
114
115
struct watchdog_core_data * wd_data = wdd -> wd_data ;
115
116
unsigned int timeout_ms = wdd -> timeout * 1000 ;
116
- unsigned long keepalive_interval ;
117
- unsigned long last_heartbeat ;
118
- unsigned long virt_timeout ;
117
+ ktime_t keepalive_interval ;
118
+ ktime_t last_heartbeat , latest_heartbeat ;
119
+ ktime_t virt_timeout ;
119
120
unsigned int hw_heartbeat_ms ;
120
121
121
- virt_timeout = wd_data -> last_keepalive + msecs_to_jiffies (timeout_ms );
122
+ virt_timeout = ktime_add (wd_data -> last_keepalive ,
123
+ ms_to_ktime (timeout_ms ));
122
124
hw_heartbeat_ms = min_not_zero (timeout_ms , wdd -> max_hw_heartbeat_ms );
123
- keepalive_interval = msecs_to_jiffies (hw_heartbeat_ms / 2 );
125
+ keepalive_interval = ms_to_ktime (hw_heartbeat_ms / 2 );
124
126
125
127
if (!watchdog_active (wdd ))
126
128
return keepalive_interval ;
@@ -130,39 +132,45 @@ static long watchdog_next_keepalive(struct watchdog_device *wdd)
130
132
* after the most recent ping from userspace, the last
131
133
* worker ping has to come in hw_heartbeat_ms before this timeout.
132
134
*/
133
- last_heartbeat = virt_timeout - msecs_to_jiffies (hw_heartbeat_ms );
134
- return min_t (long , last_heartbeat - jiffies , keepalive_interval );
135
+ last_heartbeat = ktime_sub (virt_timeout , ms_to_ktime (hw_heartbeat_ms ));
136
+ latest_heartbeat = ktime_sub (last_heartbeat , ktime_get ());
137
+ if (ktime_before (latest_heartbeat , keepalive_interval ))
138
+ return latest_heartbeat ;
139
+ return keepalive_interval ;
135
140
}
136
141
137
142
static inline void watchdog_update_worker (struct watchdog_device * wdd )
138
143
{
139
144
struct watchdog_core_data * wd_data = wdd -> wd_data ;
140
145
141
146
if (watchdog_need_worker (wdd )) {
142
- long t = watchdog_next_keepalive (wdd );
147
+ ktime_t t = watchdog_next_keepalive (wdd );
143
148
144
149
if (t > 0 )
145
- kthread_mod_delayed_work (watchdog_kworker ,
146
- & wd_data -> work , t );
150
+ hrtimer_start (& wd_data -> timer , t , HRTIMER_MODE_REL );
147
151
} else {
148
- kthread_cancel_delayed_work_sync (& wd_data -> work );
152
+ hrtimer_cancel (& wd_data -> timer );
149
153
}
150
154
}
151
155
152
156
static int __watchdog_ping (struct watchdog_device * wdd )
153
157
{
154
158
struct watchdog_core_data * wd_data = wdd -> wd_data ;
155
- unsigned long earliest_keepalive = wd_data -> last_hw_keepalive +
156
- msecs_to_jiffies (wdd -> min_hw_heartbeat_ms );
159
+ ktime_t earliest_keepalive , now ;
157
160
int err ;
158
161
159
- if (time_is_after_jiffies (earliest_keepalive )) {
160
- kthread_mod_delayed_work (watchdog_kworker , & wd_data -> work ,
161
- earliest_keepalive - jiffies );
162
+ earliest_keepalive = ktime_add (wd_data -> last_hw_keepalive ,
163
+ ms_to_ktime (wdd -> min_hw_heartbeat_ms ));
164
+ now = ktime_get ();
165
+
166
+ if (ktime_after (earliest_keepalive , now )) {
167
+ hrtimer_start (& wd_data -> timer ,
168
+ ktime_sub (earliest_keepalive , now ),
169
+ HRTIMER_MODE_REL );
162
170
return 0 ;
163
171
}
164
172
165
- wd_data -> last_hw_keepalive = jiffies ;
173
+ wd_data -> last_hw_keepalive = now ;
166
174
167
175
if (wdd -> ops -> ping )
168
176
err = wdd -> ops -> ping (wdd ); /* ping the watchdog */
@@ -195,7 +203,7 @@ static int watchdog_ping(struct watchdog_device *wdd)
195
203
196
204
set_bit (_WDOG_KEEPALIVE , & wd_data -> status );
197
205
198
- wd_data -> last_keepalive = jiffies ;
206
+ wd_data -> last_keepalive = ktime_get () ;
199
207
return __watchdog_ping (wdd );
200
208
}
201
209
@@ -210,16 +218,24 @@ static void watchdog_ping_work(struct kthread_work *work)
210
218
{
211
219
struct watchdog_core_data * wd_data ;
212
220
213
- wd_data = container_of (container_of (work , struct kthread_delayed_work ,
214
- work ),
215
- struct watchdog_core_data , work );
221
+ wd_data = container_of (work , struct watchdog_core_data , work );
216
222
217
223
mutex_lock (& wd_data -> lock );
218
224
if (watchdog_worker_should_ping (wd_data ))
219
225
__watchdog_ping (wd_data -> wdd );
220
226
mutex_unlock (& wd_data -> lock );
221
227
}
222
228
229
+ static enum hrtimer_restart watchdog_timer_expired (struct hrtimer * timer )
230
+ {
231
+ struct watchdog_core_data * wd_data ;
232
+
233
+ wd_data = container_of (timer , struct watchdog_core_data , timer );
234
+
235
+ kthread_queue_work (watchdog_kworker , & wd_data -> work );
236
+ return HRTIMER_NORESTART ;
237
+ }
238
+
223
239
/*
224
240
* watchdog_start: wrapper to start the watchdog.
225
241
* @wdd: the watchdog device to start
@@ -234,15 +250,15 @@ static void watchdog_ping_work(struct kthread_work *work)
234
250
static int watchdog_start (struct watchdog_device * wdd )
235
251
{
236
252
struct watchdog_core_data * wd_data = wdd -> wd_data ;
237
- unsigned long started_at ;
253
+ ktime_t started_at ;
238
254
int err ;
239
255
240
256
if (watchdog_active (wdd ))
241
257
return 0 ;
242
258
243
259
set_bit (_WDOG_KEEPALIVE , & wd_data -> status );
244
260
245
- started_at = jiffies ;
261
+ started_at = ktime_get () ;
246
262
if (watchdog_hw_running (wdd ) && wdd -> ops -> ping )
247
263
err = wdd -> ops -> ping (wdd );
248
264
else
@@ -928,7 +944,9 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
928
944
if (IS_ERR_OR_NULL (watchdog_kworker ))
929
945
return - ENODEV ;
930
946
931
- kthread_init_delayed_work (& wd_data -> work , watchdog_ping_work );
947
+ kthread_init_work (& wd_data -> work , watchdog_ping_work );
948
+ hrtimer_init (& wd_data -> timer , CLOCK_MONOTONIC , HRTIMER_MODE_REL );
949
+ wd_data -> timer .function = watchdog_timer_expired ;
932
950
933
951
if (wdd -> id == 0 ) {
934
952
old_wd_data = wd_data ;
@@ -964,7 +982,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
964
982
}
965
983
966
984
/* Record time of most recent heartbeat as 'just before now'. */
967
- wd_data -> last_hw_keepalive = jiffies - 1 ;
985
+ wd_data -> last_hw_keepalive = ktime_sub ( ktime_get (), 1 ) ;
968
986
969
987
/*
970
988
* If the watchdog is running, prevent its driver from being unloaded,
@@ -974,8 +992,7 @@ static int watchdog_cdev_register(struct watchdog_device *wdd, dev_t devno)
974
992
__module_get (wdd -> ops -> owner );
975
993
kref_get (& wd_data -> kref );
976
994
if (handle_boot_enabled )
977
- kthread_queue_delayed_work (watchdog_kworker ,
978
- & wd_data -> work , 0 );
995
+ hrtimer_start (& wd_data -> timer , 0 , HRTIMER_MODE_REL );
979
996
else
980
997
pr_info ("watchdog%d running and kernel based pre-userspace handler disabled\n" ,
981
998
wdd -> id );
@@ -1012,7 +1029,8 @@ static void watchdog_cdev_unregister(struct watchdog_device *wdd)
1012
1029
watchdog_stop (wdd );
1013
1030
}
1014
1031
1015
- kthread_cancel_delayed_work_sync (& wd_data -> work );
1032
+ hrtimer_cancel (& wd_data -> timer );
1033
+ kthread_cancel_work_sync (& wd_data -> work );
1016
1034
1017
1035
kref_put (& wd_data -> kref , watchdog_core_data_release );
1018
1036
}
0 commit comments