From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (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 F3F103CA4B6 for ; Fri, 3 Apr 2026 16:17:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775233039; cv=none; b=YGqI5ToUgnh2pITqesJZjhW870g59z7Hg0hFGBXL01HdssUJzlwp/e6HmSYByiIZEWskKvUSZRvJYzfkbZXUOeFbICHXd/1oH+CTvNlpZcgPUr9FsQJPYCHEZ5sq+SDQMUWEQu7NFimgQ0Kq8SKYCcW2cJWKFSDaIa7UcspqD5Y= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775233039; c=relaxed/simple; bh=6s8EdJF0Ne40QeF5g2v7KPRsUDchO31WGm3SSOKGu3Q=; h=From:To:Cc:Subject:In-Reply-To:References:Date:Message-ID: MIME-Version:Content-Type; b=Y1tEdKsh7waBBmwAzOSCMQTXdahM0gXBKNe3WhR2KSBwc3u9MDX2lQhG5ujxBySLFOCv2Nemh/t5KK4R/xOASXEFARkElRQXtIVZBVY2VUi3d/drAFtKOyM7Nyj1lGpDCHXNJnlKKq0rwoqPezI+Avb5GIVuVsv/jcK7ffVLJQU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pmIN3pd7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pmIN3pd7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id E19BDC4CEF7; Fri, 3 Apr 2026 16:17:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1775233038; bh=6s8EdJF0Ne40QeF5g2v7KPRsUDchO31WGm3SSOKGu3Q=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=pmIN3pd7GaGHRGtuKkipTm4emuiU5GsDq3hWRO6du6+ZTLPdSaeRrcFV5ExbZVuY3 M5ORQYCKFK0ONIIv7UT52XTQl+Tcp3JV+BXS/XH96wiItqN4he/IAQibKe19GeRAyW UJjd0DIoHVzgOPQDC4Vw32x5D3X4yQi8DvUJa3SNc0sIYFfov00B3aOM2b4O/6V/rH xKw15332tR7RgRCa/s47uwokdbKzJxtCQNfZdPTrlczLpD8EdP/oFG7yetlLhbvcjZ ZohRqvkQN86HapLGw/ZhDOQrqYB9XvHUU640fb8fbbdSvqrBOGmsvpbFdLBWodsSfL 2WEvNvS18gzRw== From: Thomas Gleixner To: Peter Zijlstra Cc: Borislav Petkov , Calvin Owens , Petr Mladek , linux-kernel@vger.kernel.org, arighi@nvidia.com, yaozhenguo1@gmail.com, tj@kernel.org, feng.tang@linux.alibaba.com, lirongqing@baidu.com, realwujing@gmail.com, hu.shengming@zte.com.cn, dianders@chromium.org, joel.granados@kernel.org, Ingo Molnar , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , Frederic Weisbecker , Anna-Maria Behnsen , x86@kernel.org Subject: Re: [PATCH] clockevents: Prevent timer interrupt starvation In-Reply-To: <20260403121648.GZ3738010@noisy.programming.kicks-ass.net> References: <87v7ejetl1.ffs@tglx> <875x6a913n.ffs@tglx> <20260401163435.GGac1JG42tWmsCKL37@fat_crate.local> <87jyup70ka.ffs@tglx> <20260403121648.GZ3738010@noisy.programming.kicks-ass.net> Date: Fri, 03 Apr 2026 18:17:15 +0200 Message-ID: <87341c6mt0.ffs@tglx> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain On Fri, Apr 03 2026 at 14:16, Peter Zijlstra wrote: > On Thu, Apr 02, 2026 at 07:07:49PM +0200, Thomas Gleixner wrote: > /** > @@ -324,16 +325,31 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires, > return dev->set_next_ktime(expires, dev); > > delta = ktime_to_ns(ktime_sub(expires, ktime_get())); > - if (delta <= 0) > - return force ? clockevents_program_min_delta(dev) : -ETIME; > + if (delta <= 0) { > + rc = -ETIME; > + goto error; > + } That's not working in the case that user space manages to set the expiry time so it stays in the min_delta_ns window, which is doable. I just tried. Then we are back to square one. Less convoluted but untested version of my initial idea below. Thanks, tglx --- --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -80,6 +80,7 @@ enum clock_event_state { * @shift: nanoseconds to cycles divisor (power of two) * @state_use_accessors:current state of the device, assigned by the core code * @features: features + * @next_event_forced: True if the last programming was a forced event * @retries: number of forced programming retries * @set_state_periodic: switch state to periodic * @set_state_oneshot: switch state to oneshot @@ -108,6 +109,7 @@ struct clock_event_device { u32 shift; enum clock_event_state state_use_accessors; unsigned int features; + unsigned int next_event_forced; unsigned long retries; int (*set_state_periodic)(struct clock_event_device *); --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -172,6 +172,7 @@ void clockevents_shutdown(struct clock_e { clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); dev->next_event = KTIME_MAX; + dev->next_event_forced = 0; } /** @@ -224,13 +225,7 @@ static int clockevents_increase_min_delt return 0; } -/** - * clockevents_program_min_delta - Set clock event device to the minimum delay. - * @dev: device to program - * - * Returns 0 on success, -ETIME when the retry loop failed. - */ -static int clockevents_program_min_delta(struct clock_event_device *dev) +static int __clockevents_program_min_delta(struct clock_event_device *dev) { unsigned long long clc; int64_t delta; @@ -263,13 +258,7 @@ static int clockevents_program_min_delta #else /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ -/** - * clockevents_program_min_delta - Set clock event device to the minimum delay. - * @dev: device to program - * - * Returns 0 on success, -ETIME when the retry loop failed. - */ -static int clockevents_program_min_delta(struct clock_event_device *dev) +static int __clockevents_program_min_delta(struct clock_event_device *dev) { unsigned long long clc; int64_t delta = 0; @@ -293,6 +282,21 @@ static int clockevents_program_min_delta #endif /* CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST */ /** + * clockevents_program_min_delta - Set clock event device to the minimum delay. + * @dev: device to program + * + * Returns 0 on success, -ETIME when the retry loop failed. + */ +static int clockevents_program_min_delta(struct clock_event_device *dev) +{ + if (dev->next_event_forced) + return 0; + + dev->next_event_forced = 1; + return __clockevents_program_min_delta(dev); +} + +/** * clockevents_program_event - Reprogram the clock event device. * @dev: device to program * @expires: absolute expiry time (monotonic clock) @@ -324,16 +328,18 @@ int clockevents_program_event(struct clo return dev->set_next_ktime(expires, dev); delta = ktime_to_ns(ktime_sub(expires, ktime_get())); - if (delta <= 0) - return force ? clockevents_program_min_delta(dev) : -ETIME; - delta = min(delta, (int64_t) dev->max_delta_ns); - delta = max(delta, (int64_t) dev->min_delta_ns); + if (!dev->next_event_forced || delta > dev->min_delta_ns) { - clc = ((unsigned long long) delta * dev->mult) >> dev->shift; - rc = dev->set_next_event((unsigned long) clc, dev); + delta = min(delta, (int64_t) dev->max_delta_ns); + delta = max(delta, (int64_t) dev->min_delta_ns); + clc = ((unsigned long long) delta * dev->mult) >> dev->shift; + rc = dev->set_next_event((unsigned long) clc, dev); + if (!rc) + return 0; + } - return (rc && force) ? clockevents_program_min_delta(dev) : rc; + return force ? clockevents_program_min_delta(dev) : rc; } /* --- a/kernel/time/hrtimer.c +++ b/kernel/time/hrtimer.c @@ -1888,6 +1888,7 @@ void hrtimer_interrupt(struct clock_even BUG_ON(!cpu_base->hres_active); cpu_base->nr_events++; dev->next_event = KTIME_MAX; + dev->next_event_forced = 0; raw_spin_lock_irqsave(&cpu_base->lock, flags); entry_time = now = hrtimer_update_base(cpu_base); --- a/kernel/time/tick-common.c +++ b/kernel/time/tick-common.c @@ -110,6 +110,7 @@ void tick_handle_periodic(struct clock_e int cpu = smp_processor_id(); ktime_t next = dev->next_event; + dev->next_event_forced = 0; tick_periodic(cpu); /* --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -1513,6 +1513,7 @@ static void tick_nohz_lowres_handler(str struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); dev->next_event = KTIME_MAX; + dev->next_event_forced = 0; if (likely(tick_nohz_handler(&ts->sched_timer) == HRTIMER_RESTART)) tick_program_event(hrtimer_get_expires(&ts->sched_timer), 1);