Merge branch 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull timer updates from Ingo Molnar:
"The main changes in this cycle were:
- clockevents state machine cleanups and enhancements (Viresh Kumar)
- clockevents broadcast notifier horror to state machine conversion
and related cleanups (Thomas Gleixner, Rafael J Wysocki)
- clocksource and timekeeping core updates (John Stultz)
- clocksource driver updates and fixes (Ben Dooks, Dmitry Osipenko,
Hans de Goede, Laurent Pinchart, Maxime Ripard, Xunlei Pang)
- y2038 fixes (Xunlei Pang, John Stultz)
- NMI-safe ktime_get_raw_fast() and general refactoring of the clock
code, in preparation to perf's per event clock ID support (Peter
Zijlstra)
- generic sched/clock fixes, optimizations and cleanups (Daniel
Thompson)
- clockevents cpu_down() race fix (Preeti U Murthy)"
* 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (94 commits)
timers/PM: Drop unnecessary braces from tick_freeze()
timers/PM: Fix up tick_unfreeze()
timekeeping: Get rid of stale comment
clockevents: Cleanup dead cpu explicitely
clockevents: Make tick handover explicit
clockevents: Remove broadcast oneshot control leftovers
sched/idle: Use explicit broadcast oneshot control function
ARM: Tegra: Use explicit broadcast oneshot control function
ARM: OMAP: Use explicit broadcast oneshot control function
intel_idle: Use explicit broadcast oneshot control function
ACPI/idle: Use explicit broadcast control function
ACPI/PAD: Use explicit broadcast oneshot control function
x86/amd/idle, clockevents: Use explicit broadcast oneshot control functions
clockevents: Provide explicit broadcast oneshot control functions
clockevents: Remove the broadcast control leftovers
ARM: OMAP: Use explicit broadcast control function
intel_idle: Use explicit broadcast control function
cpuidle: Use explicit broadcast control function
ACPI/processor: Use explicit broadcast control function
ACPI/PAD: Use explicit broadcast control function
...
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/lockdep.h>
|
||||
#include <linux/tick.h>
|
||||
#include <trace/events/power.h>
|
||||
|
||||
#include "smpboot.h"
|
||||
@@ -338,6 +339,8 @@ static int __ref take_cpu_down(void *_param)
|
||||
return err;
|
||||
|
||||
cpu_notify(CPU_DYING | param->mod, param->hcpu);
|
||||
/* Give up timekeeping duties */
|
||||
tick_handover_do_timer();
|
||||
/* Park the stopper thread */
|
||||
kthread_park(current);
|
||||
return 0;
|
||||
@@ -411,10 +414,12 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
|
||||
while (!idle_cpu(cpu))
|
||||
cpu_relax();
|
||||
|
||||
hotplug_cpu__broadcast_tick_pull(cpu);
|
||||
/* This actually kills the CPU. */
|
||||
__cpu_die(cpu);
|
||||
|
||||
/* CPU is completely dead: tell everyone. Too late to complain. */
|
||||
tick_cleanup_dead_cpu(cpu);
|
||||
cpu_notify_nofail(CPU_DEAD | mod, hcpu);
|
||||
|
||||
check_for_tasks(cpu);
|
||||
|
||||
+2
-3
@@ -158,8 +158,7 @@ static void cpuidle_idle_call(void)
|
||||
* is used from another cpu as a broadcast timer, this call may
|
||||
* fail if it is not available
|
||||
*/
|
||||
if (broadcast &&
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &dev->cpu))
|
||||
if (broadcast && tick_broadcast_enter())
|
||||
goto use_default;
|
||||
|
||||
/* Take note of the planned idle state. */
|
||||
@@ -176,7 +175,7 @@ static void cpuidle_idle_call(void)
|
||||
idle_set_state(this_rq(), NULL);
|
||||
|
||||
if (broadcast)
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
|
||||
tick_broadcast_exit();
|
||||
|
||||
/*
|
||||
* Give the governor an opportunity to reflect on the outcome
|
||||
|
||||
@@ -33,12 +33,6 @@ config ARCH_USES_GETTIMEOFFSET
|
||||
config GENERIC_CLOCKEVENTS
|
||||
bool
|
||||
|
||||
# Migration helper. Builds, but does not invoke
|
||||
config GENERIC_CLOCKEVENTS_BUILD
|
||||
bool
|
||||
default y
|
||||
depends on GENERIC_CLOCKEVENTS
|
||||
|
||||
# Architecture can handle broadcast in a driver-agnostic way
|
||||
config ARCH_HAS_TICK_BROADCAST
|
||||
bool
|
||||
|
||||
@@ -2,15 +2,13 @@ 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 timecounter.o posix-clock.o alarmtimer.o
|
||||
|
||||
obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o
|
||||
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o
|
||||
obj-$(CONFIG_GENERIC_CLOCKEVENTS) += clockevents.o tick-common.o
|
||||
ifeq ($(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST),y)
|
||||
obj-y += tick-broadcast.o
|
||||
obj-$(CONFIG_TICK_ONESHOT) += tick-broadcast-hrtimer.o
|
||||
endif
|
||||
obj-$(CONFIG_GENERIC_SCHED_CLOCK) += sched_clock.o
|
||||
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
|
||||
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
|
||||
obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o tick-sched.o
|
||||
obj-$(CONFIG_TIMER_STATS) += timer_stats.o
|
||||
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
|
||||
obj-$(CONFIG_TEST_UDELAY) += test_udelay.o
|
||||
|
||||
+147
-82
@@ -94,25 +94,76 @@ u64 clockevent_delta2ns(unsigned long latch, struct clock_event_device *evt)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clockevent_delta2ns);
|
||||
|
||||
static int __clockevents_set_state(struct clock_event_device *dev,
|
||||
enum clock_event_state state)
|
||||
{
|
||||
/* Transition with legacy set_mode() callback */
|
||||
if (dev->set_mode) {
|
||||
/* Legacy callback doesn't support new modes */
|
||||
if (state > CLOCK_EVT_STATE_ONESHOT)
|
||||
return -ENOSYS;
|
||||
/*
|
||||
* 'clock_event_state' and 'clock_event_mode' have 1-to-1
|
||||
* mapping until *_ONESHOT, and so a simple cast will work.
|
||||
*/
|
||||
dev->set_mode((enum clock_event_mode)state, dev);
|
||||
dev->mode = (enum clock_event_mode)state;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
|
||||
return 0;
|
||||
|
||||
/* Transition with new state-specific callbacks */
|
||||
switch (state) {
|
||||
case CLOCK_EVT_STATE_DETACHED:
|
||||
/*
|
||||
* This is an internal state, which is guaranteed to go from
|
||||
* SHUTDOWN to DETACHED. No driver interaction required.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
case CLOCK_EVT_STATE_SHUTDOWN:
|
||||
return dev->set_state_shutdown(dev);
|
||||
|
||||
case CLOCK_EVT_STATE_PERIODIC:
|
||||
/* Core internal bug */
|
||||
if (!(dev->features & CLOCK_EVT_FEAT_PERIODIC))
|
||||
return -ENOSYS;
|
||||
return dev->set_state_periodic(dev);
|
||||
|
||||
case CLOCK_EVT_STATE_ONESHOT:
|
||||
/* Core internal bug */
|
||||
if (!(dev->features & CLOCK_EVT_FEAT_ONESHOT))
|
||||
return -ENOSYS;
|
||||
return dev->set_state_oneshot(dev);
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* clockevents_set_mode - set the operating mode of a clock event device
|
||||
* clockevents_set_state - set the operating state of a clock event device
|
||||
* @dev: device to modify
|
||||
* @mode: new mode
|
||||
* @state: new state
|
||||
*
|
||||
* Must be called with interrupts disabled !
|
||||
*/
|
||||
void clockevents_set_mode(struct clock_event_device *dev,
|
||||
enum clock_event_mode mode)
|
||||
void clockevents_set_state(struct clock_event_device *dev,
|
||||
enum clock_event_state state)
|
||||
{
|
||||
if (dev->mode != mode) {
|
||||
dev->set_mode(mode, dev);
|
||||
dev->mode = mode;
|
||||
if (dev->state != state) {
|
||||
if (__clockevents_set_state(dev, state))
|
||||
return;
|
||||
|
||||
dev->state = state;
|
||||
|
||||
/*
|
||||
* A nsec2cyc multiplicator of 0 is invalid and we'd crash
|
||||
* on it, so fix it up and emit a warning:
|
||||
*/
|
||||
if (mode == CLOCK_EVT_MODE_ONESHOT) {
|
||||
if (state == CLOCK_EVT_STATE_ONESHOT) {
|
||||
if (unlikely(!dev->mult)) {
|
||||
dev->mult = 1;
|
||||
WARN_ON(1);
|
||||
@@ -127,10 +178,28 @@ void clockevents_set_mode(struct clock_event_device *dev,
|
||||
*/
|
||||
void clockevents_shutdown(struct clock_event_device *dev)
|
||||
{
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
|
||||
dev->next_event.tv64 = KTIME_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
* clockevents_tick_resume - Resume the tick device before using it again
|
||||
* @dev: device to resume
|
||||
*/
|
||||
int clockevents_tick_resume(struct clock_event_device *dev)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dev->set_mode) {
|
||||
dev->set_mode(CLOCK_EVT_MODE_RESUME, dev);
|
||||
dev->mode = CLOCK_EVT_MODE_RESUME;
|
||||
} else if (dev->tick_resume) {
|
||||
ret = dev->tick_resume(dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS_MIN_ADJUST
|
||||
|
||||
/* Limit min_delta to a jiffie */
|
||||
@@ -183,7 +252,7 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
|
||||
delta = dev->min_delta_ns;
|
||||
dev->next_event = ktime_add_ns(ktime_get(), delta);
|
||||
|
||||
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
|
||||
if (dev->state == CLOCK_EVT_STATE_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
dev->retries++;
|
||||
@@ -220,7 +289,7 @@ static int clockevents_program_min_delta(struct clock_event_device *dev)
|
||||
delta = dev->min_delta_ns;
|
||||
dev->next_event = ktime_add_ns(ktime_get(), delta);
|
||||
|
||||
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
|
||||
if (dev->state == CLOCK_EVT_STATE_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
dev->retries++;
|
||||
@@ -252,7 +321,7 @@ int clockevents_program_event(struct clock_event_device *dev, ktime_t expires,
|
||||
|
||||
dev->next_event = expires;
|
||||
|
||||
if (dev->mode == CLOCK_EVT_MODE_SHUTDOWN)
|
||||
if (dev->state == CLOCK_EVT_STATE_SHUTDOWN)
|
||||
return 0;
|
||||
|
||||
/* Shortcut for clockevent devices that can deal with ktime. */
|
||||
@@ -297,7 +366,7 @@ static int clockevents_replace(struct clock_event_device *ced)
|
||||
struct clock_event_device *dev, *newdev = NULL;
|
||||
|
||||
list_for_each_entry(dev, &clockevent_devices, list) {
|
||||
if (dev == ced || dev->mode != CLOCK_EVT_MODE_UNUSED)
|
||||
if (dev == ced || dev->state != CLOCK_EVT_STATE_DETACHED)
|
||||
continue;
|
||||
|
||||
if (!tick_check_replacement(newdev, dev))
|
||||
@@ -323,7 +392,7 @@ static int clockevents_replace(struct clock_event_device *ced)
|
||||
static int __clockevents_try_unbind(struct clock_event_device *ced, int cpu)
|
||||
{
|
||||
/* Fast track. Device is unused */
|
||||
if (ced->mode == CLOCK_EVT_MODE_UNUSED) {
|
||||
if (ced->state == CLOCK_EVT_STATE_DETACHED) {
|
||||
list_del_init(&ced->list);
|
||||
return 0;
|
||||
}
|
||||
@@ -373,6 +442,37 @@ int clockevents_unbind_device(struct clock_event_device *ced, int cpu)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clockevents_unbind);
|
||||
|
||||
/* Sanity check of state transition callbacks */
|
||||
static int clockevents_sanity_check(struct clock_event_device *dev)
|
||||
{
|
||||
/* Legacy set_mode() callback */
|
||||
if (dev->set_mode) {
|
||||
/* We shouldn't be supporting new modes now */
|
||||
WARN_ON(dev->set_state_periodic || dev->set_state_oneshot ||
|
||||
dev->set_state_shutdown || dev->tick_resume);
|
||||
|
||||
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dev->features & CLOCK_EVT_FEAT_DUMMY)
|
||||
return 0;
|
||||
|
||||
/* New state-specific callbacks */
|
||||
if (!dev->set_state_shutdown)
|
||||
return -EINVAL;
|
||||
|
||||
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
|
||||
!dev->set_state_periodic)
|
||||
return -EINVAL;
|
||||
|
||||
if ((dev->features & CLOCK_EVT_FEAT_ONESHOT) &&
|
||||
!dev->set_state_oneshot)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* clockevents_register_device - register a clock event device
|
||||
* @dev: device to register
|
||||
@@ -381,7 +481,11 @@ void clockevents_register_device(struct clock_event_device *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
|
||||
BUG_ON(clockevents_sanity_check(dev));
|
||||
|
||||
/* Initialize state to DETACHED */
|
||||
dev->state = CLOCK_EVT_STATE_DETACHED;
|
||||
|
||||
if (!dev->cpumask) {
|
||||
WARN_ON(num_possible_cpus() > 1);
|
||||
dev->cpumask = cpumask_of(smp_processor_id());
|
||||
@@ -445,11 +549,11 @@ int __clockevents_update_freq(struct clock_event_device *dev, u32 freq)
|
||||
{
|
||||
clockevents_config(dev, freq);
|
||||
|
||||
if (dev->mode == CLOCK_EVT_MODE_ONESHOT)
|
||||
if (dev->state == CLOCK_EVT_STATE_ONESHOT)
|
||||
return clockevents_program_event(dev, dev->next_event, false);
|
||||
|
||||
if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
|
||||
dev->set_mode(CLOCK_EVT_MODE_PERIODIC, dev);
|
||||
if (dev->state == CLOCK_EVT_STATE_PERIODIC)
|
||||
return __clockevents_set_state(dev, CLOCK_EVT_STATE_PERIODIC);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -491,30 +595,27 @@ void clockevents_handle_noop(struct clock_event_device *dev)
|
||||
* @old: device to release (can be NULL)
|
||||
* @new: device to request (can be NULL)
|
||||
*
|
||||
* Called from the notifier chain. clockevents_lock is held already
|
||||
* Called from various tick functions with clockevents_lock held and
|
||||
* interrupts disabled.
|
||||
*/
|
||||
void clockevents_exchange_device(struct clock_event_device *old,
|
||||
struct clock_event_device *new)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
local_irq_save(flags);
|
||||
/*
|
||||
* Caller releases a clock event device. We queue it into the
|
||||
* released list and do a notify add later.
|
||||
*/
|
||||
if (old) {
|
||||
module_put(old->owner);
|
||||
clockevents_set_mode(old, CLOCK_EVT_MODE_UNUSED);
|
||||
clockevents_set_state(old, CLOCK_EVT_STATE_DETACHED);
|
||||
list_del(&old->list);
|
||||
list_add(&old->list, &clockevents_released);
|
||||
}
|
||||
|
||||
if (new) {
|
||||
BUG_ON(new->mode != CLOCK_EVT_MODE_UNUSED);
|
||||
BUG_ON(new->state != CLOCK_EVT_STATE_DETACHED);
|
||||
clockevents_shutdown(new);
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -541,74 +642,40 @@ void clockevents_resume(void)
|
||||
dev->resume(dev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/**
|
||||
* clockevents_notify - notification about relevant events
|
||||
* Returns 0 on success, any other value on error
|
||||
* tick_cleanup_dead_cpu - Cleanup the tick and clockevents of a dead cpu
|
||||
*/
|
||||
int clockevents_notify(unsigned long reason, void *arg)
|
||||
void tick_cleanup_dead_cpu(int cpu)
|
||||
{
|
||||
struct clock_event_device *dev, *tmp;
|
||||
unsigned long flags;
|
||||
int cpu, ret = 0;
|
||||
|
||||
raw_spin_lock_irqsave(&clockevents_lock, flags);
|
||||
|
||||
switch (reason) {
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
|
||||
tick_broadcast_on_off(reason, arg);
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_ENTER:
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_EXIT:
|
||||
ret = tick_broadcast_oneshot_control(reason);
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_CPU_DYING:
|
||||
tick_handover_do_timer(arg);
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_SUSPEND:
|
||||
tick_suspend();
|
||||
tick_suspend_broadcast();
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_RESUME:
|
||||
tick_resume();
|
||||
break;
|
||||
|
||||
case CLOCK_EVT_NOTIFY_CPU_DEAD:
|
||||
tick_shutdown_broadcast_oneshot(arg);
|
||||
tick_shutdown_broadcast(arg);
|
||||
tick_shutdown(arg);
|
||||
/*
|
||||
* Unregister the clock event devices which were
|
||||
* released from the users in the notify chain.
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &clockevents_released, list)
|
||||
tick_shutdown_broadcast_oneshot(cpu);
|
||||
tick_shutdown_broadcast(cpu);
|
||||
tick_shutdown(cpu);
|
||||
/*
|
||||
* Unregister the clock event devices which were
|
||||
* released from the users in the notify chain.
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &clockevents_released, list)
|
||||
list_del(&dev->list);
|
||||
/*
|
||||
* Now check whether the CPU has left unused per cpu devices
|
||||
*/
|
||||
list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
|
||||
if (cpumask_test_cpu(cpu, dev->cpumask) &&
|
||||
cpumask_weight(dev->cpumask) == 1 &&
|
||||
!tick_is_broadcast_device(dev)) {
|
||||
BUG_ON(dev->state != CLOCK_EVT_STATE_DETACHED);
|
||||
list_del(&dev->list);
|
||||
/*
|
||||
* Now check whether the CPU has left unused per cpu devices
|
||||
*/
|
||||
cpu = *((int *)arg);
|
||||
list_for_each_entry_safe(dev, tmp, &clockevent_devices, list) {
|
||||
if (cpumask_test_cpu(cpu, dev->cpumask) &&
|
||||
cpumask_weight(dev->cpumask) == 1 &&
|
||||
!tick_is_broadcast_device(dev)) {
|
||||
BUG_ON(dev->mode != CLOCK_EVT_MODE_UNUSED);
|
||||
list_del(&dev->list);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&clockevents_lock, flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(clockevents_notify);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
struct bus_type clockevents_subsys = {
|
||||
@@ -727,5 +794,3 @@ static int __init clockevents_init_sysfs(void)
|
||||
}
|
||||
device_initcall(clockevents_init_sysfs);
|
||||
#endif /* SYSFS */
|
||||
|
||||
#endif /* GENERIC_CLOCK_EVENTS */
|
||||
|
||||
+79
-92
@@ -142,13 +142,6 @@ static void __clocksource_unstable(struct clocksource *cs)
|
||||
schedule_work(&watchdog_work);
|
||||
}
|
||||
|
||||
static void clocksource_unstable(struct clocksource *cs, int64_t delta)
|
||||
{
|
||||
printk(KERN_WARNING "Clocksource %s unstable (delta = %Ld ns)\n",
|
||||
cs->name, delta);
|
||||
__clocksource_unstable(cs);
|
||||
}
|
||||
|
||||
/**
|
||||
* clocksource_mark_unstable - mark clocksource unstable via watchdog
|
||||
* @cs: clocksource to be marked unstable
|
||||
@@ -174,7 +167,7 @@ void clocksource_mark_unstable(struct clocksource *cs)
|
||||
static void clocksource_watchdog(unsigned long data)
|
||||
{
|
||||
struct clocksource *cs;
|
||||
cycle_t csnow, wdnow, delta;
|
||||
cycle_t csnow, wdnow, cslast, wdlast, delta;
|
||||
int64_t wd_nsec, cs_nsec;
|
||||
int next_cpu, reset_pending;
|
||||
|
||||
@@ -213,6 +206,8 @@ static void clocksource_watchdog(unsigned long data)
|
||||
|
||||
delta = clocksource_delta(csnow, cs->cs_last, cs->mask);
|
||||
cs_nsec = clocksource_cyc2ns(delta, cs->mult, cs->shift);
|
||||
wdlast = cs->wd_last; /* save these in case we print them */
|
||||
cslast = cs->cs_last;
|
||||
cs->cs_last = csnow;
|
||||
cs->wd_last = wdnow;
|
||||
|
||||
@@ -221,7 +216,12 @@ static void clocksource_watchdog(unsigned long data)
|
||||
|
||||
/* Check the deviation from the watchdog clocksource. */
|
||||
if ((abs(cs_nsec - wd_nsec) > WATCHDOG_THRESHOLD)) {
|
||||
clocksource_unstable(cs, cs_nsec - wd_nsec);
|
||||
pr_warn("timekeeping watchdog: Marking clocksource '%s' as unstable, because the skew is too large:\n", 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",
|
||||
cs->name, csnow, cslast, cs->mask);
|
||||
__clocksource_unstable(cs);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -469,26 +469,25 @@ static u32 clocksource_max_adjustment(struct clocksource *cs)
|
||||
* @shift: cycle to nanosecond divisor (power of two)
|
||||
* @maxadj: maximum adjustment value to mult (~11%)
|
||||
* @mask: bitmask for two's complement subtraction of non 64 bit counters
|
||||
* @max_cyc: maximum cycle value before potential overflow (does not include
|
||||
* any safety margin)
|
||||
*
|
||||
* NOTE: This function includes a safety margin of 50%, in other words, we
|
||||
* return half the number of nanoseconds the hardware counter can technically
|
||||
* cover. This is done so that we can potentially detect problems caused by
|
||||
* delayed timers or bad hardware, which might result in time intervals that
|
||||
* are larger then what the math used can handle without overflows.
|
||||
*/
|
||||
u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask)
|
||||
u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask, u64 *max_cyc)
|
||||
{
|
||||
u64 max_nsecs, max_cycles;
|
||||
|
||||
/*
|
||||
* Calculate the maximum number of cycles that we can pass to the
|
||||
* cyc2ns function without overflowing a 64-bit signed result. The
|
||||
* maximum number of cycles is equal to ULLONG_MAX/(mult+maxadj)
|
||||
* which is equivalent to the below.
|
||||
* max_cycles < (2^63)/(mult + maxadj)
|
||||
* max_cycles < 2^(log2((2^63)/(mult + maxadj)))
|
||||
* max_cycles < 2^(log2(2^63) - log2(mult + maxadj))
|
||||
* max_cycles < 2^(63 - log2(mult + maxadj))
|
||||
* max_cycles < 1 << (63 - log2(mult + maxadj))
|
||||
* Please note that we add 1 to the result of the log2 to account for
|
||||
* any rounding errors, ensure the above inequality is satisfied and
|
||||
* no overflow will occur.
|
||||
* cyc2ns() function without overflowing a 64-bit result.
|
||||
*/
|
||||
max_cycles = 1ULL << (63 - (ilog2(mult + maxadj) + 1));
|
||||
max_cycles = ULLONG_MAX;
|
||||
do_div(max_cycles, mult+maxadj);
|
||||
|
||||
/*
|
||||
* The actual maximum number of cycles we can defer the clocksource is
|
||||
@@ -499,27 +498,26 @@ u64 clocks_calc_max_nsecs(u32 mult, u32 shift, u32 maxadj, u64 mask)
|
||||
max_cycles = min(max_cycles, mask);
|
||||
max_nsecs = clocksource_cyc2ns(max_cycles, mult - maxadj, shift);
|
||||
|
||||
/* return the max_cycles value as well if requested */
|
||||
if (max_cyc)
|
||||
*max_cyc = max_cycles;
|
||||
|
||||
/* Return 50% of the actual maximum, so we can detect bad values */
|
||||
max_nsecs >>= 1;
|
||||
|
||||
return max_nsecs;
|
||||
}
|
||||
|
||||
/**
|
||||
* clocksource_max_deferment - Returns max time the clocksource can be deferred
|
||||
* @cs: Pointer to clocksource
|
||||
* clocksource_update_max_deferment - Updates the clocksource max_idle_ns & max_cycles
|
||||
* @cs: Pointer to clocksource to be updated
|
||||
*
|
||||
*/
|
||||
static u64 clocksource_max_deferment(struct clocksource *cs)
|
||||
static inline void clocksource_update_max_deferment(struct clocksource *cs)
|
||||
{
|
||||
u64 max_nsecs;
|
||||
|
||||
max_nsecs = clocks_calc_max_nsecs(cs->mult, cs->shift, cs->maxadj,
|
||||
cs->mask);
|
||||
/*
|
||||
* To ensure that the clocksource does not wrap whilst we are idle,
|
||||
* limit the time the clocksource can be deferred by 12.5%. Please
|
||||
* note a margin of 12.5% is used because this can be computed with
|
||||
* a shift, versus say 10% which would require division.
|
||||
*/
|
||||
return max_nsecs - (max_nsecs >> 3);
|
||||
cs->max_idle_ns = clocks_calc_max_nsecs(cs->mult, cs->shift,
|
||||
cs->maxadj, cs->mask,
|
||||
&cs->max_cycles);
|
||||
}
|
||||
|
||||
#ifndef CONFIG_ARCH_USES_GETTIMEOFFSET
|
||||
@@ -648,7 +646,7 @@ static void clocksource_enqueue(struct clocksource *cs)
|
||||
}
|
||||
|
||||
/**
|
||||
* __clocksource_updatefreq_scale - Used update clocksource with new freq
|
||||
* __clocksource_update_freq_scale - Used update clocksource with new freq
|
||||
* @cs: clocksource to be registered
|
||||
* @scale: Scale factor multiplied against freq to get clocksource hz
|
||||
* @freq: clocksource frequency (cycles per second) divided by scale
|
||||
@@ -656,48 +654,64 @@ static void clocksource_enqueue(struct clocksource *cs)
|
||||
* This should only be called from the clocksource->enable() method.
|
||||
*
|
||||
* This *SHOULD NOT* be called directly! Please use the
|
||||
* clocksource_updatefreq_hz() or clocksource_updatefreq_khz helper functions.
|
||||
* __clocksource_update_freq_hz() or __clocksource_update_freq_khz() helper
|
||||
* functions.
|
||||
*/
|
||||
void __clocksource_updatefreq_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||
void __clocksource_update_freq_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||
{
|
||||
u64 sec;
|
||||
|
||||
/*
|
||||
* Calc the maximum number of seconds which we can run before
|
||||
* wrapping around. For clocksources which have a mask > 32bit
|
||||
* we need to limit the max sleep time to have a good
|
||||
* conversion precision. 10 minutes is still a reasonable
|
||||
* amount. That results in a shift value of 24 for a
|
||||
* clocksource with mask >= 40bit and f >= 4GHz. That maps to
|
||||
* ~ 0.06ppm granularity for NTP. We apply the same 12.5%
|
||||
* margin as we do in clocksource_max_deferment()
|
||||
* Default clocksources are *special* and self-define their mult/shift.
|
||||
* But, you're not special, so you should specify a freq value.
|
||||
*/
|
||||
sec = (cs->mask - (cs->mask >> 3));
|
||||
do_div(sec, freq);
|
||||
do_div(sec, scale);
|
||||
if (!sec)
|
||||
sec = 1;
|
||||
else if (sec > 600 && cs->mask > UINT_MAX)
|
||||
sec = 600;
|
||||
|
||||
clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
|
||||
NSEC_PER_SEC / scale, sec * scale);
|
||||
if (freq) {
|
||||
/*
|
||||
* Calc the maximum number of seconds which we can run before
|
||||
* wrapping around. For clocksources which have a mask > 32-bit
|
||||
* we need to limit the max sleep time to have a good
|
||||
* conversion precision. 10 minutes is still a reasonable
|
||||
* amount. That results in a shift value of 24 for a
|
||||
* clocksource with mask >= 40-bit and f >= 4GHz. That maps to
|
||||
* ~ 0.06ppm granularity for NTP.
|
||||
*/
|
||||
sec = cs->mask;
|
||||
do_div(sec, freq);
|
||||
do_div(sec, scale);
|
||||
if (!sec)
|
||||
sec = 1;
|
||||
else if (sec > 600 && cs->mask > UINT_MAX)
|
||||
sec = 600;
|
||||
|
||||
clocks_calc_mult_shift(&cs->mult, &cs->shift, freq,
|
||||
NSEC_PER_SEC / scale, sec * scale);
|
||||
}
|
||||
/*
|
||||
* for clocksources that have large mults, to avoid overflow.
|
||||
* Since mult may be adjusted by ntp, add an safety extra margin
|
||||
*
|
||||
* Ensure clocksources that have large 'mult' values don't overflow
|
||||
* when adjusted.
|
||||
*/
|
||||
cs->maxadj = clocksource_max_adjustment(cs);
|
||||
while ((cs->mult + cs->maxadj < cs->mult)
|
||||
|| (cs->mult - cs->maxadj > cs->mult)) {
|
||||
while (freq && ((cs->mult + cs->maxadj < cs->mult)
|
||||
|| (cs->mult - cs->maxadj > cs->mult))) {
|
||||
cs->mult >>= 1;
|
||||
cs->shift--;
|
||||
cs->maxadj = clocksource_max_adjustment(cs);
|
||||
}
|
||||
|
||||
cs->max_idle_ns = clocksource_max_deferment(cs);
|
||||
/*
|
||||
* Only warn for *special* clocksources that self-define
|
||||
* their mult/shift values and don't specify a freq.
|
||||
*/
|
||||
WARN_ONCE(cs->mult + cs->maxadj < cs->mult,
|
||||
"timekeeping: Clocksource %s might overflow on 11%% adjustment\n",
|
||||
cs->name);
|
||||
|
||||
clocksource_update_max_deferment(cs);
|
||||
|
||||
pr_info("clocksource %s: mask: 0x%llx max_cycles: 0x%llx, max_idle_ns: %lld ns\n",
|
||||
cs->name, cs->mask, cs->max_cycles, cs->max_idle_ns);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clocksource_updatefreq_scale);
|
||||
EXPORT_SYMBOL_GPL(__clocksource_update_freq_scale);
|
||||
|
||||
/**
|
||||
* __clocksource_register_scale - Used to install new clocksources
|
||||
@@ -714,7 +728,7 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||
{
|
||||
|
||||
/* Initialize mult/shift and max_idle_ns */
|
||||
__clocksource_updatefreq_scale(cs, scale, freq);
|
||||
__clocksource_update_freq_scale(cs, scale, freq);
|
||||
|
||||
/* Add clocksource to the clocksource list */
|
||||
mutex_lock(&clocksource_mutex);
|
||||
@@ -726,33 +740,6 @@ int __clocksource_register_scale(struct clocksource *cs, u32 scale, u32 freq)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__clocksource_register_scale);
|
||||
|
||||
|
||||
/**
|
||||
* clocksource_register - Used to install new clocksources
|
||||
* @cs: clocksource to be registered
|
||||
*
|
||||
* Returns -EBUSY if registration fails, zero otherwise.
|
||||
*/
|
||||
int clocksource_register(struct clocksource *cs)
|
||||
{
|
||||
/* calculate max adjustment for given mult/shift */
|
||||
cs->maxadj = clocksource_max_adjustment(cs);
|
||||
WARN_ONCE(cs->mult + cs->maxadj < cs->mult,
|
||||
"Clocksource %s might overflow on 11%% adjustment\n",
|
||||
cs->name);
|
||||
|
||||
/* calculate max idle time permitted for this clocksource */
|
||||
cs->max_idle_ns = clocksource_max_deferment(cs);
|
||||
|
||||
mutex_lock(&clocksource_mutex);
|
||||
clocksource_enqueue(cs);
|
||||
clocksource_enqueue_watchdog(cs);
|
||||
clocksource_select();
|
||||
mutex_unlock(&clocksource_mutex);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(clocksource_register);
|
||||
|
||||
static void __clocksource_change_rating(struct clocksource *cs, int rating)
|
||||
{
|
||||
list_del(&cs->list);
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
|
||||
#include <trace/events/timer.h>
|
||||
|
||||
#include "timekeeping.h"
|
||||
#include "tick-internal.h"
|
||||
|
||||
/*
|
||||
* The timer bases:
|
||||
@@ -1707,17 +1707,10 @@ static int hrtimer_cpu_notify(struct notifier_block *self,
|
||||
break;
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
case CPU_DYING:
|
||||
case CPU_DYING_FROZEN:
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DYING, &scpu);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
case CPU_DEAD_FROZEN:
|
||||
{
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_CPU_DEAD, &scpu);
|
||||
migrate_hrtimers(scpu);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#include "tick-internal.h"
|
||||
#include "timekeeping.h"
|
||||
|
||||
/* The Jiffies based clocksource is the lowest common
|
||||
* denominator clock source which should function on
|
||||
@@ -71,6 +71,7 @@ static struct clocksource clocksource_jiffies = {
|
||||
.mask = 0xffffffff, /*32bits*/
|
||||
.mult = NSEC_PER_JIFFY << JIFFIES_SHIFT, /* details above */
|
||||
.shift = JIFFIES_SHIFT,
|
||||
.max_cycles = 10,
|
||||
};
|
||||
|
||||
__cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock);
|
||||
@@ -94,7 +95,7 @@ EXPORT_SYMBOL(jiffies);
|
||||
|
||||
static int __init init_jiffies_clocksource(void)
|
||||
{
|
||||
return clocksource_register(&clocksource_jiffies);
|
||||
return __clocksource_register(&clocksource_jiffies);
|
||||
}
|
||||
|
||||
core_initcall(init_jiffies_clocksource);
|
||||
@@ -130,6 +131,6 @@ int register_refined_jiffies(long cycles_per_second)
|
||||
|
||||
refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT;
|
||||
|
||||
clocksource_register(&refined_jiffies);
|
||||
__clocksource_register(&refined_jiffies);
|
||||
return 0;
|
||||
}
|
||||
|
||||
+12
-2
@@ -17,7 +17,6 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include "tick-internal.h"
|
||||
#include "ntp_internal.h"
|
||||
|
||||
/*
|
||||
@@ -459,6 +458,16 @@ out:
|
||||
return leap;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_CMOS_UPDATE
|
||||
int __weak update_persistent_clock64(struct timespec64 now64)
|
||||
{
|
||||
struct timespec now;
|
||||
|
||||
now = timespec64_to_timespec(now64);
|
||||
return update_persistent_clock(now);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_GENERIC_CMOS_UPDATE) || defined(CONFIG_RTC_SYSTOHC)
|
||||
static void sync_cmos_clock(struct work_struct *work);
|
||||
|
||||
@@ -494,8 +503,9 @@ static void sync_cmos_clock(struct work_struct *work)
|
||||
if (persistent_clock_is_local)
|
||||
adjust.tv_sec -= (sys_tz.tz_minuteswest * 60);
|
||||
#ifdef CONFIG_GENERIC_CMOS_UPDATE
|
||||
fail = update_persistent_clock(timespec64_to_timespec(adjust));
|
||||
fail = update_persistent_clock64(adjust);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_RTC_SYSTOHC
|
||||
if (fail == -ENODEV)
|
||||
fail = rtc_set_ntp_time(adjust);
|
||||
|
||||
+162
-76
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* sched_clock.c: support for extending counters to full 64-bit ns counter
|
||||
* sched_clock.c: Generic sched_clock() support, to extend low level
|
||||
* hardware time counters to full 64-bit ns values.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
@@ -18,15 +19,53 @@
|
||||
#include <linux/seqlock.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
struct clock_data {
|
||||
ktime_t wrap_kt;
|
||||
/**
|
||||
* struct clock_read_data - data required to read from sched_clock()
|
||||
*
|
||||
* @epoch_ns: sched_clock() value at last update
|
||||
* @epoch_cyc: Clock cycle value at last update.
|
||||
* @sched_clock_mask: Bitmask for two's complement subtraction of non 64bit
|
||||
* clocks.
|
||||
* @read_sched_clock: Current clock source (or dummy source when suspended).
|
||||
* @mult: Multipler for scaled math conversion.
|
||||
* @shift: Shift value for scaled math conversion.
|
||||
*
|
||||
* Care must be taken when updating this structure; it is read by
|
||||
* some very hot code paths. It occupies <=40 bytes and, when combined
|
||||
* with the seqcount used to synchronize access, comfortably fits into
|
||||
* a 64 byte cache line.
|
||||
*/
|
||||
struct clock_read_data {
|
||||
u64 epoch_ns;
|
||||
u64 epoch_cyc;
|
||||
seqcount_t seq;
|
||||
unsigned long rate;
|
||||
u64 sched_clock_mask;
|
||||
u64 (*read_sched_clock)(void);
|
||||
u32 mult;
|
||||
u32 shift;
|
||||
bool suspended;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct clock_data - all data needed for sched_clock() (including
|
||||
* registration of a new clock source)
|
||||
*
|
||||
* @seq: Sequence counter for protecting updates. The lowest
|
||||
* bit is the index for @read_data.
|
||||
* @read_data: Data required to read from sched_clock.
|
||||
* @wrap_kt: Duration for which clock can run before wrapping.
|
||||
* @rate: Tick rate of the registered clock.
|
||||
* @actual_read_sched_clock: Registered hardware level clock read function.
|
||||
*
|
||||
* The ordering of this structure has been chosen to optimize cache
|
||||
* performance. In particular 'seq' and 'read_data[0]' (combined) should fit
|
||||
* into a single 64-byte cache line.
|
||||
*/
|
||||
struct clock_data {
|
||||
seqcount_t seq;
|
||||
struct clock_read_data read_data[2];
|
||||
ktime_t wrap_kt;
|
||||
unsigned long rate;
|
||||
|
||||
u64 (*actual_read_sched_clock)(void);
|
||||
};
|
||||
|
||||
static struct hrtimer sched_clock_timer;
|
||||
@@ -34,12 +73,6 @@ static int irqtime = -1;
|
||||
|
||||
core_param(irqtime, irqtime, int, 0400);
|
||||
|
||||
static struct clock_data cd = {
|
||||
.mult = NSEC_PER_SEC / HZ,
|
||||
};
|
||||
|
||||
static u64 __read_mostly sched_clock_mask;
|
||||
|
||||
static u64 notrace jiffy_sched_clock_read(void)
|
||||
{
|
||||
/*
|
||||
@@ -49,7 +82,11 @@ static u64 notrace jiffy_sched_clock_read(void)
|
||||
return (u64)(jiffies - INITIAL_JIFFIES);
|
||||
}
|
||||
|
||||
static u64 __read_mostly (*read_sched_clock)(void) = jiffy_sched_clock_read;
|
||||
static struct clock_data cd ____cacheline_aligned = {
|
||||
.read_data[0] = { .mult = NSEC_PER_SEC / HZ,
|
||||
.read_sched_clock = jiffy_sched_clock_read, },
|
||||
.actual_read_sched_clock = jiffy_sched_clock_read,
|
||||
};
|
||||
|
||||
static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
|
||||
{
|
||||
@@ -58,111 +95,136 @@ static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
|
||||
|
||||
unsigned long long notrace sched_clock(void)
|
||||
{
|
||||
u64 epoch_ns;
|
||||
u64 epoch_cyc;
|
||||
u64 cyc;
|
||||
u64 cyc, res;
|
||||
unsigned long seq;
|
||||
|
||||
if (cd.suspended)
|
||||
return cd.epoch_ns;
|
||||
struct clock_read_data *rd;
|
||||
|
||||
do {
|
||||
seq = raw_read_seqcount_begin(&cd.seq);
|
||||
epoch_cyc = cd.epoch_cyc;
|
||||
epoch_ns = cd.epoch_ns;
|
||||
seq = raw_read_seqcount(&cd.seq);
|
||||
rd = cd.read_data + (seq & 1);
|
||||
|
||||
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
|
||||
rd->sched_clock_mask;
|
||||
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
|
||||
} while (read_seqcount_retry(&cd.seq, seq));
|
||||
|
||||
cyc = read_sched_clock();
|
||||
cyc = (cyc - epoch_cyc) & sched_clock_mask;
|
||||
return epoch_ns + cyc_to_ns(cyc, cd.mult, cd.shift);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomically update the sched_clock epoch.
|
||||
* Updating the data required to read the clock.
|
||||
*
|
||||
* sched_clock() will never observe mis-matched data even if called from
|
||||
* an NMI. We do this by maintaining an odd/even copy of the data and
|
||||
* steering sched_clock() to one or the other using a sequence counter.
|
||||
* In order to preserve the data cache profile of sched_clock() as much
|
||||
* as possible the system reverts back to the even copy when the update
|
||||
* completes; the odd copy is used *only* during an update.
|
||||
*/
|
||||
static void notrace update_sched_clock(void)
|
||||
static void update_clock_read_data(struct clock_read_data *rd)
|
||||
{
|
||||
/* update the backup (odd) copy with the new data */
|
||||
cd.read_data[1] = *rd;
|
||||
|
||||
/* steer readers towards the odd copy */
|
||||
raw_write_seqcount_latch(&cd.seq);
|
||||
|
||||
/* now its safe for us to update the normal (even) copy */
|
||||
cd.read_data[0] = *rd;
|
||||
|
||||
/* switch readers back to the even copy */
|
||||
raw_write_seqcount_latch(&cd.seq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Atomically update the sched_clock() epoch.
|
||||
*/
|
||||
static void update_sched_clock(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
u64 cyc;
|
||||
u64 ns;
|
||||
struct clock_read_data rd;
|
||||
|
||||
cyc = read_sched_clock();
|
||||
ns = cd.epoch_ns +
|
||||
cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
|
||||
cd.mult, cd.shift);
|
||||
rd = cd.read_data[0];
|
||||
|
||||
raw_local_irq_save(flags);
|
||||
raw_write_seqcount_begin(&cd.seq);
|
||||
cd.epoch_ns = ns;
|
||||
cd.epoch_cyc = cyc;
|
||||
raw_write_seqcount_end(&cd.seq);
|
||||
raw_local_irq_restore(flags);
|
||||
cyc = cd.actual_read_sched_clock();
|
||||
ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
|
||||
|
||||
rd.epoch_ns = ns;
|
||||
rd.epoch_cyc = cyc;
|
||||
|
||||
update_clock_read_data(&rd);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
|
||||
{
|
||||
update_sched_clock();
|
||||
hrtimer_forward_now(hrt, cd.wrap_kt);
|
||||
|
||||
return HRTIMER_RESTART;
|
||||
}
|
||||
|
||||
void __init sched_clock_register(u64 (*read)(void), int bits,
|
||||
unsigned long rate)
|
||||
void __init
|
||||
sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)
|
||||
{
|
||||
u64 res, wrap, new_mask, new_epoch, cyc, ns;
|
||||
u32 new_mult, new_shift;
|
||||
ktime_t new_wrap_kt;
|
||||
unsigned long r;
|
||||
char r_unit;
|
||||
struct clock_read_data rd;
|
||||
|
||||
if (cd.rate > rate)
|
||||
return;
|
||||
|
||||
WARN_ON(!irqs_disabled());
|
||||
|
||||
/* calculate the mult/shift to convert counter ticks to ns. */
|
||||
/* Calculate the mult/shift to convert counter ticks to ns. */
|
||||
clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600);
|
||||
|
||||
new_mask = CLOCKSOURCE_MASK(bits);
|
||||
|
||||
/* calculate how many ns until we wrap */
|
||||
wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask);
|
||||
new_wrap_kt = ns_to_ktime(wrap - (wrap >> 3));
|
||||
|
||||
/* update epoch for new counter and update epoch_ns from old counter*/
|
||||
new_epoch = read();
|
||||
cyc = read_sched_clock();
|
||||
ns = cd.epoch_ns + cyc_to_ns((cyc - cd.epoch_cyc) & sched_clock_mask,
|
||||
cd.mult, cd.shift);
|
||||
|
||||
raw_write_seqcount_begin(&cd.seq);
|
||||
read_sched_clock = read;
|
||||
sched_clock_mask = new_mask;
|
||||
cd.rate = rate;
|
||||
cd.wrap_kt = new_wrap_kt;
|
||||
cd.mult = new_mult;
|
||||
cd.shift = new_shift;
|
||||
cd.epoch_cyc = new_epoch;
|
||||
cd.epoch_ns = ns;
|
||||
raw_write_seqcount_end(&cd.seq);
|
||||
|
||||
/* Calculate how many nanosecs until we risk wrapping */
|
||||
wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask, NULL);
|
||||
cd.wrap_kt = ns_to_ktime(wrap);
|
||||
|
||||
rd = cd.read_data[0];
|
||||
|
||||
/* Update epoch for new counter and update 'epoch_ns' from old counter*/
|
||||
new_epoch = read();
|
||||
cyc = cd.actual_read_sched_clock();
|
||||
ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
|
||||
cd.actual_read_sched_clock = read;
|
||||
|
||||
rd.read_sched_clock = read;
|
||||
rd.sched_clock_mask = new_mask;
|
||||
rd.mult = new_mult;
|
||||
rd.shift = new_shift;
|
||||
rd.epoch_cyc = new_epoch;
|
||||
rd.epoch_ns = ns;
|
||||
|
||||
update_clock_read_data(&rd);
|
||||
|
||||
r = rate;
|
||||
if (r >= 4000000) {
|
||||
r /= 1000000;
|
||||
r_unit = 'M';
|
||||
} else if (r >= 1000) {
|
||||
r /= 1000;
|
||||
r_unit = 'k';
|
||||
} else
|
||||
r_unit = ' ';
|
||||
} else {
|
||||
if (r >= 1000) {
|
||||
r /= 1000;
|
||||
r_unit = 'k';
|
||||
} else {
|
||||
r_unit = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
/* calculate the ns resolution of this counter */
|
||||
/* Calculate the ns resolution of this counter */
|
||||
res = cyc_to_ns(1ULL, new_mult, new_shift);
|
||||
|
||||
pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
|
||||
bits, r, r_unit, res, wrap);
|
||||
|
||||
/* Enable IRQ time accounting if we have a fast enough sched_clock */
|
||||
/* Enable IRQ time accounting if we have a fast enough sched_clock() */
|
||||
if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
|
||||
enable_sched_clock_irqtime();
|
||||
|
||||
@@ -172,10 +234,10 @@ void __init sched_clock_register(u64 (*read)(void), int bits,
|
||||
void __init sched_clock_postinit(void)
|
||||
{
|
||||
/*
|
||||
* If no sched_clock function has been provided at that point,
|
||||
* If no sched_clock() function has been provided at that point,
|
||||
* make it the final one one.
|
||||
*/
|
||||
if (read_sched_clock == jiffy_sched_clock_read)
|
||||
if (cd.actual_read_sched_clock == jiffy_sched_clock_read)
|
||||
sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
|
||||
|
||||
update_sched_clock();
|
||||
@@ -189,29 +251,53 @@ void __init sched_clock_postinit(void)
|
||||
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Clock read function for use when the clock is suspended.
|
||||
*
|
||||
* This function makes it appear to sched_clock() as if the clock
|
||||
* stopped counting at its last update.
|
||||
*
|
||||
* This function must only be called from the critical
|
||||
* section in sched_clock(). It relies on the read_seqcount_retry()
|
||||
* at the end of the critical section to be sure we observe the
|
||||
* correct copy of 'epoch_cyc'.
|
||||
*/
|
||||
static u64 notrace suspended_sched_clock_read(void)
|
||||
{
|
||||
unsigned long seq = raw_read_seqcount(&cd.seq);
|
||||
|
||||
return cd.read_data[seq & 1].epoch_cyc;
|
||||
}
|
||||
|
||||
static int sched_clock_suspend(void)
|
||||
{
|
||||
struct clock_read_data *rd = &cd.read_data[0];
|
||||
|
||||
update_sched_clock();
|
||||
hrtimer_cancel(&sched_clock_timer);
|
||||
cd.suspended = true;
|
||||
rd->read_sched_clock = suspended_sched_clock_read;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sched_clock_resume(void)
|
||||
{
|
||||
cd.epoch_cyc = read_sched_clock();
|
||||
struct clock_read_data *rd = &cd.read_data[0];
|
||||
|
||||
rd->epoch_cyc = cd.actual_read_sched_clock();
|
||||
hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL);
|
||||
cd.suspended = false;
|
||||
rd->read_sched_clock = cd.actual_read_sched_clock;
|
||||
}
|
||||
|
||||
static struct syscore_ops sched_clock_ops = {
|
||||
.suspend = sched_clock_suspend,
|
||||
.resume = sched_clock_resume,
|
||||
.suspend = sched_clock_suspend,
|
||||
.resume = sched_clock_resume,
|
||||
};
|
||||
|
||||
static int __init sched_clock_syscore_init(void)
|
||||
{
|
||||
register_syscore_ops(&sched_clock_ops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
device_initcall(sched_clock_syscore_init);
|
||||
|
||||
@@ -33,12 +33,14 @@ static cpumask_var_t tick_broadcast_mask;
|
||||
static cpumask_var_t tick_broadcast_on;
|
||||
static cpumask_var_t tmpmask;
|
||||
static DEFINE_RAW_SPINLOCK(tick_broadcast_lock);
|
||||
static int tick_broadcast_force;
|
||||
static int tick_broadcast_forced;
|
||||
|
||||
#ifdef CONFIG_TICK_ONESHOT
|
||||
static void tick_broadcast_clear_oneshot(int cpu);
|
||||
static void tick_resume_broadcast_oneshot(struct clock_event_device *bc);
|
||||
#else
|
||||
static inline void tick_broadcast_clear_oneshot(int cpu) { }
|
||||
static inline void tick_resume_broadcast_oneshot(struct clock_event_device *bc) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -303,7 +305,7 @@ static void tick_handle_periodic_broadcast(struct clock_event_device *dev)
|
||||
/*
|
||||
* The device is in periodic mode. No reprogramming necessary:
|
||||
*/
|
||||
if (dev->mode == CLOCK_EVT_MODE_PERIODIC)
|
||||
if (dev->state == CLOCK_EVT_STATE_PERIODIC)
|
||||
goto unlock;
|
||||
|
||||
/*
|
||||
@@ -324,49 +326,54 @@ unlock:
|
||||
raw_spin_unlock(&tick_broadcast_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Powerstate information: The system enters/leaves a state, where
|
||||
* affected devices might stop
|
||||
/**
|
||||
* tick_broadcast_control - Enable/disable or force broadcast mode
|
||||
* @mode: The selected broadcast mode
|
||||
*
|
||||
* Called when the system enters a state where affected tick devices
|
||||
* might stop. Note: TICK_BROADCAST_FORCE cannot be undone.
|
||||
*
|
||||
* Called with interrupts disabled, so clockevents_lock is not
|
||||
* required here because the local clock event device cannot go away
|
||||
* under us.
|
||||
*/
|
||||
static void tick_do_broadcast_on_off(unsigned long *reason)
|
||||
void tick_broadcast_control(enum tick_broadcast_mode mode)
|
||||
{
|
||||
struct clock_event_device *bc, *dev;
|
||||
struct tick_device *td;
|
||||
unsigned long flags;
|
||||
int cpu, bc_stopped;
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
|
||||
cpu = smp_processor_id();
|
||||
td = &per_cpu(tick_cpu_device, cpu);
|
||||
td = this_cpu_ptr(&tick_cpu_device);
|
||||
dev = td->evtdev;
|
||||
bc = tick_broadcast_device.evtdev;
|
||||
|
||||
/*
|
||||
* Is the device not affected by the powerstate ?
|
||||
*/
|
||||
if (!dev || !(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
if (!tick_device_is_functional(dev))
|
||||
goto out;
|
||||
return;
|
||||
|
||||
raw_spin_lock(&tick_broadcast_lock);
|
||||
cpu = smp_processor_id();
|
||||
bc = tick_broadcast_device.evtdev;
|
||||
bc_stopped = cpumask_empty(tick_broadcast_mask);
|
||||
|
||||
switch (*reason) {
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_ON:
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_FORCE:
|
||||
switch (mode) {
|
||||
case TICK_BROADCAST_FORCE:
|
||||
tick_broadcast_forced = 1;
|
||||
case TICK_BROADCAST_ON:
|
||||
cpumask_set_cpu(cpu, tick_broadcast_on);
|
||||
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_mask)) {
|
||||
if (tick_broadcast_device.mode ==
|
||||
TICKDEV_MODE_PERIODIC)
|
||||
clockevents_shutdown(dev);
|
||||
}
|
||||
if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
|
||||
tick_broadcast_force = 1;
|
||||
break;
|
||||
case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
|
||||
if (tick_broadcast_force)
|
||||
|
||||
case TICK_BROADCAST_OFF:
|
||||
if (tick_broadcast_forced)
|
||||
break;
|
||||
cpumask_clear_cpu(cpu, tick_broadcast_on);
|
||||
if (!tick_device_is_functional(dev))
|
||||
@@ -388,22 +395,9 @@ static void tick_do_broadcast_on_off(unsigned long *reason)
|
||||
else
|
||||
tick_broadcast_setup_oneshot(bc);
|
||||
}
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Powerstate information: The system enters/leaves a state, where
|
||||
* affected devices might stop.
|
||||
*/
|
||||
void tick_broadcast_on_off(unsigned long reason, int *oncpu)
|
||||
{
|
||||
if (!cpumask_test_cpu(*oncpu, cpu_online_mask))
|
||||
printk(KERN_ERR "tick-broadcast: ignoring broadcast for "
|
||||
"offline CPU #%d\n", *oncpu);
|
||||
else
|
||||
tick_do_broadcast_on_off(&reason);
|
||||
raw_spin_unlock(&tick_broadcast_lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tick_broadcast_control);
|
||||
|
||||
/*
|
||||
* Set the periodic handler depending on broadcast on/off
|
||||
@@ -416,14 +410,14 @@ void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
|
||||
dev->event_handler = tick_handle_periodic_broadcast;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/*
|
||||
* Remove a CPU from broadcasting
|
||||
*/
|
||||
void tick_shutdown_broadcast(unsigned int *cpup)
|
||||
void tick_shutdown_broadcast(unsigned int cpu)
|
||||
{
|
||||
struct clock_event_device *bc;
|
||||
unsigned long flags;
|
||||
unsigned int cpu = *cpup;
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
|
||||
@@ -438,6 +432,7 @@ void tick_shutdown_broadcast(unsigned int *cpup)
|
||||
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
void tick_suspend_broadcast(void)
|
||||
{
|
||||
@@ -453,38 +448,48 @@ void tick_suspend_broadcast(void)
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
|
||||
int tick_resume_broadcast(void)
|
||||
/*
|
||||
* This is called from tick_resume_local() on a resuming CPU. That's
|
||||
* called from the core resume function, tick_unfreeze() and the magic XEN
|
||||
* resume hackery.
|
||||
*
|
||||
* In none of these cases the broadcast device mode can change and the
|
||||
* bit of the resuming CPU in the broadcast mask is safe as well.
|
||||
*/
|
||||
bool tick_resume_check_broadcast(void)
|
||||
{
|
||||
if (tick_broadcast_device.mode == TICKDEV_MODE_ONESHOT)
|
||||
return false;
|
||||
else
|
||||
return cpumask_test_cpu(smp_processor_id(), tick_broadcast_mask);
|
||||
}
|
||||
|
||||
void tick_resume_broadcast(void)
|
||||
{
|
||||
struct clock_event_device *bc;
|
||||
unsigned long flags;
|
||||
int broadcast = 0;
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
|
||||
bc = tick_broadcast_device.evtdev;
|
||||
|
||||
if (bc) {
|
||||
clockevents_set_mode(bc, CLOCK_EVT_MODE_RESUME);
|
||||
clockevents_tick_resume(bc);
|
||||
|
||||
switch (tick_broadcast_device.mode) {
|
||||
case TICKDEV_MODE_PERIODIC:
|
||||
if (!cpumask_empty(tick_broadcast_mask))
|
||||
tick_broadcast_start_periodic(bc);
|
||||
broadcast = cpumask_test_cpu(smp_processor_id(),
|
||||
tick_broadcast_mask);
|
||||
break;
|
||||
case TICKDEV_MODE_ONESHOT:
|
||||
if (!cpumask_empty(tick_broadcast_mask))
|
||||
broadcast = tick_resume_broadcast_oneshot(bc);
|
||||
tick_resume_broadcast_oneshot(bc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
|
||||
return broadcast;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_TICK_ONESHOT
|
||||
|
||||
static cpumask_var_t tick_broadcast_oneshot_mask;
|
||||
@@ -532,8 +537,8 @@ static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (bc->mode != CLOCK_EVT_MODE_ONESHOT)
|
||||
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
|
||||
if (bc->state != CLOCK_EVT_STATE_ONESHOT)
|
||||
clockevents_set_state(bc, CLOCK_EVT_STATE_ONESHOT);
|
||||
|
||||
ret = clockevents_program_event(bc, expires, force);
|
||||
if (!ret)
|
||||
@@ -541,10 +546,9 @@ static int tick_broadcast_set_event(struct clock_event_device *bc, int cpu,
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
|
||||
static void tick_resume_broadcast_oneshot(struct clock_event_device *bc)
|
||||
{
|
||||
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
|
||||
return 0;
|
||||
clockevents_set_state(bc, CLOCK_EVT_STATE_ONESHOT);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -562,8 +566,8 @@ void tick_check_oneshot_broadcast_this_cpu(void)
|
||||
* switched over, leave the device alone.
|
||||
*/
|
||||
if (td->mode == TICKDEV_MODE_ONESHOT) {
|
||||
clockevents_set_mode(td->evtdev,
|
||||
CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(td->evtdev,
|
||||
CLOCK_EVT_STATE_ONESHOT);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -666,31 +670,26 @@ static void broadcast_shutdown_local(struct clock_event_device *bc,
|
||||
if (dev->next_event.tv64 < bc->next_event.tv64)
|
||||
return;
|
||||
}
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_SHUTDOWN);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_SHUTDOWN);
|
||||
}
|
||||
|
||||
static void broadcast_move_bc(int deadcpu)
|
||||
{
|
||||
struct clock_event_device *bc = tick_broadcast_device.evtdev;
|
||||
|
||||
if (!bc || !broadcast_needs_cpu(bc, deadcpu))
|
||||
return;
|
||||
/* This moves the broadcast assignment to this cpu */
|
||||
clockevents_program_event(bc, bc->next_event, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Powerstate information: The system enters/leaves a state, where
|
||||
* affected devices might stop
|
||||
/**
|
||||
* tick_broadcast_oneshot_control - Enter/exit broadcast oneshot mode
|
||||
* @state: The target state (enter/exit)
|
||||
*
|
||||
* The system enters/leaves a state, where affected devices might stop
|
||||
* Returns 0 on success, -EBUSY if the cpu is used to broadcast wakeups.
|
||||
*
|
||||
* Called with interrupts disabled, so clockevents_lock is not
|
||||
* required here because the local clock event device cannot go away
|
||||
* under us.
|
||||
*/
|
||||
int tick_broadcast_oneshot_control(unsigned long reason)
|
||||
int tick_broadcast_oneshot_control(enum tick_broadcast_state state)
|
||||
{
|
||||
struct clock_event_device *bc, *dev;
|
||||
struct tick_device *td;
|
||||
unsigned long flags;
|
||||
ktime_t now;
|
||||
int cpu, ret = 0;
|
||||
ktime_t now;
|
||||
|
||||
/*
|
||||
* Periodic mode does not care about the enter/exit of power
|
||||
@@ -703,17 +702,17 @@ int tick_broadcast_oneshot_control(unsigned long reason)
|
||||
* We are called with preemtion disabled from the depth of the
|
||||
* idle code, so we can't be moved away.
|
||||
*/
|
||||
cpu = smp_processor_id();
|
||||
td = &per_cpu(tick_cpu_device, cpu);
|
||||
td = this_cpu_ptr(&tick_cpu_device);
|
||||
dev = td->evtdev;
|
||||
|
||||
if (!(dev->features & CLOCK_EVT_FEAT_C3STOP))
|
||||
return 0;
|
||||
|
||||
raw_spin_lock(&tick_broadcast_lock);
|
||||
bc = tick_broadcast_device.evtdev;
|
||||
cpu = smp_processor_id();
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
if (reason == CLOCK_EVT_NOTIFY_BROADCAST_ENTER) {
|
||||
if (state == TICK_BROADCAST_ENTER) {
|
||||
if (!cpumask_test_and_set_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
||||
WARN_ON_ONCE(cpumask_test_cpu(cpu, tick_broadcast_pending_mask));
|
||||
broadcast_shutdown_local(bc, dev);
|
||||
@@ -741,7 +740,7 @@ int tick_broadcast_oneshot_control(unsigned long reason)
|
||||
cpumask_clear_cpu(cpu, tick_broadcast_oneshot_mask);
|
||||
} else {
|
||||
if (cpumask_test_and_clear_cpu(cpu, tick_broadcast_oneshot_mask)) {
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
||||
/*
|
||||
* The cpu which was handling the broadcast
|
||||
* timer marked this cpu in the broadcast
|
||||
@@ -805,9 +804,10 @@ int tick_broadcast_oneshot_control(unsigned long reason)
|
||||
}
|
||||
}
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
raw_spin_unlock(&tick_broadcast_lock);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(tick_broadcast_oneshot_control);
|
||||
|
||||
/*
|
||||
* Reset the one shot broadcast for a cpu
|
||||
@@ -842,7 +842,7 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
|
||||
|
||||
/* Set it up only once ! */
|
||||
if (bc->event_handler != tick_handle_oneshot_broadcast) {
|
||||
int was_periodic = bc->mode == CLOCK_EVT_MODE_PERIODIC;
|
||||
int was_periodic = bc->state == CLOCK_EVT_STATE_PERIODIC;
|
||||
|
||||
bc->event_handler = tick_handle_oneshot_broadcast;
|
||||
|
||||
@@ -858,7 +858,7 @@ void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
|
||||
tick_broadcast_oneshot_mask, tmpmask);
|
||||
|
||||
if (was_periodic && !cpumask_empty(tmpmask)) {
|
||||
clockevents_set_mode(bc, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(bc, CLOCK_EVT_STATE_ONESHOT);
|
||||
tick_broadcast_init_next_event(tmpmask,
|
||||
tick_next_period);
|
||||
tick_broadcast_set_event(bc, cpu, tick_next_period, 1);
|
||||
@@ -894,14 +894,28 @@ void tick_broadcast_switch_to_oneshot(void)
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
void hotplug_cpu__broadcast_tick_pull(int deadcpu)
|
||||
{
|
||||
struct clock_event_device *bc;
|
||||
unsigned long flags;
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
bc = tick_broadcast_device.evtdev;
|
||||
|
||||
if (bc && broadcast_needs_cpu(bc, deadcpu)) {
|
||||
/* This moves the broadcast assignment to this CPU: */
|
||||
clockevents_program_event(bc, bc->next_event, 1);
|
||||
}
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove a dead CPU from broadcasting
|
||||
*/
|
||||
void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
|
||||
void tick_shutdown_broadcast_oneshot(unsigned int cpu)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int cpu = *cpup;
|
||||
|
||||
raw_spin_lock_irqsave(&tick_broadcast_lock, flags);
|
||||
|
||||
@@ -913,10 +927,9 @@ void tick_shutdown_broadcast_oneshot(unsigned int *cpup)
|
||||
cpumask_clear_cpu(cpu, tick_broadcast_pending_mask);
|
||||
cpumask_clear_cpu(cpu, tick_broadcast_force_mask);
|
||||
|
||||
broadcast_move_bc(cpu);
|
||||
|
||||
raw_spin_unlock_irqrestore(&tick_broadcast_lock, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Check, whether the broadcast device is in one shot mode
|
||||
|
||||
+63
-19
@@ -102,7 +102,7 @@ void tick_handle_periodic(struct clock_event_device *dev)
|
||||
|
||||
tick_periodic(cpu);
|
||||
|
||||
if (dev->mode != CLOCK_EVT_MODE_ONESHOT)
|
||||
if (dev->state != CLOCK_EVT_STATE_ONESHOT)
|
||||
return;
|
||||
for (;;) {
|
||||
/*
|
||||
@@ -140,7 +140,7 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
|
||||
|
||||
if ((dev->features & CLOCK_EVT_FEAT_PERIODIC) &&
|
||||
!tick_broadcast_oneshot_active()) {
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_PERIODIC);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_PERIODIC);
|
||||
} else {
|
||||
unsigned long seq;
|
||||
ktime_t next;
|
||||
@@ -150,7 +150,7 @@ void tick_setup_periodic(struct clock_event_device *dev, int broadcast)
|
||||
next = tick_next_period;
|
||||
} while (read_seqretry(&jiffies_lock, seq));
|
||||
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
||||
|
||||
for (;;) {
|
||||
if (!clockevents_program_event(dev, next, false))
|
||||
@@ -332,14 +332,16 @@ out_bc:
|
||||
tick_install_broadcast_device(newdev);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
/*
|
||||
* Transfer the do_timer job away from a dying cpu.
|
||||
*
|
||||
* Called with interrupts disabled.
|
||||
* Called with interrupts disabled. Not locking required. If
|
||||
* tick_do_timer_cpu is owned by this cpu, nothing can change it.
|
||||
*/
|
||||
void tick_handover_do_timer(int *cpup)
|
||||
void tick_handover_do_timer(void)
|
||||
{
|
||||
if (*cpup == tick_do_timer_cpu) {
|
||||
if (tick_do_timer_cpu == smp_processor_id()) {
|
||||
int cpu = cpumask_first(cpu_online_mask);
|
||||
|
||||
tick_do_timer_cpu = (cpu < nr_cpu_ids) ? cpu :
|
||||
@@ -354,9 +356,9 @@ void tick_handover_do_timer(int *cpup)
|
||||
* access the hardware device itself.
|
||||
* We just set the mode and remove it from the lists.
|
||||
*/
|
||||
void tick_shutdown(unsigned int *cpup)
|
||||
void tick_shutdown(unsigned int cpu)
|
||||
{
|
||||
struct tick_device *td = &per_cpu(tick_cpu_device, *cpup);
|
||||
struct tick_device *td = &per_cpu(tick_cpu_device, cpu);
|
||||
struct clock_event_device *dev = td->evtdev;
|
||||
|
||||
td->mode = TICKDEV_MODE_PERIODIC;
|
||||
@@ -365,27 +367,42 @@ void tick_shutdown(unsigned int *cpup)
|
||||
* Prevent that the clock events layer tries to call
|
||||
* the set mode function!
|
||||
*/
|
||||
dev->state = CLOCK_EVT_STATE_DETACHED;
|
||||
dev->mode = CLOCK_EVT_MODE_UNUSED;
|
||||
clockevents_exchange_device(dev, NULL);
|
||||
dev->event_handler = clockevents_handle_noop;
|
||||
td->evtdev = NULL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void tick_suspend(void)
|
||||
/**
|
||||
* tick_suspend_local - Suspend the local tick device
|
||||
*
|
||||
* Called from the local cpu for freeze with interrupts disabled.
|
||||
*
|
||||
* No locks required. Nothing can change the per cpu device.
|
||||
*/
|
||||
void tick_suspend_local(void)
|
||||
{
|
||||
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
|
||||
|
||||
clockevents_shutdown(td->evtdev);
|
||||
}
|
||||
|
||||
void tick_resume(void)
|
||||
/**
|
||||
* tick_resume_local - Resume the local tick device
|
||||
*
|
||||
* Called from the local CPU for unfreeze or XEN resume magic.
|
||||
*
|
||||
* No locks required. Nothing can change the per cpu device.
|
||||
*/
|
||||
void tick_resume_local(void)
|
||||
{
|
||||
struct tick_device *td = this_cpu_ptr(&tick_cpu_device);
|
||||
int broadcast = tick_resume_broadcast();
|
||||
|
||||
clockevents_set_mode(td->evtdev, CLOCK_EVT_MODE_RESUME);
|
||||
bool broadcast = tick_resume_check_broadcast();
|
||||
|
||||
clockevents_tick_resume(td->evtdev);
|
||||
if (!broadcast) {
|
||||
if (td->mode == TICKDEV_MODE_PERIODIC)
|
||||
tick_setup_periodic(td->evtdev, 0);
|
||||
@@ -394,6 +411,35 @@ void tick_resume(void)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* tick_suspend - Suspend the tick and the broadcast device
|
||||
*
|
||||
* Called from syscore_suspend() via timekeeping_suspend with only one
|
||||
* CPU online and interrupts disabled or from tick_unfreeze() under
|
||||
* tick_freeze_lock.
|
||||
*
|
||||
* No locks required. Nothing can change the per cpu device.
|
||||
*/
|
||||
void tick_suspend(void)
|
||||
{
|
||||
tick_suspend_local();
|
||||
tick_suspend_broadcast();
|
||||
}
|
||||
|
||||
/**
|
||||
* tick_resume - Resume the tick and the broadcast device
|
||||
*
|
||||
* Called from syscore_resume() via timekeeping_resume with only one
|
||||
* CPU online and interrupts disabled.
|
||||
*
|
||||
* No locks required. Nothing can change the per cpu device.
|
||||
*/
|
||||
void tick_resume(void)
|
||||
{
|
||||
tick_resume_broadcast();
|
||||
tick_resume_local();
|
||||
}
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(tick_freeze_lock);
|
||||
static unsigned int tick_freeze_depth;
|
||||
|
||||
@@ -411,12 +457,10 @@ void tick_freeze(void)
|
||||
raw_spin_lock(&tick_freeze_lock);
|
||||
|
||||
tick_freeze_depth++;
|
||||
if (tick_freeze_depth == num_online_cpus()) {
|
||||
if (tick_freeze_depth == num_online_cpus())
|
||||
timekeeping_suspend();
|
||||
} else {
|
||||
tick_suspend();
|
||||
tick_suspend_broadcast();
|
||||
}
|
||||
else
|
||||
tick_suspend_local();
|
||||
|
||||
raw_spin_unlock(&tick_freeze_lock);
|
||||
}
|
||||
@@ -437,7 +481,7 @@ void tick_unfreeze(void)
|
||||
if (tick_freeze_depth == num_online_cpus())
|
||||
timekeeping_resume();
|
||||
else
|
||||
tick_resume();
|
||||
tick_resume_local();
|
||||
|
||||
tick_freeze_depth--;
|
||||
|
||||
|
||||
+92
-125
@@ -5,15 +5,12 @@
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include "timekeeping.h"
|
||||
#include "tick-sched.h"
|
||||
|
||||
extern seqlock_t jiffies_lock;
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS
|
||||
|
||||
#define CS_NAME_LEN 32
|
||||
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BUILD
|
||||
|
||||
#define TICK_DO_TIMER_NONE -1
|
||||
#define TICK_DO_TIMER_BOOT -2
|
||||
# define TICK_DO_TIMER_NONE -1
|
||||
# define TICK_DO_TIMER_BOOT -2
|
||||
|
||||
DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
|
||||
extern ktime_t tick_next_period;
|
||||
@@ -23,21 +20,72 @@ extern int tick_do_timer_cpu __read_mostly;
|
||||
extern void tick_setup_periodic(struct clock_event_device *dev, int broadcast);
|
||||
extern void tick_handle_periodic(struct clock_event_device *dev);
|
||||
extern void tick_check_new_device(struct clock_event_device *dev);
|
||||
extern void tick_handover_do_timer(int *cpup);
|
||||
extern void tick_shutdown(unsigned int *cpup);
|
||||
extern void tick_shutdown(unsigned int cpu);
|
||||
extern void tick_suspend(void);
|
||||
extern void tick_resume(void);
|
||||
extern bool tick_check_replacement(struct clock_event_device *curdev,
|
||||
struct clock_event_device *newdev);
|
||||
extern void tick_install_replacement(struct clock_event_device *dev);
|
||||
extern int tick_is_oneshot_available(void);
|
||||
extern struct tick_device *tick_get_device(int cpu);
|
||||
|
||||
extern int clockevents_tick_resume(struct clock_event_device *dev);
|
||||
/* Check, if the device is functional or a dummy for broadcast */
|
||||
static inline int tick_device_is_functional(struct clock_event_device *dev)
|
||||
{
|
||||
return !(dev->features & CLOCK_EVT_FEAT_DUMMY);
|
||||
}
|
||||
|
||||
extern void clockevents_shutdown(struct clock_event_device *dev);
|
||||
|
||||
extern void clockevents_exchange_device(struct clock_event_device *old,
|
||||
struct clock_event_device *new);
|
||||
extern void clockevents_set_state(struct clock_event_device *dev,
|
||||
enum clock_event_state state);
|
||||
extern int clockevents_program_event(struct clock_event_device *dev,
|
||||
ktime_t expires, bool force);
|
||||
extern void clockevents_handle_noop(struct clock_event_device *dev);
|
||||
extern int __clockevents_update_freq(struct clock_event_device *dev, u32 freq);
|
||||
extern ssize_t sysfs_get_uname(const char *buf, char *dst, size_t cnt);
|
||||
|
||||
/*
|
||||
* NO_HZ / high resolution timer shared code
|
||||
*/
|
||||
/* Broadcasting support */
|
||||
# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||
extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu);
|
||||
extern void tick_install_broadcast_device(struct clock_event_device *dev);
|
||||
extern int tick_is_broadcast_device(struct clock_event_device *dev);
|
||||
extern void tick_shutdown_broadcast(unsigned int cpu);
|
||||
extern void tick_suspend_broadcast(void);
|
||||
extern void tick_resume_broadcast(void);
|
||||
extern bool tick_resume_check_broadcast(void);
|
||||
extern void tick_broadcast_init(void);
|
||||
extern void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
|
||||
extern int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
|
||||
extern struct tick_device *tick_get_broadcast_device(void);
|
||||
extern struct cpumask *tick_get_broadcast_mask(void);
|
||||
# else /* !CONFIG_GENERIC_CLOCKEVENTS_BROADCAST: */
|
||||
static inline void tick_install_broadcast_device(struct clock_event_device *dev) { }
|
||||
static inline int tick_is_broadcast_device(struct clock_event_device *dev) { return 0; }
|
||||
static inline int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu) { return 0; }
|
||||
static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
|
||||
static inline void tick_shutdown_broadcast(unsigned int cpu) { }
|
||||
static inline void tick_suspend_broadcast(void) { }
|
||||
static inline void tick_resume_broadcast(void) { }
|
||||
static inline bool tick_resume_check_broadcast(void) { return false; }
|
||||
static inline void tick_broadcast_init(void) { }
|
||||
static inline int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq) { return -ENODEV; }
|
||||
|
||||
/* Set the periodic handler in non broadcast mode */
|
||||
static inline void tick_set_periodic_handler(struct clock_event_device *dev, int broadcast)
|
||||
{
|
||||
dev->event_handler = tick_handle_periodic;
|
||||
}
|
||||
# endif /* !CONFIG_GENERIC_CLOCKEVENTS_BROADCAST */
|
||||
|
||||
#else /* !GENERIC_CLOCKEVENTS: */
|
||||
static inline void tick_suspend(void) { }
|
||||
static inline void tick_resume(void) { }
|
||||
#endif /* !GENERIC_CLOCKEVENTS */
|
||||
|
||||
/* Oneshot related functions */
|
||||
#ifdef CONFIG_TICK_ONESHOT
|
||||
extern void tick_setup_oneshot(struct clock_event_device *newdev,
|
||||
void (*handler)(struct clock_event_device *),
|
||||
@@ -46,58 +94,42 @@ extern int tick_program_event(ktime_t expires, int force);
|
||||
extern void tick_oneshot_notify(void);
|
||||
extern int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *));
|
||||
extern void tick_resume_oneshot(void);
|
||||
# ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||
extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
|
||||
extern int tick_broadcast_oneshot_control(unsigned long reason);
|
||||
extern void tick_broadcast_switch_to_oneshot(void);
|
||||
extern void tick_shutdown_broadcast_oneshot(unsigned int *cpup);
|
||||
extern int tick_resume_broadcast_oneshot(struct clock_event_device *bc);
|
||||
extern int tick_broadcast_oneshot_active(void);
|
||||
extern void tick_check_oneshot_broadcast_this_cpu(void);
|
||||
bool tick_broadcast_oneshot_available(void);
|
||||
# else /* BROADCAST */
|
||||
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
|
||||
static inline void tick_broadcast_switch_to_oneshot(void) { }
|
||||
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
|
||||
static inline int tick_broadcast_oneshot_active(void) { return 0; }
|
||||
static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
|
||||
static inline bool tick_broadcast_oneshot_available(void) { return true; }
|
||||
# endif /* !BROADCAST */
|
||||
|
||||
#else /* !ONESHOT */
|
||||
static inline bool tick_oneshot_possible(void) { return true; }
|
||||
extern int tick_oneshot_mode_active(void);
|
||||
extern void tick_clock_notify(void);
|
||||
extern int tick_check_oneshot_change(int allow_nohz);
|
||||
extern int tick_init_highres(void);
|
||||
#else /* !CONFIG_TICK_ONESHOT: */
|
||||
static inline
|
||||
void tick_setup_oneshot(struct clock_event_device *newdev,
|
||||
void (*handler)(struct clock_event_device *),
|
||||
ktime_t nextevt)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
static inline void tick_resume_oneshot(void)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
static inline int tick_program_event(ktime_t expires, int force)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ktime_t nextevt) { BUG(); }
|
||||
static inline void tick_resume_oneshot(void) { BUG(); }
|
||||
static inline int tick_program_event(ktime_t expires, int force) { return 0; }
|
||||
static inline void tick_oneshot_notify(void) { }
|
||||
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc)
|
||||
{
|
||||
BUG();
|
||||
}
|
||||
static inline int tick_broadcast_oneshot_control(unsigned long reason) { return 0; }
|
||||
static inline void tick_shutdown_broadcast_oneshot(unsigned int *cpup) { }
|
||||
static inline int tick_resume_broadcast_oneshot(struct clock_event_device *bc)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline bool tick_oneshot_possible(void) { return false; }
|
||||
static inline int tick_oneshot_mode_active(void) { return 0; }
|
||||
static inline void tick_clock_notify(void) { }
|
||||
static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
|
||||
#endif /* !CONFIG_TICK_ONESHOT */
|
||||
|
||||
/* Functions related to oneshot broadcasting */
|
||||
#if defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST) && defined(CONFIG_TICK_ONESHOT)
|
||||
extern void tick_broadcast_setup_oneshot(struct clock_event_device *bc);
|
||||
extern void tick_broadcast_switch_to_oneshot(void);
|
||||
extern void tick_shutdown_broadcast_oneshot(unsigned int cpu);
|
||||
extern int tick_broadcast_oneshot_active(void);
|
||||
extern void tick_check_oneshot_broadcast_this_cpu(void);
|
||||
bool tick_broadcast_oneshot_available(void);
|
||||
extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
|
||||
#else /* !(BROADCAST && ONESHOT): */
|
||||
static inline void tick_broadcast_setup_oneshot(struct clock_event_device *bc) { BUG(); }
|
||||
static inline void tick_broadcast_switch_to_oneshot(void) { }
|
||||
static inline void tick_shutdown_broadcast_oneshot(unsigned int cpu) { }
|
||||
static inline int tick_broadcast_oneshot_active(void) { return 0; }
|
||||
static inline bool tick_broadcast_oneshot_available(void) { return false; }
|
||||
#endif /* !TICK_ONESHOT */
|
||||
static inline void tick_check_oneshot_broadcast_this_cpu(void) { }
|
||||
static inline bool tick_broadcast_oneshot_available(void) { return tick_oneshot_possible(); }
|
||||
#endif /* !(BROADCAST && ONESHOT) */
|
||||
|
||||
/* NO_HZ_FULL internal */
|
||||
#ifdef CONFIG_NO_HZ_FULL
|
||||
@@ -105,68 +137,3 @@ extern void tick_nohz_init(void);
|
||||
# else
|
||||
static inline void tick_nohz_init(void) { }
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Broadcasting support
|
||||
*/
|
||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||
extern int tick_device_uses_broadcast(struct clock_event_device *dev, int cpu);
|
||||
extern void tick_install_broadcast_device(struct clock_event_device *dev);
|
||||
extern int tick_is_broadcast_device(struct clock_event_device *dev);
|
||||
extern void tick_broadcast_on_off(unsigned long reason, int *oncpu);
|
||||
extern void tick_shutdown_broadcast(unsigned int *cpup);
|
||||
extern void tick_suspend_broadcast(void);
|
||||
extern int tick_resume_broadcast(void);
|
||||
extern void tick_broadcast_init(void);
|
||||
extern void
|
||||
tick_set_periodic_handler(struct clock_event_device *dev, int broadcast);
|
||||
int tick_broadcast_update_freq(struct clock_event_device *dev, u32 freq);
|
||||
|
||||
#else /* !BROADCAST */
|
||||
|
||||
static inline void tick_install_broadcast_device(struct clock_event_device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int tick_is_broadcast_device(struct clock_event_device *dev)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int tick_device_uses_broadcast(struct clock_event_device *dev,
|
||||
int cpu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline void tick_do_periodic_broadcast(struct clock_event_device *d) { }
|
||||
static inline void tick_broadcast_on_off(unsigned long reason, int *oncpu) { }
|
||||
static inline void tick_shutdown_broadcast(unsigned int *cpup) { }
|
||||
static inline void tick_suspend_broadcast(void) { }
|
||||
static inline int tick_resume_broadcast(void) { return 0; }
|
||||
static inline void tick_broadcast_init(void) { }
|
||||
static inline int tick_broadcast_update_freq(struct clock_event_device *dev,
|
||||
u32 freq) { return -ENODEV; }
|
||||
|
||||
/*
|
||||
* Set the periodic handler in non broadcast mode
|
||||
*/
|
||||
static inline void tick_set_periodic_handler(struct clock_event_device *dev,
|
||||
int broadcast)
|
||||
{
|
||||
dev->event_handler = tick_handle_periodic;
|
||||
}
|
||||
#endif /* !BROADCAST */
|
||||
|
||||
/*
|
||||
* Check, if the device is functional or a dummy for broadcast
|
||||
*/
|
||||
static inline int tick_device_is_functional(struct clock_event_device *dev)
|
||||
{
|
||||
return !(dev->features & CLOCK_EVT_FEAT_DUMMY);
|
||||
}
|
||||
|
||||
int __clockevents_update_freq(struct clock_event_device *dev, u32 freq);
|
||||
|
||||
#endif
|
||||
|
||||
extern void do_timer(unsigned long ticks);
|
||||
extern void update_wall_time(void);
|
||||
|
||||
@@ -38,7 +38,7 @@ void tick_resume_oneshot(void)
|
||||
{
|
||||
struct clock_event_device *dev = __this_cpu_read(tick_cpu_device.evtdev);
|
||||
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
||||
clockevents_program_event(dev, ktime_get(), true);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ void tick_setup_oneshot(struct clock_event_device *newdev,
|
||||
ktime_t next_event)
|
||||
{
|
||||
newdev->event_handler = handler;
|
||||
clockevents_set_mode(newdev, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(newdev, CLOCK_EVT_STATE_ONESHOT);
|
||||
clockevents_program_event(newdev, next_event, true);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ int tick_switch_to_oneshot(void (*handler)(struct clock_event_device *))
|
||||
|
||||
td->mode = TICKDEV_MODE_ONESHOT;
|
||||
dev->event_handler = handler;
|
||||
clockevents_set_mode(dev, CLOCK_EVT_MODE_ONESHOT);
|
||||
clockevents_set_state(dev, CLOCK_EVT_STATE_ONESHOT);
|
||||
tick_broadcast_switch_to_oneshot();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
/*
|
||||
* Per cpu nohz control structure
|
||||
*/
|
||||
DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
|
||||
static DEFINE_PER_CPU(struct tick_sched, tick_cpu_sched);
|
||||
|
||||
/*
|
||||
* The time, when the last jiffy update happened. Protected by jiffies_lock.
|
||||
@@ -416,6 +416,11 @@ static int __init setup_tick_nohz(char *str)
|
||||
|
||||
__setup("nohz=", setup_tick_nohz);
|
||||
|
||||
int tick_nohz_tick_stopped(void)
|
||||
{
|
||||
return __this_cpu_read(tick_cpu_sched.tick_stopped);
|
||||
}
|
||||
|
||||
/**
|
||||
* tick_nohz_update_jiffies - update jiffies when idle was interrupted
|
||||
*
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#ifndef _TICK_SCHED_H
|
||||
#define _TICK_SCHED_H
|
||||
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
enum tick_device_mode {
|
||||
TICKDEV_MODE_PERIODIC,
|
||||
TICKDEV_MODE_ONESHOT,
|
||||
};
|
||||
|
||||
struct tick_device {
|
||||
struct clock_event_device *evtdev;
|
||||
enum tick_device_mode mode;
|
||||
};
|
||||
|
||||
enum tick_nohz_mode {
|
||||
NOHZ_MODE_INACTIVE,
|
||||
NOHZ_MODE_LOWRES,
|
||||
NOHZ_MODE_HIGHRES,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct tick_sched - sched tick emulation and no idle tick control/stats
|
||||
* @sched_timer: hrtimer to schedule the periodic tick in high
|
||||
* resolution mode
|
||||
* @last_tick: Store the last tick expiry time when the tick
|
||||
* timer is modified for nohz sleeps. This is necessary
|
||||
* to resume the tick timer operation in the timeline
|
||||
* when the CPU returns from nohz sleep.
|
||||
* @tick_stopped: Indicator that the idle tick has been stopped
|
||||
* @idle_jiffies: jiffies at the entry to idle for idle time accounting
|
||||
* @idle_calls: Total number of idle calls
|
||||
* @idle_sleeps: Number of idle calls, where the sched tick was stopped
|
||||
* @idle_entrytime: Time when the idle call was entered
|
||||
* @idle_waketime: Time when the idle was interrupted
|
||||
* @idle_exittime: Time when the idle state was left
|
||||
* @idle_sleeptime: Sum of the time slept in idle with sched tick stopped
|
||||
* @iowait_sleeptime: Sum of the time slept in idle with sched tick stopped, with IO outstanding
|
||||
* @sleep_length: Duration of the current idle sleep
|
||||
* @do_timer_lst: CPU was the last one doing do_timer before going idle
|
||||
*/
|
||||
struct tick_sched {
|
||||
struct hrtimer sched_timer;
|
||||
unsigned long check_clocks;
|
||||
enum tick_nohz_mode nohz_mode;
|
||||
ktime_t last_tick;
|
||||
int inidle;
|
||||
int tick_stopped;
|
||||
unsigned long idle_jiffies;
|
||||
unsigned long idle_calls;
|
||||
unsigned long idle_sleeps;
|
||||
int idle_active;
|
||||
ktime_t idle_entrytime;
|
||||
ktime_t idle_waketime;
|
||||
ktime_t idle_exittime;
|
||||
ktime_t idle_sleeptime;
|
||||
ktime_t iowait_sleeptime;
|
||||
ktime_t sleep_length;
|
||||
unsigned long last_jiffies;
|
||||
unsigned long next_jiffies;
|
||||
ktime_t idle_expires;
|
||||
int do_timer_last;
|
||||
};
|
||||
|
||||
extern struct tick_sched *tick_get_tick_sched(int cpu);
|
||||
|
||||
extern void tick_setup_sched_timer(void);
|
||||
#if defined CONFIG_NO_HZ_COMMON || defined CONFIG_HIGH_RES_TIMERS
|
||||
extern void tick_cancel_sched_timer(int cpu);
|
||||
#else
|
||||
static inline void tick_cancel_sched_timer(int cpu) { }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
+325
-165
@@ -59,17 +59,15 @@ struct tk_fast {
|
||||
};
|
||||
|
||||
static struct tk_fast tk_fast_mono ____cacheline_aligned;
|
||||
static struct tk_fast tk_fast_raw ____cacheline_aligned;
|
||||
|
||||
/* flag for if timekeeping is suspended */
|
||||
int __read_mostly timekeeping_suspended;
|
||||
|
||||
/* Flag for if there is a persistent clock on this platform */
|
||||
bool __read_mostly persistent_clock_exist = false;
|
||||
|
||||
static inline void tk_normalize_xtime(struct timekeeper *tk)
|
||||
{
|
||||
while (tk->tkr.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr.shift)) {
|
||||
tk->tkr.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr.shift;
|
||||
while (tk->tkr_mono.xtime_nsec >= ((u64)NSEC_PER_SEC << tk->tkr_mono.shift)) {
|
||||
tk->tkr_mono.xtime_nsec -= (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
|
||||
tk->xtime_sec++;
|
||||
}
|
||||
}
|
||||
@@ -79,20 +77,20 @@ static inline struct timespec64 tk_xtime(struct timekeeper *tk)
|
||||
struct timespec64 ts;
|
||||
|
||||
ts.tv_sec = tk->xtime_sec;
|
||||
ts.tv_nsec = (long)(tk->tkr.xtime_nsec >> tk->tkr.shift);
|
||||
ts.tv_nsec = (long)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
|
||||
return ts;
|
||||
}
|
||||
|
||||
static void tk_set_xtime(struct timekeeper *tk, const struct timespec64 *ts)
|
||||
{
|
||||
tk->xtime_sec = ts->tv_sec;
|
||||
tk->tkr.xtime_nsec = (u64)ts->tv_nsec << tk->tkr.shift;
|
||||
tk->tkr_mono.xtime_nsec = (u64)ts->tv_nsec << tk->tkr_mono.shift;
|
||||
}
|
||||
|
||||
static void tk_xtime_add(struct timekeeper *tk, const struct timespec64 *ts)
|
||||
{
|
||||
tk->xtime_sec += ts->tv_sec;
|
||||
tk->tkr.xtime_nsec += (u64)ts->tv_nsec << tk->tkr.shift;
|
||||
tk->tkr_mono.xtime_nsec += (u64)ts->tv_nsec << tk->tkr_mono.shift;
|
||||
tk_normalize_xtime(tk);
|
||||
}
|
||||
|
||||
@@ -118,6 +116,117 @@ static inline void tk_update_sleep_time(struct timekeeper *tk, ktime_t delta)
|
||||
tk->offs_boot = ktime_add(tk->offs_boot, delta);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DEBUG_TIMEKEEPING
|
||||
#define WARNING_FREQ (HZ*300) /* 5 minute rate-limiting */
|
||||
/*
|
||||
* These simple flag variables are managed
|
||||
* without locks, which is racy, but ok since
|
||||
* we don't really care about being super
|
||||
* precise about how many events were seen,
|
||||
* just that a problem was observed.
|
||||
*/
|
||||
static int timekeeping_underflow_seen;
|
||||
static int timekeeping_overflow_seen;
|
||||
|
||||
/* last_warning is only modified under the timekeeping lock */
|
||||
static long timekeeping_last_warning;
|
||||
|
||||
static void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
|
||||
{
|
||||
|
||||
cycle_t max_cycles = tk->tkr_mono.clock->max_cycles;
|
||||
const char *name = tk->tkr_mono.clock->name;
|
||||
|
||||
if (offset > max_cycles) {
|
||||
printk_deferred("WARNING: timekeeping: Cycle offset (%lld) is larger than allowed by the '%s' clock's max_cycles value (%lld): time overflow danger\n",
|
||||
offset, name, max_cycles);
|
||||
printk_deferred(" timekeeping: Your kernel is sick, but tries to cope by capping time updates\n");
|
||||
} else {
|
||||
if (offset > (max_cycles >> 1)) {
|
||||
printk_deferred("INFO: timekeeping: Cycle offset (%lld) is larger than the the '%s' clock's 50%% safety margin (%lld)\n",
|
||||
offset, name, max_cycles >> 1);
|
||||
printk_deferred(" timekeeping: Your kernel is still fine, but is feeling a bit nervous\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (timekeeping_underflow_seen) {
|
||||
if (jiffies - timekeeping_last_warning > WARNING_FREQ) {
|
||||
printk_deferred("WARNING: Underflow in clocksource '%s' observed, time update ignored.\n", name);
|
||||
printk_deferred(" Please report this, consider using a different clocksource, if possible.\n");
|
||||
printk_deferred(" Your kernel is probably still fine.\n");
|
||||
timekeeping_last_warning = jiffies;
|
||||
}
|
||||
timekeeping_underflow_seen = 0;
|
||||
}
|
||||
|
||||
if (timekeeping_overflow_seen) {
|
||||
if (jiffies - timekeeping_last_warning > WARNING_FREQ) {
|
||||
printk_deferred("WARNING: Overflow in clocksource '%s' observed, time update capped.\n", name);
|
||||
printk_deferred(" Please report this, consider using a different clocksource, if possible.\n");
|
||||
printk_deferred(" Your kernel is probably still fine.\n");
|
||||
timekeeping_last_warning = jiffies;
|
||||
}
|
||||
timekeeping_overflow_seen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr)
|
||||
{
|
||||
cycle_t now, last, mask, max, delta;
|
||||
unsigned int seq;
|
||||
|
||||
/*
|
||||
* Since we're called holding a seqlock, the data may shift
|
||||
* under us while we're doing the calculation. This can cause
|
||||
* false positives, since we'd note a problem but throw the
|
||||
* results away. So nest another seqlock here to atomically
|
||||
* grab the points we are checking with.
|
||||
*/
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
now = tkr->read(tkr->clock);
|
||||
last = tkr->cycle_last;
|
||||
mask = tkr->mask;
|
||||
max = tkr->clock->max_cycles;
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
delta = clocksource_delta(now, last, mask);
|
||||
|
||||
/*
|
||||
* Try to catch underflows by checking if we are seeing small
|
||||
* mask-relative negative values.
|
||||
*/
|
||||
if (unlikely((~delta & mask) < (mask >> 3))) {
|
||||
timekeeping_underflow_seen = 1;
|
||||
delta = 0;
|
||||
}
|
||||
|
||||
/* Cap delta value to the max_cycles values to avoid mult overflows */
|
||||
if (unlikely(delta > max)) {
|
||||
timekeeping_overflow_seen = 1;
|
||||
delta = tkr->clock->max_cycles;
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
#else
|
||||
static inline void timekeeping_check_update(struct timekeeper *tk, cycle_t offset)
|
||||
{
|
||||
}
|
||||
static inline cycle_t timekeeping_get_delta(struct tk_read_base *tkr)
|
||||
{
|
||||
cycle_t cycle_now, delta;
|
||||
|
||||
/* read clocksource */
|
||||
cycle_now = tkr->read(tkr->clock);
|
||||
|
||||
/* calculate the delta since the last update_wall_time */
|
||||
delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask);
|
||||
|
||||
return delta;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* tk_setup_internals - Set up internals to use clocksource clock.
|
||||
*
|
||||
@@ -135,11 +244,16 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
|
||||
u64 tmp, ntpinterval;
|
||||
struct clocksource *old_clock;
|
||||
|
||||
old_clock = tk->tkr.clock;
|
||||
tk->tkr.clock = clock;
|
||||
tk->tkr.read = clock->read;
|
||||
tk->tkr.mask = clock->mask;
|
||||
tk->tkr.cycle_last = tk->tkr.read(clock);
|
||||
old_clock = tk->tkr_mono.clock;
|
||||
tk->tkr_mono.clock = clock;
|
||||
tk->tkr_mono.read = clock->read;
|
||||
tk->tkr_mono.mask = clock->mask;
|
||||
tk->tkr_mono.cycle_last = tk->tkr_mono.read(clock);
|
||||
|
||||
tk->tkr_raw.clock = clock;
|
||||
tk->tkr_raw.read = clock->read;
|
||||
tk->tkr_raw.mask = clock->mask;
|
||||
tk->tkr_raw.cycle_last = tk->tkr_mono.cycle_last;
|
||||
|
||||
/* Do the ns -> cycle conversion first, using original mult */
|
||||
tmp = NTP_INTERVAL_LENGTH;
|
||||
@@ -163,11 +277,14 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
|
||||
if (old_clock) {
|
||||
int shift_change = clock->shift - old_clock->shift;
|
||||
if (shift_change < 0)
|
||||
tk->tkr.xtime_nsec >>= -shift_change;
|
||||
tk->tkr_mono.xtime_nsec >>= -shift_change;
|
||||
else
|
||||
tk->tkr.xtime_nsec <<= shift_change;
|
||||
tk->tkr_mono.xtime_nsec <<= shift_change;
|
||||
}
|
||||
tk->tkr.shift = clock->shift;
|
||||
tk->tkr_raw.xtime_nsec = 0;
|
||||
|
||||
tk->tkr_mono.shift = clock->shift;
|
||||
tk->tkr_raw.shift = clock->shift;
|
||||
|
||||
tk->ntp_error = 0;
|
||||
tk->ntp_error_shift = NTP_SCALE_SHIFT - clock->shift;
|
||||
@@ -178,7 +295,8 @@ static void tk_setup_internals(struct timekeeper *tk, struct clocksource *clock)
|
||||
* active clocksource. These value will be adjusted via NTP
|
||||
* to counteract clock drifting.
|
||||
*/
|
||||
tk->tkr.mult = clock->mult;
|
||||
tk->tkr_mono.mult = clock->mult;
|
||||
tk->tkr_raw.mult = clock->mult;
|
||||
tk->ntp_err_mult = 0;
|
||||
}
|
||||
|
||||
@@ -193,14 +311,10 @@ static inline u32 arch_gettimeoffset(void) { return 0; }
|
||||
|
||||
static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
|
||||
{
|
||||
cycle_t cycle_now, delta;
|
||||
cycle_t delta;
|
||||
s64 nsec;
|
||||
|
||||
/* read clocksource: */
|
||||
cycle_now = tkr->read(tkr->clock);
|
||||
|
||||
/* calculate the delta since the last update_wall_time: */
|
||||
delta = clocksource_delta(cycle_now, tkr->cycle_last, tkr->mask);
|
||||
delta = timekeeping_get_delta(tkr);
|
||||
|
||||
nsec = delta * tkr->mult + tkr->xtime_nsec;
|
||||
nsec >>= tkr->shift;
|
||||
@@ -209,25 +323,6 @@ static inline s64 timekeeping_get_ns(struct tk_read_base *tkr)
|
||||
return nsec + arch_gettimeoffset();
|
||||
}
|
||||
|
||||
static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
|
||||
{
|
||||
struct clocksource *clock = tk->tkr.clock;
|
||||
cycle_t cycle_now, delta;
|
||||
s64 nsec;
|
||||
|
||||
/* read clocksource: */
|
||||
cycle_now = tk->tkr.read(clock);
|
||||
|
||||
/* calculate the delta since the last update_wall_time: */
|
||||
delta = clocksource_delta(cycle_now, tk->tkr.cycle_last, tk->tkr.mask);
|
||||
|
||||
/* convert delta to nanoseconds. */
|
||||
nsec = clocksource_cyc2ns(delta, clock->mult, clock->shift);
|
||||
|
||||
/* If arch requires, add in get_arch_timeoffset() */
|
||||
return nsec + arch_gettimeoffset();
|
||||
}
|
||||
|
||||
/**
|
||||
* update_fast_timekeeper - Update the fast and NMI safe monotonic timekeeper.
|
||||
* @tkr: Timekeeping readout base from which we take the update
|
||||
@@ -267,18 +362,18 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
|
||||
* slightly wrong timestamp (a few nanoseconds). See
|
||||
* @ktime_get_mono_fast_ns.
|
||||
*/
|
||||
static void update_fast_timekeeper(struct tk_read_base *tkr)
|
||||
static void update_fast_timekeeper(struct tk_read_base *tkr, struct tk_fast *tkf)
|
||||
{
|
||||
struct tk_read_base *base = tk_fast_mono.base;
|
||||
struct tk_read_base *base = tkf->base;
|
||||
|
||||
/* Force readers off to base[1] */
|
||||
raw_write_seqcount_latch(&tk_fast_mono.seq);
|
||||
raw_write_seqcount_latch(&tkf->seq);
|
||||
|
||||
/* Update base[0] */
|
||||
memcpy(base, tkr, sizeof(*base));
|
||||
|
||||
/* Force readers back to base[0] */
|
||||
raw_write_seqcount_latch(&tk_fast_mono.seq);
|
||||
raw_write_seqcount_latch(&tkf->seq);
|
||||
|
||||
/* Update base[1] */
|
||||
memcpy(base + 1, base, sizeof(*base));
|
||||
@@ -316,22 +411,33 @@ static void update_fast_timekeeper(struct tk_read_base *tkr)
|
||||
* of the following timestamps. Callers need to be aware of that and
|
||||
* deal with it.
|
||||
*/
|
||||
u64 notrace ktime_get_mono_fast_ns(void)
|
||||
static __always_inline u64 __ktime_get_fast_ns(struct tk_fast *tkf)
|
||||
{
|
||||
struct tk_read_base *tkr;
|
||||
unsigned int seq;
|
||||
u64 now;
|
||||
|
||||
do {
|
||||
seq = raw_read_seqcount(&tk_fast_mono.seq);
|
||||
tkr = tk_fast_mono.base + (seq & 0x01);
|
||||
now = ktime_to_ns(tkr->base_mono) + timekeeping_get_ns(tkr);
|
||||
seq = raw_read_seqcount(&tkf->seq);
|
||||
tkr = tkf->base + (seq & 0x01);
|
||||
now = ktime_to_ns(tkr->base) + timekeeping_get_ns(tkr);
|
||||
} while (read_seqcount_retry(&tkf->seq, seq));
|
||||
|
||||
} while (read_seqcount_retry(&tk_fast_mono.seq, seq));
|
||||
return now;
|
||||
}
|
||||
|
||||
u64 ktime_get_mono_fast_ns(void)
|
||||
{
|
||||
return __ktime_get_fast_ns(&tk_fast_mono);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_mono_fast_ns);
|
||||
|
||||
u64 ktime_get_raw_fast_ns(void)
|
||||
{
|
||||
return __ktime_get_fast_ns(&tk_fast_raw);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ktime_get_raw_fast_ns);
|
||||
|
||||
/* Suspend-time cycles value for halted fast timekeeper. */
|
||||
static cycle_t cycles_at_suspend;
|
||||
|
||||
@@ -353,12 +459,17 @@ static cycle_t dummy_clock_read(struct clocksource *cs)
|
||||
static void halt_fast_timekeeper(struct timekeeper *tk)
|
||||
{
|
||||
static struct tk_read_base tkr_dummy;
|
||||
struct tk_read_base *tkr = &tk->tkr;
|
||||
struct tk_read_base *tkr = &tk->tkr_mono;
|
||||
|
||||
memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
|
||||
cycles_at_suspend = tkr->read(tkr->clock);
|
||||
tkr_dummy.read = dummy_clock_read;
|
||||
update_fast_timekeeper(&tkr_dummy);
|
||||
update_fast_timekeeper(&tkr_dummy, &tk_fast_mono);
|
||||
|
||||
tkr = &tk->tkr_raw;
|
||||
memcpy(&tkr_dummy, tkr, sizeof(tkr_dummy));
|
||||
tkr_dummy.read = dummy_clock_read;
|
||||
update_fast_timekeeper(&tkr_dummy, &tk_fast_raw);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_GENERIC_TIME_VSYSCALL_OLD
|
||||
@@ -369,8 +480,8 @@ static inline void update_vsyscall(struct timekeeper *tk)
|
||||
|
||||
xt = timespec64_to_timespec(tk_xtime(tk));
|
||||
wm = timespec64_to_timespec(tk->wall_to_monotonic);
|
||||
update_vsyscall_old(&xt, &wm, tk->tkr.clock, tk->tkr.mult,
|
||||
tk->tkr.cycle_last);
|
||||
update_vsyscall_old(&xt, &wm, tk->tkr_mono.clock, tk->tkr_mono.mult,
|
||||
tk->tkr_mono.cycle_last);
|
||||
}
|
||||
|
||||
static inline void old_vsyscall_fixup(struct timekeeper *tk)
|
||||
@@ -387,11 +498,11 @@ static inline void old_vsyscall_fixup(struct timekeeper *tk)
|
||||
* (shifted nanoseconds), and CONFIG_GENERIC_TIME_VSYSCALL_OLD
|
||||
* users are removed, this can be killed.
|
||||
*/
|
||||
remainder = tk->tkr.xtime_nsec & ((1ULL << tk->tkr.shift) - 1);
|
||||
tk->tkr.xtime_nsec -= remainder;
|
||||
tk->tkr.xtime_nsec += 1ULL << tk->tkr.shift;
|
||||
remainder = tk->tkr_mono.xtime_nsec & ((1ULL << tk->tkr_mono.shift) - 1);
|
||||
tk->tkr_mono.xtime_nsec -= remainder;
|
||||
tk->tkr_mono.xtime_nsec += 1ULL << tk->tkr_mono.shift;
|
||||
tk->ntp_error += remainder << tk->ntp_error_shift;
|
||||
tk->ntp_error -= (1ULL << tk->tkr.shift) << tk->ntp_error_shift;
|
||||
tk->ntp_error -= (1ULL << tk->tkr_mono.shift) << tk->ntp_error_shift;
|
||||
}
|
||||
#else
|
||||
#define old_vsyscall_fixup(tk)
|
||||
@@ -456,17 +567,17 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
|
||||
*/
|
||||
seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
|
||||
nsec = (u32) tk->wall_to_monotonic.tv_nsec;
|
||||
tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
|
||||
tk->tkr_mono.base = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
|
||||
|
||||
/* Update the monotonic raw base */
|
||||
tk->base_raw = timespec64_to_ktime(tk->raw_time);
|
||||
tk->tkr_raw.base = timespec64_to_ktime(tk->raw_time);
|
||||
|
||||
/*
|
||||
* The sum of the nanoseconds portions of xtime and
|
||||
* wall_to_monotonic can be greater/equal one second. Take
|
||||
* this into account before updating tk->ktime_sec.
|
||||
*/
|
||||
nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
|
||||
nsec += (u32)(tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift);
|
||||
if (nsec >= NSEC_PER_SEC)
|
||||
seconds++;
|
||||
tk->ktime_sec = seconds;
|
||||
@@ -489,7 +600,8 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
|
||||
memcpy(&shadow_timekeeper, &tk_core.timekeeper,
|
||||
sizeof(tk_core.timekeeper));
|
||||
|
||||
update_fast_timekeeper(&tk->tkr);
|
||||
update_fast_timekeeper(&tk->tkr_mono, &tk_fast_mono);
|
||||
update_fast_timekeeper(&tk->tkr_raw, &tk_fast_raw);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -501,22 +613,23 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
|
||||
*/
|
||||
static void timekeeping_forward_now(struct timekeeper *tk)
|
||||
{
|
||||
struct clocksource *clock = tk->tkr.clock;
|
||||
struct clocksource *clock = tk->tkr_mono.clock;
|
||||
cycle_t cycle_now, delta;
|
||||
s64 nsec;
|
||||
|
||||
cycle_now = tk->tkr.read(clock);
|
||||
delta = clocksource_delta(cycle_now, tk->tkr.cycle_last, tk->tkr.mask);
|
||||
tk->tkr.cycle_last = cycle_now;
|
||||
cycle_now = tk->tkr_mono.read(clock);
|
||||
delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
|
||||
tk->tkr_mono.cycle_last = cycle_now;
|
||||
tk->tkr_raw.cycle_last = cycle_now;
|
||||
|
||||
tk->tkr.xtime_nsec += delta * tk->tkr.mult;
|
||||
tk->tkr_mono.xtime_nsec += delta * tk->tkr_mono.mult;
|
||||
|
||||
/* If arch requires, add in get_arch_timeoffset() */
|
||||
tk->tkr.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr.shift;
|
||||
tk->tkr_mono.xtime_nsec += (u64)arch_gettimeoffset() << tk->tkr_mono.shift;
|
||||
|
||||
tk_normalize_xtime(tk);
|
||||
|
||||
nsec = clocksource_cyc2ns(delta, clock->mult, clock->shift);
|
||||
nsec = clocksource_cyc2ns(delta, tk->tkr_raw.mult, tk->tkr_raw.shift);
|
||||
timespec64_add_ns(&tk->raw_time, nsec);
|
||||
}
|
||||
|
||||
@@ -537,7 +650,7 @@ int __getnstimeofday64(struct timespec64 *ts)
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
|
||||
ts->tv_sec = tk->xtime_sec;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr);
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_mono);
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -577,8 +690,8 @@ ktime_t ktime_get(void)
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
base = tk->tkr.base_mono;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr);
|
||||
base = tk->tkr_mono.base;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_mono);
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -603,8 +716,8 @@ ktime_t ktime_get_with_offset(enum tk_offsets offs)
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
base = ktime_add(tk->tkr.base_mono, *offset);
|
||||
nsecs = timekeeping_get_ns(&tk->tkr);
|
||||
base = ktime_add(tk->tkr_mono.base, *offset);
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_mono);
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -645,8 +758,8 @@ ktime_t ktime_get_raw(void)
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
base = tk->base_raw;
|
||||
nsecs = timekeeping_get_ns_raw(tk);
|
||||
base = tk->tkr_raw.base;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_raw);
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -674,7 +787,7 @@ void ktime_get_ts64(struct timespec64 *ts)
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
ts->tv_sec = tk->xtime_sec;
|
||||
nsec = timekeeping_get_ns(&tk->tkr);
|
||||
nsec = timekeeping_get_ns(&tk->tkr_mono);
|
||||
tomono = tk->wall_to_monotonic;
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
@@ -759,8 +872,8 @@ void getnstime_raw_and_real(struct timespec *ts_raw, struct timespec *ts_real)
|
||||
ts_real->tv_sec = tk->xtime_sec;
|
||||
ts_real->tv_nsec = 0;
|
||||
|
||||
nsecs_raw = timekeeping_get_ns_raw(tk);
|
||||
nsecs_real = timekeeping_get_ns(&tk->tkr);
|
||||
nsecs_raw = timekeeping_get_ns(&tk->tkr_raw);
|
||||
nsecs_real = timekeeping_get_ns(&tk->tkr_mono);
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -943,7 +1056,7 @@ static int change_clocksource(void *data)
|
||||
*/
|
||||
if (try_module_get(new->owner)) {
|
||||
if (!new->enable || new->enable(new) == 0) {
|
||||
old = tk->tkr.clock;
|
||||
old = tk->tkr_mono.clock;
|
||||
tk_setup_internals(tk, new);
|
||||
if (old->disable)
|
||||
old->disable(old);
|
||||
@@ -971,11 +1084,11 @@ int timekeeping_notify(struct clocksource *clock)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
|
||||
if (tk->tkr.clock == clock)
|
||||
if (tk->tkr_mono.clock == clock)
|
||||
return 0;
|
||||
stop_machine(change_clocksource, clock, NULL);
|
||||
tick_clock_notify();
|
||||
return tk->tkr.clock == clock ? 0 : -1;
|
||||
return tk->tkr_mono.clock == clock ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -993,7 +1106,7 @@ void getrawmonotonic64(struct timespec64 *ts)
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
nsecs = timekeeping_get_ns_raw(tk);
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_raw);
|
||||
ts64 = tk->raw_time;
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
@@ -1016,7 +1129,7 @@ int timekeeping_valid_for_hres(void)
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
|
||||
ret = tk->tkr.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
|
||||
ret = tk->tkr_mono.clock->flags & CLOCK_SOURCE_VALID_FOR_HRES;
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -1035,7 +1148,7 @@ u64 timekeeping_max_deferment(void)
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
|
||||
ret = tk->tkr.clock->max_idle_ns;
|
||||
ret = tk->tkr_mono.clock->max_idle_ns;
|
||||
|
||||
} while (read_seqcount_retry(&tk_core.seq, seq));
|
||||
|
||||
@@ -1057,6 +1170,14 @@ void __weak read_persistent_clock(struct timespec *ts)
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
void __weak read_persistent_clock64(struct timespec64 *ts64)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
read_persistent_clock(&ts);
|
||||
*ts64 = timespec_to_timespec64(ts);
|
||||
}
|
||||
|
||||
/**
|
||||
* read_boot_clock - Return time of the system start.
|
||||
*
|
||||
@@ -1072,6 +1193,20 @@ void __weak read_boot_clock(struct timespec *ts)
|
||||
ts->tv_nsec = 0;
|
||||
}
|
||||
|
||||
void __weak read_boot_clock64(struct timespec64 *ts64)
|
||||
{
|
||||
struct timespec ts;
|
||||
|
||||
read_boot_clock(&ts);
|
||||
*ts64 = timespec_to_timespec64(ts);
|
||||
}
|
||||
|
||||
/* Flag for if timekeeping_resume() has injected sleeptime */
|
||||
static bool sleeptime_injected;
|
||||
|
||||
/* Flag for if there is a persistent clock on this platform */
|
||||
static bool persistent_clock_exists;
|
||||
|
||||
/*
|
||||
* timekeeping_init - Initializes the clocksource and common timekeeping values
|
||||
*/
|
||||
@@ -1081,20 +1216,17 @@ void __init timekeeping_init(void)
|
||||
struct clocksource *clock;
|
||||
unsigned long flags;
|
||||
struct timespec64 now, boot, tmp;
|
||||
struct timespec ts;
|
||||
|
||||
read_persistent_clock(&ts);
|
||||
now = timespec_to_timespec64(ts);
|
||||
read_persistent_clock64(&now);
|
||||
if (!timespec64_valid_strict(&now)) {
|
||||
pr_warn("WARNING: Persistent clock returned invalid value!\n"
|
||||
" Check your CMOS/BIOS settings.\n");
|
||||
now.tv_sec = 0;
|
||||
now.tv_nsec = 0;
|
||||
} else if (now.tv_sec || now.tv_nsec)
|
||||
persistent_clock_exist = true;
|
||||
persistent_clock_exists = true;
|
||||
|
||||
read_boot_clock(&ts);
|
||||
boot = timespec_to_timespec64(ts);
|
||||
read_boot_clock64(&boot);
|
||||
if (!timespec64_valid_strict(&boot)) {
|
||||
pr_warn("WARNING: Boot clock returned invalid value!\n"
|
||||
" Check your CMOS/BIOS settings.\n");
|
||||
@@ -1114,7 +1246,6 @@ void __init timekeeping_init(void)
|
||||
tk_set_xtime(tk, &now);
|
||||
tk->raw_time.tv_sec = 0;
|
||||
tk->raw_time.tv_nsec = 0;
|
||||
tk->base_raw.tv64 = 0;
|
||||
if (boot.tv_sec == 0 && boot.tv_nsec == 0)
|
||||
boot = tk_xtime(tk);
|
||||
|
||||
@@ -1127,7 +1258,7 @@ void __init timekeeping_init(void)
|
||||
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
|
||||
}
|
||||
|
||||
/* time in seconds when suspend began */
|
||||
/* time in seconds when suspend began for persistent clock */
|
||||
static struct timespec64 timekeeping_suspend_time;
|
||||
|
||||
/**
|
||||
@@ -1152,12 +1283,49 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
|
||||
tk_debug_account_sleep_time(delta);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
|
||||
/**
|
||||
* We have three kinds of time sources to use for sleep time
|
||||
* injection, the preference order is:
|
||||
* 1) non-stop clocksource
|
||||
* 2) persistent clock (ie: RTC accessible when irqs are off)
|
||||
* 3) RTC
|
||||
*
|
||||
* 1) and 2) are used by timekeeping, 3) by RTC subsystem.
|
||||
* If system has neither 1) nor 2), 3) will be used finally.
|
||||
*
|
||||
*
|
||||
* If timekeeping has injected sleeptime via either 1) or 2),
|
||||
* 3) becomes needless, so in this case we don't need to call
|
||||
* rtc_resume(), and this is what timekeeping_rtc_skipresume()
|
||||
* means.
|
||||
*/
|
||||
bool timekeeping_rtc_skipresume(void)
|
||||
{
|
||||
return sleeptime_injected;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1) can be determined whether to use or not only when doing
|
||||
* timekeeping_resume() which is invoked after rtc_suspend(),
|
||||
* so we can't skip rtc_suspend() surely if system has 1).
|
||||
*
|
||||
* But if system has 2), 2) will definitely be used, so in this
|
||||
* case we don't need to call rtc_suspend(), and this is what
|
||||
* timekeeping_rtc_skipsuspend() means.
|
||||
*/
|
||||
bool timekeeping_rtc_skipsuspend(void)
|
||||
{
|
||||
return persistent_clock_exists;
|
||||
}
|
||||
|
||||
/**
|
||||
* timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values
|
||||
* @delta: pointer to a timespec64 delta value
|
||||
*
|
||||
* This hook is for architectures that cannot support read_persistent_clock
|
||||
* This hook is for architectures that cannot support read_persistent_clock64
|
||||
* because their RTC/persistent clock is only accessible when irqs are enabled.
|
||||
* and also don't have an effective nonstop clocksource.
|
||||
*
|
||||
* This function should only be called by rtc_resume(), and allows
|
||||
* a suspend offset to be injected into the timekeeping values.
|
||||
@@ -1167,13 +1335,6 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
unsigned long flags;
|
||||
|
||||
/*
|
||||
* Make sure we don't set the clock twice, as timekeeping_resume()
|
||||
* already did it
|
||||
*/
|
||||
if (has_persistent_clock())
|
||||
return;
|
||||
|
||||
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
||||
write_seqcount_begin(&tk_core.seq);
|
||||
|
||||
@@ -1189,26 +1350,21 @@ void timekeeping_inject_sleeptime64(struct timespec64 *delta)
|
||||
/* signal hrtimers about time change */
|
||||
clock_was_set();
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* timekeeping_resume - Resumes the generic timekeeping subsystem.
|
||||
*
|
||||
* This is for the generic clocksource timekeeping.
|
||||
* xtime/wall_to_monotonic/jiffies/etc are
|
||||
* still managed by arch specific suspend/resume code.
|
||||
*/
|
||||
void timekeeping_resume(void)
|
||||
{
|
||||
struct timekeeper *tk = &tk_core.timekeeper;
|
||||
struct clocksource *clock = tk->tkr.clock;
|
||||
struct clocksource *clock = tk->tkr_mono.clock;
|
||||
unsigned long flags;
|
||||
struct timespec64 ts_new, ts_delta;
|
||||
struct timespec tmp;
|
||||
cycle_t cycle_now, cycle_delta;
|
||||
bool suspendtime_found = false;
|
||||
|
||||
read_persistent_clock(&tmp);
|
||||
ts_new = timespec_to_timespec64(tmp);
|
||||
sleeptime_injected = false;
|
||||
read_persistent_clock64(&ts_new);
|
||||
|
||||
clockevents_resume();
|
||||
clocksource_resume();
|
||||
@@ -1228,16 +1384,16 @@ void timekeeping_resume(void)
|
||||
* The less preferred source will only be tried if there is no better
|
||||
* usable source. The rtc part is handled separately in rtc core code.
|
||||
*/
|
||||
cycle_now = tk->tkr.read(clock);
|
||||
cycle_now = tk->tkr_mono.read(clock);
|
||||
if ((clock->flags & CLOCK_SOURCE_SUSPEND_NONSTOP) &&
|
||||
cycle_now > tk->tkr.cycle_last) {
|
||||
cycle_now > tk->tkr_mono.cycle_last) {
|
||||
u64 num, max = ULLONG_MAX;
|
||||
u32 mult = clock->mult;
|
||||
u32 shift = clock->shift;
|
||||
s64 nsec = 0;
|
||||
|
||||
cycle_delta = clocksource_delta(cycle_now, tk->tkr.cycle_last,
|
||||
tk->tkr.mask);
|
||||
cycle_delta = clocksource_delta(cycle_now, tk->tkr_mono.cycle_last,
|
||||
tk->tkr_mono.mask);
|
||||
|
||||
/*
|
||||
* "cycle_delta * mutl" may cause 64 bits overflow, if the
|
||||
@@ -1253,17 +1409,19 @@ void timekeeping_resume(void)
|
||||
nsec += ((u64) cycle_delta * mult) >> shift;
|
||||
|
||||
ts_delta = ns_to_timespec64(nsec);
|
||||
suspendtime_found = true;
|
||||
sleeptime_injected = true;
|
||||
} else if (timespec64_compare(&ts_new, &timekeeping_suspend_time) > 0) {
|
||||
ts_delta = timespec64_sub(ts_new, timekeeping_suspend_time);
|
||||
suspendtime_found = true;
|
||||
sleeptime_injected = true;
|
||||
}
|
||||
|
||||
if (suspendtime_found)
|
||||
if (sleeptime_injected)
|
||||
__timekeeping_inject_sleeptime(tk, &ts_delta);
|
||||
|
||||
/* Re-base the last cycle value */
|
||||
tk->tkr.cycle_last = cycle_now;
|
||||
tk->tkr_mono.cycle_last = cycle_now;
|
||||
tk->tkr_raw.cycle_last = cycle_now;
|
||||
|
||||
tk->ntp_error = 0;
|
||||
timekeeping_suspended = 0;
|
||||
timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET);
|
||||
@@ -1272,9 +1430,7 @@ void timekeeping_resume(void)
|
||||
|
||||
touch_softlockup_watchdog();
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
|
||||
|
||||
/* Resume hrtimers */
|
||||
tick_resume();
|
||||
hrtimers_resume();
|
||||
}
|
||||
|
||||
@@ -1284,10 +1440,8 @@ int timekeeping_suspend(void)
|
||||
unsigned long flags;
|
||||
struct timespec64 delta, delta_delta;
|
||||
static struct timespec64 old_delta;
|
||||
struct timespec tmp;
|
||||
|
||||
read_persistent_clock(&tmp);
|
||||
timekeeping_suspend_time = timespec_to_timespec64(tmp);
|
||||
read_persistent_clock64(&timekeeping_suspend_time);
|
||||
|
||||
/*
|
||||
* On some systems the persistent_clock can not be detected at
|
||||
@@ -1295,31 +1449,33 @@ int timekeeping_suspend(void)
|
||||
* value returned, update the persistent_clock_exists flag.
|
||||
*/
|
||||
if (timekeeping_suspend_time.tv_sec || timekeeping_suspend_time.tv_nsec)
|
||||
persistent_clock_exist = true;
|
||||
persistent_clock_exists = true;
|
||||
|
||||
raw_spin_lock_irqsave(&timekeeper_lock, flags);
|
||||
write_seqcount_begin(&tk_core.seq);
|
||||
timekeeping_forward_now(tk);
|
||||
timekeeping_suspended = 1;
|
||||
|
||||
/*
|
||||
* To avoid drift caused by repeated suspend/resumes,
|
||||
* which each can add ~1 second drift error,
|
||||
* try to compensate so the difference in system time
|
||||
* and persistent_clock time stays close to constant.
|
||||
*/
|
||||
delta = timespec64_sub(tk_xtime(tk), timekeeping_suspend_time);
|
||||
delta_delta = timespec64_sub(delta, old_delta);
|
||||
if (abs(delta_delta.tv_sec) >= 2) {
|
||||
if (persistent_clock_exists) {
|
||||
/*
|
||||
* if delta_delta is too large, assume time correction
|
||||
* has occured and set old_delta to the current delta.
|
||||
* To avoid drift caused by repeated suspend/resumes,
|
||||
* which each can add ~1 second drift error,
|
||||
* try to compensate so the difference in system time
|
||||
* and persistent_clock time stays close to constant.
|
||||
*/
|
||||
old_delta = delta;
|
||||
} else {
|
||||
/* Otherwise try to adjust old_system to compensate */
|
||||
timekeeping_suspend_time =
|
||||
timespec64_add(timekeeping_suspend_time, delta_delta);
|
||||
delta = timespec64_sub(tk_xtime(tk), timekeeping_suspend_time);
|
||||
delta_delta = timespec64_sub(delta, old_delta);
|
||||
if (abs(delta_delta.tv_sec) >= 2) {
|
||||
/*
|
||||
* if delta_delta is too large, assume time correction
|
||||
* has occurred and set old_delta to the current delta.
|
||||
*/
|
||||
old_delta = delta;
|
||||
} else {
|
||||
/* Otherwise try to adjust old_system to compensate */
|
||||
timekeeping_suspend_time =
|
||||
timespec64_add(timekeeping_suspend_time, delta_delta);
|
||||
}
|
||||
}
|
||||
|
||||
timekeeping_update(tk, TK_MIRROR);
|
||||
@@ -1327,7 +1483,7 @@ int timekeeping_suspend(void)
|
||||
write_seqcount_end(&tk_core.seq);
|
||||
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
|
||||
|
||||
clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
|
||||
tick_suspend();
|
||||
clocksource_suspend();
|
||||
clockevents_suspend();
|
||||
|
||||
@@ -1416,15 +1572,15 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
|
||||
*
|
||||
* XXX - TODO: Doc ntp_error calculation.
|
||||
*/
|
||||
if ((mult_adj > 0) && (tk->tkr.mult + mult_adj < mult_adj)) {
|
||||
if ((mult_adj > 0) && (tk->tkr_mono.mult + mult_adj < mult_adj)) {
|
||||
/* NTP adjustment caused clocksource mult overflow */
|
||||
WARN_ON_ONCE(1);
|
||||
return;
|
||||
}
|
||||
|
||||
tk->tkr.mult += mult_adj;
|
||||
tk->tkr_mono.mult += mult_adj;
|
||||
tk->xtime_interval += interval;
|
||||
tk->tkr.xtime_nsec -= offset;
|
||||
tk->tkr_mono.xtime_nsec -= offset;
|
||||
tk->ntp_error -= (interval - offset) << tk->ntp_error_shift;
|
||||
}
|
||||
|
||||
@@ -1486,13 +1642,13 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
|
||||
tk->ntp_err_mult = 0;
|
||||
}
|
||||
|
||||
if (unlikely(tk->tkr.clock->maxadj &&
|
||||
(abs(tk->tkr.mult - tk->tkr.clock->mult)
|
||||
> tk->tkr.clock->maxadj))) {
|
||||
if (unlikely(tk->tkr_mono.clock->maxadj &&
|
||||
(abs(tk->tkr_mono.mult - tk->tkr_mono.clock->mult)
|
||||
> tk->tkr_mono.clock->maxadj))) {
|
||||
printk_once(KERN_WARNING
|
||||
"Adjusting %s more than 11%% (%ld vs %ld)\n",
|
||||
tk->tkr.clock->name, (long)tk->tkr.mult,
|
||||
(long)tk->tkr.clock->mult + tk->tkr.clock->maxadj);
|
||||
tk->tkr_mono.clock->name, (long)tk->tkr_mono.mult,
|
||||
(long)tk->tkr_mono.clock->mult + tk->tkr_mono.clock->maxadj);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1509,9 +1665,9 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
|
||||
* We'll correct this error next time through this function, when
|
||||
* xtime_nsec is not as small.
|
||||
*/
|
||||
if (unlikely((s64)tk->tkr.xtime_nsec < 0)) {
|
||||
s64 neg = -(s64)tk->tkr.xtime_nsec;
|
||||
tk->tkr.xtime_nsec = 0;
|
||||
if (unlikely((s64)tk->tkr_mono.xtime_nsec < 0)) {
|
||||
s64 neg = -(s64)tk->tkr_mono.xtime_nsec;
|
||||
tk->tkr_mono.xtime_nsec = 0;
|
||||
tk->ntp_error += neg << tk->ntp_error_shift;
|
||||
}
|
||||
}
|
||||
@@ -1526,13 +1682,13 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
|
||||
*/
|
||||
static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
|
||||
{
|
||||
u64 nsecps = (u64)NSEC_PER_SEC << tk->tkr.shift;
|
||||
u64 nsecps = (u64)NSEC_PER_SEC << tk->tkr_mono.shift;
|
||||
unsigned int clock_set = 0;
|
||||
|
||||
while (tk->tkr.xtime_nsec >= nsecps) {
|
||||
while (tk->tkr_mono.xtime_nsec >= nsecps) {
|
||||
int leap;
|
||||
|
||||
tk->tkr.xtime_nsec -= nsecps;
|
||||
tk->tkr_mono.xtime_nsec -= nsecps;
|
||||
tk->xtime_sec++;
|
||||
|
||||
/* Figure out if its a leap sec and apply if needed */
|
||||
@@ -1577,9 +1733,10 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
|
||||
|
||||
/* Accumulate one shifted interval */
|
||||
offset -= interval;
|
||||
tk->tkr.cycle_last += interval;
|
||||
tk->tkr_mono.cycle_last += interval;
|
||||
tk->tkr_raw.cycle_last += interval;
|
||||
|
||||
tk->tkr.xtime_nsec += tk->xtime_interval << shift;
|
||||
tk->tkr_mono.xtime_nsec += tk->xtime_interval << shift;
|
||||
*clock_set |= accumulate_nsecs_to_secs(tk);
|
||||
|
||||
/* Accumulate raw time */
|
||||
@@ -1622,14 +1779,17 @@ void update_wall_time(void)
|
||||
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
|
||||
offset = real_tk->cycle_interval;
|
||||
#else
|
||||
offset = clocksource_delta(tk->tkr.read(tk->tkr.clock),
|
||||
tk->tkr.cycle_last, tk->tkr.mask);
|
||||
offset = clocksource_delta(tk->tkr_mono.read(tk->tkr_mono.clock),
|
||||
tk->tkr_mono.cycle_last, tk->tkr_mono.mask);
|
||||
#endif
|
||||
|
||||
/* Check if there's really nothing to do */
|
||||
if (offset < real_tk->cycle_interval)
|
||||
goto out;
|
||||
|
||||
/* Do some additional sanity checking */
|
||||
timekeeping_check_update(real_tk, offset);
|
||||
|
||||
/*
|
||||
* With NO_HZ we may have to accumulate many cycle_intervals
|
||||
* (think "ticks") worth of time at once. To do this efficiently,
|
||||
@@ -1784,8 +1944,8 @@ ktime_t ktime_get_update_offsets_tick(ktime_t *offs_real, ktime_t *offs_boot,
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
|
||||
base = tk->tkr.base_mono;
|
||||
nsecs = tk->tkr.xtime_nsec >> tk->tkr.shift;
|
||||
base = tk->tkr_mono.base;
|
||||
nsecs = tk->tkr_mono.xtime_nsec >> tk->tkr_mono.shift;
|
||||
|
||||
*offs_real = tk->offs_real;
|
||||
*offs_boot = tk->offs_boot;
|
||||
@@ -1816,8 +1976,8 @@ ktime_t ktime_get_update_offsets_now(ktime_t *offs_real, ktime_t *offs_boot,
|
||||
do {
|
||||
seq = read_seqcount_begin(&tk_core.seq);
|
||||
|
||||
base = tk->tkr.base_mono;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr);
|
||||
base = tk->tkr_mono.base;
|
||||
nsecs = timekeeping_get_ns(&tk->tkr_mono);
|
||||
|
||||
*offs_real = tk->offs_real;
|
||||
*offs_boot = tk->offs_boot;
|
||||
|
||||
@@ -19,4 +19,11 @@ extern void timekeeping_clocktai(struct timespec *ts);
|
||||
extern int timekeeping_suspend(void);
|
||||
extern void timekeeping_resume(void);
|
||||
|
||||
extern void do_timer(unsigned long ticks);
|
||||
extern void update_wall_time(void);
|
||||
|
||||
extern seqlock_t jiffies_lock;
|
||||
|
||||
#define CS_NAME_LEN 32
|
||||
|
||||
#endif
|
||||
|
||||
+67
-82
@@ -90,8 +90,18 @@ struct tvec_base {
|
||||
struct tvec tv5;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
/*
|
||||
* __TIMER_INITIALIZER() needs to set ->base to a valid pointer (because we've
|
||||
* made NULL special, hint: lock_timer_base()) and we cannot get a compile time
|
||||
* pointer to per-cpu entries because we don't know where we'll map the section,
|
||||
* even for the boot cpu.
|
||||
*
|
||||
* And so we use boot_tvec_bases for boot CPU and per-cpu __tvec_bases for the
|
||||
* rest of them.
|
||||
*/
|
||||
struct tvec_base boot_tvec_bases;
|
||||
EXPORT_SYMBOL(boot_tvec_bases);
|
||||
|
||||
static DEFINE_PER_CPU(struct tvec_base *, tvec_bases) = &boot_tvec_bases;
|
||||
|
||||
/* Functions below help us manage 'deferrable' flag */
|
||||
@@ -1027,6 +1037,8 @@ int try_to_del_timer_sync(struct timer_list *timer)
|
||||
EXPORT_SYMBOL(try_to_del_timer_sync);
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
static DEFINE_PER_CPU(struct tvec_base, __tvec_bases);
|
||||
|
||||
/**
|
||||
* del_timer_sync - deactivate a timer and wait for the handler to finish.
|
||||
* @timer: the timer to be deactivated
|
||||
@@ -1532,64 +1544,6 @@ signed long __sched schedule_timeout_uninterruptible(signed long timeout)
|
||||
}
|
||||
EXPORT_SYMBOL(schedule_timeout_uninterruptible);
|
||||
|
||||
static int init_timers_cpu(int cpu)
|
||||
{
|
||||
int j;
|
||||
struct tvec_base *base;
|
||||
static char tvec_base_done[NR_CPUS];
|
||||
|
||||
if (!tvec_base_done[cpu]) {
|
||||
static char boot_done;
|
||||
|
||||
if (boot_done) {
|
||||
/*
|
||||
* The APs use this path later in boot
|
||||
*/
|
||||
base = kzalloc_node(sizeof(*base), GFP_KERNEL,
|
||||
cpu_to_node(cpu));
|
||||
if (!base)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Make sure tvec_base has TIMER_FLAG_MASK bits free */
|
||||
if (WARN_ON(base != tbase_get_base(base))) {
|
||||
kfree(base);
|
||||
return -ENOMEM;
|
||||
}
|
||||
per_cpu(tvec_bases, cpu) = base;
|
||||
} else {
|
||||
/*
|
||||
* This is for the boot CPU - we use compile-time
|
||||
* static initialisation because per-cpu memory isn't
|
||||
* ready yet and because the memory allocators are not
|
||||
* initialised either.
|
||||
*/
|
||||
boot_done = 1;
|
||||
base = &boot_tvec_bases;
|
||||
}
|
||||
spin_lock_init(&base->lock);
|
||||
tvec_base_done[cpu] = 1;
|
||||
base->cpu = cpu;
|
||||
} else {
|
||||
base = per_cpu(tvec_bases, cpu);
|
||||
}
|
||||
|
||||
|
||||
for (j = 0; j < TVN_SIZE; j++) {
|
||||
INIT_LIST_HEAD(base->tv5.vec + j);
|
||||
INIT_LIST_HEAD(base->tv4.vec + j);
|
||||
INIT_LIST_HEAD(base->tv3.vec + j);
|
||||
INIT_LIST_HEAD(base->tv2.vec + j);
|
||||
}
|
||||
for (j = 0; j < TVR_SIZE; j++)
|
||||
INIT_LIST_HEAD(base->tv1.vec + j);
|
||||
|
||||
base->timer_jiffies = jiffies;
|
||||
base->next_timer = base->timer_jiffies;
|
||||
base->active_timers = 0;
|
||||
base->all_timers = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
static void migrate_timer_list(struct tvec_base *new_base, struct list_head *head)
|
||||
{
|
||||
@@ -1631,55 +1585,86 @@ static void migrate_timers(int cpu)
|
||||
migrate_timer_list(new_base, old_base->tv5.vec + i);
|
||||
}
|
||||
|
||||
old_base->active_timers = 0;
|
||||
old_base->all_timers = 0;
|
||||
|
||||
spin_unlock(&old_base->lock);
|
||||
spin_unlock_irq(&new_base->lock);
|
||||
put_cpu_var(tvec_bases);
|
||||
}
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static int timer_cpu_notify(struct notifier_block *self,
|
||||
unsigned long action, void *hcpu)
|
||||
{
|
||||
long cpu = (long)hcpu;
|
||||
int err;
|
||||
|
||||
switch(action) {
|
||||
case CPU_UP_PREPARE:
|
||||
case CPU_UP_PREPARE_FROZEN:
|
||||
err = init_timers_cpu(cpu);
|
||||
if (err < 0)
|
||||
return notifier_from_errno(err);
|
||||
break;
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
switch (action) {
|
||||
case CPU_DEAD:
|
||||
case CPU_DEAD_FROZEN:
|
||||
migrate_timers(cpu);
|
||||
migrate_timers((long)hcpu);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
}
|
||||
|
||||
static struct notifier_block timers_nb = {
|
||||
.notifier_call = timer_cpu_notify,
|
||||
};
|
||||
static inline void timer_register_cpu_notifier(void)
|
||||
{
|
||||
cpu_notifier(timer_cpu_notify, 0);
|
||||
}
|
||||
#else
|
||||
static inline void timer_register_cpu_notifier(void) { }
|
||||
#endif /* CONFIG_HOTPLUG_CPU */
|
||||
|
||||
static void __init init_timer_cpu(struct tvec_base *base, int cpu)
|
||||
{
|
||||
int j;
|
||||
|
||||
BUG_ON(base != tbase_get_base(base));
|
||||
|
||||
base->cpu = cpu;
|
||||
per_cpu(tvec_bases, cpu) = base;
|
||||
spin_lock_init(&base->lock);
|
||||
|
||||
for (j = 0; j < TVN_SIZE; j++) {
|
||||
INIT_LIST_HEAD(base->tv5.vec + j);
|
||||
INIT_LIST_HEAD(base->tv4.vec + j);
|
||||
INIT_LIST_HEAD(base->tv3.vec + j);
|
||||
INIT_LIST_HEAD(base->tv2.vec + j);
|
||||
}
|
||||
for (j = 0; j < TVR_SIZE; j++)
|
||||
INIT_LIST_HEAD(base->tv1.vec + j);
|
||||
|
||||
base->timer_jiffies = jiffies;
|
||||
base->next_timer = base->timer_jiffies;
|
||||
}
|
||||
|
||||
static void __init init_timer_cpus(void)
|
||||
{
|
||||
struct tvec_base *base;
|
||||
int local_cpu = smp_processor_id();
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
if (cpu == local_cpu)
|
||||
base = &boot_tvec_bases;
|
||||
#ifdef CONFIG_SMP
|
||||
else
|
||||
base = per_cpu_ptr(&__tvec_bases, cpu);
|
||||
#endif
|
||||
|
||||
init_timer_cpu(base, cpu);
|
||||
}
|
||||
}
|
||||
|
||||
void __init init_timers(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* ensure there are enough low bits for flags in timer->base pointer */
|
||||
BUILD_BUG_ON(__alignof__(struct tvec_base) & TIMER_FLAG_MASK);
|
||||
|
||||
err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
|
||||
(void *)(long)smp_processor_id());
|
||||
BUG_ON(err != NOTIFY_OK);
|
||||
|
||||
init_timer_cpus();
|
||||
init_timer_stats();
|
||||
register_cpu_notifier(&timers_nb);
|
||||
timer_register_cpu_notifier();
|
||||
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/kallsyms.h>
|
||||
#include <linux/tick.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include "tick-internal.h"
|
||||
|
||||
struct timer_list_iter {
|
||||
int cpu;
|
||||
@@ -228,9 +228,35 @@ print_tickdevice(struct seq_file *m, struct tick_device *td, int cpu)
|
||||
print_name_offset(m, dev->set_next_event);
|
||||
SEQ_printf(m, "\n");
|
||||
|
||||
SEQ_printf(m, " set_mode: ");
|
||||
print_name_offset(m, dev->set_mode);
|
||||
SEQ_printf(m, "\n");
|
||||
if (dev->set_mode) {
|
||||
SEQ_printf(m, " set_mode: ");
|
||||
print_name_offset(m, dev->set_mode);
|
||||
SEQ_printf(m, "\n");
|
||||
} else {
|
||||
if (dev->set_state_shutdown) {
|
||||
SEQ_printf(m, " shutdown: ");
|
||||
print_name_offset(m, dev->set_state_shutdown);
|
||||
SEQ_printf(m, "\n");
|
||||
}
|
||||
|
||||
if (dev->set_state_periodic) {
|
||||
SEQ_printf(m, " periodic: ");
|
||||
print_name_offset(m, dev->set_state_periodic);
|
||||
SEQ_printf(m, "\n");
|
||||
}
|
||||
|
||||
if (dev->set_state_oneshot) {
|
||||
SEQ_printf(m, " oneshot: ");
|
||||
print_name_offset(m, dev->set_state_oneshot);
|
||||
SEQ_printf(m, "\n");
|
||||
}
|
||||
|
||||
if (dev->tick_resume) {
|
||||
SEQ_printf(m, " resume: ");
|
||||
print_name_offset(m, dev->tick_resume);
|
||||
SEQ_printf(m, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
SEQ_printf(m, " event_handler: ");
|
||||
print_name_offset(m, dev->event_handler);
|
||||
|
||||
Reference in New Issue
Block a user