Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 6 Dec 2011 00:53:43 +0000 (16:53 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 6 Dec 2011 00:53:43 +0000 (16:53 -0800)
* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  clockevents: Set noop handler in clockevents_exchange_device()
  tick-broadcast: Stop active broadcast device when replacing it
  clocksource: Fix bug with max_deferment margin calculation
  rtc: Fix some bugs that allowed accumulating time drift in suspend/resume
  rtc: Disable the alarm in the hardware

1  2 
drivers/rtc/class.c
drivers/rtc/interface.c

diff --combined drivers/rtc/class.c
  #include "rtc-core.h"
  
  
 -static DEFINE_IDR(rtc_idr);
 -static DEFINE_MUTEX(idr_lock);
 +static DEFINE_IDA(rtc_ida);
  struct class *rtc_class;
  
  static void rtc_device_release(struct device *dev)
  {
        struct rtc_device *rtc = to_rtc_device(dev);
 -      mutex_lock(&idr_lock);
 -      idr_remove(&rtc_idr, rtc->id);
 -      mutex_unlock(&idr_lock);
 +      ida_simple_remove(&rtc_ida, rtc->id);
        kfree(rtc);
  }
  
@@@ -63,7 -66,7 +63,7 @@@ static int rtc_suspend(struct device *d
         */
        delta = timespec_sub(old_system, old_rtc);
        delta_delta = timespec_sub(delta, old_delta);
-       if (abs(delta_delta.tv_sec)  >= 2) {
+       if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
                /*
                 * if delta_delta is too large, assume time correction
                 * has occured and set old_delta to the current delta.
@@@ -97,9 -100,8 +97,8 @@@ static int rtc_resume(struct device *de
        rtc_tm_to_time(&tm, &new_rtc.tv_sec);
        new_rtc.tv_nsec = 0;
  
-       if (new_rtc.tv_sec <= old_rtc.tv_sec) {
-               if (new_rtc.tv_sec < old_rtc.tv_sec)
-                       pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
+       if (new_rtc.tv_sec < old_rtc.tv_sec) {
+               pr_debug("%s:  time travel!\n", dev_name(&rtc->dev));
                return 0;
        }
  
        sleep_time = timespec_sub(sleep_time,
                        timespec_sub(new_system, old_system));
  
-       timekeeping_inject_sleeptime(&sleep_time);
+       if (sleep_time.tv_sec >= 0)
+               timekeeping_inject_sleeptime(&sleep_time);
        return 0;
  }
  
@@@ -143,16 -146,25 +143,16 @@@ struct rtc_device *rtc_device_register(
        struct rtc_wkalrm alrm;
        int id, err;
  
 -      if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
 -              err = -ENOMEM;
 +      id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
 +      if (id < 0) {
 +              err = id;
                goto exit;
        }
  
 -
 -      mutex_lock(&idr_lock);
 -      err = idr_get_new(&rtc_idr, NULL, &id);
 -      mutex_unlock(&idr_lock);
 -
 -      if (err < 0)
 -              goto exit;
 -
 -      id = id & MAX_ID_MASK;
 -
        rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
        if (rtc == NULL) {
                err = -ENOMEM;
 -              goto exit_idr;
 +              goto exit_ida;
        }
  
        rtc->id = id;
  exit_kfree:
        kfree(rtc);
  
 -exit_idr:
 -      mutex_lock(&idr_lock);
 -      idr_remove(&rtc_idr, id);
 -      mutex_unlock(&idr_lock);
 +exit_ida:
 +      ida_simple_remove(&rtc_ida, id);
  
  exit:
        dev_err(dev, "rtc core: unable to register %s, err = %d\n",
@@@ -262,7 -276,7 +262,7 @@@ static void __exit rtc_exit(void
  {
        rtc_dev_exit();
        class_destroy(rtc_class);
 -      idr_destroy(&rtc_idr);
 +      ida_destroy(&rtc_ida);
  }
  
  subsys_initcall(rtc_init);
diff --combined drivers/rtc/interface.c
@@@ -13,7 -13,6 +13,7 @@@
  
  #include <linux/rtc.h>
  #include <linux/sched.h>
 +#include <linux/module.h>
  #include <linux/log2.h>
  #include <linux/workqueue.h>
  
@@@ -319,6 -318,20 +319,20 @@@ int rtc_read_alarm(struct rtc_device *r
  }
  EXPORT_SYMBOL_GPL(rtc_read_alarm);
  
+ static int ___rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
+ {
+       int err;
+       if (!rtc->ops)
+               err = -ENODEV;
+       else if (!rtc->ops->set_alarm)
+               err = -EINVAL;
+       else
+               err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
+       return err;
+ }
  static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
  {
        struct rtc_time tm;
         * over right here, before we set the alarm.
         */
  
-       if (!rtc->ops)
-               err = -ENODEV;
-       else if (!rtc->ops->set_alarm)
-               err = -EINVAL;
-       else
-               err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
-       return err;
+       return ___rtc_set_alarm(rtc, alarm);
  }
  
  int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
@@@ -640,7 -646,7 +647,7 @@@ EXPORT_SYMBOL_GPL(rtc_irq_unregister)
  static int rtc_update_hrtimer(struct rtc_device *rtc, int enabled)
  {
        /*
 -       * We unconditionally cancel the timer here, because otherwise
 +       * We always cancel the timer here first, because otherwise
         * we could run into BUG_ON(timer->state != HRTIMER_STATE_CALLBACK);
         * when we manage to start the timer before the callback
         * returns HRTIMER_RESTART.
@@@ -709,7 -715,7 +716,7 @@@ int rtc_irq_set_freq(struct rtc_device 
        int err = 0;
        unsigned long flags;
  
 -      if (freq <= 0 || freq > 5000)
 +      if (freq <= 0 || freq > RTC_MAX_FREQ)
                return -EINVAL;
  retry:
        spin_lock_irqsave(&rtc->irq_task_lock, flags);
@@@ -763,6 -769,20 +770,20 @@@ static int rtc_timer_enqueue(struct rtc
        return 0;
  }
  
+ static void rtc_alarm_disable(struct rtc_device *rtc)
+ {
+       struct rtc_wkalrm alarm;
+       struct rtc_time tm;
+       __rtc_read_time(rtc, &tm);
+       alarm.time = rtc_ktime_to_tm(ktime_add(rtc_tm_to_ktime(tm),
+                                    ktime_set(300, 0)));
+       alarm.enabled = 0;
+       ___rtc_set_alarm(rtc, &alarm);
+ }
  /**
   * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
   * @rtc rtc device
@@@ -784,8 -804,10 +805,10 @@@ static void rtc_timer_remove(struct rtc
                struct rtc_wkalrm alarm;
                int err;
                next = timerqueue_getnext(&rtc->timerqueue);
-               if (!next)
+               if (!next) {
+                       rtc_alarm_disable(rtc);
                        return;
+               }
                alarm.time = rtc_ktime_to_tm(next->expires);
                alarm.enabled = 1;
                err = __rtc_set_alarm(rtc, &alarm);
@@@ -847,7 -869,8 +870,8 @@@ again
                err = __rtc_set_alarm(rtc, &alarm);
                if (err == -ETIME)
                        goto again;
-       }
+       } else
+               rtc_alarm_disable(rtc);
  
        mutex_unlock(&rtc->ops_lock);
  }