]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rtc: cmos: unregister HPET IRQ handler on probe failure
authorHaoxiang Li <haoxiang_li2024@163.com>
Tue, 23 Jun 2026 10:08:48 +0000 (18:08 +0800)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Wed, 24 Jun 2026 21:49:00 +0000 (23:49 +0200)
cmos_do_probe() registers cmos_interrupt() as the HPET RTC IRQ
handler before requesting the RTC IRQ and registering the RTC
device. If either request_irq() or devm_rtc_register_device()
fails afterwards, the error path leaves the HPET RTC IRQ handler
installed. This leaves a stale handler behind and make a later
hpet_register_irq_handler() fail with -EBUSY.

Track whether the HPET handler was registered successfully and
undo the registration on the probe error path. Also mask the HPET
RTC IRQ bits to match the normal shutdown cleanup.

Fixes: 9d8af78b0797 ("rtc: add HPET RTC emulation to RTC_DRV_CMOS")
Signed-off-by: Haoxiang Li <haoxiang_li2024@163.com>
Link: https://patch.msgid.link/20260623100848.2127281-1-haoxiang_li2024@163.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/rtc/rtc-cmos.c

index f89ab58f5048a2ae2c8d1855946ce9f4e7223925..fa04ece151b8bb41f4fbdbb5519418990fb77407 100644 (file)
@@ -934,6 +934,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
        unsigned char                   rtc_control;
        unsigned                        address_space;
        u32                             flags = 0;
+       bool                            hpet_registered = false;
        struct nvmem_config nvmem_cfg = {
                .name = "cmos_nvram",
                .word_size = 1,
@@ -1091,6 +1092,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
                                                " failed in rtc_init().");
                                goto cleanup1;
                        }
+                       hpet_registered = true;
                } else
                        rtc_cmos_int_handler = cmos_interrupt;
 
@@ -1140,6 +1142,10 @@ cleanup2:
        if (is_valid_irq(rtc_irq))
                free_irq(rtc_irq, cmos_rtc.rtc);
 cleanup1:
+       if (hpet_registered) {
+               hpet_mask_rtc_irq_bit(RTC_IRQMASK);
+               hpet_unregister_irq_handler(cmos_interrupt);
+       }
        cmos_rtc.dev = NULL;
 cleanup0:
        if (RTC_IOMAPPED)