aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJohn Stultz <john.stultz@linaro.org>2011-06-16 21:27:09 -0400
committerJohn Stultz <john.stultz@linaro.org>2011-06-21 18:38:33 -0400
commitc008ba58af24dc5d0d8e9fe6e59d876910254761 (patch)
tree0e718ce49992b6a7dfde619cd6ebf05afe06ae12 /kernel
parente08f6d4131ab964420f0bcabecc68d75fb49df79 (diff)
alarmtimers: Handle late rtc module loading
The alarmtimers code currently picks a rtc device to use at late init time. However, if your rtc driver is loaded as a module, it may be registered after the alarmtimers late init code, leaving the alarmtimers nonfunctional. This patch moves the the rtcdevice selection to when we actually try to use it, allowing us to make use of rtc modules that may have been loaded at any point since bootup. CC: Thomas Gleixner <tglx@linutronix.de> CC: Meelis Roos <mroos@ut.ee> Reported-by: Meelis Roos <mroos@ut.ee> Signed-off-by: John Stultz <john.stultz@linaro.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/alarmtimer.c137
1 files changed, 67 insertions, 70 deletions
diff --git a/kernel/time/alarmtimer.c b/kernel/time/alarmtimer.c
index 2d966244ea60..98ecf4e36f2f 100644
--- a/kernel/time/alarmtimer.c
+++ b/kernel/time/alarmtimer.c
@@ -42,15 +42,72 @@ static struct alarm_base {
42 clockid_t base_clockid; 42 clockid_t base_clockid;
43} alarm_bases[ALARM_NUMTYPE]; 43} alarm_bases[ALARM_NUMTYPE];
44 44
45/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */
46static ktime_t freezer_delta;
47static DEFINE_SPINLOCK(freezer_delta_lock);
48
45#ifdef CONFIG_RTC_CLASS 49#ifdef CONFIG_RTC_CLASS
46/* rtc timer and device for setting alarm wakeups at suspend */ 50/* rtc timer and device for setting alarm wakeups at suspend */
47static struct rtc_timer rtctimer; 51static struct rtc_timer rtctimer;
48static struct rtc_device *rtcdev; 52static struct rtc_device *rtcdev;
49#endif 53static DEFINE_SPINLOCK(rtcdev_lock);
50 54
51/* freezer delta & lock used to handle clock_nanosleep triggered wakeups */ 55/**
52static ktime_t freezer_delta; 56 * has_wakealarm - check rtc device has wakealarm ability
53static DEFINE_SPINLOCK(freezer_delta_lock); 57 * @dev: current device
58 * @name_ptr: name to be returned
59 *
60 * This helper function checks to see if the rtc device can wake
61 * from suspend.
62 */
63static int has_wakealarm(struct device *dev, void *name_ptr)
64{
65 struct rtc_device *candidate = to_rtc_device(dev);
66
67 if (!candidate->ops->set_alarm)
68 return 0;
69 if (!device_may_wakeup(candidate->dev.parent))
70 return 0;
71
72 *(const char **)name_ptr = dev_name(dev);
73 return 1;
74}
75
76/**
77 * alarmtimer_get_rtcdev - Return selected rtcdevice
78 *
79 * This function returns the rtc device to use for wakealarms.
80 * If one has not already been chosen, it checks to see if a
81 * functional rtc device is available.
82 */
83static struct rtc_device *alarmtimer_get_rtcdev(void)
84{
85 struct device *dev;
86 char *str;
87 unsigned long flags;
88 struct rtc_device *ret;
89
90 spin_lock_irqsave(&rtcdev_lock, flags);
91 if (!rtcdev) {
92 /* Find an rtc device and init the rtc_timer */
93 dev = class_find_device(rtc_class, NULL, &str, has_wakealarm);
94 /* If we have a device then str is valid. See has_wakealarm() */
95 if (dev) {
96 rtcdev = rtc_class_open(str);
97 /*
98 * Drop the reference we got in class_find_device,
99 * rtc_open takes its own.
100 */
101 put_device(dev);
102 rtc_timer_init(&rtctimer, NULL, NULL);
103 }
104 }
105 ret = rtcdev;
106 spin_unlock_irqrestore(&rtcdev_lock, flags);
107
108 return ret;
109}
110#endif
54 111
55 112
56/** 113/**
@@ -166,6 +223,7 @@ static int alarmtimer_suspend(struct device *dev)
166 struct rtc_time tm; 223 struct rtc_time tm;
167 ktime_t min, now; 224 ktime_t min, now;
168 unsigned long flags; 225 unsigned long flags;
226 struct rtc_device *rtc;
169 int i; 227 int i;
170 228
171 spin_lock_irqsave(&freezer_delta_lock, flags); 229 spin_lock_irqsave(&freezer_delta_lock, flags);
@@ -173,8 +231,9 @@ static int alarmtimer_suspend(struct device *dev)
173 freezer_delta = ktime_set(0, 0); 231 freezer_delta = ktime_set(0, 0);
174 spin_unlock_irqrestore(&freezer_delta_lock, flags); 232 spin_unlock_irqrestore(&freezer_delta_lock, flags);
175 233
234 rtc = alarmtimer_get_rtcdev();
176 /* If we have no rtcdev, just return */ 235 /* If we have no rtcdev, just return */
177 if (!rtcdev) 236 if (!rtc)
178 return 0; 237 return 0;
179 238
180 /* Find the soonest timer to expire*/ 239 /* Find the soonest timer to expire*/
@@ -199,12 +258,12 @@ static int alarmtimer_suspend(struct device *dev)
199 WARN_ON(min.tv64 < NSEC_PER_SEC); 258 WARN_ON(min.tv64 < NSEC_PER_SEC);
200 259
201 /* Setup an rtc timer to fire that far in the future */ 260 /* Setup an rtc timer to fire that far in the future */
202 rtc_timer_cancel(rtcdev, &rtctimer); 261 rtc_timer_cancel(rtc, &rtctimer);
203 rtc_read_time(rtcdev, &tm); 262 rtc_read_time(rtc, &tm);
204 now = rtc_tm_to_ktime(tm); 263 now = rtc_tm_to_ktime(tm);
205 now = ktime_add(now, min); 264 now = ktime_add(now, min);
206 265
207 rtc_timer_start(rtcdev, &rtctimer, now, ktime_set(0, 0)); 266 rtc_timer_start(rtc, &rtctimer, now, ktime_set(0, 0));
208 267
209 return 0; 268 return 0;
210} 269}
@@ -638,65 +697,3 @@ static int __init alarmtimer_init(void)
638} 697}
639device_initcall(alarmtimer_init); 698device_initcall(alarmtimer_init);
640 699
641#ifdef CONFIG_RTC_CLASS
642/**
643 * has_wakealarm - check rtc device has wakealarm ability
644 * @dev: current device
645 * @name_ptr: name to be returned
646 *
647 * This helper function checks to see if the rtc device can wake
648 * from suspend.
649 */
650static int __init has_wakealarm(struct device *dev, void *name_ptr)
651{
652 struct rtc_device *candidate = to_rtc_device(dev);
653
654 if (!candidate->ops->set_alarm)
655 return 0;
656 if (!device_may_wakeup(candidate->dev.parent))
657 return 0;
658
659 *(const char **)name_ptr = dev_name(dev);
660 return 1;
661}
662
663/**
664 * alarmtimer_init_late - Late initializing of alarmtimer code
665 *
666 * This function locates a rtc device to use for wakealarms.
667 * Run as late_initcall to make sure rtc devices have been
668 * registered.
669 */
670static int __init alarmtimer_init_late(void)
671{
672 struct device *dev;
673 char *str;
674
675 /* Find an rtc device and init the rtc_timer */
676 dev = class_find_device(rtc_class, NULL, &str, has_wakealarm);
677 /* If we have a device then str is valid. See has_wakealarm() */
678 if (dev) {
679 rtcdev = rtc_class_open(str);
680 /*
681 * Drop the reference we got in class_find_device,
682 * rtc_open takes its own.
683 */
684 put_device(dev);
685 }
686 if (!rtcdev) {
687 printk(KERN_WARNING "No RTC device found, ALARM timers will"
688 " not wake from suspend");
689 }
690 rtc_timer_init(&rtctimer, NULL, NULL);
691
692 return 0;
693}
694#else
695static int __init alarmtimer_init_late(void)
696{
697 printk(KERN_WARNING "Kernel not built with RTC support, ALARM timers"
698 " will not wake from suspend");
699 return 0;
700}
701#endif
702late_initcall(alarmtimer_init_late);