From nobody Mon Feb 9 06:25:26 2026 Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 15BD532ED27 for ; Wed, 21 Jan 2026 16:28:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.92.199 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769012888; cv=none; b=Y9yKZFDimHtIiB3eQfKB147XC+89vCa7BxDhbG2z9uf51ug/+UE0fzY8MjduSlZoG9CHWcCmh5jRGzbeWFt+nOXqLW0GZrPcsYiiX1X2bED+qyrhdHTtgJrqydjhfbGmDDkZkirloK9Fhg/cNQX3wMn3C3xtK/6f+tSRbsqPcWI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769012888; c=relaxed/simple; bh=nkRh0zoa1wb7KWILX2rkE+WfDaLMenhee0GDCugCODg=; h=Message-ID:Date:From:To:Cc:Subject:References:MIME-Version: Content-Type; b=Yl4cCLspJlils24avyjwb1MHd2mRDxhxy/jn4rdxVZraT8hXQ99R/acTyrcijBsiPpX8pEcY6skByajjSnaFRS8iuL54jGPYtgoZIcMbQKfmgrmo+cY61FVACxAzNkmK3CqvaIen0AxC1ukx/6pWbc4eEvwXkLqjeN+1wWFo7Yo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org; spf=none smtp.mailfrom=infradead.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b=Ipw+2iMo; arc=none smtp.client-ip=90.155.92.199 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=infradead.org Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=infradead.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=infradead.org header.i=@infradead.org header.b="Ipw+2iMo" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: Subject:Cc:To:From:Date:Message-ID:Sender:Reply-To:Content-Transfer-Encoding: Content-ID:Content-Description:In-Reply-To; bh=i/e6ipjEvjUpvQ1N8nr9Vxs1Rh/qX1Ik2QYKpUjY4A4=; b=Ipw+2iMo0IchgSM0VYstr9pQGz /idx/x9qE5X8X1R1wqQMMPC0kv8KgQnsnYm+VO0q7ysb03I9n75c5JVoCewskX9guGGGaeS8jzW3E gbdalUbMQjMlzjXg+XYyO1JF/NpioJfb636p1Y5L5e8LEWie0PcRRkQqnN+fBwOqBTEN57d8219ZN 9cUU7pmQrMiScl8PI6Lg7KRGdmdgbwgk/oqQT7A1jrjVZIf8L1gbILOTTG9i0LNL/hsN5mY/SaJyN RM9fsUMYTmleN/oVrmRAkTpKla0A23XWiR+Huwg9CoojifSZlCrhKKmVb/fFqKD2kv4VP2s/iEzNB sr+oa9aQ==; Received: from 77-249-17-252.cable.dynamic.v4.ziggo.nl ([77.249.17.252] helo=noisy.programming.kicks-ass.net) by desiato.infradead.org with esmtpsa (Exim 4.98.2 #2 (Red Hat Linux)) id 1vib3l-0000000GOpQ-0WNc; Wed, 21 Jan 2026 16:27:57 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 0) id E2071300BD2; Wed, 21 Jan 2026 17:27:55 +0100 (CET) Message-ID: <20260121162507.877520597@infradead.org> User-Agent: quilt/0.68 Date: Wed, 21 Jan 2026 17:20:14 +0100 From: Peter Zijlstra To: tglx@linutronix.de Cc: arnd@arndb.de, anna-maria@linutronix.de, frederic@kernel.org, peterz@infradead.org, luto@kernel.org, mingo@redhat.com, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, vschneid@redhat.com, linux-kernel@vger.kernel.org, oliver.sang@intel.com Subject: [PATCH v2 4/6] hrtimer: Re-arrange hrtimer_interrupt() References: <20260121162010.647043073@infradead.org> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rework hrtimer_interrupt() such that reprogramming is split out into an independent function at the end of the interrupt. This prepares for reprogramming getting delayed beyond the end of hrtimer_interrupt(). Notably, this changes the hang handling to always wait 100ms instead of trying to keep it proportional to the actual delay. This simplifies the state, also this really shouldn't be happening. Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Gleixner --- kernel/time/hrtimer.c | 87 ++++++++++++++++++++++-----------------------= ----- 1 file changed, 39 insertions(+), 48 deletions(-) --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1889,6 +1889,29 @@ static __latent_entropy void hrtimer_run #ifdef CONFIG_HIGH_RES_TIMERS =20 /* + * Very similar to hrtimer_force_reprogram(), except it deals with + * in_hrirq and hang_detected. + */ +static void __hrtimer_rearm(struct hrtimer_cpu_base *cpu_base, ktime_t now) +{ + ktime_t expires_next =3D hrtimer_update_next_event(cpu_base); + + cpu_base->expires_next =3D expires_next; + cpu_base->in_hrtirq =3D 0; + + if (unlikely(cpu_base->hang_detected)) { + /* + * Give the system a chance to do something else than looping + * on hrtimer interrupts. + */ + expires_next =3D ktime_add_ns(now, 100 * NSEC_PER_MSEC); + cpu_base->hang_detected =3D 0; + } + + tick_program_event(expires_next, 1); +} + +/* * High resolution timer interrupt * Called with interrupts disabled */ @@ -1924,63 +1947,31 @@ void hrtimer_interrupt(struct clock_even =20 __hrtimer_run_queues(cpu_base, now, flags, HRTIMER_ACTIVE_HARD); =20 - /* Reevaluate the clock bases for the [soft] next expiry */ - expires_next =3D hrtimer_update_next_event(cpu_base); - /* - * Store the new expiry value so the migration code can verify - * against it. - */ - cpu_base->expires_next =3D expires_next; - cpu_base->in_hrtirq =3D 0; - raw_spin_unlock_irqrestore(&cpu_base->lock, flags); - - /* Reprogramming necessary ? */ - if (!tick_program_event(expires_next, 0)) { - cpu_base->hang_detected =3D 0; - return; - } - /* * The next timer was already expired due to: * - tracing * - long lasting callbacks * - being scheduled away when running in a VM * - * We need to prevent that we loop forever in the hrtimer - * interrupt routine. We give it 3 attempts to avoid - * overreacting on some spurious event. - * - * Acquire base lock for updating the offsets and retrieving - * the current time. + * We need to prevent that we loop forever in the hrtiner interrupt + * routine. We give it 3 attempts to avoid overreacting on some + * spurious event. */ - raw_spin_lock_irqsave(&cpu_base->lock, flags); + expires_next =3D hrtimer_update_next_event(cpu_base); now =3D hrtimer_update_base(cpu_base); - cpu_base->nr_retries++; - if (++retries < 3) - goto retry; - /* - * Give the system a chance to do something else than looping - * here. We stored the entry time, so we know exactly how long - * we spent here. We schedule the next event this amount of - * time away. - */ - cpu_base->nr_hangs++; - cpu_base->hang_detected =3D 1; - raw_spin_unlock_irqrestore(&cpu_base->lock, flags); + if (expires_next < now) { + if (++retries < 3) + goto retry; + + delta =3D ktime_sub(now, entry_time); + cpu_base->max_hang_time =3D max_t(unsigned int, + cpu_base->max_hang_time, delta); + cpu_base->nr_hangs++; + cpu_base->hang_detected =3D 1; + } =20 - delta =3D ktime_sub(now, entry_time); - if ((unsigned int)delta > cpu_base->max_hang_time) - cpu_base->max_hang_time =3D (unsigned int) delta; - /* - * Limit it to a sensible value as we enforce a longer - * delay. Give the CPU at least 100ms to catch up. - */ - if (delta > 100 * NSEC_PER_MSEC) - expires_next =3D ktime_add_ns(now, 100 * NSEC_PER_MSEC); - else - expires_next =3D ktime_add(now, delta); - tick_program_event(expires_next, 1); - pr_warn_once("hrtimer: interrupt took %llu ns\n", ktime_to_ns(delta)); + __hrtimer_rearm(cpu_base, now); + raw_spin_unlock_irqrestore(&cpu_base->lock, flags); } #endif /* !CONFIG_HIGH_RES_TIMERS */