Skip to content

Commit e22f4d1

Browse files
Harini Talexandrebelloni
authored andcommitted
rtc: zynqmp: Restore alarm functionality after kexec transition
During kexec reboots, RTC alarms that are fired during the kernel transition experience delayed execution. The new kernel would eventually honor these alarms, but the interrupt handlers would only execute after the driver probe is completed rather than at the intended alarm time. This is because pending alarm interrupt status from the previous kernel is not properly cleared during driver initialization, causing timing discrepancies in alarm delivery. To ensure precise alarm timing across kexec transitions, enhance the probe function to: 1. Clear any pending alarm interrupt status from previous boot. 2. Detect existing valid alarms and preserve their state. 3. Re-enable alarm interrupts for future alarms. Signed-off-by: Harini T <harini.t@amd.com> Link: https://lore.kernel.org/r/20250730142110.2354507-1-harini.t@amd.com Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
1 parent f38bdd7 commit e22f4d1

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

drivers/rtc/rtc-zynqmp.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,10 @@ static irqreturn_t xlnx_rtc_interrupt(int irq, void *id)
277277
static int xlnx_rtc_probe(struct platform_device *pdev)
278278
{
279279
struct xlnx_rtc_dev *xrtcdev;
280+
bool is_alarm_set = false;
281+
u32 pending_alrm_irq;
282+
u32 current_time;
283+
u32 alarm_time;
280284
int ret;
281285

282286
xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL);
@@ -296,6 +300,17 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
296300
if (IS_ERR(xrtcdev->reg_base))
297301
return PTR_ERR(xrtcdev->reg_base);
298302

303+
/* Clear any pending alarm interrupts from previous kernel/boot */
304+
pending_alrm_irq = readl(xrtcdev->reg_base + RTC_INT_STS) & RTC_INT_ALRM;
305+
if (pending_alrm_irq)
306+
writel(pending_alrm_irq, xrtcdev->reg_base + RTC_INT_STS);
307+
308+
/* Check if a valid alarm is already set from previous kernel/boot */
309+
alarm_time = readl(xrtcdev->reg_base + RTC_ALRM);
310+
current_time = readl(xrtcdev->reg_base + RTC_CUR_TM);
311+
if (alarm_time > current_time && alarm_time != 0)
312+
is_alarm_set = true;
313+
299314
xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm");
300315
if (xrtcdev->alarm_irq < 0)
301316
return xrtcdev->alarm_irq;
@@ -337,6 +352,10 @@ static int xlnx_rtc_probe(struct platform_device *pdev)
337352

338353
xlnx_init_rtc(xrtcdev);
339354

355+
/* Re-enable alarm interrupt if a valid alarm was found */
356+
if (is_alarm_set)
357+
writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN);
358+
340359
device_init_wakeup(&pdev->dev, true);
341360

342361
return devm_rtc_register_device(xrtcdev->rtc);

0 commit comments

Comments
 (0)