On Sun, 30 Mar 2014 12:04:16 -0400
Sasha Levin <sasha.le...@oracle.com> wrote:

> > Look good, thanks!  
> 
> Or not...
> 
> Hit it again during overnight fuzzing:
> 

 I think this is a different bug, please try this.

diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index cae212f..2c77d8e 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -712,6 +712,20 @@ cmos_do_probe(struct device *dev, struct resource *ports, 
int rtc_irq)
                }
        }
 
+       spin_lock_irq(&rtc_lock);
+       rtc_control = CMOS_READ(RTC_CONTROL);
+       spin_unlock_irq(&rtc_lock);
+
+       /* FIXME:
+        * <asm-generic/rtc.h> doesn't know 12-hour mode either.
+        */
+       if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
+               dev_warn(dev, "only 24-hr supported\n");
+               retval = -ENXIO;
+               goto cleanup0;
+       }
+
+
        cmos_rtc.dev = dev;
        dev_set_drvdata(dev, &cmos_rtc);
 
@@ -739,49 +753,49 @@ cmos_do_probe(struct device *dev, struct resource *ports, 
int rtc_irq)
        /* disable irqs */
        cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
 
-       rtc_control = CMOS_READ(RTC_CONTROL);
-
        spin_unlock_irq(&rtc_lock);
 
-       /* FIXME:
-        * <asm-generic/rtc.h> doesn't know 12-hour mode either.
-        */
-       if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
-               dev_warn(dev, "only 24-hr supported\n");
-               retval = -ENXIO;
-               goto cleanup1;
-       }
-
        if (is_valid_irq(rtc_irq)) {
-               irq_handler_t rtc_cmos_int_handler;
+
+               irq_handler_t rtc_cmos_int_handler = NULL;
 
                if (is_hpet_enabled()) {
-                       rtc_cmos_int_handler = hpet_rtc_interrupt;
+
                        retval = hpet_register_irq_handler(cmos_interrupt);
                        if (retval) {
                                dev_warn(dev, "hpet_register_irq_handler "
                                                " failed in rtc_init().");
-                               goto cleanup1;
+                       } else {
+                               rtc_cmos_int_handler = hpet_rtc_interrupt;
                        }
-               } else
+               } else {
                        rtc_cmos_int_handler = cmos_interrupt;
+               }
 
-               retval = request_irq(rtc_irq, rtc_cmos_int_handler,
-                               0, dev_name(&cmos_rtc.rtc->dev),
-                               cmos_rtc.rtc);
-               if (retval < 0) {
-                       dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
-                       goto cleanup1;
+               if (rtc_cmos_int_handler) {
+                       retval = request_irq(rtc_irq, rtc_cmos_int_handler,
+                                       0, dev_name(&cmos_rtc.rtc->dev),
+                                       cmos_rtc.rtc);
+                       if (retval < 0) {
+
+                               dev_err(dev, "IRQ %d is already in use\n", 
rtc_irq);
+
+                               cmos_rtc.irq = -1;
+
+                               if (is_hpet_enabled()) {
+                                       
hpet_unregister_irq_handler(cmos_interrupt);
+                               }
+                       }
                }
        }
+
        hpet_rtc_timer_init();
 
        /* export at least the first block of NVRAM */
        nvram.size = address_space - NVRAM_OFFSET;
        retval = sysfs_create_bin_file(&dev->kobj, &nvram);
        if (retval < 0) {
-               dev_dbg(dev, "can't create nvram file? %d\n", retval);
-               goto cleanup2;
+               dev_err(dev, "can't create nvram file? %d\n", retval);
        }
 
        dev_info(dev, "%s%s, %zd bytes nvram%s\n",
@@ -795,12 +809,6 @@ cmos_do_probe(struct device *dev, struct resource *ports, 
int rtc_irq)
 
        return 0;
 
-cleanup2:
-       if (is_valid_irq(rtc_irq))
-               free_irq(rtc_irq, cmos_rtc.rtc);
-cleanup1:
-       cmos_rtc.dev = NULL;
-       rtc_device_unregister(cmos_rtc.rtc);
 cleanup0:
        release_region(ports->start, resource_size(ports));
        return retval;
@@ -823,8 +831,12 @@ static void __exit cmos_do_remove(struct device *dev)
        sysfs_remove_bin_file(&dev->kobj, &nvram);
 
        if (is_valid_irq(cmos->irq)) {
+
                free_irq(cmos->irq, cmos->rtc);
-               hpet_unregister_irq_handler(cmos_interrupt);
+
+               if (is_hpet_enabled()) {
+                       hpet_unregister_irq_handler(cmos_interrupt);
+               }
        }
 
        rtc_device_unregister(cmos->rtc);



-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Torino, Italy

  http://www.towertech.it

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to