Skip to content

Commit 90db544

Browse files
committed
Merge tag 'timers_urgent_for_v6.8_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer fixes from Borislav Petkov: - Preserve the number of idle calls and sleep entries across CPU hotplug events in order to be able to compute correct averages - Limit the duration of the clocksource watchdog checking interval as too long intervals lead to wrongly marking the TSC as unstable * tag 'timers_urgent_for_v6.8_rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: tick/sched: Preserve number of idle sleeps across CPU hotplug events clocksource: Skip watchdog check for large watchdog intervals
2 parents 9d45191 + 9a574ea commit 90db544

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

kernel/time/clocksource.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ static u64 suspend_start;
9999
* Interval: 0.5sec.
100100
*/
101101
#define WATCHDOG_INTERVAL (HZ >> 1)
102+
#define WATCHDOG_INTERVAL_MAX_NS ((2 * WATCHDOG_INTERVAL) * (NSEC_PER_SEC / HZ))
102103

103104
/*
104105
* Threshold: 0.0312s, when doubled: 0.0625s.
@@ -134,6 +135,7 @@ static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
134135
static DEFINE_SPINLOCK(watchdog_lock);
135136
static int watchdog_running;
136137
static atomic_t watchdog_reset_pending;
138+
static int64_t watchdog_max_interval;
137139

138140
static inline void clocksource_watchdog_lock(unsigned long *flags)
139141
{
@@ -399,8 +401,8 @@ static inline void clocksource_reset_watchdog(void)
399401
static void clocksource_watchdog(struct timer_list *unused)
400402
{
401403
u64 csnow, wdnow, cslast, wdlast, delta;
404+
int64_t wd_nsec, cs_nsec, interval;
402405
int next_cpu, reset_pending;
403-
int64_t wd_nsec, cs_nsec;
404406
struct clocksource *cs;
405407
enum wd_read_status read_ret;
406408
unsigned long extra_wait = 0;
@@ -470,6 +472,27 @@ static void clocksource_watchdog(struct timer_list *unused)
470472
if (atomic_read(&watchdog_reset_pending))
471473
continue;
472474

475+
/*
476+
* The processing of timer softirqs can get delayed (usually
477+
* on account of ksoftirqd not getting to run in a timely
478+
* manner), which causes the watchdog interval to stretch.
479+
* Skew detection may fail for longer watchdog intervals
480+
* on account of fixed margins being used.
481+
* Some clocksources, e.g. acpi_pm, cannot tolerate
482+
* watchdog intervals longer than a few seconds.
483+
*/
484+
interval = max(cs_nsec, wd_nsec);
485+
if (unlikely(interval > WATCHDOG_INTERVAL_MAX_NS)) {
486+
if (system_state > SYSTEM_SCHEDULING &&
487+
interval > 2 * watchdog_max_interval) {
488+
watchdog_max_interval = interval;
489+
pr_warn("Long readout interval, skipping watchdog check: cs_nsec: %lld wd_nsec: %lld\n",
490+
cs_nsec, wd_nsec);
491+
}
492+
watchdog_timer.expires = jiffies;
493+
continue;
494+
}
495+
473496
/* Check the deviation from the watchdog clocksource. */
474497
md = cs->uncertainty_margin + watchdog->uncertainty_margin;
475498
if (abs(cs_nsec - wd_nsec) > md) {

kernel/time/tick-sched.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1577,6 +1577,7 @@ void tick_cancel_sched_timer(int cpu)
15771577
{
15781578
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
15791579
ktime_t idle_sleeptime, iowait_sleeptime;
1580+
unsigned long idle_calls, idle_sleeps;
15801581

15811582
# ifdef CONFIG_HIGH_RES_TIMERS
15821583
if (ts->sched_timer.base)
@@ -1585,9 +1586,13 @@ void tick_cancel_sched_timer(int cpu)
15851586

15861587
idle_sleeptime = ts->idle_sleeptime;
15871588
iowait_sleeptime = ts->iowait_sleeptime;
1589+
idle_calls = ts->idle_calls;
1590+
idle_sleeps = ts->idle_sleeps;
15881591
memset(ts, 0, sizeof(*ts));
15891592
ts->idle_sleeptime = idle_sleeptime;
15901593
ts->iowait_sleeptime = iowait_sleeptime;
1594+
ts->idle_calls = idle_calls;
1595+
ts->idle_sleeps = idle_sleeps;
15911596
}
15921597
#endif
15931598

0 commit comments

Comments
 (0)