mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
@ 2026-11-10  7:13 Arun Iyengar via B4 Relay
  2026-11-10  7:48 ` Alexandre Belloni
                   ` (2 more replies)
  0 siblings, 3 replies; 4+ messages in thread
From: Arun Iyengar via B4 Relay @ 2026-11-10  7:13 UTC (permalink / raw)
  To: Alexandre Belloni; +Cc: linux-rtc, linux-kernel, stable

From: Arun Iyengar <aiyengar1990@gmail.com>

For an RTC with RTC_FEATURE_ALARM_RES_MINUTE, rtc_set_alarm() rounds the
alarm down to the start of its minute, so that it never fires late. When
the alarm is less than a minute away and in the same minute as the
current time, the rounded time is already in the past.
rtc_timer_enqueue() then gets -ETIME from __rtc_set_alarm() and expires
the timer from the irq work right away, and the hardware alarm is never
armed.

That loses every short wake alarm. With a HYM8563, which has minute
resolution, "rtcwake -m freeze -s 15" sets an alarm that expires in
software before the system suspends, so nothing wakes it: with the
alarm set at 17:55:00 for 17:55:17, /proc/driver/rtc reads back
"alrm_time: 17:55:00, alarm_IRQ: no", and the system stays in
suspend-to-idle until something else wakes it.

Round the alarm up to the next minute when rounding down would put an
alarm that is still in the future into the past. It then fires at most
59 seconds late instead of never. Alarms that are already in the past,
or that round down to a time still in the future, are handled as before.

Fixes: d87f741dddab ("rtc: handle alarms with a minute resolution")
Cc: stable@vger.kernel.org
Signed-off-by: Arun Iyengar <aiyengar1990@gmail.com>
---
Tested on an Orange Pi 5 (RK3588S) with a HYM8563: "rtcwake -m no -s 15"
now reads back the alarm at the next full minute with "alarm_IRQ: yes",
and 47 consecutive "rtcwake -m freeze -s 15" cycles all woke from the
RTC interrupt. Before the fix the alarm was lost whenever the 15 s
stayed inside the current minute, and the system never woke.

This patch was developed with Claude (Anthropic) as a coding assistant:
it wrote the code and the commit message, and I reviewed and tested it
as described above.
---
 drivers/rtc/interface.c | 33 +++++++++++++++++++++++++++------
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 96626f8068f9..004819c9a846 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -535,18 +535,39 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
 		rtc_timer_remove(rtc, &rtc->aie_timer);
 
 	alarm_time = rtc_tm_to_ktime(alarm->time);
-	/*
-	 * Round down so we never miss a deadline, checking for past deadline is
-	 * done in __rtc_set_alarm
-	 */
-	if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features))
-		alarm_time = ktime_sub_ns(alarm_time, (u64)alarm->time.tm_sec * NSEC_PER_SEC);
+	if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features) &&
+	    alarm->time.tm_sec) {
+		ktime_t down = ktime_sub_ns(alarm_time,
+					    (u64)alarm->time.tm_sec * NSEC_PER_SEC);
+		struct rtc_time tm;
+		ktime_t now;
+
+		err = __rtc_read_time(rtc, &tm);
+		if (err)
+			goto unlock;
+		now = rtc_tm_to_ktime(tm);
+
+		/*
+		 * Round down so we never miss a deadline. If that puts an alarm
+		 * that is still in the future into the past, the timer would
+		 * expire right away and the hardware alarm would never be
+		 * armed: whoever relies on it, e.g. to wake the system from
+		 * suspend, would wait forever. Round up to the next minute
+		 * instead. An alarm already in the past is left alone, it is
+		 * handled by __rtc_set_alarm.
+		 */
+		if (ktime_after(down, now) || !ktime_after(alarm_time, now))
+			alarm_time = down;
+		else
+			alarm_time = ktime_add_ns(down, 60 * NSEC_PER_SEC);
+	}
 
 	rtc->aie_timer.node.expires = alarm_time;
 	rtc->aie_timer.period = 0;
 	if (alarm->enabled)
 		err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
 
