a0e928ed7c
Pull timer updates from Ingo Molnar: "This cycle had the following changes: - Timer tracing improvements (Anna-Maria Gleixner) - Continued tasklet reduction work: remove the hrtimer_tasklet (Thomas Gleixner) - Fix CPU hotplug remove race in the tick-broadcast mask handling code (Thomas Gleixner) - Force upper bound for setting CLOCK_REALTIME, to fix ABI inconsistencies with handling values that are close to the maximum supported and the vagueness of when uptime related wraparound might occur. Make the consistent maximum the year 2232 across all relevant ABIs and APIs. (Thomas Gleixner) - various cleanups and smaller fixes" * 'timers-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: tick: Fix typos in comments tick/broadcast: Fix warning about undefined tick_broadcast_oneshot_offline() timekeeping: Force upper bound for setting CLOCK_REALTIME timer/trace: Improve timer tracing timer/trace: Replace deprecated vsprintf pointer extension %pf by %ps timer: Move trace point to get proper index tick/sched: Update tick_sched struct documentation tick: Remove outgoing CPU from broadcast masks timekeeping: Consistently use unsigned int for seqcount snapshot softirq: Remove tasklet_hrtimer xfrm: Replace hrtimer tasklet with softirq hrtimer mac80211_hwsim: Replace hrtimer tasklet with softirq hrtimer
121 lines
3.0 KiB
C
121 lines
3.0 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* This file contains the jiffies based clocksource.
|
|
*
|
|
* Copyright (C) 2004, 2005 IBM, John Stultz (johnstul@us.ibm.com)
|
|
*/
|
|
#include <linux/clocksource.h>
|
|
#include <linux/jiffies.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
|
|
#include "timekeeping.h"
|
|
|
|
|
|
/* Since jiffies uses a simple TICK_NSEC multiplier
|
|
* conversion, the .shift value could be zero. However
|
|
* this would make NTP adjustments impossible as they are
|
|
* in units of 1/2^.shift. Thus we use JIFFIES_SHIFT to
|
|
* shift both the nominator and denominator the same
|
|
* amount, and give ntp adjustments in units of 1/2^8
|
|
*
|
|
* The value 8 is somewhat carefully chosen, as anything
|
|
* larger can result in overflows. TICK_NSEC grows as HZ
|
|
* shrinks, so values greater than 8 overflow 32bits when
|
|
* HZ=100.
|
|
*/
|
|
#if HZ < 34
|
|
#define JIFFIES_SHIFT 6
|
|
#elif HZ < 67
|
|
#define JIFFIES_SHIFT 7
|
|
#else
|
|
#define JIFFIES_SHIFT 8
|
|
#endif
|
|
|
|
static u64 jiffies_read(struct clocksource *cs)
|
|
{
|
|
return (u64) jiffies;
|
|
}
|
|
|
|
/*
|
|
* The Jiffies based clocksource is the lowest common
|
|
* denominator clock source which should function on
|
|
* all systems. It has the same coarse resolution as
|
|
* the timer interrupt frequency HZ and it suffers
|
|
* inaccuracies caused by missed or lost timer
|
|
* interrupts and the inability for the timer
|
|
* interrupt hardware to accuratly tick at the
|
|
* requested HZ value. It is also not recommended
|
|
* for "tick-less" systems.
|
|
*/
|
|
static struct clocksource clocksource_jiffies = {
|
|
.name = "jiffies",
|
|
.rating = 1, /* lowest valid rating*/
|
|
.read = jiffies_read,
|
|
.mask = CLOCKSOURCE_MASK(32),
|
|
.mult = TICK_NSEC << JIFFIES_SHIFT, /* details above */
|
|
.shift = JIFFIES_SHIFT,
|
|
.max_cycles = 10,
|
|
};
|
|
|
|
__cacheline_aligned_in_smp DEFINE_SEQLOCK(jiffies_lock);
|
|
|
|
#if (BITS_PER_LONG < 64)
|
|
u64 get_jiffies_64(void)
|
|
{
|
|
unsigned int seq;
|
|
u64 ret;
|
|
|
|
do {
|
|
seq = read_seqbegin(&jiffies_lock);
|
|
ret = jiffies_64;
|
|
} while (read_seqretry(&jiffies_lock, seq));
|
|
return ret;
|
|
}
|
|
EXPORT_SYMBOL(get_jiffies_64);
|
|
#endif
|
|
|
|
EXPORT_SYMBOL(jiffies);
|
|
|
|
static int __init init_jiffies_clocksource(void)
|
|
{
|
|
return __clocksource_register(&clocksource_jiffies);
|
|
}
|
|
|
|
core_initcall(init_jiffies_clocksource);
|
|
|
|
struct clocksource * __init __weak clocksource_default_clock(void)
|
|
{
|
|
return &clocksource_jiffies;
|
|
}
|
|
|
|
static struct clocksource refined_jiffies;
|
|
|
|
int register_refined_jiffies(long cycles_per_second)
|
|
{
|
|
u64 nsec_per_tick, shift_hz;
|
|
long cycles_per_tick;
|
|
|
|
|
|
|
|
refined_jiffies = clocksource_jiffies;
|
|
refined_jiffies.name = "refined-jiffies";
|
|
refined_jiffies.rating++;
|
|
|
|
/* Calc cycles per tick */
|
|
cycles_per_tick = (cycles_per_second + HZ/2)/HZ;
|
|
/* shift_hz stores hz<<8 for extra accuracy */
|
|
shift_hz = (u64)cycles_per_second << 8;
|
|
shift_hz += cycles_per_tick/2;
|
|
do_div(shift_hz, cycles_per_tick);
|
|
/* Calculate nsec_per_tick using shift_hz */
|
|
nsec_per_tick = (u64)NSEC_PER_SEC << 8;
|
|
nsec_per_tick += (u32)shift_hz/2;
|
|
do_div(nsec_per_tick, (u32)shift_hz);
|
|
|
|
refined_jiffies.mult = ((u32)nsec_per_tick) << JIFFIES_SHIFT;
|
|
|
|
__clocksource_register(&refined_jiffies);
|
|
return 0;
|
|
}
|