Commit 90db544e authored by Linus Torvalds's avatar Linus Torvalds

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
parents 9d451912 9a574ea9
...@@ -99,6 +99,7 @@ static u64 suspend_start; ...@@ -99,6 +99,7 @@ static u64 suspend_start;
* Interval: 0.5sec. * Interval: 0.5sec.
*/ */
#define WATCHDOG_INTERVAL (HZ >> 1) #define WATCHDOG_INTERVAL (HZ >> 1)
#define WATCHDOG_INTERVAL_MAX_NS ((2 * WATCHDOG_INTERVAL) * (NSEC_PER_SEC / HZ))
/* /*
* Threshold: 0.0312s, when doubled: 0.0625s. * Threshold: 0.0312s, when doubled: 0.0625s.
...@@ -134,6 +135,7 @@ static DECLARE_WORK(watchdog_work, clocksource_watchdog_work); ...@@ -134,6 +135,7 @@ static DECLARE_WORK(watchdog_work, clocksource_watchdog_work);
static DEFINE_SPINLOCK(watchdog_lock); static DEFINE_SPINLOCK(watchdog_lock);
static int watchdog_running; static int watchdog_running;
static atomic_t watchdog_reset_pending; static atomic_t watchdog_reset_pending;
static int64_t watchdog_max_interval;
static inline void clocksource_watchdog_lock(unsigned long *flags) static inline void clocksource_watchdog_lock(unsigned long *flags)
{ {
...@@ -399,8 +401,8 @@ static inline void clocksource_reset_watchdog(void) ...@@ -399,8 +401,8 @@ static inline void clocksource_reset_watchdog(void)
static void clocksource_watchdog(struct timer_list *unused) static void clocksource_watchdog(struct timer_list *unused)
{ {
u64 csnow, wdnow, cslast, wdlast, delta; u64 csnow, wdnow, cslast, wdlast, delta;
int64_t wd_nsec, cs_nsec, interval;
int next_cpu, reset_pending; int next_cpu, reset_pending;
int64_t wd_nsec, cs_nsec;
struct clocksource *cs; struct clocksource *cs;
enum wd_read_status read_ret; enum wd_read_status read_ret;
unsigned long extra_wait = 0; unsigned long extra_wait = 0;
...@@ -470,6 +472,27 @@ static void clocksource_watchdog(struct timer_list *unused) ...@@ -470,6 +472,27 @@ static void clocksource_watchdog(struct timer_list *unused)
if (atomic_read(&watchdog_reset_pending)) if (atomic_read(&watchdog_reset_pending))
continue; continue;
/*
* The processing of timer softirqs can get delayed (usually
* on account of ksoftirqd not getting to run in a timely
* manner), which causes the watchdog interval to stretch.
* Skew detection may fail for longer watchdog intervals
* on account of fixed margins being used.
* Some clocksources, e.g. acpi_pm, cannot tolerate
* watchdog intervals longer than a few seconds.
*/
interval = max(cs_nsec, wd_nsec);
if (unlikely(interval > WATCHDOG_INTERVAL_MAX_NS)) {
if (system_state > SYSTEM_SCHEDULING &&
interval > 2 * watchdog_max_interval) {
watchdog_max_interval = interval;
pr_warn("Long readout interval, skipping watchdog check: cs_nsec: %lld wd_nsec: %lld\n",
cs_nsec, wd_nsec);
}
watchdog_timer.expires = jiffies;
continue;
}
/* Check the deviation from the watchdog clocksource. */ /* Check the deviation from the watchdog clocksource. */
md = cs->uncertainty_margin + watchdog->uncertainty_margin; md = cs->uncertainty_margin + watchdog->uncertainty_margin;
if (abs(cs_nsec - wd_nsec) > md) { if (abs(cs_nsec - wd_nsec) > md) {
......
...@@ -1577,6 +1577,7 @@ void tick_cancel_sched_timer(int cpu) ...@@ -1577,6 +1577,7 @@ void tick_cancel_sched_timer(int cpu)
{ {
struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu); struct tick_sched *ts = &per_cpu(tick_cpu_sched, cpu);
ktime_t idle_sleeptime, iowait_sleeptime; ktime_t idle_sleeptime, iowait_sleeptime;
unsigned long idle_calls, idle_sleeps;
# ifdef CONFIG_HIGH_RES_TIMERS # ifdef CONFIG_HIGH_RES_TIMERS
if (ts->sched_timer.base) if (ts->sched_timer.base)
...@@ -1585,9 +1586,13 @@ void tick_cancel_sched_timer(int cpu) ...@@ -1585,9 +1586,13 @@ void tick_cancel_sched_timer(int cpu)
idle_sleeptime = ts->idle_sleeptime; idle_sleeptime = ts->idle_sleeptime;
iowait_sleeptime = ts->iowait_sleeptime; iowait_sleeptime = ts->iowait_sleeptime;
idle_calls = ts->idle_calls;
idle_sleeps = ts->idle_sleeps;
memset(ts, 0, sizeof(*ts)); memset(ts, 0, sizeof(*ts));
ts->idle_sleeptime = idle_sleeptime; ts->idle_sleeptime = idle_sleeptime;
ts->iowait_sleeptime = iowait_sleeptime; ts->iowait_sleeptime = iowait_sleeptime;
ts->idle_calls = idle_calls;
ts->idle_sleeps = idle_sleeps;
} }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment