Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2666d69 authored by Thomas Gleixner's avatar Thomas Gleixner
Browse files

Merge branch 'fortglx/4.5/time' of https://git.linaro.org/people/john.stultz/linux into timers/core

Get the core time(keeping) updates from John Stultz

    - NTP robustness tweaks
    - Another signed overflow nailed down
    - More y2038 changes
    - Stop alarmtimer after resume
    - MAINTAINERS update
    - Selftest fixes
parents d33f250a ec02b076
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -9348,7 +9348,7 @@ M: Andreas Noever <andreas.noever@gmail.com>
S:	Maintained
F:	drivers/thunderbolt/

TIMEKEEPING, CLOCKSOURCE CORE, NTP
TIMEKEEPING, CLOCKSOURCE CORE, NTP, ALARMTIMER
M:	John Stultz <john.stultz@linaro.org>
M:	Thomas Gleixner <tglx@linutronix.de>
L:	linux-kernel@vger.kernel.org
@@ -9361,6 +9361,7 @@ F: include/uapi/linux/time.h
F:	include/uapi/linux/timex.h
F:	kernel/time/clocksource.c
F:	kernel/time/time*.c
F:	kernel/time/alarmtimer.c
F:	kernel/time/ntp.c
F:	tools/testing/selftests/timers/

+26 −0
Original line number Diff line number Diff line
@@ -125,6 +125,32 @@ static inline bool timeval_valid(const struct timeval *tv)

extern struct timespec timespec_trunc(struct timespec t, unsigned gran);

/*
 * Validates if a timespec/timeval used to inject a time offset is valid.
 * Offsets can be postive or negative. The value of the timeval/timespec
 * is the sum of its fields, but *NOTE*: the field tv_usec/tv_nsec must
 * always be non-negative.
 */
static inline bool timeval_inject_offset_valid(const struct timeval *tv)
{
	/* We don't check the tv_sec as it can be positive or negative */

	/* Can't have more microseconds then a second */
	if (tv->tv_usec < 0 || tv->tv_usec >= USEC_PER_SEC)
		return false;
	return true;
}

static inline bool timespec_inject_offset_valid(const struct timespec *ts)
{
	/* We don't check the tv_sec as it can be positive or negative */

	/* Can't have more nanoseconds then a second */
	if (ts->tv_nsec < 0 || ts->tv_nsec >= NSEC_PER_SEC)
		return false;
	return true;
}

#define CURRENT_TIME		(current_kernel_time())
#define CURRENT_TIME_SEC	((struct timespec) { get_seconds(), 0 })

+17 −0
Original line number Diff line number Diff line
@@ -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 @@ static int alarm_timer_nsleep(const clockid_t which_clock, int flags,
/* Suspend hook structures */
static const struct dev_pm_ops alarmtimer_pm_ops = {
	.suspend = alarmtimer_suspend,
	.resume = alarmtimer_resume,
};

static struct platform_driver alarmtimer_driver = {
+2 −2
Original line number Diff line number Diff line
@@ -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
Original line number Diff line number Diff line
@@ -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,9 +680,15 @@ int ntp_validate_timex(struct timex *txc)
			return -EINVAL;
	}

	if ((txc->modes & ADJ_SETOFFSET) && (!capable(CAP_SYS_TIME)))
	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
	 * only happen on 64-bit systems:
Loading