@@ -107,7 +107,7 @@ static u64 suspend_start;
107
107
* This delay could be due to SMIs, NMIs, or to VCPU preemptions. Used as
108
108
* a lower bound for cs->uncertainty_margin values when registering clocks.
109
109
*/
110
- #define WATCHDOG_MAX_SKEW (50 * NSEC_PER_USEC)
110
+ #define WATCHDOG_MAX_SKEW (100 * NSEC_PER_USEC)
111
111
112
112
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
113
113
static void clocksource_watchdog_work (struct work_struct * work );
@@ -199,23 +199,30 @@ void clocksource_mark_unstable(struct clocksource *cs)
199
199
spin_unlock_irqrestore (& watchdog_lock , flags );
200
200
}
201
201
202
- ulong max_cswd_read_retries = 3 ;
202
+ ulong max_cswd_read_retries = 2 ;
203
203
module_param (max_cswd_read_retries , ulong , 0644 );
204
204
EXPORT_SYMBOL_GPL (max_cswd_read_retries );
205
205
static int verify_n_cpus = 8 ;
206
206
module_param (verify_n_cpus , int , 0644 );
207
207
208
- static bool cs_watchdog_read (struct clocksource * cs , u64 * csnow , u64 * wdnow )
208
+ enum wd_read_status {
209
+ WD_READ_SUCCESS ,
210
+ WD_READ_UNSTABLE ,
211
+ WD_READ_SKIP
212
+ };
213
+
214
+ static enum wd_read_status cs_watchdog_read (struct clocksource * cs , u64 * csnow , u64 * wdnow )
209
215
{
210
216
unsigned int nretries ;
211
- u64 wd_end , wd_delta ;
212
- int64_t wd_delay ;
217
+ u64 wd_end , wd_end2 , wd_delta ;
218
+ int64_t wd_delay , wd_seq_delay ;
213
219
214
220
for (nretries = 0 ; nretries <= max_cswd_read_retries ; nretries ++ ) {
215
221
local_irq_disable ();
216
222
* wdnow = watchdog -> read (watchdog );
217
223
* csnow = cs -> read (cs );
218
224
wd_end = watchdog -> read (watchdog );
225
+ wd_end2 = watchdog -> read (watchdog );
219
226
local_irq_enable ();
220
227
221
228
wd_delta = clocksource_delta (wd_end , * wdnow , watchdog -> mask );
@@ -226,13 +233,34 @@ static bool cs_watchdog_read(struct clocksource *cs, u64 *csnow, u64 *wdnow)
226
233
pr_warn ("timekeeping watchdog on CPU%d: %s retried %d times before success\n" ,
227
234
smp_processor_id (), watchdog -> name , nretries );
228
235
}
229
- return true ;
236
+ return WD_READ_SUCCESS ;
230
237
}
238
+
239
+ /*
240
+ * Now compute delay in consecutive watchdog read to see if
241
+ * there is too much external interferences that cause
242
+ * significant delay in reading both clocksource and watchdog.
243
+ *
244
+ * If consecutive WD read-back delay > WATCHDOG_MAX_SKEW/2,
245
+ * report system busy, reinit the watchdog and skip the current
246
+ * watchdog test.
247
+ */
248
+ wd_delta = clocksource_delta (wd_end2 , wd_end , watchdog -> mask );
249
+ wd_seq_delay = clocksource_cyc2ns (wd_delta , watchdog -> mult , watchdog -> shift );
250
+ if (wd_seq_delay > WATCHDOG_MAX_SKEW /2 )
251
+ goto skip_test ;
231
252
}
232
253
233
254
pr_warn ("timekeeping watchdog on CPU%d: %s read-back delay of %lldns, attempt %d, marking unstable\n" ,
234
255
smp_processor_id (), watchdog -> name , wd_delay , nretries );
235
- return false;
256
+ return WD_READ_UNSTABLE ;
257
+
258
+ skip_test :
259
+ pr_info ("timekeeping watchdog on CPU%d: %s wd-wd read-back delay of %lldns\n" ,
260
+ smp_processor_id (), watchdog -> name , wd_seq_delay );
261
+ pr_info ("wd-%s-wd read-back delay of %lldns, clock-skew test skipped!\n" ,
262
+ cs -> name , wd_delay );
263
+ return WD_READ_SKIP ;
236
264
}
237
265
238
266
static u64 csnow_mid ;
@@ -356,6 +384,7 @@ static void clocksource_watchdog(struct timer_list *unused)
356
384
int next_cpu , reset_pending ;
357
385
int64_t wd_nsec , cs_nsec ;
358
386
struct clocksource * cs ;
387
+ enum wd_read_status read_ret ;
359
388
u32 md ;
360
389
361
390
spin_lock (& watchdog_lock );
@@ -373,9 +402,12 @@ static void clocksource_watchdog(struct timer_list *unused)
373
402
continue ;
374
403
}
375
404
376
- if (!cs_watchdog_read (cs , & csnow , & wdnow )) {
377
- /* Clock readout unreliable, so give it up. */
378
- __clocksource_unstable (cs );
405
+ read_ret = cs_watchdog_read (cs , & csnow , & wdnow );
406
+
407
+ if (read_ret != WD_READ_SUCCESS ) {
408
+ if (read_ret == WD_READ_UNSTABLE )
409
+ /* Clock readout unreliable, so give it up. */
410
+ __clocksource_unstable (cs );
379
411
continue ;
380
412
}
381
413
0 commit comments