From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from casper.infradead.org (casper.infradead.org [90.155.50.34]) (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 C5922946A for ; Fri, 3 Apr 2026 12:17:27 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=90.155.50.34 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775218650; cv=none; b=m2ux7WzFizEAaynX3TDdhTqkqpk0wPuWtYQNJAZiPqsJ9BMcVqSFH9sPk/HoE06vW9+adQVtaTyIyUOGPcJq7J3IdMITu66l/3X6GEAF6Dw9BUg3iTsVRo9XRLhftRVZioeQoDEeMsVqzinUQC+qMHUussNhCsuAmYExJKn+VlY= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775218650; c=relaxed/simple; bh=X5lpaWh+t5ZuTF7xyCfYHGOldWgltG1n/UsJVSvh8RE=; h=Date:From:To:Cc:Subject:Message-ID:References:MIME-Version: Content-Type:Content-Disposition:In-Reply-To; b=RG1Gdvw+nEwbbIUWJIGKu9PvuwrAPtPTW8BfCm+UMAnGifx3MyLV0pdpmYobkJCz495OhUt7o1cYbpSsjK0fN/3rIjTbZntsS/6TGXi3ase5YlxcQrB9/2U3JRHwxiesOpKbBllwD9dr/lg5SAz55boF/mQSRjPSC39OAKOSEo0= 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=GXMTdgZu; arc=none smtp.client-ip=90.155.50.34 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="GXMTdgZu" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=In-Reply-To:Content-Type:MIME-Version: References:Message-ID:Subject:Cc:To:From:Date:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=ZXCGuVgkT/FnO69LN1x+94oywZ686R0Y41jvWA3QQs0=; b=GXMTdgZuukuhN0W1MxbW3WT/Lr jNy9Sd1AauSO+sdW27C7fyVntgoLmoxEaZAMWaR9bxEpx7Hp7s0UsYITvV3N5gT/RwO3cNy1bHCxL 2XoU5G1wfrUJFLnCJXSL64B8IGB4Q0PRFQbIEGNTyJNylMPl0gsoe98GGcPQZDHZAXAN1xYPk7lmP zoS45K2mO3QC4fzpFPwaTrglALHpH5dIIOBzcDJC5MBc6wmq5LGPWxkNUsfWn3l5kojFrNGA1xFSV zRAUgV2pnGYU0cpRBEiPbTeVYeeXG/0wcYnIhMmzc9GxuvRerm1Vi8KUgcWtHnnp60bR9Wtw1buEV TUtKPVxg==; Received: from 2001-1c00-8d85-4b00-266e-96ff-fe07-7dcc.cable.dynamic.v6.ziggo.nl ([2001:1c00:8d85:4b00:266e:96ff:fe07:7dcc] helo=noisy.programming.kicks-ass.net) by casper.infradead.org with esmtpsa (Exim 4.98.2 #2 (Red Hat Linux)) id 1w8dSF-0000000EOR3-1EDf; Fri, 03 Apr 2026 12:16:51 +0000 Received: by noisy.programming.kicks-ass.net (Postfix, from userid 1000) id 1234E3004F8; Fri, 03 Apr 2026 14:16:48 +0200 (CEST) Date: Fri, 3 Apr 2026 14:16:48 +0200 From: Peter Zijlstra To: Thomas Gleixner 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 Message-ID: <20260403121648.GZ3738010@noisy.programming.kicks-ass.net> References: <87v7ejetl1.ffs@tglx> <875x6a913n.ffs@tglx> <20260401163435.GGac1JG42tWmsCKL37@fat_crate.local> <87jyup70ka.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; charset=us-ascii Content-Disposition: inline In-Reply-To: <87jyup70ka.ffs@tglx> On Thu, Apr 02, 2026 at 07:07:49PM +0200, Thomas Gleixner wrote: > --- 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,6 +328,11 @@ int clockevents_program_event(struct clo > return dev->set_next_ktime(expires, dev); > > delta = ktime_to_ns(ktime_sub(expires, ktime_get())); > + > + /* Don't reprogram when a forced event is pending */ > + if (dev->next_event_forced && delta <= (int64_t)dev->min_delta_ns) > + return 0; > + > if (delta <= 0) > return force ? clockevents_program_min_delta(dev) : -ETIME; > This last hunk seems duplicate of the clockevents_program_min_delta() change, that also will bail when next_event_forced is set. Also, I note, thing (except shutdown) will ever clear next_event_forced; and I'm thinking that any interrupt or normal reprogram should be doing that. Now, there doesn't seem to be a generic intercept for dev->event_handler, so clearing on interrupt is hard, but would something like the completely untested below work? --- diff --git a/include/linux/clockchips.h b/include/linux/clockchips.h index b0df28ddd394..a79f8fa10104 100644 --- a/include/linux/clockchips.h +++ b/include/linux/clockchips.h @@ -108,6 +108,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 *); diff --git a/kernel/time/clockevents.c b/kernel/time/clockevents.c index eaae1ce9f060..8f6621361e46 100644 --- a/kernel/time/clockevents.c +++ b/kernel/time/clockevents.c @@ -172,6 +172,7 @@ void clockevents_shutdown(struct clock_event_device *dev) { clockevents_switch_state(dev, CLOCK_EVT_STATE_SHUTDOWN); dev->next_event = KTIME_MAX; + dev->next_event_forced = 0; } /** @@ -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; + } 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) + goto error; - return (rc && force) ? clockevents_program_min_delta(dev) : rc; + dev->next_event_forced = 0; + return 0; + +error: + if (force) { + if (dev->next_event_forced) + return 0; + + dev->next_event_forced = 1; + return clockevents_program_min_delta(dev); + } + return rc; } /*