diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 13:32:09 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-03-20 13:32:09 -0400 |
commit | 161f7a7161191ab9c2e97f787829ef8dd2b95771 (patch) | |
tree | 9776d3f963c7f0d247b7fb324eab4811a1302f67 /drivers/rtc | |
parent | 2ba68940c893c8f0bfc8573c041254251bb6aeab (diff) | |
parent | a078c6d0e6288fad6d83fb6d5edd91ddb7b6ab33 (diff) |
Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer changes for v3.4 from Ingo Molnar
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (32 commits)
ntp: Fix integer overflow when setting time
math: Introduce div64_long
cs5535-clockevt: Allow the MFGPT IRQ to be shared
cs5535-clockevt: Don't ignore MFGPT on SMP-capable kernels
x86/time: Eliminate unused irq0_irqs counter
clocksource: scx200_hrt: Fix the build
x86/tsc: Reduce the TSC sync check time for core-siblings
timer: Fix bad idle check on irq entry
nohz: Remove ts->Einidle checks before restarting the tick
nohz: Remove update_ts_time_stat from tick_nohz_start_idle
clockevents: Leave the broadcast device in shutdown mode when not needed
clocksource: Load the ACPI PM clocksource asynchronously
clocksource: scx200_hrt: Convert scx200 to use clocksource_register_hz
clocksource: Get rid of clocksource_calc_mult_shift()
clocksource: dbx500: convert to clocksource_register_hz()
clocksource: scx200_hrt: use pr_<level> instead of printk
time: Move common updates to a function
time: Reorder so the hot data is together
time: Remove most of xtime_lock usage in timekeeping.c
ntp: Add ntp_lock to replace xtime_locking
...
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/interface.c | 30 |
1 files changed, 27 insertions, 3 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 8a1c031391d6..dc87eda65814 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
@@ -73,6 +73,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
73 | err = -EINVAL; | 73 | err = -EINVAL; |
74 | 74 | ||
75 | mutex_unlock(&rtc->ops_lock); | 75 | mutex_unlock(&rtc->ops_lock); |
76 | /* A timer might have just expired */ | ||
77 | schedule_work(&rtc->irqwork); | ||
76 | return err; | 78 | return err; |
77 | } | 79 | } |
78 | EXPORT_SYMBOL_GPL(rtc_set_time); | 80 | EXPORT_SYMBOL_GPL(rtc_set_time); |
@@ -112,6 +114,8 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
112 | err = -EINVAL; | 114 | err = -EINVAL; |
113 | 115 | ||
114 | mutex_unlock(&rtc->ops_lock); | 116 | mutex_unlock(&rtc->ops_lock); |
117 | /* A timer might have just expired */ | ||
118 | schedule_work(&rtc->irqwork); | ||
115 | 119 | ||
116 | return err; | 120 | return err; |
117 | } | 121 | } |
@@ -380,18 +384,27 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm); | |||
380 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 384 | int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
381 | { | 385 | { |
382 | int err; | 386 | int err; |
387 | struct rtc_time now; | ||
383 | 388 | ||
384 | err = rtc_valid_tm(&alarm->time); | 389 | err = rtc_valid_tm(&alarm->time); |
385 | if (err != 0) | 390 | if (err != 0) |
386 | return err; | 391 | return err; |
387 | 392 | ||
393 | err = rtc_read_time(rtc, &now); | ||
394 | if (err) | ||
395 | return err; | ||
396 | |||
388 | err = mutex_lock_interruptible(&rtc->ops_lock); | 397 | err = mutex_lock_interruptible(&rtc->ops_lock); |
389 | if (err) | 398 | if (err) |
390 | return err; | 399 | return err; |
391 | 400 | ||
392 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); | 401 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); |
393 | rtc->aie_timer.period = ktime_set(0, 0); | 402 | rtc->aie_timer.period = ktime_set(0, 0); |
394 | if (alarm->enabled) { | 403 | |
404 | /* Alarm has to be enabled & in the futrure for us to enqueue it */ | ||
405 | if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 < | ||
406 | rtc->aie_timer.node.expires.tv64)) { | ||
407 | |||
395 | rtc->aie_timer.enabled = 1; | 408 | rtc->aie_timer.enabled = 1; |
396 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); | 409 | timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); |
397 | } | 410 | } |
@@ -763,6 +776,14 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) | |||
763 | return 0; | 776 | return 0; |
764 | } | 777 | } |
765 | 778 | ||
779 | static void rtc_alarm_disable(struct rtc_device *rtc) | ||
780 | { | ||
781 | if (!rtc->ops || !rtc->ops->alarm_irq_enable) | ||
782 | return; | ||
783 | |||
784 | rtc->ops->alarm_irq_enable(rtc->dev.parent, false); | ||
785 | } | ||
786 | |||
766 | /** | 787 | /** |
767 | * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue | 788 | * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue |
768 | * @rtc rtc device | 789 | * @rtc rtc device |
@@ -784,8 +805,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) | |||
784 | struct rtc_wkalrm alarm; | 805 | struct rtc_wkalrm alarm; |
785 | int err; | 806 | int err; |
786 | next = timerqueue_getnext(&rtc->timerqueue); | 807 | next = timerqueue_getnext(&rtc->timerqueue); |
787 | if (!next) | 808 | if (!next) { |
809 | rtc_alarm_disable(rtc); | ||
788 | return; | 810 | return; |
811 | } | ||
789 | alarm.time = rtc_ktime_to_tm(next->expires); | 812 | alarm.time = rtc_ktime_to_tm(next->expires); |
790 | alarm.enabled = 1; | 813 | alarm.enabled = 1; |
791 | err = __rtc_set_alarm(rtc, &alarm); | 814 | err = __rtc_set_alarm(rtc, &alarm); |
@@ -847,7 +870,8 @@ again: | |||
847 | err = __rtc_set_alarm(rtc, &alarm); | 870 | err = __rtc_set_alarm(rtc, &alarm); |
848 | if (err == -ETIME) | 871 | if (err == -ETIME) |
849 | goto again; | 872 | goto again; |
850 | } | 873 | } else |
874 | rtc_alarm_disable(rtc); | ||
851 | 875 | ||
852 | mutex_unlock(&rtc->ops_lock); | 876 | mutex_unlock(&rtc->ops_lock); |
853 | } | 877 | } |