Pull timer updates from Thomas Gleixner: "Updates for the time(r) subsystem: Core: - Make the clocksource watchdog more robust by better validation checks of the measurement. Drivers: - New drivers for MStar and SSD20xd SOCs - The usual cleanups and improvements all over the place" * tag 'timers-core-2022-01-13' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: dt-bindings: timer: Add Mstar MSC313e timer devicetree bindings documentation clocksource/drivers/msc313e: Add support for ssd20xd-based platforms clocksource/drivers: Add MStar MSC313e timer support clocksource/drivers/pistachio: Fix -Wunused-but-set-variable warning clocksource/drivers/timer-imx-sysctr: Set cpumask to cpu_possible_mask clocksource/drivers/imx-sysctr: Mark two variable with __ro_after_init clocksource/drivers/renesas,ostm: Make RENESAS_OSTM symbol visible clocksource/drivers/renesas-ostm: Add RZ/G2L OSTM support dt-bindings: timer: renesas: ostm: Document Renesas RZ/G2L OSTM clocksource/drivers/exynos_mct: Fix silly typo resulting in checkpatch warning clocksource: Reduce the default clocksource_watchdog() retries to 2 clocksource: Avoid accidental unstable marking of clocksources dt-bindings: timer: tpm-timer: Add imx8ulp compatible string reset: Add of_reset_control_get_optional_exclusive() clocksource/drivers/exynos_mct: Refactor resources allocation dt-bindings: timer: remove rockchip,rk3066-timer compatible string from rockchip,rk-timer.yaml dt-bindings: timer: cadence_ttc: Add power-domains
Showing the changes to kernel (1 of 16 files). Show all
Unified · Split
| @@ -107,7 +107,7 @@ static u64 suspend_start; · 106 unmodified lines | ||
| 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) · 85 unmodified lines | ||
| 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) · 4 unmodified lines | ||
| 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) · 117 unmodified lines | ||
| 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) · 11 unmodified lines | ||
| 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 | |