Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Thomas Gleixner: "Rather large, but nothing exiting: - new range check for settimeofday() to prevent that boot time becomes negative. - fix for file time rounding - a few simplifications of the hrtimer code - fix for the proc/timerlist code so the output of clock realtime timers is accurate - more y2038 work - tree wide conversion of clockevent drivers to the new callbacks" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (88 commits) hrtimer: Handle failure of tick_init_highres() gracefully hrtimer: Unconfuse switch_hrtimer_base() a bit hrtimer: Simplify get_target_base() by returning current base hrtimer: Drop return code of hrtimer_switch_to_hres() time: Introduce timespec64_to_jiffies()/jiffies_to_timespec64() time: Introduce current_kernel_time64() time: Introduce struct itimerspec64 time: Add the common weak version of update_persistent_clock() time: Always make sure wall_to_monotonic isn't positive time: Fix nanosecond file time rounding in timespec_trunc() timer_list: Add the base offset so remaining nsecs are accurate for non monotonic timers cris/time: Migrate to new 'set-state' interface kernel: broadcast-hrtimer: Migrate to new 'set-state' interface xtensa/time: Migrate to new 'set-state' interface unicore/time: Migrate to new 'set-state' interface um/time: Migrate to new 'set-state' interface sparc/time: Migrate to new 'set-state' interface sh/localtimer: Migrate to new 'set-state' interface score/time: Migrate to new 'set-state' interface s390/time: Migrate to new 'set-state' interface ...
This commit is contained in:
@@ -183,7 +183,7 @@ struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
|
||||
int pinned)
|
||||
{
|
||||
if (pinned || !base->migration_enabled)
|
||||
return this_cpu_ptr(&hrtimer_bases);
|
||||
return base;
|
||||
return &per_cpu(hrtimer_bases, get_nohz_timer_target());
|
||||
}
|
||||
#else
|
||||
@@ -191,23 +191,32 @@ static inline
|
||||
struct hrtimer_cpu_base *get_target_base(struct hrtimer_cpu_base *base,
|
||||
int pinned)
|
||||
{
|
||||
return this_cpu_ptr(&hrtimer_bases);
|
||||
return base;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Switch the timer base to the current CPU when possible.
|
||||
* We switch the timer base to a power-optimized selected CPU target,
|
||||
* if:
|
||||
* - NO_HZ_COMMON is enabled
|
||||
* - timer migration is enabled
|
||||
* - the timer callback is not running
|
||||
* - the timer is not the first expiring timer on the new target
|
||||
*
|
||||
* If one of the above requirements is not fulfilled we move the timer
|
||||
* to the current CPU or leave it on the previously assigned CPU if
|
||||
* the timer callback is currently running.
|
||||
*/
|
||||
static inline struct hrtimer_clock_base *
|
||||
switch_hrtimer_base(struct hrtimer *timer, struct hrtimer_clock_base *base,
|
||||
int pinned)
|
||||
{
|
||||
struct hrtimer_cpu_base *new_cpu_base, *this_base;
|
||||
struct hrtimer_cpu_base *new_cpu_base, *this_cpu_base;
|
||||
struct hrtimer_clock_base *new_base;
|
||||
int basenum = base->index;
|
||||
|
||||
this_base = this_cpu_ptr(&hrtimer_bases);
|
||||
new_cpu_base = get_target_base(this_base, pinned);
|
||||
this_cpu_base = this_cpu_ptr(&hrtimer_bases);
|
||||
new_cpu_base = get_target_base(this_cpu_base, pinned);
|
||||
again:
|
||||
new_base = &new_cpu_base->clock_base[basenum];
|
||||
|
||||
@@ -229,19 +238,19 @@ again:
|
||||
raw_spin_unlock(&base->cpu_base->lock);
|
||||
raw_spin_lock(&new_base->cpu_base->lock);
|
||||
|
||||
if (new_cpu_base != this_base &&
|
||||
if (new_cpu_base != this_cpu_base &&
|
||||
hrtimer_check_target(timer, new_base)) {
|
||||
raw_spin_unlock(&new_base->cpu_base->lock);
|
||||
raw_spin_lock(&base->cpu_base->lock);
|
||||
new_cpu_base = this_base;
|
||||
new_cpu_base = this_cpu_base;
|
||||
timer->base = base;
|
||||
goto again;
|
||||
}
|
||||
timer->base = new_base;
|
||||
} else {
|
||||
if (new_cpu_base != this_base &&
|
||||
if (new_cpu_base != this_cpu_base &&
|
||||
hrtimer_check_target(timer, new_base)) {
|
||||
new_cpu_base = this_base;
|
||||
new_cpu_base = this_cpu_base;
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
@@ -679,14 +688,14 @@ static void retrigger_next_event(void *arg)
|
||||
/*
|
||||
* Switch to high resolution mode
|
||||
*/
|
||||
static int hrtimer_switch_to_hres(void)
|
||||
static void hrtimer_switch_to_hres(void)
|
||||
{
|
||||
struct hrtimer_cpu_base *base = this_cpu_ptr(&hrtimer_bases);
|
||||
|
||||
if (tick_init_highres()) {
|
||||
printk(KERN_WARNING "Could not switch to high resolution "
|
||||
"mode on CPU %d\n", base->cpu);
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
base->hres_active = 1;
|
||||
hrtimer_resolution = HIGH_RES_NSEC;
|
||||
@@ -694,7 +703,6 @@ static int hrtimer_switch_to_hres(void)
|
||||
tick_setup_sched_timer();
|
||||
/* "Retrigger" the interrupt to get things going */
|
||||
retrigger_next_event(NULL);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void clock_was_set_work(struct work_struct *work)
|
||||
@@ -718,7 +726,7 @@ void clock_was_set_delayed(void)
|
||||
static inline int __hrtimer_hres_active(struct hrtimer_cpu_base *b) { return 0; }
|
||||
static inline int hrtimer_hres_active(void) { return 0; }
|
||||
static inline int hrtimer_is_hres_enabled(void) { return 0; }
|
||||
static inline int hrtimer_switch_to_hres(void) { return 0; }
|
||||
static inline void hrtimer_switch_to_hres(void) { }
|
||||
static inline void
|
||||
hrtimer_force_reprogram(struct hrtimer_cpu_base *base, int skip_equal) { }
|
||||
static inline int hrtimer_reprogram(struct hrtimer *timer,
|
||||
|
@@ -487,6 +487,11 @@ out:
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_CMOS_UPDATE
|
||||
int __weak update_persistent_clock(struct timespec now)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
int __weak update_persistent_clock64(struct timespec64 now64)
|
||||
{
|
||||
struct timespec now;
|
||||
|
@@ -18,30 +18,23 @@
|
||||
|
||||
static struct hrtimer bctimer;
|
||||
|
||||
static void bc_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *bc)
|
||||
static int bc_shutdown(struct clock_event_device *evt)
|
||||
{
|
||||
switch (mode) {
|
||||
case CLOCK_EVT_MODE_UNUSED:
|
||||
case CLOCK_EVT_MODE_SHUTDOWN:
|
||||
/*
|
||||
* Note, we cannot cancel the timer here as we might
|
||||
* run into the following live lock scenario:
|
||||
*
|
||||
* cpu 0 cpu1
|
||||
* lock(broadcast_lock);
|
||||
* hrtimer_interrupt()
|
||||
* bc_handler()
|
||||
* tick_handle_oneshot_broadcast();
|
||||
* lock(broadcast_lock);
|
||||
* hrtimer_cancel()
|
||||
* wait_for_callback()
|
||||
*/
|
||||
hrtimer_try_to_cancel(&bctimer);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* Note, we cannot cancel the timer here as we might
|
||||
* run into the following live lock scenario:
|
||||
*
|
||||
* cpu 0 cpu1
|
||||
* lock(broadcast_lock);
|
||||
* hrtimer_interrupt()
|
||||
* bc_handler()
|
||||
* tick_handle_oneshot_broadcast();
|
||||
* lock(broadcast_lock);
|
||||
* hrtimer_cancel()
|
||||
* wait_for_callback()
|
||||
*/
|
||||
hrtimer_try_to_cancel(&bctimer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -82,7 +75,7 @@ static int bc_set_next(ktime_t expires, struct clock_event_device *bc)
|
||||
}
|
||||
|
||||
static struct clock_event_device ce_broadcast_hrtimer = {
|
||||
.set_mode = bc_set_mode,
|
||||
.set_state_shutdown = bc_shutdown,
|
||||
.set_next_ktime = bc_set_next,
|
||||
.features = CLOCK_EVT_FEAT_ONESHOT |
|
||||
CLOCK_EVT_FEAT_KTIME |
|
||||
@@ -102,13 +95,11 @@ static enum hrtimer_restart bc_handler(struct hrtimer *t)
|
||||
{
|
||||
ce_broadcast_hrtimer.event_handler(&ce_broadcast_hrtimer);
|
||||
|
||||
switch (ce_broadcast_hrtimer.mode) {
|
||||
case CLOCK_EVT_MODE_ONESHOT:
|
||||
if (clockevent_state_oneshot(&ce_broadcast_hrtimer))
|
||||
if (ce_broadcast_hrtimer.next_event.tv64 != KTIME_MAX)
|
||||
return HRTIMER_RESTART;
|
||||
default:
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
void tick_setup_hrtimer_broadcast(void)
|
||||
|
@@ -304,9 +304,6 @@ void tick_check_new_device(struct clock_event_device *newdev)
|
||||
int cpu;
|
||||
|
||||
cpu = smp_processor_id();
|
||||
if (!cpumask_test_cpu(cpu, newdev->cpumask))
|
||||
goto out_bc;
|
||||
|
||||
td = &per_cpu(tick_cpu_device, cpu);
|
||||
curdev = td->evtdev;
|
||||
|
||||
|
@@ -291,26 +291,20 @@ EXPORT_SYMBOL(jiffies_to_usecs);
|
||||
* @t: Timespec
|
||||
* @gran: Granularity in ns.
|
||||
*
|
||||
* Truncate a timespec to a granularity. gran must be smaller than a second.
|
||||
* Always rounds down.
|
||||
*
|
||||
* This function should be only used for timestamps returned by
|
||||
* current_kernel_time() or CURRENT_TIME, not with do_gettimeofday() because
|
||||
* it doesn't handle the better resolution of the latter.
|
||||
* Truncate a timespec to a granularity. Always rounds down. gran must
|
||||
* not be 0 nor greater than a second (NSEC_PER_SEC, or 10^9 ns).
|
||||
*/
|
||||
struct timespec timespec_trunc(struct timespec t, unsigned gran)
|
||||
{
|
||||
/*
|
||||
* Division is pretty slow so avoid it for common cases.
|
||||
* Currently current_kernel_time() never returns better than
|
||||
* jiffies resolution. Exploit that.
|
||||
*/
|
||||
if (gran <= jiffies_to_usecs(1) * 1000) {
|
||||
/* Avoid division in the common cases 1 ns and 1 s. */
|
||||
if (gran == 1) {
|
||||
/* nothing */
|
||||
} else if (gran == 1000000000) {
|
||||
} else if (gran == NSEC_PER_SEC) {
|
||||
t.tv_nsec = 0;
|
||||
} else {
|
||||
} else if (gran > 1 && gran < NSEC_PER_SEC) {
|
||||
t.tv_nsec -= t.tv_nsec % gran;
|
||||
} else {
|
||||
WARN(1, "illegal file time granularity: %u", gran);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -550,7 +544,7 @@ EXPORT_SYMBOL(__usecs_to_jiffies);
|
||||
* value to a scaled second value.
|
||||
*/
|
||||
static unsigned long
|
||||
__timespec_to_jiffies(unsigned long sec, long nsec)
|
||||
__timespec64_to_jiffies(u64 sec, long nsec)
|
||||
{
|
||||
nsec = nsec + TICK_NSEC - 1;
|
||||
|
||||
@@ -558,22 +552,27 @@ __timespec_to_jiffies(unsigned long sec, long nsec)
|
||||
sec = MAX_SEC_IN_JIFFIES;
|
||||
nsec = 0;
|
||||
}
|
||||
return (((u64)sec * SEC_CONVERSION) +
|
||||
return ((sec * SEC_CONVERSION) +
|
||||
(((u64)nsec * NSEC_CONVERSION) >>
|
||||
(NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
|
||||
|
||||
}
|
||||
|
||||
unsigned long
|
||||
timespec_to_jiffies(const struct timespec *value)
|
||||
static unsigned long
|
||||
__timespec_to_jiffies(unsigned long sec, long nsec)
|
||||
{
|
||||
return __timespec_to_jiffies(value->tv_sec, value->tv_nsec);
|
||||
return __timespec64_to_jiffies((u64)sec, nsec);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(timespec_to_jiffies);
|
||||
unsigned long
|
||||
timespec64_to_jiffies(const struct timespec64 *value)
|
||||
{
|
||||
return __timespec64_to_jiffies(value->tv_sec, value->tv_nsec);
|
||||
}
|
||||
EXPORT_SYMBOL(timespec64_to_jiffies);
|
||||
|
||||
void
|
||||
jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
|
||||
jiffies_to_timespec64(const unsigned long jiffies, struct timespec64 *value)
|
||||
{
|
||||
/*
|
||||
* Convert jiffies to nanoseconds and separate with
|
||||
@@ -584,7 +583,7 @@ jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
|
||||
NSEC_PER_SEC, &rem);
|
||||
value->tv_nsec = rem;
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_timespec);
|
||||
EXPORT_SYMBOL(jiffies_to_timespec64);
|
||||
|
||||
/*
|
||||
* We could use a similar algorithm to timespec_to_jiffies (with a
|
||||
|
@@ -911,6 +911,7 @@ int do_settimeofday64(const struct timespec64 *ts)
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
struct timespec64 ts_delta, xt;
|
||||
unsigned long flags;
|
||||
int ret = 0;
|
||||
|
||||
if (!timespec64_valid_strict(ts))
|
||||
return -EINVAL;
|
||||
@@ -924,10 +925,15 @@ int do_settimeofday64(const struct timespec64 *ts)
|
||||
ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
|
||||
ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
|
||||
|
||||
if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
|
||||
|
||||
tk_set_xtime(tk, ts);
|
||||
|
||||
out:
|
||||
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
|
||||
|
||||
write_seqcount_end(&tk_core.seq);
|
||||
@@ -936,7 +942,7 @@ int do_settimeofday64(const struct timespec64 *ts)
|
||||
/* signal hrtimers about time change */
|
||||
clock_was_set();
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(do_settimeofday64);
|
||||
|
||||
@@ -965,7 +971,8 @@ int timekeeping_inject_offset(struct timespec *ts)
|
||||
|
||||
/* Make sure the proposed value is valid */
|
||||
tmp = timespec64_add(tk_xtime(tk), ts64);
|
||||
if (!timespec64_valid_strict(&tmp)) {
|
||||
if (timespec64_compare(&tk->wall_to_monotonic, &ts64) > 0 ||
|
||||
!timespec64_valid_strict(&tmp)) {
|
||||
ret = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
@@ -1874,7 +1881,7 @@ struct timespec __current_kernel_time(void)
|
||||
return timespec64_to_timespec(tk_xtime(tk));
|
||||
}
|
||||
|
||||
struct timespec current_kernel_time(void)
|
||||
struct timespec64 current_kernel_time64(void)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
struct timespec64 now;
|
||||
@@ -1886,9 +1893,9 @@ struct timespec current_kernel_time(void)
|
||||
now = tk_xtime(tk);
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
return timespec64_to_timespec(now);
|
||||
return now;
|
||||
}
|
||||
EXPORT_SYMBOL(current_kernel_time);
|
||||
EXPORT_SYMBOL(current_kernel_time64);
|
||||
|
||||
struct timespec64 get_monotonic_coarse64(void)
|
||||
{
|
||||
|
@@ -137,7 +137,7 @@ print_base(struct seq_file *m, struct hrtimer_clock_base *base, u64 now)
|
||||
(unsigned long long) ktime_to_ns(base->offset));
|
||||
#endif
|
||||
SEQ_printf(m, "active timers:\n");
|
||||
print_active_timers(m, base, now);
|
||||
print_active_timers(m, base, now + ktime_to_ns(base->offset));
|
||||
}
|
||||
|
||||
static void print_cpu(struct seq_file *m, int cpu, u64 now)
|
||||
|
Reference in New Issue
Block a user