Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / time / alarmtimer.c
index aa27d391bfc8b408ced23985bc4946067b5eba87..f11d83b1294992db1e13c5f9266fb14f1bbde573 100644 (file)
@@ -37,7 +37,6 @@
 static struct alarm_base {
        spinlock_t              lock;
        struct timerqueue_head  timerqueue;
-       struct hrtimer          timer;
        ktime_t                 (*gettime)(void);
        clockid_t               base_clockid;
 } alarm_bases[ALARM_NUMTYPE];
@@ -46,6 +45,8 @@ static struct alarm_base {
 static ktime_t freezer_delta;
 static DEFINE_SPINLOCK(freezer_delta_lock);
 
+static struct wakeup_source *ws;
+
 #ifdef CONFIG_RTC_CLASS
 /* rtc timer and device for setting alarm wakeups at suspend */
 static struct rtc_timer                rtctimer;
@@ -130,50 +131,35 @@ static inline void alarmtimer_rtc_timer_init(void) { }
  * @base: pointer to the base where the timer is being run
  * @alarm: pointer to alarm being enqueued.
  *
- * Adds alarm to a alarm_base timerqueue and if necessary sets
- * an hrtimer to run.
+ * Adds alarm to a alarm_base timerqueue
  *
  * Must hold base->lock when calling.
  */
 static void alarmtimer_enqueue(struct alarm_base *base, struct alarm *alarm)
 {
+       if (alarm->state & ALARMTIMER_STATE_ENQUEUED)
+               timerqueue_del(&base->timerqueue, &alarm->node);
+
        timerqueue_add(&base->timerqueue, &alarm->node);
        alarm->state |= ALARMTIMER_STATE_ENQUEUED;
-
-       if (&alarm->node == timerqueue_getnext(&base->timerqueue)) {
-               hrtimer_try_to_cancel(&base->timer);
-               hrtimer_start(&base->timer, alarm->node.expires,
-                               HRTIMER_MODE_ABS);
-       }
 }
 
 /**
- * alarmtimer_remove - Removes an alarm timer from an alarm_base timerqueue
+ * alarmtimer_dequeue - Removes an alarm timer from an alarm_base timerqueue
  * @base: pointer to the base where the timer is running
  * @alarm: pointer to alarm being removed
  *
- * Removes alarm to a alarm_base timerqueue and if necessary sets
- * a new timer to run.
+ * Removes alarm to a alarm_base timerqueue
  *
  * Must hold base->lock when calling.
  */
-static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
+static void alarmtimer_dequeue(struct alarm_base *base, struct alarm *alarm)
 {
-       struct timerqueue_node *next = timerqueue_getnext(&base->timerqueue);
-
        if (!(alarm->state & ALARMTIMER_STATE_ENQUEUED))
                return;
 
        timerqueue_del(&base->timerqueue, &alarm->node);
        alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
-
-       if (next == &alarm->node) {
-               hrtimer_try_to_cancel(&base->timer);
-               next = timerqueue_getnext(&base->timerqueue);
-               if (!next)
-                       return;
-               hrtimer_start(&base->timer, next->expires, HRTIMER_MODE_ABS);
-       }
 }
 
 
@@ -188,42 +174,23 @@ static void alarmtimer_remove(struct alarm_base *base, struct alarm *alarm)
  */
 static enum hrtimer_restart alarmtimer_fired(struct hrtimer *timer)
 {
-       struct alarm_base *base = container_of(timer, struct alarm_base, timer);
-       struct timerqueue_node *next;
+       struct alarm *alarm = container_of(timer, struct alarm, timer);
+       struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
-       ktime_t now;
        int ret = HRTIMER_NORESTART;
        int restart = ALARMTIMER_NORESTART;
 
        spin_lock_irqsave(&base->lock, flags);
-       now = base->gettime();
-       while ((next = timerqueue_getnext(&base->timerqueue))) {
-               struct alarm *alarm;
-               ktime_t expired = next->expires;
-
-               if (expired.tv64 > now.tv64)
-                       break;
-
-               alarm = container_of(next, struct alarm, node);
-
-               timerqueue_del(&base->timerqueue, &alarm->node);
-               alarm->state &= ~ALARMTIMER_STATE_ENQUEUED;
-
-               alarm->state |= ALARMTIMER_STATE_CALLBACK;
-               spin_unlock_irqrestore(&base->lock, flags);
-               if (alarm->function)
-                       restart = alarm->function(alarm, now);
-               spin_lock_irqsave(&base->lock, flags);
-               alarm->state &= ~ALARMTIMER_STATE_CALLBACK;
+       alarmtimer_dequeue(base, alarm);
+       spin_unlock_irqrestore(&base->lock, flags);
 
-               if (restart != ALARMTIMER_NORESTART) {
-                       timerqueue_add(&base->timerqueue, &alarm->node);
-                       alarm->state |= ALARMTIMER_STATE_ENQUEUED;
-               }
-       }
+       if (alarm->function)
+               restart = alarm->function(alarm, base->gettime());
 
-       if (next) {
-               hrtimer_set_expires(&base->timer, next->expires);
+       spin_lock_irqsave(&base->lock, flags);
+       if (restart != ALARMTIMER_NORESTART) {
+               hrtimer_set_expires(&alarm->timer, alarm->node.expires);
+               alarmtimer_enqueue(base, alarm);
                ret = HRTIMER_RESTART;
        }
        spin_unlock_irqrestore(&base->lock, flags);
@@ -250,6 +217,7 @@ static int alarmtimer_suspend(struct device *dev)
        unsigned long flags;
        struct rtc_device *rtc;
        int i;
+       int ret;
 
        spin_lock_irqsave(&freezer_delta_lock, flags);
        min = freezer_delta;
@@ -279,8 +247,10 @@ static int alarmtimer_suspend(struct device *dev)
        if (min.tv64 == 0)
                return 0;
 
-       /* XXX - Should we enforce a minimum sleep time? */
-       WARN_ON(min.tv64 < NSEC_PER_SEC);
+       if (ktime_to_ns(min) < 2 * NSEC_PER_SEC) {
+               __pm_wakeup_event(ws, 2 * MSEC_PER_SEC);
+               return -EBUSY;
+       }
 
        /* Setup an rtc timer to fire that far in the future */
        rtc_timer_cancel(rtc, &rtctimer);
@@ -288,9 +258,11 @@ static int alarmtimer_suspend(struct device *dev)
        now = rtc_tm_to_ktime(tm);
        now = ktime_add(now, min);
 
-       rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
-
-       return 0;
+       /* Set alarm, if in the past reject suspend briefly to handle */
+       ret = rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
+       if (ret < 0)
+               __pm_wakeup_event(ws, MSEC_PER_SEC);
+       return ret;
 }
 #else
 static int alarmtimer_suspend(struct device *dev)
@@ -324,6 +296,9 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
                enum alarmtimer_restart (*function)(struct alarm *, ktime_t))
 {
        timerqueue_init(&alarm->node);
+       hrtimer_init(&alarm->timer, alarm_bases[type].base_clockid,
+                       HRTIMER_MODE_ABS);
+       alarm->timer.function = alarmtimer_fired;
        alarm->function = function;
        alarm->type = type;
        alarm->state = ALARMTIMER_STATE_INACTIVE;
@@ -334,17 +309,19 @@ void alarm_init(struct alarm *alarm, enum alarmtimer_type type,
  * @alarm: ptr to alarm to set
  * @start: time to run the alarm
  */
-void alarm_start(struct alarm *alarm, ktime_t start)
+int alarm_start(struct alarm *alarm, ktime_t start)
 {
        struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
+       int ret;
 
        spin_lock_irqsave(&base->lock, flags);
-       if (alarmtimer_active(alarm))
-               alarmtimer_remove(base, alarm);
        alarm->node.expires = start;
        alarmtimer_enqueue(base, alarm);
+       ret = hrtimer_start(&alarm->timer, alarm->node.expires,
+                               HRTIMER_MODE_ABS);
        spin_unlock_irqrestore(&base->lock, flags);
+       return ret;
 }
 
 /**
@@ -358,18 +335,12 @@ int alarm_try_to_cancel(struct alarm *alarm)
 {
        struct alarm_base *base = &alarm_bases[alarm->type];
        unsigned long flags;
-       int ret = -1;
-       spin_lock_irqsave(&base->lock, flags);
-
-       if (alarmtimer_callback_running(alarm))
-               goto out;
+       int ret;
 
-       if (alarmtimer_is_queued(alarm)) {
-               alarmtimer_remove(base, alarm);
-               ret = 1;
-       } else
-               ret = 0;
-out:
+       spin_lock_irqsave(&base->lock, flags);
+       ret = hrtimer_try_to_cancel(&alarm->timer);
+       if (ret >= 0)
+               alarmtimer_dequeue(base, alarm);
        spin_unlock_irqrestore(&base->lock, flags);
        return ret;
 }
@@ -802,10 +773,6 @@ static int __init alarmtimer_init(void)
        for (i = 0; i < ALARM_NUMTYPE; i++) {
                timerqueue_init_head(&alarm_bases[i].timerqueue);
                spin_lock_init(&alarm_bases[i].lock);
-               hrtimer_init(&alarm_bases[i].timer,
-                               alarm_bases[i].base_clockid,
-                               HRTIMER_MODE_ABS);
-               alarm_bases[i].timer.function = alarmtimer_fired;
        }
 
        error = alarmtimer_rtc_interface_setup();
@@ -821,6 +788,7 @@ static int __init alarmtimer_init(void)
                error = PTR_ERR(pdev);
                goto out_drv;
        }
+       ws = wakeup_source_register("alarmtimer");
        return 0;
 
 out_drv: