--- zzzz-none-000/linux-3.10.107/drivers/rtc/interface.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/rtc/interface.c 2021-02-04 17:41:59.000000000 +0000 @@ -30,6 +30,15 @@ else { memset(tm, 0, sizeof(struct rtc_time)); err = rtc->ops->read_time(rtc->dev.parent, tm); + if (err < 0) { + dev_dbg(&rtc->dev, "read_time: fail to read: %d\n", + err); + return err; + } + + err = rtc_valid_tm(tm); + if (err < 0) + dev_dbg(&rtc->dev, "read_time: rtc_time isn't valid\n"); } return err; } @@ -64,14 +73,17 @@ err = -ENODEV; else if (rtc->ops->set_time) err = rtc->ops->set_time(rtc->dev.parent, tm); - else if (rtc->ops->set_mmss) { - unsigned long secs; - err = rtc_tm_to_time(tm, &secs); - if (err == 0) - err = rtc->ops->set_mmss(rtc->dev.parent, secs); + else if (rtc->ops->set_mmss64) { + time64_t secs64 = rtc_tm_to_time64(tm); + + err = rtc->ops->set_mmss64(rtc->dev.parent, secs64); + } else if (rtc->ops->set_mmss) { + time64_t secs64 = rtc_tm_to_time64(tm); + err = rtc->ops->set_mmss(rtc->dev.parent, secs64); } else err = -EINVAL; + pm_stay_awake(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); /* A timer might have just expired */ schedule_work(&rtc->irqwork); @@ -79,48 +91,6 @@ } EXPORT_SYMBOL_GPL(rtc_set_time); -int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs) -{ - int err; - - err = mutex_lock_interruptible(&rtc->ops_lock); - if (err) - return err; - - if (!rtc->ops) - err = -ENODEV; - else if (rtc->ops->set_mmss) - err = rtc->ops->set_mmss(rtc->dev.parent, secs); - else if (rtc->ops->read_time && rtc->ops->set_time) { - struct rtc_time new, old; - - err = rtc->ops->read_time(rtc->dev.parent, &old); - if (err == 0) { - rtc_time_to_tm(secs, &new); - - /* - * avoid writing when we're going to change the day of - * the month. We will retry in the next minute. This - * basically means that if the RTC must not drift - * by more than 1 minute in 11 minutes. - */ - if (!((old.tm_hour == 23 && old.tm_min == 59) || - (new.tm_hour == 23 && new.tm_min == 59))) - err = rtc->ops->set_time(rtc->dev.parent, - &new); - } - } - else - err = -EINVAL; - - mutex_unlock(&rtc->ops_lock); - /* A timer might have just expired */ - schedule_work(&rtc->irqwork); - - return err; -} -EXPORT_SYMBOL_GPL(rtc_set_mmss); - static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { int err; @@ -147,7 +117,7 @@ int err; struct rtc_time before, now; int first_time = 1; - unsigned long t_now, t_alm; + time64_t t_now, t_alm; enum { none, day, month, year } missing = none; unsigned days; @@ -248,8 +218,8 @@ } /* with luck, no rollover is needed */ - rtc_tm_to_time(&now, &t_now); - rtc_tm_to_time(&alarm->time, &t_alm); + t_now = rtc_tm_to_time64(&now); + t_alm = rtc_tm_to_time64(&alarm->time); if (t_now < t_alm) goto done; @@ -263,7 +233,7 @@ case day: dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day"); t_alm += 24 * 60 * 60; - rtc_time_to_tm(t_alm, &alarm->time); + rtc_time64_to_tm(t_alm, &alarm->time); break; /* Month rollover ... if it's the 31th, an alarm on the 3rd will @@ -290,7 +260,8 @@ dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year"); do { alarm->time.tm_year++; - } while (rtc_valid_tm(&alarm->time) != 0); + } while (!is_leap_year(alarm->time.tm_year + 1900) + && rtc_valid_tm(&alarm->time) != 0); break; default: @@ -298,7 +269,16 @@ } done: - return 0; + err = rtc_valid_tm(&alarm->time); + + if (err) { + dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", + alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, + alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, + alarm->time.tm_sec); + } + + return err; } int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -326,17 +306,19 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { struct rtc_time tm; - long now, scheduled; + time64_t now, scheduled; int err; err = rtc_valid_tm(&alarm->time); if (err) return err; - rtc_tm_to_time(&alarm->time, &scheduled); + scheduled = rtc_tm_to_time64(&alarm->time); /* Make sure we're not setting alarms in the past */ err = __rtc_read_time(rtc, &tm); - rtc_tm_to_time(&tm, &now); + if (err) + return err; + now = rtc_tm_to_time64(&tm); if (scheduled <= now) return -ETIME; /* @@ -367,19 +349,27 @@ err = mutex_lock_interruptible(&rtc->ops_lock); if (err) return err; - if (rtc->aie_timer.enabled) { + if (rtc->aie_timer.enabled) rtc_timer_remove(rtc, &rtc->aie_timer); - } + rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time); rtc->aie_timer.period = ktime_set(0, 0); - if (alarm->enabled) { + if (alarm->enabled) err = rtc_timer_enqueue(rtc, &rtc->aie_timer); - } + mutex_unlock(&rtc->ops_lock); return err; } EXPORT_SYMBOL_GPL(rtc_set_alarm); +static void rtc_alarm_disable(struct rtc_device *rtc) +{ + if (!rtc->ops || !rtc->ops->alarm_irq_enable) + return; + + rtc->ops->alarm_irq_enable(rtc->dev.parent, false); +} + /* Called once per device from rtc_device_register */ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) { @@ -407,7 +397,11 @@ rtc->aie_timer.enabled = 1; timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node); + } else if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 >= + rtc->aie_timer.node.expires.tv64)){ + rtc_alarm_disable(rtc); } + mutex_unlock(&rtc->ops_lock); return err; } @@ -582,6 +576,9 @@ void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { + if (IS_ERR_OR_NULL(rtc)) + return; + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); } @@ -698,9 +695,9 @@ spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; - if (rtc->irq_task != task) + else if (rtc->irq_task != task) err = -EACCES; - if (!err) { + else { if (rtc_update_hrtimer(rtc, enabled) < 0) { spin_unlock_irqrestore(&rtc->irq_task_lock, flags); cpu_relax(); @@ -734,9 +731,9 @@ spin_lock_irqsave(&rtc->irq_task_lock, flags); if (rtc->irq_task != NULL && task == NULL) err = -EBUSY; - if (rtc->irq_task != task) + else if (rtc->irq_task != task) err = -EACCES; - if (!err) { + else { rtc->irq_freq = freq; if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) { spin_unlock_irqrestore(&rtc->irq_task_lock, flags); @@ -785,9 +782,10 @@ alarm.time = rtc_ktime_to_tm(timer->node.expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); - else if (err) { + } else if (err) { timerqueue_del(&rtc->timerqueue, &timer->node); timer->enabled = 0; return err; @@ -796,14 +794,6 @@ return 0; } -static void rtc_alarm_disable(struct rtc_device *rtc) -{ - if (!rtc->ops || !rtc->ops->alarm_irq_enable) - return; - - rtc->ops->alarm_irq_enable(rtc->dev.parent, false); -} - /** * rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue * @rtc rtc device @@ -832,8 +822,10 @@ alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; err = __rtc_set_alarm(rtc, &alarm); - if (err == -ETIME) + if (err == -ETIME) { + pm_stay_awake(rtc->dev.parent); schedule_work(&rtc->irqwork); + } } } @@ -859,7 +851,6 @@ mutex_lock(&rtc->ops_lock); again: - pm_relax(rtc->dev.parent); __rtc_read_time(rtc, &tm); now = rtc_tm_to_ktime(tm); while ((next = timerqueue_getnext(&rtc->timerqueue))) { @@ -886,14 +877,28 @@ if (next) { struct rtc_wkalrm alarm; int err; + int retry = 3; + alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; +reprogram: err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; + else if (err) { + if (retry-- > 0) + goto reprogram; + + timer = container_of(next, struct rtc_timer, node); + timerqueue_del(&rtc->timerqueue, &timer->node); + timer->enabled = 0; + dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err); + goto again; + } } else rtc_alarm_disable(rtc); + pm_relax(rtc->dev.parent); mutex_unlock(&rtc->ops_lock); } @@ -905,7 +910,7 @@ * * Kernel interface to initializing an rtc_timer. */ -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data) +void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) { timerqueue_init(&timer->node); timer->enabled = 0; @@ -921,7 +926,7 @@ * * Kernel interface to set an rtc_timer */ -int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer, +int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ktime_t expires, ktime_t period) { int ret = 0; @@ -944,14 +949,12 @@ * * Kernel interface to cancel an rtc_timer */ -int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer) +void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer) { - int ret = 0; mutex_lock(&rtc->ops_lock); if (timer->enabled) rtc_timer_remove(rtc, timer); mutex_unlock(&rtc->ops_lock); - return ret; }