You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branches 'timers-core-for-linus' and 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates - and a leftover fix - from Thomas Gleixner:
"A rather large (commit wise) update from the timer side:
- A bulk update to make compile tests work in the clocksource drivers
- An overhaul of the h8300 timers
- Some more Y2038 work
- A few overflow prevention checks in the timekeeping/ntp code
- The usual pile of fixes and improvements to the various
clocksource/clockevent drivers and core code"
Also:
"A single fix for the posix-clock poll code which did not make it into
4.4"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (84 commits)
clocksource/drivers/acpi_pm: Convert to pr_* macros
clocksource: Make clocksource validation work for all clocksources
timekeeping: Cap adjustments so they don't exceed the maxadj value
ntp: Fix second_overflow's input parameter type to be 64bits
ntp: Change time_reftime to time64_t and utilize 64bit __ktime_get_real_seconds
timekeeping: Provide internal function __ktime_get_real_seconds
clocksource/drivers/h8300: Use ioread / iowrite
clocksource/drivers/h8300: Initializer cleanup.
clocksource/drivers/h8300: Simplify delta handling
clocksource/drivers/h8300: Fix timer not overflow case
clocksource/drivers/h8300: Change to overflow interrupt
clocksource/drivers/lpc32: Correct pr_err() output format
clocksource/drivers/arm_global_timer: Fix suspend resume
clocksource/drivers/pistachio: Fix wrong calculated clocksource read value
clockevents/drivers/arm_global_timer: Use writel_relaxed in gt_compare_set
clocksource/drivers/dw_apb_timer: Inline apbt_readl and apbt_writel
clocksource/drivers/dw_apb_timer: Use {readl|writel}_relaxed in critical path
clocksource/drivers/dw_apb_timer: Fix apbt_readl return types
clocksource/drivers/tango-xtal: Replace code by clocksource_mmio_init
clocksource/drivers/h8300: Increase the compilation test coverage
...
* 'timers-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
posix-clock: Fix return code on the poll method's error path
This commit is contained in:
@@ -271,11 +271,27 @@ static int alarmtimer_suspend(struct device *dev)
|
||||
__pm_wakeup_event(ws, MSEC_PER_SEC);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int alarmtimer_resume(struct device *dev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
|
||||
rtc = alarmtimer_get_rtcdev();
|
||||
if (rtc)
|
||||
rtc_timer_cancel(rtc, &rtctimer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int alarmtimer_suspend(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int alarmtimer_resume(struct device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void alarmtimer_freezerset(ktime_t absexp, enum alarmtimer_type type)
|
||||
@@ -800,6 +816,7 @@ out:
|
||||
/* Suspend hook structures */
|
||||
static const struct dev_pm_ops alarmtimer_pm_ops = {
|
||||
.suspend = alarmtimer_suspend,
|
||||
.resume = alarmtimer_resume,
|
||||
};
|
||||
|
||||
static struct platform_driver alarmtimer_driver = {
|
||||
|
||||
@@ -218,8 +218,8 @@ static void clocksource_watchdog(unsigned long data)
|
||||
|
||||
/* Check the deviation from the watchdog clocksource. */
|
||||
if (abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD) {
|
||||
pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable because the skew is too large:\n",
|
||||
cs->name);
|
||||
pr_warn("timekeeping watchdog on CPU%d: Marking clocksource '%s' as unstable because the skew is too large:\n",
|
||||
smp_processor_id(), cs->name);
|
||||
pr_warn(" '%s' wd_now: %llx wd_last: %llx mask: %llx\n",
|
||||
watchdog->name, wdnow, wdlast, watchdog->mask);
|
||||
pr_warn(" '%s' cs_now: %llx cs_last: %llx mask: %llx\n",
|
||||
|
||||
+28
-16
@@ -16,8 +16,11 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/math64.h>
|
||||
|
||||
#include "ntp_internal.h"
|
||||
#include "timekeeping_internal.h"
|
||||
|
||||
|
||||
/*
|
||||
* NTP timekeeping variables:
|
||||
@@ -70,7 +73,7 @@ static long time_esterror = NTP_PHASE_LIMIT;
|
||||
static s64 time_freq;
|
||||
|
||||
/* time at last adjustment (secs): */
|
||||
static long time_reftime;
|
||||
static time64_t time_reftime;
|
||||
|
||||
static long time_adjust;
|
||||
|
||||
@@ -297,25 +300,27 @@ static void ntp_update_offset(long offset)
|
||||
if (!(time_status & STA_PLL))
|
||||
return;
|
||||
|
||||
if (!(time_status & STA_NANO))
|
||||
if (!(time_status & STA_NANO)) {
|
||||
/* Make sure the multiplication below won't overflow */
|
||||
offset = clamp(offset, -USEC_PER_SEC, USEC_PER_SEC);
|
||||
offset *= NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scale the phase adjustment and
|
||||
* clamp to the operating range.
|
||||
*/
|
||||
offset = min(offset, MAXPHASE);
|
||||
offset = max(offset, -MAXPHASE);
|
||||
offset = clamp(offset, -MAXPHASE, MAXPHASE);
|
||||
|
||||
/*
|
||||
* Select how the frequency is to be controlled
|
||||
* and in which mode (PLL or FLL).
|
||||
*/
|
||||
secs = get_seconds() - time_reftime;
|
||||
secs = (long)(__ktime_get_real_seconds() - time_reftime);
|
||||
if (unlikely(time_status & STA_FREQHOLD))
|
||||
secs = 0;
|
||||
|
||||
time_reftime = get_seconds();
|
||||
time_reftime = __ktime_get_real_seconds();
|
||||
|
||||
offset64 = offset;
|
||||
freq_adj = ntp_update_offset_fll(offset64, secs);
|
||||
@@ -390,10 +395,11 @@ ktime_t ntp_get_next_leap(void)
|
||||
*
|
||||
* Also handles leap second processing, and returns leap offset
|
||||
*/
|
||||
int second_overflow(unsigned long secs)
|
||||
int second_overflow(time64_t secs)
|
||||
{
|
||||
s64 delta;
|
||||
int leap = 0;
|
||||
s32 rem;
|
||||
|
||||
/*
|
||||
* Leap second processing. If in leap-insert state at the end of the
|
||||
@@ -404,19 +410,19 @@ int second_overflow(unsigned long secs)
|
||||
case TIME_OK:
|
||||
if (time_status & STA_INS) {
|
||||
time_state = TIME_INS;
|
||||
ntp_next_leap_sec = secs + SECS_PER_DAY -
|
||||
(secs % SECS_PER_DAY);
|
||||
div_s64_rem(secs, SECS_PER_DAY, &rem);
|
||||
ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
|
||||
} else if (time_status & STA_DEL) {
|
||||
time_state = TIME_DEL;
|
||||
ntp_next_leap_sec = secs + SECS_PER_DAY -
|
||||
((secs+1) % SECS_PER_DAY);
|
||||
div_s64_rem(secs + 1, SECS_PER_DAY, &rem);
|
||||
ntp_next_leap_sec = secs + SECS_PER_DAY - rem;
|
||||
}
|
||||
break;
|
||||
case TIME_INS:
|
||||
if (!(time_status & STA_INS)) {
|
||||
ntp_next_leap_sec = TIME64_MAX;
|
||||
time_state = TIME_OK;
|
||||
} else if (secs % SECS_PER_DAY == 0) {
|
||||
} else if (secs == ntp_next_leap_sec) {
|
||||
leap = -1;
|
||||
time_state = TIME_OOP;
|
||||
printk(KERN_NOTICE
|
||||
@@ -427,7 +433,7 @@ int second_overflow(unsigned long secs)
|
||||
if (!(time_status & STA_DEL)) {
|
||||
ntp_next_leap_sec = TIME64_MAX;
|
||||
time_state = TIME_OK;
|
||||
} else if ((secs + 1) % SECS_PER_DAY == 0) {
|
||||
} else if (secs == ntp_next_leap_sec) {
|
||||
leap = 1;
|
||||
ntp_next_leap_sec = TIME64_MAX;
|
||||
time_state = TIME_WAIT;
|
||||
@@ -590,7 +596,7 @@ static inline void process_adj_status(struct timex *txc, struct timespec64 *ts)
|
||||
* reference time to current time.
|
||||
*/
|
||||
if (!(time_status & STA_PLL) && (txc->status & STA_PLL))
|
||||
time_reftime = get_seconds();
|
||||
time_reftime = __ktime_get_real_seconds();
|
||||
|
||||
/* only set allowed bits */
|
||||
time_status &= STA_RONLY;
|
||||
@@ -674,8 +680,14 @@ int ntp_validate_timex(struct timex *txc)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
|
||||
return -EPERM;
|
||||
if (txc->modes & ADJ_SETOFFSET) {
|
||||
/* In order to inject time, you gotta be super-user! */
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EPERM;
|
||||
|
||||
if (!timeval_inject_offset_valid(&txc->time))
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for potential multiplication overflows that can
|
||||
|
||||
@@ -6,7 +6,7 @@ extern void ntp_clear(void);
|
||||
/* Returns how long ticks are at present, in ns / 2^NTP_SCALE_SHIFT. */
|
||||
extern u64 ntp_tick_length(void);
|
||||
extern ktime_t ntp_get_next_leap(void);
|
||||
extern int second_overflow(unsigned long secs);
|
||||
extern int second_overflow(time64_t secs);
|
||||
extern int ntp_validate_timex(struct timex *);
|
||||
extern int __do_adjtimex(struct timex *, struct timespec64 *, s32 *);
|
||||
extern void __hardpps(const struct timespec64 *, const struct timespec64 *);
|
||||
|
||||
@@ -69,10 +69,10 @@ static ssize_t posix_clock_read(struct file *fp, char __user *buf,
|
||||
static unsigned int posix_clock_poll(struct file *fp, poll_table *wait)
|
||||
{
|
||||
struct posix_clock *clk = get_posix_clock(fp);
|
||||
int result = 0;
|
||||
unsigned int result = 0;
|
||||
|
||||
if (!clk)
|
||||
return -ENODEV;
|
||||
return POLLERR;
|
||||
|
||||
if (clk->ops.poll)
|
||||
result = clk->ops.poll(clk, fp, wait);
|
||||
|
||||
@@ -603,15 +603,31 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
|
||||
|
||||
/*
|
||||
* If the tick is due in the next period, keep it ticking or
|
||||
* restart it proper.
|
||||
* force prod the timer.
|
||||
*/
|
||||
delta = next_tick - basemono;
|
||||
if (delta <= (u64)TICK_NSEC) {
|
||||
tick.tv64 = 0;
|
||||
/*
|
||||
* We've not stopped the tick yet, and there's a timer in the
|
||||
* next period, so no point in stopping it either, bail.
|
||||
*/
|
||||
if (!ts->tick_stopped)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If, OTOH, we did stop it, but there's a pending (expired)
|
||||
* timer reprogram the timer hardware to fire now.
|
||||
*
|
||||
* We will not restart the tick proper, just prod the timer
|
||||
* hardware into firing an interrupt to process the pending
|
||||
* timers. Just like tick_irq_exit() will not restart the tick
|
||||
* for 'normal' interrupts.
|
||||
*
|
||||
* Only once we exit the idle loop will we re-enable the tick,
|
||||
* see tick_nohz_idle_exit().
|
||||
*/
|
||||
if (delta == 0) {
|
||||
/* Tick is stopped, but required now. Enforce it */
|
||||
tick_nohz_restart(ts, now);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -305,8 +305,7 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
|
||||
|
||||
delta = timekeeping_get_delta(tkr);
|
||||
|
||||
nsec = delta * tkr->mult + tkr->xtime_nsec;
|
||||
nsec >>= tkr->shift;
|
||||
nsec = (delta * tkr->mult + tkr->xtime_nsec) >> tkr->shift;
|
||||
|
||||
/* If arch requires, add in get_arch_timeoffset() */
|
||||
return nsec + arch_gettimeoffset();
|
||||
@@ -846,6 +845,19 @@ time64_t ktime_get_real_seconds(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
|
||||
|
||||
/**
|
||||
* __ktime_get_real_seconds - The same as ktime_get_real_seconds
|
||||
* but without the sequence counter protect. This internal function
|
||||
* is called just when timekeeping lock is already held.
|
||||
*/
|
||||
time64_t __ktime_get_real_seconds(void)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
|
||||
return tk->xtime_sec;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_NTP_PPS
|
||||
|
||||
/**
|
||||
@@ -959,7 +971,7 @@ int timekeeping_inject_offset(struct timespec *ts)
|
||||
struct timespec64 ts64, tmp;
|
||||
int ret = 0;
|
||||
|
||||
if ((unsigned long)ts->tv_nsec >= NSEC_PER_SEC)
|
||||
if (!timespec_inject_offset_valid(ts))
|
||||
return -EINVAL;
|
||||
|
||||
ts64 = timespec_to_timespec64(*ts);
|
||||
@@ -1592,9 +1604,12 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
|
||||
{
|
||||
s64 interval = tk->cycle_interval;
|
||||
s64 xinterval = tk->xtime_interval;
|
||||
u32 base = tk->tkr_mono.clock->mult;
|
||||
u32 max = tk->tkr_mono.clock->maxadj;
|
||||
u32 cur_adj = tk->tkr_mono.mult;
|
||||
s64 tick_error;
|
||||
bool negative;
|
||||
u32 adj;
|
||||
u32 adj_scale;
|
||||
|
||||
/* Remove any current error adj from freq calculation */
|
||||
if (tk->ntp_err_mult)
|
||||
@@ -1613,13 +1628,33 @@ static __always_inline void timekeeping_freqadjust(struct timekeeper *tk,
|
||||
/* preserve the direction of correction */
|
||||
negative = (tick_error < 0);
|
||||
|
||||
/* Sort out the magnitude of the correction */
|
||||
/* If any adjustment would pass the max, just return */
|
||||
if (negative && (cur_adj - 1) <= (base - max))
|
||||
return;
|
||||
if (!negative && (cur_adj + 1) >= (base + max))
|
||||
return;
|
||||
/*
|
||||
* Sort out the magnitude of the correction, but
|
||||
* avoid making so large a correction that we go
|
||||
* over the max adjustment.
|
||||
*/
|
||||
adj_scale = 0;
|
||||
tick_error = abs(tick_error);
|
||||
for (adj = 0; tick_error > interval; adj++)
|
||||
while (tick_error > interval) {
|
||||
u32 adj = 1 << (adj_scale + 1);
|
||||
|
||||
/* Check if adjustment gets us within 1 unit from the max */
|
||||
if (negative && (cur_adj - adj) <= (base - max))
|
||||
break;
|
||||
if (!negative && (cur_adj + adj) >= (base + max))
|
||||
break;
|
||||
|
||||
adj_scale++;
|
||||
tick_error >>= 1;
|
||||
}
|
||||
|
||||
/* scale the corrections */
|
||||
timekeeping_apply_adjustment(tk, offset, negative, adj);
|
||||
timekeeping_apply_adjustment(tk, offset, negative, adj_scale);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -17,7 +17,11 @@ 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;
|
||||
/*
|
||||
* Prevent time going backwards by checking the MSB of mask in
|
||||
* the result. If set, return 0.
|
||||
*/
|
||||
return ret & ~(mask >> 1) ? 0 : ret;
|
||||
}
|
||||
#else
|
||||
static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
|
||||
@@ -26,4 +30,6 @@ static inline cycle_t clocksource_delta(cycle_t now, cycle_t last, cycle_t mask)
|
||||
}
|
||||
#endif
|
||||
|
||||
extern time64_t __ktime_get_real_seconds(void);
|
||||
|
||||
#endif /* _TIMEKEEPING_INTERNAL_H */
|
||||
|
||||
Reference in New Issue
Block a user