Merge tag 'fortglx/4.19/time-part2' of https://git.linaro.org/people/john.stultz/linux into timers/core
Pull the second set of timekeeping things for 4.19 from John Stultz * NTP argument clenaups and constification from Ondrej Mosnacek * Fix to avoid RTC injecting sleeptime when suspend fails from Mukesh Ojha * Broading suspsend-timing to include non-stop clocksources that aren't currently used for timekeeping from Baolin Wang
This commit is contained in:
commit
e5af5ff34c
|
@ -194,6 +194,9 @@ extern void clocksource_suspend(void);
|
||||||
extern void clocksource_resume(void);
|
extern void clocksource_resume(void);
|
||||||
extern struct clocksource * __init clocksource_default_clock(void);
|
extern struct clocksource * __init clocksource_default_clock(void);
|
||||||
extern void clocksource_mark_unstable(struct clocksource *cs);
|
extern void clocksource_mark_unstable(struct clocksource *cs);
|
||||||
|
extern void
|
||||||
|
clocksource_start_suspend_timing(struct clocksource *cs, u64 start_cycles);
|
||||||
|
extern u64 clocksource_stop_suspend_timing(struct clocksource *cs, u64 now);
|
||||||
|
|
||||||
extern u64
|
extern u64
|
||||||
clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles);
|
clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cycles);
|
||||||
|
|
|
@ -177,7 +177,7 @@ static inline time64_t ktime_get_clocktai_seconds(void)
|
||||||
extern bool timekeeping_rtc_skipsuspend(void);
|
extern bool timekeeping_rtc_skipsuspend(void);
|
||||||
extern bool timekeeping_rtc_skipresume(void);
|
extern bool timekeeping_rtc_skipresume(void);
|
||||||
|
|
||||||
extern void timekeeping_inject_sleeptime64(struct timespec64 *delta);
|
extern void timekeeping_inject_sleeptime64(const struct timespec64 *delta);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* struct system_time_snapshot - simultaneous raw/real time capture with
|
* struct system_time_snapshot - simultaneous raw/real time capture with
|
||||||
|
|
|
@ -94,6 +94,8 @@ EXPORT_SYMBOL_GPL(clocks_calc_mult_shift);
|
||||||
/*[Clocksource internal variables]---------
|
/*[Clocksource internal variables]---------
|
||||||
* curr_clocksource:
|
* curr_clocksource:
|
||||||
* currently selected clocksource.
|
* currently selected clocksource.
|
||||||
|
* suspend_clocksource:
|
||||||
|
* used to calculate the suspend time.
|
||||||
* clocksource_list:
|
* clocksource_list:
|
||||||
* linked list with the registered clocksources
|
* linked list with the registered clocksources
|
||||||
* clocksource_mutex:
|
* clocksource_mutex:
|
||||||
|
@ -102,10 +104,12 @@ EXPORT_SYMBOL_GPL(clocks_calc_mult_shift);
|
||||||
* Name of the user-specified clocksource.
|
* Name of the user-specified clocksource.
|
||||||
*/
|
*/
|
||||||
static struct clocksource *curr_clocksource;
|
static struct clocksource *curr_clocksource;
|
||||||
|
static struct clocksource *suspend_clocksource;
|
||||||
static LIST_HEAD(clocksource_list);
|
static LIST_HEAD(clocksource_list);
|
||||||
static DEFINE_MUTEX(clocksource_mutex);
|
static DEFINE_MUTEX(clocksource_mutex);
|
||||||
static char override_name[CS_NAME_LEN];
|
static char override_name[CS_NAME_LEN];
|
||||||
static int finished_booting;
|
static int finished_booting;
|
||||||
|
static u64 suspend_start;
|
||||||
|
|
||||||
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
|
#ifdef CONFIG_CLOCKSOURCE_WATCHDOG
|
||||||
static void clocksource_watchdog_work(struct work_struct *work);
|
static void clocksource_watchdog_work(struct work_struct *work);
|
||||||
|
@ -447,6 +451,140 @@ static inline void clocksource_watchdog_unlock(unsigned long *flags) { }
|
||||||
|
|
||||||
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
|
#endif /* CONFIG_CLOCKSOURCE_WATCHDOG */
|
||||||
|
|
||||||
|
static bool clocksource_is_suspend(struct clocksource *cs)
|
||||||
|
{
|
||||||
|
return cs == suspend_clocksource;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __clocksource_suspend_select(struct clocksource *cs)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Skip the clocksource which will be stopped in suspend state.
|
||||||
|
*/
|
||||||
|
if (!(cs->flags & CLOCK_SOURCE_SUSPEND_NONSTOP))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The nonstop clocksource can be selected as the suspend clocksource to
|
||||||
|
* calculate the suspend time, so it should not supply suspend/resume
|
||||||
|
* interfaces to suspend the nonstop clocksource when system suspends.
|
||||||
|
*/
|
||||||
|
if (cs->suspend || cs->resume) {
|
||||||
|
pr_warn("Nonstop clocksource %s should not supply suspend/resume interfaces\n",
|
||||||
|
cs->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pick the best rating. */
|
||||||
|
if (!suspend_clocksource || cs->rating > suspend_clocksource->rating)
|
||||||
|
suspend_clocksource = cs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clocksource_suspend_select - Select the best clocksource for suspend timing
|
||||||
|
* @fallback: if select a fallback clocksource
|
||||||
|
*/
|
||||||
|
static void clocksource_suspend_select(bool fallback)
|
||||||
|
{
|
||||||
|
struct clocksource *cs, *old_suspend;
|
||||||
|
|
||||||
|
old_suspend = suspend_clocksource;
|
||||||
|
if (fallback)
|
||||||
|
suspend_clocksource = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry(cs, &clocksource_list, list) {
|
||||||
|
/* Skip current if we were requested for a fallback. */
|
||||||
|
if (fallback && cs == old_suspend)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__clocksource_suspend_select(cs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clocksource_start_suspend_timing - Start measuring the suspend timing
|
||||||
|
* @cs: current clocksource from timekeeping
|
||||||
|
* @start_cycles: current cycles from timekeeping
|
||||||
|
*
|
||||||
|
* This function will save the start cycle values of suspend timer to calculate
|
||||||
|
* the suspend time when resuming system.
|
||||||
|
*
|
||||||
|
* This function is called late in the suspend process from timekeeping_suspend(),
|
||||||
|
* that means processes are freezed, non-boot cpus and interrupts are disabled
|
||||||
|
* now. It is therefore possible to start the suspend timer without taking the
|
||||||
|
* clocksource mutex.
|
||||||
|
*/
|
||||||
|
void clocksource_start_suspend_timing(struct clocksource *cs, u64 start_cycles)
|
||||||
|
{
|
||||||
|
if (!suspend_clocksource)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If current clocksource is the suspend timer, we should use the
|
||||||
|
* tkr_mono.cycle_last value as suspend_start to avoid same reading
|
||||||
|
* from suspend timer.
|
||||||
|
*/
|
||||||
|
if (clocksource_is_suspend(cs)) {
|
||||||
|
suspend_start = start_cycles;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suspend_clocksource->enable &&
|
||||||
|
suspend_clocksource->enable(suspend_clocksource)) {
|
||||||
|
pr_warn_once("Failed to enable the non-suspend-able clocksource.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend_start = suspend_clocksource->read(suspend_clocksource);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* clocksource_stop_suspend_timing - Stop measuring the suspend timing
|
||||||
|
* @cs: current clocksource from timekeeping
|
||||||
|
* @cycle_now: current cycles from timekeeping
|
||||||
|
*
|
||||||
|
* This function will calculate the suspend time from suspend timer.
|
||||||
|
*
|
||||||
|
* Returns nanoseconds since suspend started, 0 if no usable suspend clocksource.
|
||||||
|
*
|
||||||
|
* This function is called early in the resume process from timekeeping_resume(),
|
||||||
|
* that means there is only one cpu, no processes are running and the interrupts
|
||||||
|
* are disabled. It is therefore possible to stop the suspend timer without
|
||||||
|
* taking the clocksource mutex.
|
||||||
|
*/
|
||||||
|
u64 clocksource_stop_suspend_timing(struct clocksource *cs, u64 cycle_now)
|
||||||
|
{
|
||||||
|
u64 now, delta, nsec = 0;
|
||||||
|
|
||||||
|
if (!suspend_clocksource)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If current clocksource is the suspend timer, we should use the
|
||||||
|
* tkr_mono.cycle_last value from timekeeping as current cycle to
|
||||||
|
* avoid same reading from suspend timer.
|
||||||
|
*/
|
||||||
|
if (clocksource_is_suspend(cs))
|
||||||
|
now = cycle_now;
|
||||||
|
else
|
||||||
|
now = suspend_clocksource->read(suspend_clocksource);
|
||||||
|
|
||||||
|
if (now > suspend_start) {
|
||||||
|
delta = clocksource_delta(now, suspend_start,
|
||||||
|
suspend_clocksource->mask);
|
||||||
|
nsec = mul_u64_u32_shr(delta, suspend_clocksource->mult,
|
||||||
|
suspend_clocksource->shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disable the suspend timer to save power if current clocksource is
|
||||||
|
* not the suspend timer.
|
||||||
|
*/
|
||||||
|
if (!clocksource_is_suspend(cs) && suspend_clocksource->disable)
|
||||||
|
suspend_clocksource->disable(suspend_clocksource);
|
||||||
|
|
||||||
|
return nsec;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* clocksource_suspend - suspend the clocksource(s)
|
* clocksource_suspend - suspend the clocksource(s)
|
||||||
*/
|
*/
|
||||||
|
@ -792,6 +930,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||||
|
|
||||||
clocksource_select();
|
clocksource_select();
|
||||||
clocksource_select_watchdog(false);
|
clocksource_select_watchdog(false);
|
||||||
|
__clocksource_suspend_select(cs);
|
||||||
mutex_unlock(&clocksource_mutex);
|
mutex_unlock(&clocksource_mutex);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -820,6 +959,7 @@ void clocksource_change_rating(struct clocksource *cs, int rating)
|
||||||
|
|
||||||
clocksource_select();
|
clocksource_select();
|
||||||
clocksource_select_watchdog(false);
|
clocksource_select_watchdog(false);
|
||||||
|
clocksource_suspend_select(false);
|
||||||
mutex_unlock(&clocksource_mutex);
|
mutex_unlock(&clocksource_mutex);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(clocksource_change_rating);
|
EXPORT_SYMBOL(clocksource_change_rating);
|
||||||
|
@ -845,6 +985,15 @@ static int clocksource_unbind(struct clocksource *cs)
|
||||||
return -EBUSY;
|
return -EBUSY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (clocksource_is_suspend(cs)) {
|
||||||
|
/*
|
||||||
|
* Select and try to install a replacement suspend clocksource.
|
||||||
|
* If no replacement suspend clocksource, we will just let the
|
||||||
|
* clocksource go and have no suspend clocksource.
|
||||||
|
*/
|
||||||
|
clocksource_suspend_select(true);
|
||||||
|
}
|
||||||
|
|
||||||
clocksource_watchdog_lock(&flags);
|
clocksource_watchdog_lock(&flags);
|
||||||
clocksource_dequeue_watchdog(cs);
|
clocksource_dequeue_watchdog(cs);
|
||||||
list_del_init(&cs->list);
|
list_del_init(&cs->list);
|
||||||
|
|
|
@ -642,7 +642,7 @@ void ntp_notify_cmos_timer(void)
|
||||||
/*
|
/*
|
||||||
* Propagate a new txc->status value into the NTP state:
|
* Propagate a new txc->status value into the NTP state:
|
||||||
*/
|
*/
|
||||||
static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
|
static inline void process_adj_status(const struct timex *txc)
|
||||||
{
|
{
|
||||||
if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
|
if ((time_status & STA_PLL) && !(txc->status & STA_PLL)) {
|
||||||
time_state = TIME_OK;
|
time_state = TIME_OK;
|
||||||
|
@ -665,12 +665,10 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void process_adjtimex_modes(struct timex *txc,
|
static inline void process_adjtimex_modes(const struct timex *txc, s32 *time_tai)
|
||||||
struct timespec64 *ts,
|
|
||||||
s32 *time_tai)
|
|
||||||
{
|
{
|
||||||
if (txc->modes & ADJ_STATUS)
|
if (txc->modes & ADJ_STATUS)
|
||||||
process_adj_status(txc, ts);
|
process_adj_status(txc);
|
||||||
|
|
||||||
if (txc->modes & ADJ_NANO)
|
if (txc->modes & ADJ_NANO)
|
||||||
time_status |= STA_NANO;
|
time_status |= STA_NANO;
|
||||||
|
@ -718,7 +716,7 @@ static inline void process_adjtimex_modes(struct timex *txc,
|
||||||
* adjtimex mainly allows reading (and writing, if superuser) of
|
* adjtimex mainly allows reading (and writing, if superuser) of
|
||||||
* kernel time-keeping variables. used by xntpd.
|
* kernel time-keeping variables. used by xntpd.
|
||||||
*/
|
*/
|
||||||
int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai)
|
int __do_adjtimex(struct timex *txc, const struct timespec64 *ts, s32 *time_tai)
|
||||||
{
|
{
|
||||||
int result;
|
int result;
|
||||||
|
|
||||||
|
@ -735,7 +733,7 @@ int __do_adjtimex(struct timex *txc, struct timespec64 *ts, s32 *time_tai)
|
||||||
|
|
||||||
/* If there are input parameters, then process them: */
|
/* If there are input parameters, then process them: */
|
||||||
if (txc->modes)
|
if (txc->modes)
|
||||||
process_adjtimex_modes(txc, ts, time_tai);
|
process_adjtimex_modes(txc, time_tai);
|
||||||
|
|
||||||
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
|
txc->offset = shift_right(time_offset * NTP_INTERVAL_FREQ,
|
||||||
NTP_SCALE_SHIFT);
|
NTP_SCALE_SHIFT);
|
||||||
|
@ -1022,12 +1020,11 @@ void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_t
|
||||||
|
|
||||||
static int __init ntp_tick_adj_setup(char *str)
|
static int __init ntp_tick_adj_setup(char *str)
|
||||||
{
|
{
|
||||||
int rc = kstrtol(str, 0, (long *)&ntp_tick_adj);
|
int rc = kstrtos64(str, 0, &ntp_tick_adj);
|
||||||
|
|
||||||
if (rc)
|
if (rc)
|
||||||
return rc;
|
return rc;
|
||||||
ntp_tick_adj <<= NTP_SCALE_SHIFT;
|
|
||||||
|
|
||||||
|
ntp_tick_adj <<= NTP_SCALE_SHIFT;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,6 @@ extern void ntp_clear(void);
|
||||||
extern u64 ntp_tick_length(void);
|
extern u64 ntp_tick_length(void);
|
||||||
extern ktime_t ntp_get_next_leap(void);
|
extern ktime_t ntp_get_next_leap(void);
|
||||||
extern int second_overflow(time64_t secs);
|
extern int second_overflow(time64_t secs);
|
||||||
extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
|
extern int __do_adjtimex(struct timex *txc, const struct timespec64 *ts, s32 *time_tai);
|
||||||
extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
|
extern void __hardpps(const struct timespec64 *phase_ts, const struct timespec64 *raw_ts);
|
||||||
#endif /* _LINUX_NTP_INTERNAL_H */
|
#endif /* _LINUX_NTP_INTERNAL_H */
|
||||||
|
|
|
@ -105,7 +105,7 @@ static inline void tk_normalize_xtime(struct timekeeper *tk)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline struct timespec64 tk_xtime(struct timekeeper *tk)
|
static inline struct timespec64 tk_xtime(const struct timekeeper *tk)
|
||||||
{
|
{
|
||||||
struct timespec64 ts;
|
struct timespec64 ts;
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
|
||||||
* a read of the fast-timekeeper tkrs (which is protected by its own locking
|
* a read of the fast-timekeeper tkrs (which is protected by its own locking
|
||||||
* and update logic).
|
* and update logic).
|
||||||
*/
|
*/
|
||||||
static inline u64 tk_clock_read(struct tk_read_base *tkr)
|
static inline u64 tk_clock_read(const struct tk_read_base *tkr)
|
||||||
{
|
{
|
||||||
struct clocksource *clock = READ_ONCE(tkr->clock);
|
struct clocksource *clock = READ_ONCE(tkr->clock);
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ static void timekeeping_check_update(struct timekeeper *tk, u64 offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 timekeeping_get_delta(struct tk_read_base *tkr)
|
static inline u64 timekeeping_get_delta(const struct tk_read_base *tkr)
|
||||||
{
|
{
|
||||||
struct timekeeper *tk = &tk_core.timekeeper;
|
struct timekeeper *tk = &tk_core.timekeeper;
|
||||||
u64 now, last, mask, max, delta;
|
u64 now, last, mask, max, delta;
|
||||||
|
@ -255,7 +255,7 @@ static inline u64 timekeeping_get_delta(struct tk_read_base *tkr)
|
||||||
static inline void timekeeping_check_update(struct timekeeper *tk, u64 offset)
|
static inline void timekeeping_check_update(struct timekeeper *tk, u64 offset)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
static inline u64 timekeeping_get_delta(struct tk_read_base *tkr)
|
static inline u64 timekeeping_get_delta(const struct tk_read_base *tkr)
|
||||||
{
|
{
|
||||||
u64 cycle_now, delta;
|
u64 cycle_now, delta;
|
||||||
|
|
||||||
|
@ -352,7 +352,7 @@ u32 (*arch_gettimeoffset)(void) = default_arch_gettimeoffset;
|
||||||
static inline u32 arch_gettimeoffset(void) { return 0; }
|
static inline u32 arch_gettimeoffset(void) { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr, u64 delta)
|
static inline u64 timekeeping_delta_to_ns(const struct tk_read_base *tkr, u64 delta)
|
||||||
{
|
{
|
||||||
u64 nsec;
|
u64 nsec;
|
||||||
|
|
||||||
|
@ -363,7 +363,7 @@ static inline u64 timekeeping_delta_to_ns(struct tk_read_base *tkr, u64 delta)
|
||||||
return nsec + arch_gettimeoffset();
|
return nsec + arch_gettimeoffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 timekeeping_get_ns(struct tk_read_base *tkr)
|
static inline u64 timekeeping_get_ns(const struct tk_read_base *tkr)
|
||||||
{
|
{
|
||||||
u64 delta;
|
u64 delta;
|
||||||
|
|
||||||
|
@ -371,7 +371,7 @@ static inline u64 timekeeping_get_ns(struct tk_read_base *tkr)
|
||||||
return timekeeping_delta_to_ns(tkr, delta);
|
return timekeeping_delta_to_ns(tkr, delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline u64 timekeeping_cycles_to_ns(struct tk_read_base *tkr, u64 cycles)
|
static inline u64 timekeeping_cycles_to_ns(const struct tk_read_base *tkr, u64 cycles)
|
||||||
{
|
{
|
||||||
u64 delta;
|
u64 delta;
|
||||||
|
|
||||||
|
@ -394,7 +394,8 @@ static inline u64 timekeeping_cycles_to_ns(struct tk_read_base *tkr, u64 cycles)
|
||||||
* slightly wrong timestamp (a few nanoseconds). See
|
* slightly wrong timestamp (a few nanoseconds). See
|
||||||
* @ktime_get_mono_fast_ns.
|
* @ktime_get_mono_fast_ns.
|
||||||
*/
|
*/
|
||||||
static void update_fast_timekeeper(struct tk_read_base *tkr, struct tk_fast *tkf)
|
static void update_fast_timekeeper(const struct tk_read_base *tkr,
|
||||||
|
struct tk_fast *tkf)
|
||||||
{
|
{
|
||||||
struct tk_read_base *base = tkf->base;
|
struct tk_read_base *base = tkf->base;
|
||||||
|
|
||||||
|
@ -549,10 +550,10 @@ EXPORT_SYMBOL_GPL(ktime_get_real_fast_ns);
|
||||||
* number of cycles every time until timekeeping is resumed at which time the
|
* number of cycles every time until timekeeping is resumed at which time the
|
||||||
* proper readout base for the fast timekeeper will be restored automatically.
|
* proper readout base for the fast timekeeper will be restored automatically.
|
||||||
*/
|
*/
|
||||||
static void halt_fast_timekeeper(struct timekeeper *tk)
|
static void halt_fast_timekeeper(const struct timekeeper *tk)
|
||||||
{
|
{
|
||||||
static struct tk_read_base tkr_dummy;
|
static struct tk_read_base tkr_dummy;
|
||||||
struct tk_read_base *tkr = &tk->tkr_mono;
|
const struct tk_read_base *tkr = &tk->tkr_mono;
|
||||||
|
|
||||||
memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
|
memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
|
||||||
cycles_at_suspend = tk_clock_read(tkr);
|
cycles_at_suspend = tk_clock_read(tkr);
|
||||||
|
@ -1277,7 +1278,7 @@ EXPORT_SYMBOL(do_settimeofday64);
|
||||||
*
|
*
|
||||||
* Adds or subtracts an offset value from the current time.
|
* Adds or subtracts an offset value from the current time.
|
||||||
*/
|
*/
|
||||||
static int timekeeping_inject_offset(struct timespec64 *ts)
|
static int timekeeping_inject_offset(const struct timespec64 *ts)
|
||||||
{
|
{
|
||||||
struct timekeeper *tk = &tk_core.timekeeper;
|
struct timekeeper *tk = &tk_core.timekeeper;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -1518,8 +1519,20 @@ void __weak read_boot_clock64(struct timespec64 *ts)
|
||||||
ts->tv_nsec = 0;
|
ts->tv_nsec = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Flag for if timekeeping_resume() has injected sleeptime */
|
/*
|
||||||
static bool sleeptime_injected;
|
* Flag reflecting whether timekeeping_resume() has injected sleeptime.
|
||||||
|
*
|
||||||
|
* The flag starts of false and is only set when a suspend reaches
|
||||||
|
* timekeeping_suspend(), timekeeping_resume() sets it to false when the
|
||||||
|
* timekeeper clocksource is not stopping across suspend and has been
|
||||||
|
* used to update sleep time. If the timekeeper clocksource has stopped
|
||||||
|
* then the flag stays true and is used by the RTC resume code to decide
|
||||||
|
* whether sleeptime must be injected and if so the flag gets false then.
|
||||||
|
*
|
||||||
|
* If a suspend fails before reaching timekeeping_resume() then the flag
|
||||||
|
* stays false and prevents erroneous sleeptime injection.
|
||||||
|
*/
|
||||||
|
static bool suspend_timing_needed;
|
||||||
|
|
||||||
/* Flag for if there is a persistent clock on this platform */
|
/* Flag for if there is a persistent clock on this platform */
|
||||||
static bool persistent_clock_exists;
|
static bool persistent_clock_exists;
|
||||||
|
@ -1585,7 +1598,7 @@ static struct timespec64 timekeeping_suspend_time;
|
||||||
* adds the sleep offset to the timekeeping variables.
|
* adds the sleep offset to the timekeeping variables.
|
||||||
*/
|
*/
|
||||||
static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
|
static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
|
||||||
struct timespec64 *delta)
|
const struct timespec64 *delta)
|
||||||
{
|
{
|
||||||
if (!timespec64_valid_strict(delta)) {
|
if (!timespec64_valid_strict(delta)) {
|
||||||
printk_deferred(KERN_WARNING
|
printk_deferred(KERN_WARNING
|
||||||
|
@ -1618,7 +1631,7 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
|
||||||
*/
|
*/
|
||||||
bool timekeeping_rtc_skipresume(void)
|
bool timekeeping_rtc_skipresume(void)
|
||||||
{
|
{
|
||||||
return sleeptime_injected;
|
return !suspend_timing_needed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1646,7 +1659,7 @@ bool timekeeping_rtc_skipsuspend(void)
|
||||||
* This function should only be called by rtc_resume(), and allows
|
* This function should only be called by rtc_resume(), and allows
|
||||||
* a suspend offset to be injected into the timekeeping values.
|
* a suspend offset to be injected into the timekeeping values.
|
||||||
*/
|
*/
|
||||||
void timekeeping_inject_sleeptime64(struct timespec64 *delta)
|
void timekeeping_inject_sleeptime64(const struct timespec64 *delta)
|
||||||
{
|
{
|
||||||
struct timekeeper *tk = &tk_core.timekeeper;
|
struct timekeeper *tk = &tk_core.timekeeper;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -1654,6 +1667,8 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
|
||||||
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
||||||
write_seqcount_begin(&tk_core.seq);
|
write_seqcount_begin(&tk_core.seq);
|
||||||
|
|
||||||
|
suspend_timing_needed = false;
|
||||||
|
|
||||||
timekeeping_forward_now(tk);
|
timekeeping_forward_now(tk);
|
||||||
|
|
||||||
__timekeeping_inject_sleeptime(tk, delta);
|
__timekeeping_inject_sleeptime(tk, delta);
|
||||||
|
@ -1677,9 +1692,9 @@ void timekeeping_resume(void)
|
||||||
struct clocksource *clock = tk->tkr_mono.clock;
|
struct clocksource *clock = tk->tkr_mono.clock;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct timespec64 ts_new, ts_delta;
|
struct timespec64 ts_new, ts_delta;
|
||||||
u64 cycle_now;
|
u64 cycle_now, nsec;
|
||||||
|
bool inject_sleeptime = false;
|
||||||
|
|
||||||
sleeptime_injected = false;
|
|
||||||
read_persistent_clock64(&ts_new);
|
read_persistent_clock64(&ts_new);
|
||||||
|
|
||||||
clockevents_resume();
|
clockevents_resume();
|
||||||
|
@ -1701,22 +1716,19 @@ void timekeeping_resume(void)
|
||||||
* usable source. The rtc part is handled separately in rtc core code.
|
* usable source. The rtc part is handled separately in rtc core code.
|
||||||
*/
|
*/
|
||||||
cycle_now = tk_clock_read(&tk->tkr_mono);
|
cycle_now = tk_clock_read(&tk->tkr_mono);
|
||||||
if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
|
nsec = clocksource_stop_suspend_timing(clock, cycle_now);
|
||||||
cycle_now > tk->tkr_mono.cycle_last) {
|
if (nsec > 0) {
|
||||||
u64 nsec, cyc_delta;
|
|
||||||
|
|
||||||
cyc_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
|
|
||||||
tk->tkr_mono.mask);
|
|
||||||
nsec = mul_u64_u32_shr(cyc_delta, clock->mult, clock->shift);
|
|
||||||
ts_delta = ns_to_timespec64(nsec);
|
ts_delta = ns_to_timespec64(nsec);
|
||||||
sleeptime_injected = true;
|
inject_sleeptime = true;
|
||||||
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
|
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
|
||||||
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
|
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
|
||||||
sleeptime_injected = true;
|
inject_sleeptime = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sleeptime_injected)
|
if (inject_sleeptime) {
|
||||||
|
suspend_timing_needed = false;
|
||||||
__timekeeping_inject_sleeptime(tk, &ts_delta);
|
__timekeeping_inject_sleeptime(tk, &ts_delta);
|
||||||
|
}
|
||||||
|
|
||||||
/* Re-base the last cycle value */
|
/* Re-base the last cycle value */
|
||||||
tk->tkr_mono.cycle_last = cycle_now;
|
tk->tkr_mono.cycle_last = cycle_now;
|
||||||
|
@ -1740,6 +1752,8 @@ int timekeeping_suspend(void)
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
struct timespec64 delta, delta_delta;
|
struct timespec64 delta, delta_delta;
|
||||||
static struct timespec64 old_delta;
|
static struct timespec64 old_delta;
|
||||||
|
struct clocksource *curr_clock;
|
||||||
|
u64 cycle_now;
|
||||||
|
|
||||||
read_persistent_clock64(&timekeeping_suspend_time);
|
read_persistent_clock64(&timekeeping_suspend_time);
|
||||||
|
|
||||||
|
@ -1751,11 +1765,22 @@ int timekeeping_suspend(void)
|
||||||
if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
|
if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
|
||||||
persistent_clock_exists = true;
|
persistent_clock_exists = true;
|
||||||
|
|
||||||
|
suspend_timing_needed = true;
|
||||||
|
|
||||||
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
||||||
write_seqcount_begin(&tk_core.seq);
|
write_seqcount_begin(&tk_core.seq);
|
||||||
timekeeping_forward_now(tk);
|
timekeeping_forward_now(tk);
|
||||||
timekeeping_suspended = 1;
|
timekeeping_suspended = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since we've called forward_now, cycle_last stores the value
|
||||||
|
* just read from the current clocksource. Save this to potentially
|
||||||
|
* use in suspend timing.
|
||||||
|
*/
|
||||||
|
curr_clock = tk->tkr_mono.clock;
|
||||||
|
cycle_now = tk->tkr_mono.cycle_last;
|
||||||
|
clocksource_start_suspend_timing(curr_clock, cycle_now);
|
||||||
|
|
||||||
if (persistent_clock_exists) {
|
if (persistent_clock_exists) {
|
||||||
/*
|
/*
|
||||||
* To avoid drift caused by repeated suspend/resumes,
|
* To avoid drift caused by repeated suspend/resumes,
|
||||||
|
@ -2240,7 +2265,7 @@ ktime_t ktime_get_update_offsets_now(unsigned int *cwsseq, ktime_t *offs_real,
|
||||||
/**
|
/**
|
||||||
* timekeeping_validate_timex - Ensures the timex is ok for use in do_adjtimex
|
* timekeeping_validate_timex - Ensures the timex is ok for use in do_adjtimex
|
||||||
*/
|
*/
|
||||||
static int timekeeping_validate_timex(struct timex *txc)
|
static int timekeeping_validate_timex(const struct timex *txc)
|
||||||
{
|
{
|
||||||
if (txc->modes & ADJ_ADJTIME) {
|
if (txc->modes & ADJ_ADJTIME) {
|
||||||
/* singleshot must not be used with any other mode bits */
|
/* singleshot must not be used with any other mode bits */
|
||||||
|
|
|
@ -70,7 +70,7 @@ static int __init tk_debug_sleep_time_init(void)
|
||||||
}
|
}
|
||||||
late_initcall(tk_debug_sleep_time_init);
|
late_initcall(tk_debug_sleep_time_init);
|
||||||
|
|
||||||
void tk_debug_account_sleep_time(struct timespec64 *t)
|
void tk_debug_account_sleep_time(const struct timespec64 *t)
|
||||||
{
|
{
|
||||||
/* Cap bin index so we don't overflow the array */
|
/* Cap bin index so we don't overflow the array */
|
||||||
int bin = min(fls(t->tv_sec), NUM_BINS-1);
|
int bin = min(fls(t->tv_sec), NUM_BINS-1);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
#include <linux/time.h>
|
#include <linux/time.h>
|
||||||
|
|
||||||
#ifdef CONFIG_DEBUG_FS
|
#ifdef CONFIG_DEBUG_FS
|
||||||
extern void tk_debug_account_sleep_time(struct timespec64 *t);
|
extern void tk_debug_account_sleep_time(const struct timespec64 *t);
|
||||||
#else
|
#else
|
||||||
#define tk_debug_account_sleep_time(x)
|
#define tk_debug_account_sleep_time(x)
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue