Merge branch 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: clockevents: Set noop handler in clockevents_exchange_device() tick-broadcast: Stop active broadcast device when replacing it clocksource: Fix bug with max_deferment margin calculation rtc: Fix some bugs that allowed accumulating time drift in suspend/resume rtc: Disable the alarm in the hardware
This commit is contained in:
commit
40c043b077
|
@ -63,7 +63,7 @@ static int rtc_suspend(struct device *dev, pm_message_t mesg)
|
||||||
*/
|
*/
|
||||||
delta = timespec_sub(old_system, old_rtc);
|
delta = timespec_sub(old_system, old_rtc);
|
||||||
delta_delta = timespec_sub(delta, old_delta);
|
delta_delta = timespec_sub(delta, old_delta);
|
||||||
if (abs(delta_delta.tv_sec) >= 2) {
|
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
|
||||||
/*
|
/*
|
||||||
* if delta_delta is too large, assume time correction
|
* if delta_delta is too large, assume time correction
|
||||||
* has occured and set old_delta to the current delta.
|
* has occured and set old_delta to the current delta.
|
||||||
|
@ -97,9 +97,8 @@ static int rtc_resume(struct device *dev)
|
||||||
rtc_tm_to_time(&tm, &new_rtc.tv_sec);
|
rtc_tm_to_time(&tm, &new_rtc.tv_sec);
|
||||||
new_rtc.tv_nsec = 0;
|
new_rtc.tv_nsec = 0;
|
||||||
|
|
||||||
if (new_rtc.tv_sec <= old_rtc.tv_sec) {
|
if (new_rtc.tv_sec < old_rtc.tv_sec) {
|
||||||
if (new_rtc.tv_sec < old_rtc.tv_sec)
|
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
|
||||||
pr_debug("%s: time travel!\n", dev_name(&rtc->dev));
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +115,8 @@ static int rtc_resume(struct device *dev)
|
||||||
sleep_time = timespec_sub(sleep_time,
|
sleep_time = timespec_sub(sleep_time,
|
||||||
timespec_sub(new_system, old_system));
|
timespec_sub(new_system, old_system));
|
||||||
|
|
||||||
timekeeping_inject_sleeptime(&sleep_time);
|
if (sleep_time.tv_sec >= 0)
|
||||||
|
timekeeping_inject_sleeptime(&sleep_time);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -319,6 +319,20 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
||||||
|
|
||||||
|
static int ___rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (!rtc->ops)
|
||||||
|
err = -ENODEV;
|
||||||
|
else if (!rtc->ops->set_alarm)
|
||||||
|
err = -EINVAL;
|
||||||
|
else
|
||||||
|
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
{
|
{
|
||||||
struct rtc_time tm;
|
struct rtc_time tm;
|
||||||
|
@ -342,14 +356,7 @@ static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
* over right here, before we set the alarm.
|
* over right here, before we set the alarm.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!rtc->ops)
|
return ___rtc_set_alarm(rtc, alarm);
|
||||||
err = -ENODEV;
|
|
||||||
else if (!rtc->ops->set_alarm)
|
|
||||||
err = -EINVAL;
|
|
||||||
else
|
|
||||||
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||||
|
@ -763,6 +770,20 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void rtc_alarm_disable(struct rtc_device *rtc)
|
||||||
|
{
|
||||||
|
struct rtc_wkalrm alarm;
|
||||||
|
struct rtc_time tm;
|
||||||
|
|
||||||
|
__rtc_read_time(rtc, &tm);
|
||||||
|
|
||||||
|
alarm.time = rtc_ktime_to_tm(ktime_add(rtc_tm_to_ktime(tm),
|
||||||
|
ktime_set(300, 0)));
|
||||||
|
alarm.enabled = 0;
|
||||||
|
|
||||||
|
___rtc_set_alarm(rtc, &alarm);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
|
* rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
|
||||||
* @rtc rtc device
|
* @rtc rtc device
|
||||||
|
@ -784,8 +805,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||||
struct rtc_wkalrm alarm;
|
struct rtc_wkalrm alarm;
|
||||||
int err;
|
int err;
|
||||||
next = timerqueue_getnext(&rtc->timerqueue);
|
next = timerqueue_getnext(&rtc->timerqueue);
|
||||||
if (!next)
|
if (!next) {
|
||||||
|
rtc_alarm_disable(rtc);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
alarm.time = rtc_ktime_to_tm(next->expires);
|
alarm.time = rtc_ktime_to_tm(next->expires);
|
||||||
alarm.enabled = 1;
|
alarm.enabled = 1;
|
||||||
err = __rtc_set_alarm(rtc, &alarm);
|
err = __rtc_set_alarm(rtc, &alarm);
|
||||||
|
@ -847,7 +870,8 @@ again:
|
||||||
err = __rtc_set_alarm(rtc, &alarm);
|
err = __rtc_set_alarm(rtc, &alarm);
|
||||||
if (err == -ETIME)
|
if (err == -ETIME)
|
||||||
goto again;
|
goto again;
|
||||||
}
|
} else
|
||||||
|
rtc_alarm_disable(rtc);
|
||||||
|
|
||||||
mutex_unlock(&rtc->ops_lock);
|
mutex_unlock(&rtc->ops_lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -387,6 +387,7 @@ void clockevents_exchange_device(struct clock_event_device *old,
|
||||||
* released list and do a notify add later.
|
* released list and do a notify add later.
|
||||||
*/
|
*/
|
||||||
if (old) {
|
if (old) {
|
||||||
|
old->event_handler = clockevents_handle_noop;
|
||||||
clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
|
clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
|
||||||
list_del(&old->list);
|
list_del(&old->list);
|
||||||
list_add(&old->list, &clockevents_released);
|
list_add(&old->list, &clockevents_released);
|
||||||
|
|
|
@ -548,7 +548,7 @@ static u64 clocksource_max_deferment(struct clocksource *cs)
|
||||||
* note a margin of 12.5% is used because this can be computed with
|
* note a margin of 12.5% is used because this can be computed with
|
||||||
* a shift, versus say 10% which would require division.
|
* a shift, versus say 10% which would require division.
|
||||||
*/
|
*/
|
||||||
return max_nsecs - (max_nsecs >> 5);
|
return max_nsecs - (max_nsecs >> 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
|
#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
|
||||||
|
@ -669,7 +669,7 @@ void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||||
* ~ 0.06ppm granularity for NTP. We apply the same 12.5%
|
* ~ 0.06ppm granularity for NTP. We apply the same 12.5%
|
||||||
* margin as we do in clocksource_max_deferment()
|
* margin as we do in clocksource_max_deferment()
|
||||||
*/
|
*/
|
||||||
sec = (cs->mask - (cs->mask >> 5));
|
sec = (cs->mask - (cs->mask >> 3));
|
||||||
do_div(sec, freq);
|
do_div(sec, freq);
|
||||||
do_div(sec, scale);
|
do_div(sec, scale);
|
||||||
if (!sec)
|
if (!sec)
|
||||||
|
|
|
@ -71,7 +71,7 @@ int tick_check_broadcast_device(struct clock_event_device *dev)
|
||||||
(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clockevents_exchange_device(NULL, dev);
|
clockevents_exchange_device(tick_broadcast_device.evtdev, dev);
|
||||||
tick_broadcast_device.evtdev = dev;
|
tick_broadcast_device.evtdev = dev;
|
||||||
if (!cpumask_empty(tick_get_broadcast_mask()))
|
if (!cpumask_empty(tick_get_broadcast_mask()))
|
||||||
tick_broadcast_start_periodic(dev);
|
tick_broadcast_start_periodic(dev);
|
||||||
|
|
Loading…
Reference in a new issue