diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-11 14:06:41 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-11 14:06:41 -0500 |
| commit | 5943a268002fce97885f2ca08827ff1b0312068c (patch) | |
| tree | 5e304e79b68263e799224ebb1a08ead474ab299b /drivers/rtc/interface.c | |
| parent | 42776163e13a56ea3096edff7a5df95408e80eb4 (diff) | |
| parent | 96c8f06a0fb359a9a89701a7afab6d837e466ab0 (diff) | |
Merge branch 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
rtc: Namespace fixup
RTC: Remove UIE emulation
RTC: Rework RTC code to use timerqueue for events
Fix up trivial conflict in drivers/rtc/rtc-dev.c
Diffstat (limited to 'drivers/rtc/interface.c')
| -rw-r--r-- | drivers/rtc/interface.c | 574 |
1 files changed, 349 insertions, 225 deletions
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index a0c816238aa9..90384b9f6b2c 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c | |||
| @@ -14,15 +14,11 @@ | |||
| 14 | #include <linux/rtc.h> | 14 | #include <linux/rtc.h> |
| 15 | #include <linux/sched.h> | 15 | #include <linux/sched.h> |
| 16 | #include <linux/log2.h> | 16 | #include <linux/log2.h> |
| 17 | #include <linux/workqueue.h> | ||
| 17 | 18 | ||
| 18 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | 19 | static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) |
| 19 | { | 20 | { |
| 20 | int err; | 21 | int err; |
| 21 | |||
| 22 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
| 23 | if (err) | ||
| 24 | return err; | ||
| 25 | |||
| 26 | if (!rtc->ops) | 22 | if (!rtc->ops) |
| 27 | err = -ENODEV; | 23 | err = -ENODEV; |
| 28 | else if (!rtc->ops->read_time) | 24 | else if (!rtc->ops->read_time) |
| @@ -31,7 +27,18 @@ int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | |||
| 31 | memset(tm, 0, sizeof(struct rtc_time)); | 27 | memset(tm, 0, sizeof(struct rtc_time)); |
| 32 | err = rtc->ops->read_time(rtc->dev.parent, tm); | 28 | err = rtc->ops->read_time(rtc->dev.parent, tm); |
| 33 | } | 29 | } |
| 30 | return err; | ||
| 31 | } | ||
| 32 | |||
| 33 | int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) | ||
| 34 | { | ||
| 35 | int err; | ||
| 34 | 36 | ||
| 37 | err = mutex_lock_interruptible(&rtc->ops_lock); | ||
| 38 | if (err) | ||
| 39 | return err; | ||
| 40 | |||
| 41 | err = __rtc_read_time(rtc, tm); | ||
| 35 | mutex_unlock(&rtc->ops_lock); | 42 | mutex_unlock(&rtc->ops_lock); |
| 36 | return err; | 43 | return err; |
| 37 | } | 44 | } |
| @@ -106,188 +113,54 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) | |||
| 106 | } | 113 | } |
| 107 | EXPORT_SYMBOL_GPL(rtc_set_mmss); | 114 | EXPORT_SYMBOL_GPL(rtc_set_mmss); |
| 108 | 115 | ||
| 109 | static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 116 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
| 110 | { | 117 | { |
| 111 | int err; | 118 | int err; |
| 112 | 119 | ||
| 113 | err = mutex_lock_interruptible(&rtc->ops_lock); | 120 | err = mutex_lock_interruptible(&rtc->ops_lock); |
| 114 | if (err) | 121 | if (err) |
| 115 | return err; | 122 | return err; |
| 116 | 123 | alarm->enabled = rtc->aie_timer.enabled; | |
| 117 | if (rtc->ops == NULL) | 124 | if (alarm->enabled) |
| 118 | err = -ENODEV; | 125 | alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires); |
| 119 | else if (!rtc->ops->read_alarm) | ||
| 120 | err = -EINVAL; | ||
| 121 | else { | ||
| 122 | memset(alarm, 0, sizeof(struct rtc_wkalrm)); | ||
| 123 | err = rtc->ops->read_alarm(rtc->dev.parent, alarm); | ||
| 124 | } | ||
| 125 | |||
| 126 | mutex_unlock(&rtc->ops_lock); | 126 | mutex_unlock(&rtc->ops_lock); |
| 127 | return err; | 127 | |
| 128 | return 0; | ||
| 128 | } | 129 | } |
| 130 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | ||
| 129 | 131 | ||
| 130 | int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 132 | int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
| 131 | { | 133 | { |
| 134 | struct rtc_time tm; | ||
| 135 | long now, scheduled; | ||
| 132 | int err; | 136 | int err; |
| 133 | struct rtc_time before, now; | ||
| 134 | int first_time = 1; | ||
| 135 | unsigned long t_now, t_alm; | ||
| 136 | enum { none, day, month, year } missing = none; | ||
| 137 | unsigned days; | ||
| 138 | |||
| 139 | /* The lower level RTC driver may return -1 in some fields, | ||
| 140 | * creating invalid alarm->time values, for reasons like: | ||
| 141 | * | ||
| 142 | * - The hardware may not be capable of filling them in; | ||
| 143 | * many alarms match only on time-of-day fields, not | ||
| 144 | * day/month/year calendar data. | ||
| 145 | * | ||
| 146 | * - Some hardware uses illegal values as "wildcard" match | ||
| 147 | * values, which non-Linux firmware (like a BIOS) may try | ||
| 148 | * to set up as e.g. "alarm 15 minutes after each hour". | ||
| 149 | * Linux uses only oneshot alarms. | ||
| 150 | * | ||
| 151 | * When we see that here, we deal with it by using values from | ||
| 152 | * a current RTC timestamp for any missing (-1) values. The | ||
| 153 | * RTC driver prevents "periodic alarm" modes. | ||
| 154 | * | ||
| 155 | * But this can be racey, because some fields of the RTC timestamp | ||
| 156 | * may have wrapped in the interval since we read the RTC alarm, | ||
| 157 | * which would lead to us inserting inconsistent values in place | ||
| 158 | * of the -1 fields. | ||
| 159 | * | ||
| 160 | * Reading the alarm and timestamp in the reverse sequence | ||
| 161 | * would have the same race condition, and not solve the issue. | ||
| 162 | * | ||
| 163 | * So, we must first read the RTC timestamp, | ||
| 164 | * then read the RTC alarm value, | ||
| 165 | * and then read a second RTC timestamp. | ||
| 166 | * | ||
| 167 | * If any fields of the second timestamp have changed | ||
| 168 | * when compared with the first timestamp, then we know | ||
| 169 | * our timestamp may be inconsistent with that used by | ||
| 170 | * the low-level rtc_read_alarm_internal() function. | ||
| 171 | * | ||
| 172 | * So, when the two timestamps disagree, we just loop and do | ||
| 173 | * the process again to get a fully consistent set of values. | ||
| 174 | * | ||
| 175 | * This could all instead be done in the lower level driver, | ||
| 176 | * but since more than one lower level RTC implementation needs it, | ||
| 177 | * then it's probably best best to do it here instead of there.. | ||
| 178 | */ | ||
| 179 | 137 | ||
| 180 | /* Get the "before" timestamp */ | 138 | err = rtc_valid_tm(&alarm->time); |
| 181 | err = rtc_read_time(rtc, &before); | 139 | if (err) |
| 182 | if (err < 0) | ||
| 183 | return err; | 140 | return err; |
| 184 | do { | 141 | rtc_tm_to_time(&alarm->time, &scheduled); |
| 185 | if (!first_time) | ||
| 186 | memcpy(&before, &now, sizeof(struct rtc_time)); | ||
| 187 | first_time = 0; | ||
| 188 | |||
| 189 | /* get the RTC alarm values, which may be incomplete */ | ||
| 190 | err = rtc_read_alarm_internal(rtc, alarm); | ||
| 191 | if (err) | ||
| 192 | return err; | ||
| 193 | if (!alarm->enabled) | ||
| 194 | return 0; | ||
| 195 | |||
| 196 | /* full-function RTCs won't have such missing fields */ | ||
| 197 | if (rtc_valid_tm(&alarm->time) == 0) | ||
| 198 | return 0; | ||
| 199 | |||
| 200 | /* get the "after" timestamp, to detect wrapped fields */ | ||
| 201 | err = rtc_read_time(rtc, &now); | ||
| 202 | if (err < 0) | ||
| 203 | return err; | ||
| 204 | |||
| 205 | /* note that tm_sec is a "don't care" value here: */ | ||
| 206 | } while ( before.tm_min != now.tm_min | ||
| 207 | || before.tm_hour != now.tm_hour | ||
| 208 | || before.tm_mon != now.tm_mon | ||
| 209 | || before.tm_year != now.tm_year); | ||
| 210 | |||
| 211 | /* Fill in the missing alarm fields using the timestamp; we | ||
| 212 | * know there's at least one since alarm->time is invalid. | ||
| 213 | */ | ||
| 214 | if (alarm->time.tm_sec == -1) | ||
| 215 | alarm->time.tm_sec = now.tm_sec; | ||
| 216 | if (alarm->time.tm_min == -1) | ||
| 217 | alarm->time.tm_min = now.tm_min; | ||
| 218 | if (alarm->time.tm_hour == -1) | ||
| 219 | alarm->time.tm_hour = now.tm_hour; | ||
| 220 | |||
| 221 | /* For simplicity, only support date rollover for now */ | ||
| 222 | if (alarm->time.tm_mday == -1) { | ||
| 223 | alarm->time.tm_mday = now.tm_mday; | ||
| 224 | missing = day; | ||
| 225 | } | ||
| 226 | if (alarm->time.tm_mon == -1) { | ||
| 227 | alarm->time.tm_mon = now.tm_mon; | ||
| 228 | if (missing == none) | ||
| 229 | missing = month; | ||
| 230 | } | ||
| 231 | if (alarm->time.tm_year == -1) { | ||
| 232 | alarm->time.tm_year = now.tm_year; | ||
| 233 | if (missing == none) | ||
| 234 | missing = year; | ||
| 235 | } | ||
| 236 | |||
| 237 | /* with luck, no rollover is needed */ | ||
| 238 | rtc_tm_to_time(&now, &t_now); | ||
| 239 | rtc_tm_to_time(&alarm->time, &t_alm); | ||
| 240 | if (t_now < t_alm) | ||
| 241 | goto done; | ||
| 242 | |||
| 243 | switch (missing) { | ||
| 244 | 142 | ||
| 245 | /* 24 hour rollover ... if it's now 10am Monday, an alarm that | 143 | /* Make sure we're not setting alarms in the past */ |
| 246 | * that will trigger at 5am will do so at 5am Tuesday, which | 144 | err = __rtc_read_time(rtc, &tm); |
| 247 | * could also be in the next month or year. This is a common | 145 | rtc_tm_to_time(&tm, &now); |
| 248 | * case, especially for PCs. | 146 | if (scheduled <= now) |
| 249 | */ | 147 | return -ETIME; |
| 250 | case day: | 148 | /* |
| 251 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); | 149 | * XXX - We just checked to make sure the alarm time is not |
| 252 | t_alm += 24 * 60 * 60; | 150 | * in the past, but there is still a race window where if |
| 253 | rtc_time_to_tm(t_alm, &alarm->time); | 151 | * the is alarm set for the next second and the second ticks |
| 254 | break; | 152 | * over right here, before we set the alarm. |
| 255 | |||
| 256 | /* Month rollover ... if it's the 31th, an alarm on the 3rd will | ||
| 257 | * be next month. An alarm matching on the 30th, 29th, or 28th | ||
| 258 | * may end up in the month after that! Many newer PCs support | ||
| 259 | * this type of alarm. | ||
| 260 | */ | 153 | */ |
| 261 | case month: | ||
| 262 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month"); | ||
| 263 | do { | ||
| 264 | if (alarm->time.tm_mon < 11) | ||
| 265 | alarm->time.tm_mon++; | ||
| 266 | else { | ||
| 267 | alarm->time.tm_mon = 0; | ||
| 268 | alarm->time.tm_year++; | ||
| 269 | } | ||
| 270 | days = rtc_month_days(alarm->time.tm_mon, | ||
| 271 | alarm->time.tm_year); | ||
| 272 | } while (days < alarm->time.tm_mday); | ||
| 273 | break; | ||
| 274 | |||
| 275 | /* Year rollover ... easy except for leap years! */ | ||
| 276 | case year: | ||
| 277 | dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); | ||
| 278 | do { | ||
| 279 | alarm->time.tm_year++; | ||
| 280 | } while (rtc_valid_tm(&alarm->time) != 0); | ||
| 281 | break; | ||
| 282 | |||
| 283 | default: | ||
| 284 | dev_warn(&rtc->dev, "alarm rollover not handled\n"); | ||
| 285 | } | ||
| 286 | 154 | ||
| 287 | done: | 155 | if (!rtc->ops) |
| 288 | return 0; | 156 | err = -ENODEV; |
| 157 | else if (!rtc->ops->set_alarm) | ||
| 158 | err = -EINVAL; | ||
| 159 | else | ||
| 160 | err = rtc->ops->set_alarm(rtc->dev.parent, alarm); | ||
| 161 | |||
| 162 | return err; | ||
| 289 | } | 163 | } |
| 290 | EXPORT_SYMBOL_GPL(rtc_read_alarm); | ||
| 291 | 164 | ||
| 292 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | 165 | int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) |
| 293 | { | 166 | { |
| @@ -300,16 +173,18 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) | |||
| 300 | err = mutex_lock_interruptible(&rtc->ops_lock); | 173 | err = mutex_lock_interruptible(&rtc->ops_lock); |
| 301 | if (err) | 174 | if (err) |
| 302 | return err; | 175 | return err; |
| 303 | 176 | if (rtc->aie_timer.enabled) { | |
| 304 | if (!rtc->ops) | 177 | rtc_timer_remove(rtc, &rtc->aie_timer); |
| 305 | err = -ENODEV; | 178 | rtc->aie_timer.enabled = 0; |
| 306 | else if (!rtc->ops->set_alarm) | 179 | } |
| 307 | err = -EINVAL; | 180 | rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); |
| 308 | else | 181 | rtc->aie_timer.period = ktime_set(0, 0); |
| 309 | err = rtc->ops->set_alarm(rtc->dev.parent, alarm); | 182 | if (alarm->enabled) { |
| 310 | 183 | rtc->aie_timer.enabled = 1; | |
| 184 | rtc_timer_enqueue(rtc, &rtc->aie_timer); | ||
| 185 | } | ||
| 311 | mutex_unlock(&rtc->ops_lock); | 186 | mutex_unlock(&rtc->ops_lock); |
| 312 | return err; | 187 | return 0; |
| 313 | } | 188 | } |
| 314 | EXPORT_SYMBOL_GPL(rtc_set_alarm); | 189 | EXPORT_SYMBOL_GPL(rtc_set_alarm); |
| 315 | 190 | ||
| @@ -319,6 +194,16 @@ int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
| 319 | if (err) | 194 | if (err) |
| 320 | return err; | 195 | return err; |
| 321 | 196 | ||
| 197 | if (rtc->aie_timer.enabled != enabled) { | ||
| 198 | if (enabled) { | ||
| 199 | rtc->aie_timer.enabled = 1; | ||
| 200 | rtc_timer_enqueue(rtc, &rtc->aie_timer); | ||
| 201 | } else { | ||
| 202 | rtc_timer_remove(rtc, &rtc->aie_timer); | ||
| 203 | rtc->aie_timer.enabled = 0; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 322 | if (!rtc->ops) | 207 | if (!rtc->ops) |
| 323 | err = -ENODEV; | 208 | err = -ENODEV; |
| 324 | else if (!rtc->ops->alarm_irq_enable) | 209 | else if (!rtc->ops->alarm_irq_enable) |
| @@ -337,52 +222,53 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled) | |||
| 337 | if (err) | 222 | if (err) |
| 338 | return err; | 223 | return err; |
| 339 | 224 | ||
| 340 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | 225 | /* make sure we're changing state */ |
| 341 | if (enabled == 0 && rtc->uie_irq_active) { | 226 | if (rtc->uie_rtctimer.enabled == enabled) |
| 342 | mutex_unlock(&rtc->ops_lock); | 227 | goto out; |
| 343 | return rtc_dev_update_irq_enable_emul(rtc, enabled); | 228 | |
| 229 | if (enabled) { | ||
| 230 | struct rtc_time tm; | ||
| 231 | ktime_t now, onesec; | ||
| 232 | |||
| 233 | __rtc_read_time(rtc, &tm); | ||
| 234 | onesec = ktime_set(1, 0); | ||
| 235 | now = rtc_tm_to_ktime(tm); | ||
| 236 | rtc->uie_rtctimer.node.expires = ktime_add(now, onesec); | ||
| 237 | rtc->uie_rtctimer.period = ktime_set(1, 0); | ||
| 238 | rtc->uie_rtctimer.enabled = 1; | ||
| 239 | rtc_timer_enqueue(rtc, &rtc->uie_rtctimer); | ||
| 240 | } else { | ||
| 241 | rtc_timer_remove(rtc, &rtc->uie_rtctimer); | ||
| 242 | rtc->uie_rtctimer.enabled = 0; | ||
| 344 | } | 243 | } |
| 345 | #endif | ||
| 346 | |||
| 347 | if (!rtc->ops) | ||
| 348 | err = -ENODEV; | ||
| 349 | else if (!rtc->ops->update_irq_enable) | ||
| 350 | err = -EINVAL; | ||
| 351 | else | ||
| 352 | err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled); | ||
| 353 | 244 | ||
| 245 | out: | ||
| 354 | mutex_unlock(&rtc->ops_lock); | 246 | mutex_unlock(&rtc->ops_lock); |
| 355 | |||
| 356 | #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL | ||
| 357 | /* | ||
| 358 | * Enable emulation if the driver did not provide | ||
| 359 | * the update_irq_enable function pointer or if returned | ||
| 360 | * -EINVAL to signal that it has been configured without | ||
| 361 | * interrupts or that are not available at the moment. | ||
| 362 | */ | ||
| 363 | if (err == -EINVAL) | ||
| 364 | err = rtc_dev_update_irq_enable_emul(rtc, enabled); | ||
| 365 | #endif | ||
| 366 | return err; | 247 | return err; |
| 248 | |||
| 367 | } | 249 | } |
| 368 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); | 250 | EXPORT_SYMBOL_GPL(rtc_update_irq_enable); |
| 369 | 251 | ||
| 252 | |||
| 370 | /** | 253 | /** |
| 371 | * rtc_update_irq - report RTC periodic, alarm, and/or update irqs | 254 | * rtc_handle_legacy_irq - AIE, UIE and PIE event hook |
| 372 | * @rtc: the rtc device | 255 | * @rtc: pointer to the rtc device |
| 373 | * @num: how many irqs are being reported (usually one) | 256 | * |
| 374 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | 257 | * This function is called when an AIE, UIE or PIE mode interrupt |
| 375 | * Context: any | 258 | * has occured (or been emulated). |
| 259 | * | ||
| 260 | * Triggers the registered irq_task function callback. | ||
| 376 | */ | 261 | */ |
| 377 | void rtc_update_irq(struct rtc_device *rtc, | 262 | static void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) |
| 378 | unsigned long num, unsigned long events) | ||
| 379 | { | 263 | { |
| 380 | unsigned long flags; | 264 | unsigned long flags; |
| 381 | 265 | ||
| 266 | /* mark one irq of the appropriate mode */ | ||
| 382 | spin_lock_irqsave(&rtc->irq_lock, flags); | 267 | spin_lock_irqsave(&rtc->irq_lock, flags); |
| 383 | rtc->irq_data = (rtc->irq_data + (num << 8)) | events; | 268 | rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode); |
| 384 | spin_unlock_irqrestore(&rtc->irq_lock, flags); | 269 | spin_unlock_irqrestore(&rtc->irq_lock, flags); |
| 385 | 270 | ||
| 271 | /* call the task func */ | ||
| 386 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 272 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 387 | if (rtc->irq_task) | 273 | if (rtc->irq_task) |
| 388 | rtc->irq_task->func(rtc->irq_task->private_data); | 274 | rtc->irq_task->func(rtc->irq_task->private_data); |
| @@ -391,6 +277,69 @@ void rtc_update_irq(struct rtc_device *rtc, | |||
| 391 | wake_up_interruptible(&rtc->irq_queue); | 277 | wake_up_interruptible(&rtc->irq_queue); |
| 392 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); | 278 | kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); |
| 393 | } | 279 | } |
| 280 | |||
| 281 | |||
| 282 | /** | ||
| 283 | * rtc_aie_update_irq - AIE mode rtctimer hook | ||
| 284 | * @private: pointer to the rtc_device | ||
| 285 | * | ||
| 286 | * This functions is called when the aie_timer expires. | ||
| 287 | */ | ||
| 288 | void rtc_aie_update_irq(void *private) | ||
| 289 | { | ||
| 290 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
| 291 | rtc_handle_legacy_irq(rtc, 1, RTC_AF); | ||
| 292 | } | ||
| 293 | |||
| 294 | |||
| 295 | /** | ||
| 296 | * rtc_uie_update_irq - UIE mode rtctimer hook | ||
| 297 | * @private: pointer to the rtc_device | ||
| 298 | * | ||
| 299 | * This functions is called when the uie_timer expires. | ||
| 300 | */ | ||
| 301 | void rtc_uie_update_irq(void *private) | ||
| 302 | { | ||
| 303 | struct rtc_device *rtc = (struct rtc_device *)private; | ||
| 304 | rtc_handle_legacy_irq(rtc, 1, RTC_UF); | ||
| 305 | } | ||
| 306 | |||
| 307 | |||
| 308 | /** | ||
| 309 | * rtc_pie_update_irq - PIE mode hrtimer hook | ||
| 310 | * @timer: pointer to the pie mode hrtimer | ||
| 311 | * | ||
| 312 | * This function is used to emulate PIE mode interrupts | ||
| 313 | * using an hrtimer. This function is called when the periodic | ||
| 314 | * hrtimer expires. | ||
| 315 | */ | ||
| 316 | enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) | ||
| 317 | { | ||
| 318 | struct rtc_device *rtc; | ||
| 319 | ktime_t period; | ||
| 320 | int count; | ||
| 321 | rtc = container_of(timer, struct rtc_device, pie_timer); | ||
| 322 | |||
| 323 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
| 324 | count = hrtimer_forward_now(timer, period); | ||
| 325 | |||
| 326 | rtc_handle_legacy_irq(rtc, count, RTC_PF); | ||
| 327 | |||
| 328 | return HRTIMER_RESTART; | ||
| 329 | } | ||
| 330 | |||
| 331 | /** | ||
| 332 | * rtc_update_irq - Triggered when a RTC interrupt occurs. | ||
| 333 | * @rtc: the rtc device | ||
| 334 | * @num: how many irqs are being reported (usually one) | ||
| 335 | * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF | ||
| 336 | * Context: any | ||
| 337 | */ | ||
| 338 | void rtc_update_irq(struct rtc_device *rtc, | ||
| 339 | unsigned long num, unsigned long events) | ||
| 340 | { | ||
| 341 | schedule_work(&rtc->irqwork); | ||
| 342 | } | ||
| 394 | EXPORT_SYMBOL_GPL(rtc_update_irq); | 343 | EXPORT_SYMBOL_GPL(rtc_update_irq); |
| 395 | 344 | ||
| 396 | static int __rtc_match(struct device *dev, void *data) | 345 | static int __rtc_match(struct device *dev, void *data) |
| @@ -477,18 +426,20 @@ int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled | |||
| 477 | int err = 0; | 426 | int err = 0; |
| 478 | unsigned long flags; | 427 | unsigned long flags; |
| 479 | 428 | ||
| 480 | if (rtc->ops->irq_set_state == NULL) | ||
| 481 | return -ENXIO; | ||
| 482 | |||
| 483 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 429 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 484 | if (rtc->irq_task != NULL && task == NULL) | 430 | if (rtc->irq_task != NULL && task == NULL) |
| 485 | err = -EBUSY; | 431 | err = -EBUSY; |
| 486 | if (rtc->irq_task != task) | 432 | if (rtc->irq_task != task) |
| 487 | err = -EACCES; | 433 | err = -EACCES; |
| 488 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
| 489 | 434 | ||
| 490 | if (err == 0) | 435 | if (enabled) { |
| 491 | err = rtc->ops->irq_set_state(rtc->dev.parent, enabled); | 436 | ktime_t period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); |
| 437 | hrtimer_start(&rtc->pie_timer, period, HRTIMER_MODE_REL); | ||
| 438 | } else { | ||
| 439 | hrtimer_cancel(&rtc->pie_timer); | ||
| 440 | } | ||
| 441 | rtc->pie_enabled = enabled; | ||
| 442 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
| 492 | 443 | ||
| 493 | return err; | 444 | return err; |
| 494 | } | 445 | } |
| @@ -509,21 +460,194 @@ int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq) | |||
| 509 | int err = 0; | 460 | int err = 0; |
| 510 | unsigned long flags; | 461 | unsigned long flags; |
| 511 | 462 | ||
| 512 | if (rtc->ops->irq_set_freq == NULL) | ||
| 513 | return -ENXIO; | ||
| 514 | |||
| 515 | spin_lock_irqsave(&rtc->irq_task_lock, flags); | 463 | spin_lock_irqsave(&rtc->irq_task_lock, flags); |
| 516 | if (rtc->irq_task != NULL && task == NULL) | 464 | if (rtc->irq_task != NULL && task == NULL) |
| 517 | err = -EBUSY; | 465 | err = -EBUSY; |
| 518 | if (rtc->irq_task != task) | 466 | if (rtc->irq_task != task) |
| 519 | err = -EACCES; | 467 | err = -EACCES; |
| 520 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
| 521 | |||
| 522 | if (err == 0) { | 468 | if (err == 0) { |
| 523 | err = rtc->ops->irq_set_freq(rtc->dev.parent, freq); | 469 | rtc->irq_freq = freq; |
| 524 | if (err == 0) | 470 | if (rtc->pie_enabled) { |
| 525 | rtc->irq_freq = freq; | 471 | ktime_t period; |
| 472 | hrtimer_cancel(&rtc->pie_timer); | ||
| 473 | period = ktime_set(0, NSEC_PER_SEC/rtc->irq_freq); | ||
| 474 | hrtimer_start(&rtc->pie_timer, period, | ||
| 475 | HRTIMER_MODE_REL); | ||
| 476 | } | ||
| 526 | } | 477 | } |
| 478 | spin_unlock_irqrestore(&rtc->irq_task_lock, flags); | ||
| 527 | return err; | 479 | return err; |
| 528 | } | 480 | } |
| 529 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); | 481 | EXPORT_SYMBOL_GPL(rtc_irq_set_freq); |
| 482 | |||
| 483 | /** | ||
| 484 | * rtc_timer_enqueue - Adds a rtc_timer to the rtc_device timerqueue | ||
| 485 | * @rtc rtc device | ||
| 486 | * @timer timer being added. | ||
| 487 | * | ||
| 488 | * Enqueues a timer onto the rtc devices timerqueue and sets | ||
| 489 | * the next alarm event appropriately. | ||
| 490 | * | ||
| 491 | * Must hold ops_lock for proper serialization of timerqueue | ||
| 492 | */ | ||
| 493 | void rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer) | ||
| 494 | { | ||
| 495 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
| 496 | if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) { | ||
| 497 | struct rtc_wkalrm alarm; | ||
| 498 | int err; | ||
| 499 | alarm.time = rtc_ktime_to_tm(timer->node.expires); | ||
| 500 | alarm.enabled = 1; | ||
| 501 | err = __rtc_set_alarm(rtc, &alarm); | ||
| 502 | if (err == -ETIME) | ||
| 503 | schedule_work(&rtc->irqwork); | ||
| 504 | } | ||
| 505 | } | ||
| 506 | |||
| 507 | /** | ||
| 508 | * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue | ||
| 509 | * @rtc rtc device | ||
| 510 | * @timer timer being removed. | ||
| 511 | * | ||
| 512 | * Removes a timer onto the rtc devices timerqueue and sets | ||
| 513 | * the next alarm event appropriately. | ||
| 514 | * | ||
| 515 | * Must hold ops_lock for proper serialization of timerqueue | ||
| 516 | */ | ||
| 517 | void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer) | ||
| 518 | { | ||
| 519 | struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue); | ||
| 520 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
| 521 | |||
| 522 | if (next == &timer->node) { | ||
| 523 | struct rtc_wkalrm alarm; | ||
| 524 | int err; | ||
| 525 | next = timerqueue_getnext(&rtc->timerqueue); | ||
| 526 | if (!next) | ||
| 527 | return; | ||
| 528 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
| 529 | alarm.enabled = 1; | ||
| 530 | err = __rtc_set_alarm(rtc, &alarm); | ||
| 531 | if (err == -ETIME) | ||
| 532 | schedule_work(&rtc->irqwork); | ||
| 533 | } | ||
| 534 | } | ||
| 535 | |||
| 536 | /** | ||
| 537 | * rtc_timer_do_work - Expires rtc timers | ||
| 538 | * @rtc rtc device | ||
| 539 | * @timer timer being removed. | ||
| 540 | * | ||
| 541 | * Expires rtc timers. Reprograms next alarm event if needed. | ||
| 542 | * Called via worktask. | ||
| 543 | * | ||
| 544 | * Serializes access to timerqueue via ops_lock mutex | ||
| 545 | */ | ||
| 546 | void rtc_timer_do_work(struct work_struct *work) | ||
| 547 | { | ||
| 548 | struct rtc_timer *timer; | ||
| 549 | struct timerqueue_node *next; | ||
| 550 | ktime_t now; | ||
| 551 | struct rtc_time tm; | ||
| 552 | |||
| 553 | struct rtc_device *rtc = | ||
| 554 | container_of(work, struct rtc_device, irqwork); | ||
| 555 | |||
| 556 | mutex_lock(&rtc->ops_lock); | ||
| 557 | again: | ||
| 558 | __rtc_read_time(rtc, &tm); | ||
| 559 | now = rtc_tm_to_ktime(tm); | ||
| 560 | while ((next = timerqueue_getnext(&rtc->timerqueue))) { | ||
| 561 | if (next->expires.tv64 > now.tv64) | ||
| 562 | break; | ||
| 563 | |||
| 564 | /* expire timer */ | ||
| 565 | timer = container_of(next, struct rtc_timer, node); | ||
| 566 | timerqueue_del(&rtc->timerqueue, &timer->node); | ||
| 567 | timer->enabled = 0; | ||
| 568 | if (timer->task.func) | ||
| 569 | timer->task.func(timer->task.private_data); | ||
| 570 | |||
| 571 | /* Re-add/fwd periodic timers */ | ||
| 572 | if (ktime_to_ns(timer->period)) { | ||
| 573 | timer->node.expires = ktime_add(timer->node.expires, | ||
| 574 | timer->period); | ||
| 575 | timer->enabled = 1; | ||
| 576 | timerqueue_add(&rtc->timerqueue, &timer->node); | ||
| 577 | } | ||
| 578 | } | ||
| 579 | |||
| 580 | /* Set next alarm */ | ||
| 581 | if (next) { | ||
| 582 | struct rtc_wkalrm alarm; | ||
| 583 | int err; | ||
| 584 | alarm.time = rtc_ktime_to_tm(next->expires); | ||
| 585 | alarm.enabled = 1; | ||
| 586 | err = __rtc_set_alarm(rtc, &alarm); | ||
| 587 | if (err == -ETIME) | ||
| 588 | goto again; | ||
| 589 | } | ||
| 590 | |||
| 591 | mutex_unlock(&rtc->ops_lock); | ||
| 592 | } | ||
| 593 | |||
| 594 | |||
| 595 | /* rtc_timer_init - Initializes an rtc_timer | ||
| 596 | * @timer: timer to be intiialized | ||
| 597 | * @f: function pointer to be called when timer fires | ||
| 598 | * @data: private data passed to function pointer | ||
| 599 | * | ||
| 600 | * Kernel interface to initializing an rtc_timer. | ||
| 601 | */ | ||
| 602 | void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) | ||
| 603 | { | ||
| 604 | timerqueue_init(&timer->node); | ||
| 605 | timer->enabled = 0; | ||
| 606 | timer->task.func = f; | ||
| 607 | timer->task.private_data = data; | ||
| 608 | } | ||
| 609 | |||
| 610 | /* rtc_timer_start - Sets an rtc_timer to fire in the future | ||
| 611 | * @ rtc: rtc device to be used | ||
| 612 | * @ timer: timer being set | ||
| 613 | * @ expires: time at which to expire the timer | ||
| 614 | * @ period: period that the timer will recur | ||
| 615 | * | ||
| 616 | * Kernel interface to set an rtc_timer | ||
| 617 | */ | ||
| 618 | int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, | ||
| 619 | ktime_t expires, ktime_t period) | ||
| 620 | { | ||
| 621 | int ret = 0; | ||
| 622 | mutex_lock(&rtc->ops_lock); | ||
| 623 | if (timer->enabled) | ||
| 624 | rtc_timer_remove(rtc, timer); | ||
| 625 | |||
| 626 | timer->node.expires = expires; | ||
| 627 | timer->period = period; | ||
| 628 | |||
| 629 | timer->enabled = 1; | ||
| 630 | rtc_timer_enqueue(rtc, timer); | ||
| 631 | |||
| 632 | mutex_unlock(&rtc->ops_lock); | ||
| 633 | return ret; | ||
| 634 | } | ||
| 635 | |||
| 636 | /* rtc_timer_cancel - Stops an rtc_timer | ||
| 637 | * @ rtc: rtc device to be used | ||
| 638 | * @ timer: timer being set | ||
| 639 | * | ||
| 640 | * Kernel interface to cancel an rtc_timer | ||
| 641 | */ | ||
| 642 | int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) | ||
| 643 | { | ||
| 644 | int ret = 0; | ||
| 645 | mutex_lock(&rtc->ops_lock); | ||
| 646 | if (timer->enabled) | ||
| 647 | rtc_timer_remove(rtc, timer); | ||
| 648 | timer->enabled = 0; | ||
| 649 | mutex_unlock(&rtc->ops_lock); | ||
| 650 | return ret; | ||
| 651 | } | ||
| 652 | |||
| 653 | |||
