Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer and time updates from Thomas Gleixner: "A rather large update of timers, timekeeping & co - Core timekeeping code is year-2038 safe now for 32bit machines. Now we just need to fix all in kernel users and the gazillion of user space interfaces which rely on timespec/timeval :) - Better cache layout for the timekeeping internal data structures. - Proper nanosecond based interfaces for in kernel users. - Tree wide cleanup of code which wants nanoseconds but does hoops and loops to convert back and forth from timespecs. Some of it definitely belongs into the ugly code museum. - Consolidation of the timekeeping interface zoo. - A fast NMI safe accessor to clock monotonic for tracing. This is a long standing request to support correlated user/kernel space traces. With proper NTP frequency correction it's also suitable for correlation of traces accross separate machines. - Checkpoint/restart support for timerfd. - A few NOHZ[_FULL] improvements in the [hr]timer code. - Code move from kernel to kernel/time of all time* related code. - New clocksource/event drivers from the ARM universe. I'm really impressed that despite an architected timer in the newer chips SoC manufacturers insist on inventing new and differently broken SoC specific timers. [ Ed. "Impressed"? I don't think that word means what you think it means ] - Another round of code move from arch to drivers. Looks like most of the legacy mess in ARM regarding timers is sorted out except for a few obnoxious strongholds. - The usual updates and fixlets all over the place" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (114 commits) timekeeping: Fixup typo in update_vsyscall_old definition clocksource: document some basic timekeeping concepts timekeeping: Use cached ntp_tick_length when accumulating error timekeeping: Rework frequency adjustments to work better w/ nohz timekeeping: Minor fixup for timespec64->timespec assignment ftrace: Provide trace clocks monotonic timekeeping: Provide fast and NMI safe access to CLOCK_MONOTONIC seqcount: Add raw_write_seqcount_latch() seqcount: Provide raw_read_seqcount() timekeeping: Use tk_read_base as argument for timekeeping_get_ns() timekeeping: Create struct tk_read_base and use it in struct timekeeper timekeeping: Restructure the timekeeper some more clocksource: Get rid of cycle_last clocksource: Move cycle_last validation to core code clocksource: Make delta calculation a function wireless: ath9k: Get rid of timespec conversions drm: vmwgfx: Use nsec based interfaces drm: i915: Use nsec based interfaces timekeeping: Provide ktime_get_raw() hangcheck-timer: Use ktime_get_ns() ...
This commit is contained in:
@@ -12,6 +12,11 @@ config CLOCKSOURCE_WATCHDOG
|
||||
config ARCH_CLOCKSOURCE_DATA
|
||||
bool
|
||||
|
||||
# Clocksources require validation of the clocksource against the last
|
||||
# cycle update - x86/TSC misfeature
|
||||
config CLOCKSOURCE_VALIDATE_LAST_CYCLE
|
||||
bool
|
||||
|
||||
# Timekeeping vsyscall support
|
||||
config GENERIC_TIME_VSYSCALL
|
||||
bool
|
||||
@@ -20,10 +25,6 @@ config GENERIC_TIME_VSYSCALL
|
||||
config GENERIC_TIME_VSYSCALL_OLD
|
||||
bool
|
||||
|
||||
# ktime_t scalar 64bit nsec representation
|
||||
config KTIME_SCALAR
|
||||
bool
|
||||
|
||||
# Old style timekeeping
|
||||
config ARCH_USES_GETTIMEOFFSET
|
||||
bool
|
||||
|
@@ -1,3 +1,4 @@
|
||||
obj-y += time.o timer.o hrtimer.o itimer.o posix-timers.o posix-cpu-timers.o
|
||||
obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o
|
||||
obj-y += timeconv.o posix-clock.o alarmtimer.o
|
||||
|
||||
@@ -12,3 +13,21 @@ obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
|
||||
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
|
||||
obj-$(CONFIG_TIMER_STATS) += timer_stats.o
|
||||
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
|
||||
obj-$(CONFIG_TEST_UDELAY) += udelay_test.o
|
||||
|
||||
$(obj)/time.o: $(obj)/timeconst.h
|
||||
|
||||
quiet_cmd_hzfile = HZFILE $@
|
||||
cmd_hzfile = echo "hz=$(CONFIG_HZ)" > $@
|
||||
|
||||
targets += hz.bc
|
||||
$(obj)/hz.bc: $(objtree)/include/config/hz.h FORCE
|
||||
$(call if_changed,hzfile)
|
||||
|
||||
quiet_cmd_bc = BC $@
|
||||
cmd_bc = bc -q $(filter-out FORCE,$^) > $@
|
||||
|
||||
targets += timeconst.h
|
||||
$(obj)/timeconst.h: $(obj)/hz.bc $(src)/timeconst.bc FORCE
|
||||
$(call if_changed,bc)
|
||||
|
||||
|
@@ -32,6 +32,7 @@
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "tick-internal.h"
|
||||
#include "timekeeping_internal.h"
|
||||
|
||||
void timecounter_init(struct timecounter *tc,
|
||||
const struct cyclecounter *cc,
|
||||
@@ -249,7 +250,7 @@ void clocksource_mark_unstable(struct clocksource *cs)
|
||||
static void clocksource_watchdog(unsigned long data)
|
||||
{
|
||||
struct clocksource *cs;
|
||||
cycle_t csnow, wdnow;
|
||||
cycle_t csnow, wdnow, delta;
|
||||
int64_t wd_nsec, cs_nsec;
|
||||
int next_cpu, reset_pending;
|
||||
|
||||
@@ -282,11 +283,12 @@ static void clocksource_watchdog(unsigned long data)
|
||||
continue;
|
||||
}
|
||||
|
||||
wd_nsec = clocksource_cyc2ns((wdnow - cs->wd_last) & watchdog->mask,
|
||||
watchdog->mult, watchdog->shift);
|
||||
delta = clocksource_delta(wdnow, cs->wd_last, watchdog->mask);
|
||||
wd_nsec = clocksource_cyc2ns(delta, watchdog->mult,
|
||||
watchdog->shift);
|
||||
|
||||
cs_nsec = clocksource_cyc2ns((csnow - cs->cs_last) &
|
||||
cs->mask, cs->mult, cs->shift);
|
||||
delta = clocksource_delta(csnow, cs->cs_last, cs->mask);
|
||||
cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);
|
||||
cs->cs_last = csnow;
|
||||
cs->wd_last = wdnow;
|
||||
|
||||
|
1866
kernel/time/hrtimer.c
Normal file
1866
kernel/time/hrtimer.c
Normal file
File diff suppressed because it is too large
Load Diff
301
kernel/time/itimer.c
Normal file
301
kernel/time/itimer.c
Normal file
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* linux/kernel/itimer.c
|
||||
*
|
||||
* Copyright (C) 1992 Darren Senn
|
||||
*/
|
||||
|
||||
/* These are all the functions necessary to implement itimers */
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/posix-timers.h>
|
||||
#include <linux/hrtimer.h>
|
||||
#include <trace/events/timer.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/**
|
||||
* itimer_get_remtime - get remaining time for the timer
|
||||
*
|
||||
* @timer: the timer to read
|
||||
*
|
||||
* Returns the delta between the expiry time and now, which can be
|
||||
* less than zero or 1usec for an pending expired timer
|
||||
*/
|
||||
static struct timeval itimer_get_remtime(struct hrtimer *timer)
|
||||
{
|
||||
ktime_t rem = hrtimer_get_remaining(timer);
|
||||
|
||||
/*
|
||||
* Racy but safe: if the itimer expires after the above
|
||||
* hrtimer_get_remtime() call but before this condition
|
||||
* then we return 0 - which is correct.
|
||||
*/
|
||||
if (hrtimer_active(timer)) {
|
||||
if (rem.tv64 <= 0)
|
||||
rem.tv64 = NSEC_PER_USEC;
|
||||
} else
|
||||
rem.tv64 = 0;
|
||||
|
||||
return ktime_to_timeval(rem);
|
||||
}
|
||||
|
||||
static void get_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
||||
struct itimerval *const value)
|
||||
{
|
||||
cputime_t cval, cinterval;
|
||||
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
||||
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
|
||||
cval = it->expires;
|
||||
cinterval = it->incr;
|
||||
if (cval) {
|
||||
struct task_cputime cputime;
|
||||
cputime_t t;
|
||||
|
||||
thread_group_cputimer(tsk, &cputime);
|
||||
if (clock_id == CPUCLOCK_PROF)
|
||||
t = cputime.utime + cputime.stime;
|
||||
else
|
||||
/* CPUCLOCK_VIRT */
|
||||
t = cputime.utime;
|
||||
|
||||
if (cval < t)
|
||||
/* about to fire */
|
||||
cval = cputime_one_jiffy;
|
||||
else
|
||||
cval = cval - t;
|
||||
}
|
||||
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
|
||||
cputime_to_timeval(cval, &value->it_value);
|
||||
cputime_to_timeval(cinterval, &value->it_interval);
|
||||
}
|
||||
|
||||
int do_getitimer(int which, struct itimerval *value)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
|
||||
switch (which) {
|
||||
case ITIMER_REAL:
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
value->it_value = itimer_get_remtime(&tsk->signal->real_timer);
|
||||
value->it_interval =
|
||||
ktime_to_timeval(tsk->signal->it_real_incr);
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
break;
|
||||
case ITIMER_VIRTUAL:
|
||||
get_cpu_itimer(tsk, CPUCLOCK_VIRT, value);
|
||||
break;
|
||||
case ITIMER_PROF:
|
||||
get_cpu_itimer(tsk, CPUCLOCK_PROF, value);
|
||||
break;
|
||||
default:
|
||||
return(-EINVAL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(getitimer, int, which, struct itimerval __user *, value)
|
||||
{
|
||||
int error = -EFAULT;
|
||||
struct itimerval get_buffer;
|
||||
|
||||
if (value) {
|
||||
error = do_getitimer(which, &get_buffer);
|
||||
if (!error &&
|
||||
copy_to_user(value, &get_buffer, sizeof(get_buffer)))
|
||||
error = -EFAULT;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The timer is automagically restarted, when interval != 0
|
||||
*/
|
||||
enum hrtimer_restart it_real_fn(struct hrtimer *timer)
|
||||
{
|
||||
struct signal_struct *sig =
|
||||
container_of(timer, struct signal_struct, real_timer);
|
||||
|
||||
trace_itimer_expire(ITIMER_REAL, sig->leader_pid, 0);
|
||||
kill_pid_info(SIGALRM, SEND_SIG_PRIV, sig->leader_pid);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
static inline u32 cputime_sub_ns(cputime_t ct, s64 real_ns)
|
||||
{
|
||||
struct timespec ts;
|
||||
s64 cpu_ns;
|
||||
|
||||
cputime_to_timespec(ct, &ts);
|
||||
cpu_ns = timespec_to_ns(&ts);
|
||||
|
||||
return (cpu_ns <= real_ns) ? 0 : cpu_ns - real_ns;
|
||||
}
|
||||
|
||||
static void set_cpu_itimer(struct task_struct *tsk, unsigned int clock_id,
|
||||
const struct itimerval *const value,
|
||||
struct itimerval *const ovalue)
|
||||
{
|
||||
cputime_t cval, nval, cinterval, ninterval;
|
||||
s64 ns_ninterval, ns_nval;
|
||||
u32 error, incr_error;
|
||||
struct cpu_itimer *it = &tsk->signal->it[clock_id];
|
||||
|
||||
nval = timeval_to_cputime(&value->it_value);
|
||||
ns_nval = timeval_to_ns(&value->it_value);
|
||||
ninterval = timeval_to_cputime(&value->it_interval);
|
||||
ns_ninterval = timeval_to_ns(&value->it_interval);
|
||||
|
||||
error = cputime_sub_ns(nval, ns_nval);
|
||||
incr_error = cputime_sub_ns(ninterval, ns_ninterval);
|
||||
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
|
||||
cval = it->expires;
|
||||
cinterval = it->incr;
|
||||
if (cval || nval) {
|
||||
if (nval > 0)
|
||||
nval += cputime_one_jiffy;
|
||||
set_process_cpu_timer(tsk, clock_id, &nval, &cval);
|
||||
}
|
||||
it->expires = nval;
|
||||
it->incr = ninterval;
|
||||
it->error = error;
|
||||
it->incr_error = incr_error;
|
||||
trace_itimer_state(clock_id == CPUCLOCK_VIRT ?
|
||||
ITIMER_VIRTUAL : ITIMER_PROF, value, nval);
|
||||
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
|
||||
if (ovalue) {
|
||||
cputime_to_timeval(cval, &ovalue->it_value);
|
||||
cputime_to_timeval(cinterval, &ovalue->it_interval);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if the timeval is in canonical form
|
||||
*/
|
||||
#define timeval_valid(t) \
|
||||
(((t)->tv_sec >= 0) && (((unsigned long) (t)->tv_usec) < USEC_PER_SEC))
|
||||
|
||||
int do_setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
|
||||
{
|
||||
struct task_struct *tsk = current;
|
||||
struct hrtimer *timer;
|
||||
ktime_t expires;
|
||||
|
||||
/*
|
||||
* Validate the timevals in value.
|
||||
*/
|
||||
if (!timeval_valid(&value->it_value) ||
|
||||
!timeval_valid(&value->it_interval))
|
||||
return -EINVAL;
|
||||
|
||||
switch (which) {
|
||||
case ITIMER_REAL:
|
||||
again:
|
||||
spin_lock_irq(&tsk->sighand->siglock);
|
||||
timer = &tsk->signal->real_timer;
|
||||
if (ovalue) {
|
||||
ovalue->it_value = itimer_get_remtime(timer);
|
||||
ovalue->it_interval
|
||||
= ktime_to_timeval(tsk->signal->it_real_incr);
|
||||
}
|
||||
/* We are sharing ->siglock with it_real_fn() */
|
||||
if (hrtimer_try_to_cancel(timer) < 0) {
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
goto again;
|
||||
}
|
||||
expires = timeval_to_ktime(value->it_value);
|
||||
if (expires.tv64 != 0) {
|
||||
tsk->signal->it_real_incr =
|
||||
timeval_to_ktime(value->it_interval);
|
||||
hrtimer_start(timer, expires, HRTIMER_MODE_REL);
|
||||
} else
|
||||
tsk->signal->it_real_incr.tv64 = 0;
|
||||
|
||||
trace_itimer_state(ITIMER_REAL, value, 0);
|
||||
spin_unlock_irq(&tsk->sighand->siglock);
|
||||
break;
|
||||
case ITIMER_VIRTUAL:
|
||||
set_cpu_itimer(tsk, CPUCLOCK_VIRT, value, ovalue);
|
||||
break;
|
||||
case ITIMER_PROF:
|
||||
set_cpu_itimer(tsk, CPUCLOCK_PROF, value, ovalue);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* alarm_setitimer - set alarm in seconds
|
||||
*
|
||||
* @seconds: number of seconds until alarm
|
||||
* 0 disables the alarm
|
||||
*
|
||||
* Returns the remaining time in seconds of a pending timer or 0 when
|
||||
* the timer is not active.
|
||||
*
|
||||
* On 32 bit machines the seconds value is limited to (INT_MAX/2) to avoid
|
||||
* negative timeval settings which would cause immediate expiry.
|
||||
*/
|
||||
unsigned int alarm_setitimer(unsigned int seconds)
|
||||
{
|
||||
struct itimerval it_new, it_old;
|
||||
|
||||
#if BITS_PER_LONG < 64
|
||||
if (seconds > INT_MAX)
|
||||
seconds = INT_MAX;
|
||||
#endif
|
||||
it_new.it_value.tv_sec = seconds;
|
||||
it_new.it_value.tv_usec = 0;
|
||||
it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0;
|
||||
|
||||
do_setitimer(ITIMER_REAL, &it_new, &it_old);
|
||||
|
||||
/*
|
||||
* We can't return 0 if we have an alarm pending ... And we'd
|
||||
* better return too much than too little anyway
|
||||
*/
|
||||
if ((!it_old.it_value.tv_sec && it_old.it_value.tv_usec) ||
|
||||
it_old.it_value.tv_usec >= 500000)
|
||||
it_old.it_value.tv_sec++;
|
||||
|
||||
return it_old.it_value.tv_sec;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE3(setitimer, int, which, struct itimerval __user *, value,
|
||||
struct itimerval __user *, ovalue)
|
||||
{
|
||||
struct itimerval set_buffer, get_buffer;
|
||||
int error;
|
||||
|
||||
if (value) {
|
||||
if(copy_from_user(&set_buffer, value, sizeof(set_buffer)))
|
||||
return -EFAULT;
|
||||
} else {
|
||||
memset(&set_buffer, 0, sizeof(set_buffer));
|
||||
printk_once(KERN_WARNING "%s calls setitimer() with new_value NULL pointer."
|
||||
" Misfeature support will be removed\n",
|
||||
current->comm);
|
||||
}
|
||||
|
||||
error = do_setitimer(which, &set_buffer, ovalue ? &get_buffer : NULL);
|
||||
if (error || !ovalue)
|
||||
return error;
|
||||
|
||||
if (copy_to_user(ovalue, &get_buffer, sizeof(get_buffer)))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
@@ -466,7 +466,8 @@ static DECLARE_DELAYED_WORK(sync_cmos_work, sync_cmos_clock);
|
||||
|
||||
static void sync_cmos_clock(struct work_struct *work)
|
||||
{
|
||||
struct timespec now, next;
|
||||
struct timespec64 now;
|
||||
struct timespec next;
|
||||
int fail = 1;
|
||||
|
||||
/*
|
||||
@@ -485,9 +486,9 @@ static void sync_cmos_clock(struct work_struct *work)
|
||||
return;
|
||||
}
|
||||
|
||||
getnstimeofday(&now);
|
||||
getnstimeofday64(&now);
|
||||
if (abs(now.tv_nsec - (NSEC_PER_SEC / 2)) <= tick_nsec * 5) {
|
||||
struct timespec adjust = now;
|
||||
struct timespec adjust = timespec64_to_timespec(now);
|
||||
|
||||
fail = -ENODEV;
|
||||
if (persistent_clock_is_local)
|
||||
@@ -531,7 +532,7 @@ void ntp_notify_cmos_timer(void) { }
|
||||
/*
|
||||
* Propagate a new txc->status value into the NTP state:
|
||||
*/
|
||||
static inline void process_adj_status(struct timex *txc, struct timespec *ts)
|
||||
static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
|
||||
{
|
||||
if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
|
||||
time_state = TIME_OK;
|
||||
@@ -554,7 +555,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec *ts)
|
||||
|
||||
|
||||
static inline void process_adjtimex_modes(struct timex *txc,
|
||||
struct timespec *ts,
|
||||
struct timespec64 *ts,
|
||||
s32 *time_tai)
|
||||
{
|
||||
if (txc->modes & ADJ_STATUS)
|
||||
@@ -640,7 +641,7 @@ int ntp_validate_timex(struct timex *txc)
|
||||
* adjtimex mainly allows reading (and writing, if superuser) of
|
||||
* kernel time-keeping variables. used by xntpd.
|
||||
*/
|
||||
int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
|
||||
int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai)
|
||||
{
|
||||
int result;
|
||||
|
||||
@@ -684,7 +685,7 @@ int __do_adjtimex(struct timex *txc, struct timespec *ts, s32 *time_tai)
|
||||
/* fill PPS status fields */
|
||||
pps_fill_timex(txc);
|
||||
|
||||
txc->time.tv_sec = ts->tv_sec;
|
||||
txc->time.tv_sec = (time_t)ts->tv_sec;
|
||||
txc->time.tv_usec = ts->tv_nsec;
|
||||
if (!(time_status & STA_NANO))
|
||||
txc->time.tv_usec /= NSEC_PER_USEC;
|
||||
|
@@ -7,6 +7,6 @@ extern void ntp_clear(void);
|
||||
extern u64 ntp_tick_length(void);
|
||||
extern int second_overflow(unsigned long secs);
|
||||
extern int ntp_validate_timex(struct timex *);
|
||||
extern int __do_adjtimex(struct timex *, struct timespec *, s32 *);
|
||||
extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
|
||||
extern void __hardpps(const struct timespec *, const struct timespec *);
|
||||
#endif /* _LINUX_NTP_INTERNAL_H */
|
||||
|
1490
kernel/time/posix-cpu-timers.c
Normal file
1490
kernel/time/posix-cpu-timers.c
Normal file
File diff suppressed because it is too large
Load Diff
1123
kernel/time/posix-timers.c
Normal file
1123
kernel/time/posix-timers.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,8 @@
|
||||
#include <linux/hrtimer.h>
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include "timekeeping.h"
|
||||
|
||||
extern seqlock_t jiffies_lock;
|
||||
|
||||
#define CS_NAME_LEN 32
|
||||
|
778
kernel/time/time.c
Normal file
778
kernel/time/time.c
Normal file
@@ -0,0 +1,778 @@
|
||||
/*
|
||||
* linux/kernel/time.c
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* This file contains the interface functions for the various
|
||||
* time related system calls: time, stime, gettimeofday, settimeofday,
|
||||
* adjtime
|
||||
*/
|
||||
/*
|
||||
* Modification history kernel/time.c
|
||||
*
|
||||
* 1993-09-02 Philip Gladstone
|
||||
* Created file with time related functions from sched/core.c and adjtimex()
|
||||
* 1993-10-08 Torsten Duwe
|
||||
* adjtime interface update and CMOS clock write code
|
||||
* 1995-08-13 Torsten Duwe
|
||||
* kernel PLL updated to 1994-12-13 specs (rfc-1589)
|
||||
* 1999-01-16 Ulrich Windl
|
||||
* Introduced error checking for many cases in adjtimex().
|
||||
* Updated NTP code according to technical memorandum Jan '96
|
||||
* "A Kernel Model for Precision Timekeeping" by Dave Mills
|
||||
* Allow time_constant larger than MAXTC(6) for NTP v4 (MAXTC == 10)
|
||||
* (Even though the technical memorandum forbids it)
|
||||
* 2004-07-14 Christoph Lameter
|
||||
* Added getnstimeofday to allow the posix timer functions to return
|
||||
* with nanosecond accuracy
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/capability.h>
|
||||
#include <linux/timekeeper_internal.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/math64.h>
|
||||
#include <linux/ptrace.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/unistd.h>
|
||||
|
||||
#include "timeconst.h"
|
||||
#include "timekeeping.h"
|
||||
|
||||
/*
|
||||
* The timezone where the local system is located. Used as a default by some
|
||||
* programs who obtain this value by using gettimeofday.
|
||||
*/
|
||||
struct timezone sys_tz;
|
||||
|
||||
EXPORT_SYMBOL(sys_tz);
|
||||
|
||||
#ifdef __ARCH_WANT_SYS_TIME
|
||||
|
||||
/*
|
||||
* sys_time() can be implemented in user-level using
|
||||
* sys_gettimeofday(). Is this for backwards compatibility? If so,
|
||||
* why not move it into the appropriate arch directory (for those
|
||||
* architectures that need it).
|
||||
*/
|
||||
SYSCALL_DEFINE1(time, time_t __user *, tloc)
|
||||
{
|
||||
time_t i = get_seconds();
|
||||
|
||||
if (tloc) {
|
||||
if (put_user(i,tloc))
|
||||
return -EFAULT;
|
||||
}
|
||||
force_successful_syscall_return();
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* sys_stime() can be implemented in user-level using
|
||||
* sys_settimeofday(). Is this for backwards compatibility? If so,
|
||||
* why not move it into the appropriate arch directory (for those
|
||||
* architectures that need it).
|
||||
*/
|
||||
|
||||
SYSCALL_DEFINE1(stime, time_t __user *, tptr)
|
||||
{
|
||||
struct timespec tv;
|
||||
int err;
|
||||
|
||||
if (get_user(tv.tv_sec, tptr))
|
||||
return -EFAULT;
|
||||
|
||||
tv.tv_nsec = 0;
|
||||
|
||||
err = security_settime(&tv, NULL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
do_settimeofday(&tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __ARCH_WANT_SYS_TIME */
|
||||
|
||||
SYSCALL_DEFINE2(gettimeofday, struct timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
if (likely(tv != NULL)) {
|
||||
struct timeval ktv;
|
||||
do_gettimeofday(&ktv);
|
||||
if (copy_to_user(tv, &ktv, sizeof(ktv)))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (unlikely(tz != NULL)) {
|
||||
if (copy_to_user(tz, &sys_tz, sizeof(sys_tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Indicates if there is an offset between the system clock and the hardware
|
||||
* clock/persistent clock/rtc.
|
||||
*/
|
||||
int persistent_clock_is_local;
|
||||
|
||||
/*
|
||||
* Adjust the time obtained from the CMOS to be UTC time instead of
|
||||
* local time.
|
||||
*
|
||||
* This is ugly, but preferable to the alternatives. Otherwise we
|
||||
* would either need to write a program to do it in /etc/rc (and risk
|
||||
* confusion if the program gets run more than once; it would also be
|
||||
* hard to make the program warp the clock precisely n hours) or
|
||||
* compile in the timezone information into the kernel. Bad, bad....
|
||||
*
|
||||
* - TYT, 1992-01-01
|
||||
*
|
||||
* The best thing to do is to keep the CMOS clock in universal time (UTC)
|
||||
* as real UNIX machines always do it. This avoids all headaches about
|
||||
* daylight saving times and warping kernel clocks.
|
||||
*/
|
||||
static inline void warp_clock(void)
|
||||
{
|
||||
if (sys_tz.tz_minuteswest != 0) {
|
||||
struct timespec adjust;
|
||||
|
||||
persistent_clock_is_local = 1;
|
||||
adjust.tv_sec = sys_tz.tz_minuteswest * 60;
|
||||
adjust.tv_nsec = 0;
|
||||
timekeeping_inject_offset(&adjust);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* In case for some reason the CMOS clock has not already been running
|
||||
* in UTC, but in some local time: The first time we set the timezone,
|
||||
* we will warp the clock so that it is ticking UTC time instead of
|
||||
* local time. Presumably, if someone is setting the timezone then we
|
||||
* are running in an environment where the programs understand about
|
||||
* timezones. This should be done at boot time in the /etc/rc script,
|
||||
* as soon as possible, so that the clock can be set right. Otherwise,
|
||||
* various programs will get confused when the clock gets warped.
|
||||
*/
|
||||
|
||||
int do_sys_settimeofday(const struct timespec *tv, const struct timezone *tz)
|
||||
{
|
||||
static int firsttime = 1;
|
||||
int error = 0;
|
||||
|
||||
if (tv && !timespec_valid(tv))
|
||||
return -EINVAL;
|
||||
|
||||
error = security_settime(tv, tz);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (tz) {
|
||||
sys_tz = *tz;
|
||||
update_vsyscall_tz();
|
||||
if (firsttime) {
|
||||
firsttime = 0;
|
||||
if (!tv)
|
||||
warp_clock();
|
||||
}
|
||||
}
|
||||
if (tv)
|
||||
return do_settimeofday(tv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE2(settimeofday, struct timeval __user *, tv,
|
||||
struct timezone __user *, tz)
|
||||
{
|
||||
struct timeval user_tv;
|
||||
struct timespec new_ts;
|
||||
struct timezone new_tz;
|
||||
|
||||
if (tv) {
|
||||
if (copy_from_user(&user_tv, tv, sizeof(*tv)))
|
||||
return -EFAULT;
|
||||
new_ts.tv_sec = user_tv.tv_sec;
|
||||
new_ts.tv_nsec = user_tv.tv_usec * NSEC_PER_USEC;
|
||||
}
|
||||
if (tz) {
|
||||
if (copy_from_user(&new_tz, tz, sizeof(*tz)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL);
|
||||
}
|
||||
|
||||
SYSCALL_DEFINE1(adjtimex, struct timex __user *, txc_p)
|
||||
{
|
||||
struct timex txc; /* Local copy of parameter */
|
||||
int ret;
|
||||
|
||||
/* Copy the user data space into the kernel copy
|
||||
* structure. But bear in mind that the structures
|
||||
* may change
|
||||
*/
|
||||
if(copy_from_user(&txc, txc_p, sizeof(struct timex)))
|
||||
return -EFAULT;
|
||||
ret = do_adjtimex(&txc);
|
||||
return copy_to_user(txc_p, &txc, sizeof(struct timex)) ? -EFAULT : ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* current_fs_time - Return FS time
|
||||
* @sb: Superblock.
|
||||
*
|
||||
* Return the current time truncated to the time granularity supported by
|
||||
* the fs.
|
||||
*/
|
||||
struct timespec current_fs_time(struct super_block *sb)
|
||||
{
|
||||
struct timespec now = current_kernel_time();
|
||||
return timespec_trunc(now, sb->s_time_gran);
|
||||
}
|
||||
EXPORT_SYMBOL(current_fs_time);
|
||||
|
||||
/*
|
||||
* Convert jiffies to milliseconds and back.
|
||||
*
|
||||
* Avoid unnecessary multiplications/divisions in the
|
||||
* two most common HZ cases:
|
||||
*/
|
||||
unsigned int jiffies_to_msecs(const unsigned long j)
|
||||
{
|
||||
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
|
||||
return (MSEC_PER_SEC / HZ) * j;
|
||||
#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
|
||||
return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC);
|
||||
#else
|
||||
# if BITS_PER_LONG == 32
|
||||
return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32;
|
||||
# else
|
||||
return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_msecs);
|
||||
|
||||
unsigned int jiffies_to_usecs(const unsigned long j)
|
||||
{
|
||||
#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
|
||||
return (USEC_PER_SEC / HZ) * j;
|
||||
#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
|
||||
return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC);
|
||||
#else
|
||||
# if BITS_PER_LONG == 32
|
||||
return (HZ_TO_USEC_MUL32 * j) >> HZ_TO_USEC_SHR32;
|
||||
# else
|
||||
return (j * HZ_TO_USEC_NUM) / HZ_TO_USEC_DEN;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_usecs);
|
||||
|
||||
/**
|
||||
* timespec_trunc - Truncate timespec to a granularity
|
||||
* @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.
|
||||
*/
|
||||
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) {
|
||||
/* nothing */
|
||||
} else if (gran == 1000000000) {
|
||||
t.tv_nsec = 0;
|
||||
} else {
|
||||
t.tv_nsec -= t.tv_nsec % gran;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
EXPORT_SYMBOL(timespec_trunc);
|
||||
|
||||
/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
|
||||
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
|
||||
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
|
||||
*
|
||||
* [For the Julian calendar (which was used in Russia before 1917,
|
||||
* Britain & colonies before 1752, anywhere else before 1582,
|
||||
* and is still in use by some communities) leave out the
|
||||
* -year/100+year/400 terms, and add 10.]
|
||||
*
|
||||
* This algorithm was first published by Gauss (I think).
|
||||
*
|
||||
* WARNING: this function will overflow on 2106-02-07 06:28:16 on
|
||||
* machines where long is 32-bit! (However, as time_t is signed, we
|
||||
* will already get problems at other places on 2038-01-19 03:14:08)
|
||||
*/
|
||||
unsigned long
|
||||
mktime(const unsigned int year0, const unsigned int mon0,
|
||||
const unsigned int day, const unsigned int hour,
|
||||
const unsigned int min, const unsigned int sec)
|
||||
{
|
||||
unsigned int mon = mon0, year = year0;
|
||||
|
||||
/* 1..12 -> 11,12,1..10 */
|
||||
if (0 >= (int) (mon -= 2)) {
|
||||
mon += 12; /* Puts Feb last since it has leap day */
|
||||
year -= 1;
|
||||
}
|
||||
|
||||
return ((((unsigned long)
|
||||
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
|
||||
year*365 - 719499
|
||||
)*24 + hour /* now have hours */
|
||||
)*60 + min /* now have minutes */
|
||||
)*60 + sec; /* finally seconds */
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(mktime);
|
||||
|
||||
/**
|
||||
* set_normalized_timespec - set timespec sec and nsec parts and normalize
|
||||
*
|
||||
* @ts: pointer to timespec variable to be set
|
||||
* @sec: seconds to set
|
||||
* @nsec: nanoseconds to set
|
||||
*
|
||||
* Set seconds and nanoseconds field of a timespec variable and
|
||||
* normalize to the timespec storage format
|
||||
*
|
||||
* Note: The tv_nsec part is always in the range of
|
||||
* 0 <= tv_nsec < NSEC_PER_SEC
|
||||
* For negative values only the tv_sec field is negative !
|
||||
*/
|
||||
void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec)
|
||||
{
|
||||
while (nsec >= NSEC_PER_SEC) {
|
||||
/*
|
||||
* The following asm() prevents the compiler from
|
||||
* optimising this loop into a modulo operation. See
|
||||
* also __iter_div_u64_rem() in include/linux/time.h
|
||||
*/
|
||||
asm("" : "+rm"(nsec));
|
||||
nsec -= NSEC_PER_SEC;
|
||||
++sec;
|
||||
}
|
||||
while (nsec < 0) {
|
||||
asm("" : "+rm"(nsec));
|
||||
nsec += NSEC_PER_SEC;
|
||||
--sec;
|
||||
}
|
||||
ts->tv_sec = sec;
|
||||
ts->tv_nsec = nsec;
|
||||
}
|
||||
EXPORT_SYMBOL(set_normalized_timespec);
|
||||
|
||||
/**
|
||||
* ns_to_timespec - Convert nanoseconds to timespec
|
||||
* @nsec: the nanoseconds value to be converted
|
||||
*
|
||||
* Returns the timespec representation of the nsec parameter.
|
||||
*/
|
||||
struct timespec ns_to_timespec(const s64 nsec)
|
||||
{
|
||||
struct timespec ts;
|
||||
s32 rem;
|
||||
|
||||
if (!nsec)
|
||||
return (struct timespec) {0, 0};
|
||||
|
||||
ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
|
||||
if (unlikely(rem < 0)) {
|
||||
ts.tv_sec--;
|
||||
rem += NSEC_PER_SEC;
|
||||
}
|
||||
ts.tv_nsec = rem;
|
||||
|
||||
return ts;
|
||||
}
|
||||
EXPORT_SYMBOL(ns_to_timespec);
|
||||
|
||||
/**
|
||||
* ns_to_timeval - Convert nanoseconds to timeval
|
||||
* @nsec: the nanoseconds value to be converted
|
||||
*
|
||||
* Returns the timeval representation of the nsec parameter.
|
||||
*/
|
||||
struct timeval ns_to_timeval(const s64 nsec)
|
||||
{
|
||||
struct timespec ts = ns_to_timespec(nsec);
|
||||
struct timeval tv;
|
||||
|
||||
tv.tv_sec = ts.tv_sec;
|
||||
tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000;
|
||||
|
||||
return tv;
|
||||
}
|
||||
EXPORT_SYMBOL(ns_to_timeval);
|
||||
|
||||
#if BITS_PER_LONG == 32
|
||||
/**
|
||||
* set_normalized_timespec - set timespec sec and nsec parts and normalize
|
||||
*
|
||||
* @ts: pointer to timespec variable to be set
|
||||
* @sec: seconds to set
|
||||
* @nsec: nanoseconds to set
|
||||
*
|
||||
* Set seconds and nanoseconds field of a timespec variable and
|
||||
* normalize to the timespec storage format
|
||||
*
|
||||
* Note: The tv_nsec part is always in the range of
|
||||
* 0 <= tv_nsec < NSEC_PER_SEC
|
||||
* For negative values only the tv_sec field is negative !
|
||||
*/
|
||||
void set_normalized_timespec64(struct timespec64 *ts, time64_t sec, s64 nsec)
|
||||
{
|
||||
while (nsec >= NSEC_PER_SEC) {
|
||||
/*
|
||||
* The following asm() prevents the compiler from
|
||||
* optimising this loop into a modulo operation. See
|
||||
* also __iter_div_u64_rem() in include/linux/time.h
|
||||
*/
|
||||
asm("" : "+rm"(nsec));
|
||||
nsec -= NSEC_PER_SEC;
|
||||
++sec;
|
||||
}
|
||||
while (nsec < 0) {
|
||||
asm("" : "+rm"(nsec));
|
||||
nsec += NSEC_PER_SEC;
|
||||
--sec;
|
||||
}
|
||||
ts->tv_sec = sec;
|
||||
ts->tv_nsec = nsec;
|
||||
}
|
||||
EXPORT_SYMBOL(set_normalized_timespec64);
|
||||
|
||||
/**
|
||||
* ns_to_timespec64 - Convert nanoseconds to timespec64
|
||||
* @nsec: the nanoseconds value to be converted
|
||||
*
|
||||
* Returns the timespec64 representation of the nsec parameter.
|
||||
*/
|
||||
struct timespec64 ns_to_timespec64(const s64 nsec)
|
||||
{
|
||||
struct timespec64 ts;
|
||||
s32 rem;
|
||||
|
||||
if (!nsec)
|
||||
return (struct timespec64) {0, 0};
|
||||
|
||||
ts.tv_sec = div_s64_rem(nsec, NSEC_PER_SEC, &rem);
|
||||
if (unlikely(rem < 0)) {
|
||||
ts.tv_sec--;
|
||||
rem += NSEC_PER_SEC;
|
||||
}
|
||||
ts.tv_nsec = rem;
|
||||
|
||||
return ts;
|
||||
}
|
||||
EXPORT_SYMBOL(ns_to_timespec64);
|
||||
#endif
|
||||
/*
|
||||
* When we convert to jiffies then we interpret incoming values
|
||||
* the following way:
|
||||
*
|
||||
* - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET)
|
||||
*
|
||||
* - 'too large' values [that would result in larger than
|
||||
* MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
|
||||
*
|
||||
* - all other values are converted to jiffies by either multiplying
|
||||
* the input value by a factor or dividing it with a factor
|
||||
*
|
||||
* We must also be careful about 32-bit overflows.
|
||||
*/
|
||||
unsigned long msecs_to_jiffies(const unsigned int m)
|
||||
{
|
||||
/*
|
||||
* Negative value, means infinite timeout:
|
||||
*/
|
||||
if ((int)m < 0)
|
||||
return MAX_JIFFY_OFFSET;
|
||||
|
||||
#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
|
||||
/*
|
||||
* HZ is equal to or smaller than 1000, and 1000 is a nice
|
||||
* round multiple of HZ, divide with the factor between them,
|
||||
* but round upwards:
|
||||
*/
|
||||
return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
|
||||
#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
|
||||
/*
|
||||
* HZ is larger than 1000, and HZ is a nice round multiple of
|
||||
* 1000 - simply multiply with the factor between them.
|
||||
*
|
||||
* But first make sure the multiplication result cannot
|
||||
* overflow:
|
||||
*/
|
||||
if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
|
||||
return MAX_JIFFY_OFFSET;
|
||||
|
||||
return m * (HZ / MSEC_PER_SEC);
|
||||
#else
|
||||
/*
|
||||
* Generic case - multiply, round and divide. But first
|
||||
* check that if we are doing a net multiplication, that
|
||||
* we wouldn't overflow:
|
||||
*/
|
||||
if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
|
||||
return MAX_JIFFY_OFFSET;
|
||||
|
||||
return (MSEC_TO_HZ_MUL32 * m + MSEC_TO_HZ_ADJ32)
|
||||
>> MSEC_TO_HZ_SHR32;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(msecs_to_jiffies);
|
||||
|
||||
unsigned long usecs_to_jiffies(const unsigned int u)
|
||||
{
|
||||
if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET))
|
||||
return MAX_JIFFY_OFFSET;
|
||||
#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ)
|
||||
return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ);
|
||||
#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC)
|
||||
return u * (HZ / USEC_PER_SEC);
|
||||
#else
|
||||
return (USEC_TO_HZ_MUL32 * u + USEC_TO_HZ_ADJ32)
|
||||
>> USEC_TO_HZ_SHR32;
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(usecs_to_jiffies);
|
||||
|
||||
/*
|
||||
* The TICK_NSEC - 1 rounds up the value to the next resolution. Note
|
||||
* that a remainder subtract here would not do the right thing as the
|
||||
* resolution values don't fall on second boundries. I.e. the line:
|
||||
* nsec -= nsec % TICK_NSEC; is NOT a correct resolution rounding.
|
||||
*
|
||||
* Rather, we just shift the bits off the right.
|
||||
*
|
||||
* The >> (NSEC_JIFFIE_SC - SEC_JIFFIE_SC) converts the scaled nsec
|
||||
* value to a scaled second value.
|
||||
*/
|
||||
unsigned long
|
||||
timespec_to_jiffies(const struct timespec *value)
|
||||
{
|
||||
unsigned long sec = value->tv_sec;
|
||||
long nsec = value->tv_nsec + TICK_NSEC - 1;
|
||||
|
||||
if (sec >= MAX_SEC_IN_JIFFIES){
|
||||
sec = MAX_SEC_IN_JIFFIES;
|
||||
nsec = 0;
|
||||
}
|
||||
return (((u64)sec * SEC_CONVERSION) +
|
||||
(((u64)nsec * NSEC_CONVERSION) >>
|
||||
(NSEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(timespec_to_jiffies);
|
||||
|
||||
void
|
||||
jiffies_to_timespec(const unsigned long jiffies, struct timespec *value)
|
||||
{
|
||||
/*
|
||||
* Convert jiffies to nanoseconds and separate with
|
||||
* one divide.
|
||||
*/
|
||||
u32 rem;
|
||||
value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
|
||||
NSEC_PER_SEC, &rem);
|
||||
value->tv_nsec = rem;
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_timespec);
|
||||
|
||||
/* Same for "timeval"
|
||||
*
|
||||
* Well, almost. The problem here is that the real system resolution is
|
||||
* in nanoseconds and the value being converted is in micro seconds.
|
||||
* Also for some machines (those that use HZ = 1024, in-particular),
|
||||
* there is a LARGE error in the tick size in microseconds.
|
||||
|
||||
* The solution we use is to do the rounding AFTER we convert the
|
||||
* microsecond part. Thus the USEC_ROUND, the bits to be shifted off.
|
||||
* Instruction wise, this should cost only an additional add with carry
|
||||
* instruction above the way it was done above.
|
||||
*/
|
||||
unsigned long
|
||||
timeval_to_jiffies(const struct timeval *value)
|
||||
{
|
||||
unsigned long sec = value->tv_sec;
|
||||
long usec = value->tv_usec;
|
||||
|
||||
if (sec >= MAX_SEC_IN_JIFFIES){
|
||||
sec = MAX_SEC_IN_JIFFIES;
|
||||
usec = 0;
|
||||
}
|
||||
return (((u64)sec * SEC_CONVERSION) +
|
||||
(((u64)usec * USEC_CONVERSION + USEC_ROUND) >>
|
||||
(USEC_JIFFIE_SC - SEC_JIFFIE_SC))) >> SEC_JIFFIE_SC;
|
||||
}
|
||||
EXPORT_SYMBOL(timeval_to_jiffies);
|
||||
|
||||
void jiffies_to_timeval(const unsigned long jiffies, struct timeval *value)
|
||||
{
|
||||
/*
|
||||
* Convert jiffies to nanoseconds and separate with
|
||||
* one divide.
|
||||
*/
|
||||
u32 rem;
|
||||
|
||||
value->tv_sec = div_u64_rem((u64)jiffies * TICK_NSEC,
|
||||
NSEC_PER_SEC, &rem);
|
||||
value->tv_usec = rem / NSEC_PER_USEC;
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_timeval);
|
||||
|
||||
/*
|
||||
* Convert jiffies/jiffies_64 to clock_t and back.
|
||||
*/
|
||||
clock_t jiffies_to_clock_t(unsigned long x)
|
||||
{
|
||||
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
|
||||
# if HZ < USER_HZ
|
||||
return x * (USER_HZ / HZ);
|
||||
# else
|
||||
return x / (HZ / USER_HZ);
|
||||
# endif
|
||||
#else
|
||||
return div_u64((u64)x * TICK_NSEC, NSEC_PER_SEC / USER_HZ);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_to_clock_t);
|
||||
|
||||
unsigned long clock_t_to_jiffies(unsigned long x)
|
||||
{
|
||||
#if (HZ % USER_HZ)==0
|
||||
if (x >= ~0UL / (HZ / USER_HZ))
|
||||
return ~0UL;
|
||||
return x * (HZ / USER_HZ);
|
||||
#else
|
||||
/* Don't worry about loss of precision here .. */
|
||||
if (x >= ~0UL / HZ * USER_HZ)
|
||||
return ~0UL;
|
||||
|
||||
/* .. but do try to contain it here */
|
||||
return div_u64((u64)x * HZ, USER_HZ);
|
||||
#endif
|
||||
}
|
||||
EXPORT_SYMBOL(clock_t_to_jiffies);
|
||||
|
||||
u64 jiffies_64_to_clock_t(u64 x)
|
||||
{
|
||||
#if (TICK_NSEC % (NSEC_PER_SEC / USER_HZ)) == 0
|
||||
# if HZ < USER_HZ
|
||||
x = div_u64(x * USER_HZ, HZ);
|
||||
# elif HZ > USER_HZ
|
||||
x = div_u64(x, HZ / USER_HZ);
|
||||
# else
|
||||
/* Nothing to do */
|
||||
# endif
|
||||
#else
|
||||
/*
|
||||
* There are better ways that don't overflow early,
|
||||
* but even this doesn't overflow in hundreds of years
|
||||
* in 64 bits, so..
|
||||
*/
|
||||
x = div_u64(x * TICK_NSEC, (NSEC_PER_SEC / USER_HZ));
|
||||
#endif
|
||||
return x;
|
||||
}
|
||||
EXPORT_SYMBOL(jiffies_64_to_clock_t);
|
||||
|
||||
u64 nsec_to_clock_t(u64 x)
|
||||
{
|
||||
#if (NSEC_PER_SEC % USER_HZ) == 0
|
||||
return div_u64(x, NSEC_PER_SEC / USER_HZ);
|
||||
#elif (USER_HZ % 512) == 0
|
||||
return div_u64(x * USER_HZ / 512, NSEC_PER_SEC / 512);
|
||||
#else
|
||||
/*
|
||||
* max relative error 5.7e-8 (1.8s per year) for USER_HZ <= 1024,
|
||||
* overflow after 64.99 years.
|
||||
* exact for HZ=60, 72, 90, 120, 144, 180, 300, 600, 900, ...
|
||||
*/
|
||||
return div_u64(x * 9, (9ull * NSEC_PER_SEC + (USER_HZ / 2)) / USER_HZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* nsecs_to_jiffies64 - Convert nsecs in u64 to jiffies64
|
||||
*
|
||||
* @n: nsecs in u64
|
||||
*
|
||||
* Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64.
|
||||
* And this doesn't return MAX_JIFFY_OFFSET since this function is designed
|
||||
* for scheduler, not for use in device drivers to calculate timeout value.
|
||||
*
|
||||
* note:
|
||||
* NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
|
||||
* ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
|
||||
*/
|
||||
u64 nsecs_to_jiffies64(u64 n)
|
||||
{
|
||||
#if (NSEC_PER_SEC % HZ) == 0
|
||||
/* Common case, HZ = 100, 128, 200, 250, 256, 500, 512, 1000 etc. */
|
||||
return div_u64(n, NSEC_PER_SEC / HZ);
|
||||
#elif (HZ % 512) == 0
|
||||
/* overflow after 292 years if HZ = 1024 */
|
||||
return div_u64(n * HZ / 512, NSEC_PER_SEC / 512);
|
||||
#else
|
||||
/*
|
||||
* Generic case - optimized for cases where HZ is a multiple of 3.
|
||||
* overflow after 64.99 years, exact for HZ = 60, 72, 90, 120 etc.
|
||||
*/
|
||||
return div_u64(n * 9, (9ull * NSEC_PER_SEC + HZ / 2) / HZ);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* nsecs_to_jiffies - Convert nsecs in u64 to jiffies
|
||||
*
|
||||
* @n: nsecs in u64
|
||||
*
|
||||
* Unlike {m,u}secs_to_jiffies, type of input is not unsigned int but u64.
|
||||
* And this doesn't return MAX_JIFFY_OFFSET since this function is designed
|
||||
* for scheduler, not for use in device drivers to calculate timeout value.
|
||||
*
|
||||
* note:
|
||||
* NSEC_PER_SEC = 10^9 = (5^9 * 2^9) = (1953125 * 512)
|
||||
* ULLONG_MAX ns = 18446744073.709551615 secs = about 584 years
|
||||
*/
|
||||
unsigned long nsecs_to_jiffies(u64 n)
|
||||
{
|
||||
return (unsigned long)nsecs_to_jiffies64(n);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nsecs_to_jiffies);
|
||||
|
||||
/*
|
||||
* Add two timespec values and do a safety check for overflow.
|
||||
* It's assumed that both values are valid (>= 0)
|
||||
*/
|
||||
struct timespec timespec_add_safe(const struct timespec lhs,
|
||||
const struct timespec rhs)
|
||||
{
|
||||
struct timespec res;
|
||||
|
||||
set_normalized_timespec(&res, lhs.tv_sec + rhs.tv_sec,
|
||||
lhs.tv_nsec + rhs.tv_nsec);
|
||||
|
||||
if (res.tv_sec < lhs.tv_sec || res.tv_sec < rhs.tv_sec)
|
||||
res.tv_sec = TIME_T_MAX;
|
||||
|
||||
return res;
|
||||
}
|
108
kernel/time/timeconst.bc
Normal file
108
kernel/time/timeconst.bc
Normal file
@@ -0,0 +1,108 @@
|
||||
scale=0
|
||||
|
||||
define gcd(a,b) {
|
||||
auto t;
|
||||
while (b) {
|
||||
t = b;
|
||||
b = a % b;
|
||||
a = t;
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
/* Division by reciprocal multiplication. */
|
||||
define fmul(b,n,d) {
|
||||
return (2^b*n+d-1)/d;
|
||||
}
|
||||
|
||||
/* Adjustment factor when a ceiling value is used. Use as:
|
||||
(imul * n) + (fmulxx * n + fadjxx) >> xx) */
|
||||
define fadj(b,n,d) {
|
||||
auto v;
|
||||
d = d/gcd(n,d);
|
||||
v = 2^b*(d-1)/d;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* Compute the appropriate mul/adj values as well as a shift count,
|
||||
which brings the mul value into the range 2^b-1 <= x < 2^b. Such
|
||||
a shift value will be correct in the signed integer range and off
|
||||
by at most one in the upper half of the unsigned range. */
|
||||
define fmuls(b,n,d) {
|
||||
auto s, m;
|
||||
for (s = 0; 1; s++) {
|
||||
m = fmul(s,n,d);
|
||||
if (m >= 2^(b-1))
|
||||
return s;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
define timeconst(hz) {
|
||||
print "/* Automatically generated by kernel/timeconst.bc */\n"
|
||||
print "/* Time conversion constants for HZ == ", hz, " */\n"
|
||||
print "\n"
|
||||
|
||||
print "#ifndef KERNEL_TIMECONST_H\n"
|
||||
print "#define KERNEL_TIMECONST_H\n\n"
|
||||
|
||||
print "#include <linux/param.h>\n"
|
||||
print "#include <linux/types.h>\n\n"
|
||||
|
||||
print "#if HZ != ", hz, "\n"
|
||||
print "#error \qkernel/timeconst.h has the wrong HZ value!\q\n"
|
||||
print "#endif\n\n"
|
||||
|
||||
if (hz < 2) {
|
||||
print "#error Totally bogus HZ value!\n"
|
||||
} else {
|
||||
s=fmuls(32,1000,hz)
|
||||
obase=16
|
||||
print "#define HZ_TO_MSEC_MUL32\tU64_C(0x", fmul(s,1000,hz), ")\n"
|
||||
print "#define HZ_TO_MSEC_ADJ32\tU64_C(0x", fadj(s,1000,hz), ")\n"
|
||||
obase=10
|
||||
print "#define HZ_TO_MSEC_SHR32\t", s, "\n"
|
||||
|
||||
s=fmuls(32,hz,1000)
|
||||
obase=16
|
||||
print "#define MSEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000), ")\n"
|
||||
print "#define MSEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000), ")\n"
|
||||
obase=10
|
||||
print "#define MSEC_TO_HZ_SHR32\t", s, "\n"
|
||||
|
||||
obase=10
|
||||
cd=gcd(hz,1000)
|
||||
print "#define HZ_TO_MSEC_NUM\t\t", 1000/cd, "\n"
|
||||
print "#define HZ_TO_MSEC_DEN\t\t", hz/cd, "\n"
|
||||
print "#define MSEC_TO_HZ_NUM\t\t", hz/cd, "\n"
|
||||
print "#define MSEC_TO_HZ_DEN\t\t", 1000/cd, "\n"
|
||||
print "\n"
|
||||
|
||||
s=fmuls(32,1000000,hz)
|
||||
obase=16
|
||||
print "#define HZ_TO_USEC_MUL32\tU64_C(0x", fmul(s,1000000,hz), ")\n"
|
||||
print "#define HZ_TO_USEC_ADJ32\tU64_C(0x", fadj(s,1000000,hz), ")\n"
|
||||
obase=10
|
||||
print "#define HZ_TO_USEC_SHR32\t", s, "\n"
|
||||
|
||||
s=fmuls(32,hz,1000000)
|
||||
obase=16
|
||||
print "#define USEC_TO_HZ_MUL32\tU64_C(0x", fmul(s,hz,1000000), ")\n"
|
||||
print "#define USEC_TO_HZ_ADJ32\tU64_C(0x", fadj(s,hz,1000000), ")\n"
|
||||
obase=10
|
||||
print "#define USEC_TO_HZ_SHR32\t", s, "\n"
|
||||
|
||||
obase=10
|
||||
cd=gcd(hz,1000000)
|
||||
print "#define HZ_TO_USEC_NUM\t\t", 1000000/cd, "\n"
|
||||
print "#define HZ_TO_USEC_DEN\t\t", hz/cd, "\n"
|
||||
print "#define USEC_TO_HZ_NUM\t\t", hz/cd, "\n"
|
||||
print "#define USEC_TO_HZ_DEN\t\t", 1000000/cd, "\n"
|
||||
print "\n"
|
||||
|
||||
print "#endif /* KERNEL_TIMECONST_H */\n"
|
||||
}
|
||||
halt
|
||||
}
|
||||
|
||||
timeconst(hz)
|
File diff suppressed because it is too large
Load Diff
20
kernel/time/timekeeping.h
Normal file
20
kernel/time/timekeeping.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#ifndef _KERNEL_TIME_TIMEKEEPING_H
|
||||
#define _KERNEL_TIME_TIMEKEEPING_H
|
||||
/*
|
||||
* Internal interfaces for kernel/time/
|
||||
*/
|
||||
extern ktime_t ktime_get_update_offsets_tick(ktime_t *offs_real,
|
||||
ktime_t *offs_boot,
|
||||
ktime_t *offs_tai);
|
||||
extern ktime_t ktime_get_update_offsets_now(ktime_t *offs_real,
|
||||
ktime_t *offs_boot,
|
||||
ktime_t *offs_tai);
|
||||
|
||||
extern int timekeeping_valid_for_hres(void);
|
||||
extern u64 timekeeping_max_deferment(void);
|
||||
extern int timekeeping_inject_offset(struct timespec *ts);
|
||||
extern s32 timekeeping_get_tai_offset(void);
|
||||
extern void timekeeping_set_tai_offset(s32 tai_offset);
|
||||
extern void timekeeping_clocktai(struct timespec *ts);
|
||||
|
||||
#endif
|
@@ -67,7 +67,7 @@ static int __init tk_debug_sleep_time_init(void)
|
||||
}
|
||||
late_initcall(tk_debug_sleep_time_init);
|
||||
|
||||
void tk_debug_account_sleep_time(struct timespec *t)
|
||||
void tk_debug_account_sleep_time(struct timespec64 *t)
|
||||
{
|
||||
sleep_time_bin[fls(t->tv_sec)]++;
|
||||
}
|
||||
|
@@ -3,12 +3,27 @@
|
||||
/*
|
||||
* timekeeping debug functions
|
||||
*/
|
||||
#include <linux/clocksource.h>
|
||||
#include <linux/time.h>
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
extern void tk_debug_account_sleep_time(struct timespec *t);
|
||||
extern void tk_debug_account_sleep_time(struct timespec64 *t);
|
||||
#else
|
||||
#define tk_debug_account_sleep_time(x)
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_CLOCKSOURCE_VALIDATE_LAST_CYCLE
|
||||
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
|
||||
{
|
||||
cycle_t ret = (now - last) & mask;
|
||||
|
||||
return (s64) ret > 0 ? ret : 0;
|
||||
}
|
||||
#else
|
||||
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
|
||||
{
|
||||
return (now - last) & mask;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TIMEKEEPING_INTERNAL_H */
|
||||
|
1736
kernel/time/timer.c
Normal file
1736
kernel/time/timer.c
Normal file
File diff suppressed because it is too large
Load Diff
168
kernel/time/udelay_test.c
Normal file
168
kernel/time/udelay_test.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* udelay() test kernel module
|
||||
*
|
||||
* Test is executed by writing and reading to /sys/kernel/debug/udelay_test
|
||||
* Tests are configured by writing: USECS ITERATIONS
|
||||
* Tests are executed by reading from the same file.
|
||||
* Specifying usecs of 0 or negative values will run multiples tests.
|
||||
*
|
||||
* Copyright (C) 2014 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ktime.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define DEFAULT_ITERATIONS 100
|
||||
|
||||
#define DEBUGFS_FILENAME "udelay_test"
|
||||
|
||||
static DEFINE_MUTEX(udelay_test_lock);
|
||||
static struct dentry *udelay_test_debugfs_file;
|
||||
static int udelay_test_usecs;
|
||||
static int udelay_test_iterations = DEFAULT_ITERATIONS;
|
||||
|
||||
static int udelay_test_single(struct seq_file *s, int usecs, uint32_t iters)
|
||||
{
|
||||
int min = 0, max = 0, fail_count = 0;
|
||||
uint64_t sum = 0;
|
||||
uint64_t avg;
|
||||
int i;
|
||||
/* Allow udelay to be up to 0.5% fast */
|
||||
int allowed_error_ns = usecs * 5;
|
||||
|
||||
for (i = 0; i < iters; ++i) {
|
||||
struct timespec ts1, ts2;
|
||||
int time_passed;
|
||||
|
||||
ktime_get_ts(&ts1);
|
||||
udelay(usecs);
|
||||
ktime_get_ts(&ts2);
|
||||
time_passed = timespec_to_ns(&ts2) - timespec_to_ns(&ts1);
|
||||
|
||||
if (i == 0 || time_passed < min)
|
||||
min = time_passed;
|
||||
if (i == 0 || time_passed > max)
|
||||
max = time_passed;
|
||||
if ((time_passed + allowed_error_ns) / 1000 < usecs)
|
||||
++fail_count;
|
||||
WARN_ON(time_passed < 0);
|
||||
sum += time_passed;
|
||||
}
|
||||
|
||||
avg = sum;
|
||||
do_div(avg, iters);
|
||||
seq_printf(s, "%d usecs x %d: exp=%d allowed=%d min=%d avg=%lld max=%d",
|
||||
usecs, iters, usecs * 1000,
|
||||
(usecs * 1000) - allowed_error_ns, min, avg, max);
|
||||
if (fail_count)
|
||||
seq_printf(s, " FAIL=%d", fail_count);
|
||||
seq_puts(s, "\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int udelay_test_show(struct seq_file *s, void *v)
|
||||
{
|
||||
int usecs;
|
||||
int iters;
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&udelay_test_lock);
|
||||
usecs = udelay_test_usecs;
|
||||
iters = udelay_test_iterations;
|
||||
mutex_unlock(&udelay_test_lock);
|
||||
|
||||
if (usecs > 0 && iters > 0) {
|
||||
return udelay_test_single(s, usecs, iters);
|
||||
} else if (usecs == 0) {
|
||||
struct timespec ts;
|
||||
|
||||
ktime_get_ts(&ts);
|
||||
seq_printf(s, "udelay() test (lpj=%ld kt=%ld.%09ld)\n",
|
||||
loops_per_jiffy, ts.tv_sec, ts.tv_nsec);
|
||||
seq_puts(s, "usage:\n");
|
||||
seq_puts(s, "echo USECS [ITERS] > " DEBUGFS_FILENAME "\n");
|
||||
seq_puts(s, "cat " DEBUGFS_FILENAME "\n");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int udelay_test_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, udelay_test_show, inode->i_private);
|
||||
}
|
||||
|
||||
static ssize_t udelay_test_write(struct file *file, const char __user *buf,
|
||||
size_t count, loff_t *pos)
|
||||
{
|
||||
char lbuf[32];
|
||||
int ret;
|
||||
int usecs;
|
||||
int iters;
|
||||
|
||||
if (count >= sizeof(lbuf))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(lbuf, buf, count))
|
||||
return -EFAULT;
|
||||
lbuf[count] = '\0';
|
||||
|
||||
ret = sscanf(lbuf, "%d %d", &usecs, &iters);
|
||||
if (ret < 1)
|
||||
return -EINVAL;
|
||||
else if (ret < 2)
|
||||
iters = DEFAULT_ITERATIONS;
|
||||
|
||||
mutex_lock(&udelay_test_lock);
|
||||
udelay_test_usecs = usecs;
|
||||
udelay_test_iterations = iters;
|
||||
mutex_unlock(&udelay_test_lock);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static const struct file_operations udelay_test_debugfs_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = udelay_test_open,
|
||||
.read = seq_read,
|
||||
.write = udelay_test_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int __init udelay_test_init(void)
|
||||
{
|
||||
mutex_lock(&udelay_test_lock);
|
||||
udelay_test_debugfs_file = debugfs_create_file(DEBUGFS_FILENAME,
|
||||
S_IRUSR, NULL, NULL, &udelay_test_debugfs_ops);
|
||||
mutex_unlock(&udelay_test_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
module_init(udelay_test_init);
|
||||
|
||||
static void __exit udelay_test_exit(void)
|
||||
{
|
||||
mutex_lock(&udelay_test_lock);
|
||||
debugfs_remove(udelay_test_debugfs_file);
|
||||
mutex_unlock(&udelay_test_lock);
|
||||
}
|
||||
|
||||
module_exit(udelay_test_exit);
|
||||
|
||||
MODULE_AUTHOR("David Riley <davidriley@chromium.org>");
|
||||
MODULE_LICENSE("GPL");
|
Reference in New Issue
Block a user