+unlock:
 	mutex_unlock(&rtc->ops_lock);
 
 	return err;

---
base-commit: 7485659ecb81d5fce3a3edf2cae9fcb29c17b1cd
change-id: 20261110-rtc-minute-alarm-1d8af9689d23

Best regards,
--  
Arun Iyengar <aiyengar1990@gmail.com>



^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
  2026-11-10  7:13 [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past Arun Iyengar via B4 Relay
@ 2026-11-10  7:48 ` Alexandre Belloni
  2026-11-10 11:01 ` kernel test robot
  2026-11-10 14:31 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: Alexandre Belloni @ 2026-11-10  7:48 UTC (permalink / raw)
  To: aiyengar1990; +Cc: linux-rtc, linux-kernel, stable

On 10/11/2026 07:13:47+0000, Arun Iyengar via B4 Relay wrote:
> From: Arun Iyengar <aiyengar1990@gmail.com>
> 
> For an RTC with RTC_FEATURE_ALARM_RES_MINUTE, rtc_set_alarm() rounds the
> alarm down to the start of its minute, so that it never fires late. When
> the alarm is less than a minute away and in the same minute as the
> current time, the rounded time is already in the past.
> rtc_timer_enqueue() then gets -ETIME from __rtc_set_alarm() and expires
> the timer from the irq work right away, and the hardware alarm is never
> armed.

This is the expected behaviour, userspace has to handle the error
properly: the alarm can't be set, set it for a later time or stop there
and don't suspend.

> 
> That loses every short wake alarm. With a HYM8563, which has minute
> resolution, "rtcwake -m freeze -s 15" sets an alarm that expires in
> software before the system suspends, so nothing wakes it: with the
> alarm set at 17:55:00 for 17:55:17, /proc/driver/rtc reads back
> "alrm_time: 17:55:00, alarm_IRQ: no", and the system stays in
> suspend-to-idle until something else wakes it.
> 
> Round the alarm up to the next minute when rounding down would put an
> alarm that is still in the future into the past. It then fires at most
> 59 seconds late instead of never. Alarms that are already in the past,
> or that round down to a time still in the future, are handled as before.

Never round up, you are going to miss deadlines.


-- 
Alexandre Belloni, co-owner and COO, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
  2026-11-10  7:13 [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past Arun Iyengar via B4 Relay
  2026-11-10  7:48 ` Alexandre Belloni
@ 2026-11-10 11:01 ` kernel test robot
  2026-11-10 14:31 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-11-10 11:01 UTC (permalink / raw)
  To: Arun Iyengar via B4 Relay, Alexandre Belloni
  Cc: oe-kbuild-all, linux-rtc, linux-kernel, stable

Hi Arun,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 7485659ecb81d5fce3a3edf2cae9fcb29c17b1cd]

url:    https://github.com/intel-lab-lkp/linux/commits/Arun-Iyengar-via-B4-Relay/rtc-Don-t-lose-a-minute-resolution-alarm-that-rounds-down-into-the-past/20261110-071347
base:   7485659ecb81d5fce3a3edf2cae9fcb29c17b1cd
patch link:    https://lore.kernel.org/r/20261110-rtc-minute-alarm-v1-1-be9d7c5227a1%40gmail.com
patch subject: [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
config: parisc-allnoconfig (https://download.01.org/0day-ci/archive/20261110/202611101839.fRQuN29G-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 16.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261110/202611101839.fRQuN29G-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611101839.fRQuN29G-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from include/linux/timer.h:6,
                    from include/linux/uprobes.h:18,
                    from include/linux/mm_types.h:16,
                    from include/linux/mmzone.h:22,
                    from include/linux/topology.h:34,
                    from include/linux/irq.h:19,
                    from arch/parisc/include/asm/hardirq.h:13,
                    from include/linux/hardirq.h:11,
                    from include/linux/interrupt.h:11,
                    from include/linux/rtc.h:18,
                    from drivers/rtc/interface.c:11:
   drivers/rtc/interface.c: In function 'rtc_set_alarm':
>> drivers/rtc/interface.c:562:60: warning: integer overflow in expression of type 'long int' results in '-129542144' [-Woverflow]
     562 |                         alarm_time = ktime_add_ns(down, 60 * NSEC_PER_SEC);
         |                                                            ^
   include/linux/ktime.h:60:50: note: in definition of macro 'ktime_add_ns'
      60 | #define ktime_add_ns(kt, nsval)         ((kt) + (nsval))
         |                                                  ^~~~~


vim +562 drivers/rtc/interface.c

   512	
   513	int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
   514	{
   515		ktime_t alarm_time;
   516		int err;
   517	
   518		if (!rtc->ops)
   519			return -ENODEV;
   520		else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
   521			return -EINVAL;
   522	
   523		err = rtc_valid_tm(&alarm->time);
   524		if (err != 0)
   525			return err;
   526	
   527		err = rtc_valid_range(rtc, &alarm->time);
   528		if (err)
   529			return err;
   530	
   531		err = mutex_lock_interruptible(&rtc->ops_lock);
   532		if (err)
   533			return err;
   534		if (rtc->aie_timer.enabled)
   535			rtc_timer_remove(rtc, &rtc->aie_timer);
   536	
   537		alarm_time = rtc_tm_to_ktime(alarm->time);
   538		if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features) &&
   539		    alarm->time.tm_sec) {
   540			ktime_t down = ktime_sub_ns(alarm_time,
   541						    (u64)alarm->time.tm_sec * NSEC_PER_SEC);
   542			struct rtc_time tm;
   543			ktime_t now;
   544	
   545			err = __rtc_read_time(rtc, &tm);
   546			if (err)
   547				goto unlock;
   548			now = rtc_tm_to_ktime(tm);
   549	
   550			/*
   551			 * Round down so we never miss a deadline. If that puts an alarm
   552			 * that is still in the future into the past, the timer would
   553			 * expire right away and the hardware alarm would never be
   554			 * armed: whoever relies on it, e.g. to wake the system from
   555			 * suspend, would wait forever. Round up to the next minute
   556			 * instead. An alarm already in the past is left alone, it is
   557			 * handled by __rtc_set_alarm.
   558			 */
   559			if (ktime_after(down, now) || !ktime_after(alarm_time, now))
   560				alarm_time = down;
   561			else
 > 562				alarm_time = ktime_add_ns(down, 60 * NSEC_PER_SEC);
   563		}
   564	
   565		rtc->aie_timer.node.expires = alarm_time;
   566		rtc->aie_timer.period = 0;
   567		if (alarm->enabled)
   568			err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
   569	
   570	unlock:
   571		mutex_unlock(&rtc->ops_lock);
   572	
   573		return err;
   574	}
   575	EXPORT_SYMBOL_GPL(rtc_set_alarm);
   576	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
  2026-11-10  7:13 [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past Arun Iyengar via B4 Relay
  2026-11-10  7:48 ` Alexandre Belloni
  2026-11-10 11:01 ` kernel test robot
@ 2026-11-10 14:31 ` kernel test robot
  2 siblings, 0 replies; 4+ messages in thread
From: kernel test robot @ 2026-11-10 14:31 UTC (permalink / raw)
  To: Arun Iyengar via B4 Relay, Alexandre Belloni
  Cc: llvm, oe-kbuild-all, linux-rtc, linux-kernel, stable

Hi Arun,

kernel test robot noticed the following build warnings:

[auto build test WARNING on 7485659ecb81d5fce3a3edf2cae9fcb29c17b1cd]

url:    https://github.com/intel-lab-lkp/linux/commits/Arun-Iyengar-via-B4-Relay/rtc-Don-t-lose-a-minute-resolution-alarm-that-rounds-down-into-the-past/20261110-071347
base:   7485659ecb81d5fce3a3edf2cae9fcb29c17b1cd
patch link:    https://lore.kernel.org/r/20261110-rtc-minute-alarm-v1-1-be9d7c5227a1%40gmail.com
patch subject: [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past
config: i386-defconfig (https://download.01.org/0day-ci/archive/20261110/202611102202.ZY3wJ35v-lkp@intel.com/config)
compiler: clang version 22.1.8 (https://github.com/llvm/llvm-project ca7933e47d3a3451d81e72ac174dcb5aa28b59d1)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261110/202611102202.ZY3wJ35v-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202611102202.ZY3wJ35v-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> drivers/rtc/interface.c:562:39: warning: overflow in expression; result is -129'542'144 with type 'long' [-Winteger-overflow]
     562 |                         alarm_time = ktime_add_ns(down, 60 * NSEC_PER_SEC);
         |                                      ~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~
   include/linux/ktime.h:60:43: note: expanded from macro 'ktime_add_ns'
      60 | #define ktime_add_ns(kt, nsval)         ((kt) + (nsval))
         |                                                  ^~~~~
   1 warning generated.


vim +562 drivers/rtc/interface.c

   512	
   513	int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
   514	{
   515		ktime_t alarm_time;
   516		int err;
   517	
   518		if (!rtc->ops)
   519			return -ENODEV;
   520		else if (!test_bit(RTC_FEATURE_ALARM, rtc->features))
   521			return -EINVAL;
   522	
   523		err = rtc_valid_tm(&alarm->time);
   524		if (err != 0)
   525			return err;
   526	
   527		err = rtc_valid_range(rtc, &alarm->time);
   528		if (err)
   529			return err;
   530	
   531		err = mutex_lock_interruptible(&rtc->ops_lock);
   532		if (err)
   533			return err;
   534		if (rtc->aie_timer.enabled)
   535			rtc_timer_remove(rtc, &rtc->aie_timer);
   536	
   537		alarm_time = rtc_tm_to_ktime(alarm->time);
   538		if (test_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->features) &&
   539		    alarm->time.tm_sec) {
   540			ktime_t down = ktime_sub_ns(alarm_time,
   541						    (u64)alarm->time.tm_sec * NSEC_PER_SEC);
   542			struct rtc_time tm;
   543			ktime_t now;
   544	
   545			err = __rtc_read_time(rtc, &tm);
   546			if (err)
   547				goto unlock;
   548			now = rtc_tm_to_ktime(tm);
   549	
   550			/*
   551			 * Round down so we never miss a deadline. If that puts an alarm
   552			 * that is still in the future into the past, the timer would
   553			 * expire right away and the hardware alarm would never be
   554			 * armed: whoever relies on it, e.g. to wake the system from
   555			 * suspend, would wait forever. Round up to the next minute
   556			 * instead. An alarm already in the past is left alone, it is
   557			 * handled by __rtc_set_alarm.
   558			 */
   559			if (ktime_after(down, now) || !ktime_after(alarm_time, now))
   560				alarm_time = down;
   561			else
 > 562				alarm_time = ktime_add_ns(down, 60 * NSEC_PER_SEC);
   563		}
   564	
   565		rtc->aie_timer.node.expires = alarm_time;
   566		rtc->aie_timer.period = 0;
   567		if (alarm->enabled)
   568			err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
   569	
   570	unlock:
   571		mutex_unlock(&rtc->ops_lock);
   572	
   573		return err;
   574	}
   575	EXPORT_SYMBOL_GPL(rtc_set_alarm);
   576	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-11-10 14:32 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-10  7:13 [PATCH] rtc: Don't lose a minute-resolution alarm that rounds down into the past Arun Iyengar via B4 Relay
2026-11-10  7:48 ` Alexandre Belloni
2026-11-10 11:01 ` kernel test robot
2026-11-10 14:31 ` kernel test robot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®