Commit 768b6efa authored by David Mosberger's avatar David Mosberger

ia64: Update for new time_interpolator infrastructure.

parent 854631be
...@@ -26,6 +26,10 @@ config RWSEM_XCHGADD_ALGORITHM ...@@ -26,6 +26,10 @@ config RWSEM_XCHGADD_ALGORITHM
bool bool
default y default y
config TIME_INTERPOLATION
bool
default y
choice choice
prompt "IA-64 processor type" prompt "IA-64 processor type"
default ITANIUM default ITANIUM
......
...@@ -26,10 +26,6 @@ ...@@ -26,10 +26,6 @@
#include <asm/system.h> #include <asm/system.h>
extern unsigned long wall_jiffies; extern unsigned long wall_jiffies;
unsigned long last_nsec_offset;
static unsigned long ia64_gettimeoffset (void);
unsigned long (*gettimeoffset)(void) = &ia64_gettimeoffset;
u64 jiffies_64 = INITIAL_JIFFIES; u64 jiffies_64 = INITIAL_JIFFIES;
...@@ -65,30 +61,18 @@ do_profile (unsigned long ip) ...@@ -65,30 +61,18 @@ do_profile (unsigned long ip)
atomic_inc((atomic_t *) &prof_buffer[ip]); atomic_inc((atomic_t *) &prof_buffer[ip]);
} }
void static void
ia64_reset_wall_time (void) itc_reset (void)
{ {
last_nsec_offset = 0;
} }
/* /*
* Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or * Adjust for the fact that xtime has been advanced by delta_nsec (may be negative and/or
* larger than NSEC_PER_SEC. * larger than NSEC_PER_SEC.
*/ */
void static void
ia64_update_wall_time (long delta_nsec) itc_update (long delta_nsec)
{ {
if (last_nsec_offset > 0) {
unsigned long new, old;
do {
old = last_nsec_offset;
if (old > delta_nsec)
new = old - delta_nsec;
else
new = 0;
} while (cmpxchg(&last_nsec_offset, old, new) != old);
}
} }
/* /*
...@@ -96,7 +80,7 @@ ia64_update_wall_time (long delta_nsec) ...@@ -96,7 +80,7 @@ ia64_update_wall_time (long delta_nsec)
* xtime_lock must be at least read-locked when calling this routine. * xtime_lock must be at least read-locked when calling this routine.
*/ */
unsigned long unsigned long
ia64_gettimeoffset (void) itc_get_offset (void)
{ {
unsigned long elapsed_cycles, lost = jiffies - wall_jiffies; unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;
unsigned long now, last_tick; unsigned long now, last_tick;
...@@ -114,6 +98,12 @@ ia64_gettimeoffset (void) ...@@ -114,6 +98,12 @@ ia64_gettimeoffset (void)
return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT; return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT;
} }
static struct time_interpolator itc_interpolator = {
.get_offset = itc_get_offset,
.update = itc_update,
.reset = itc_reset
};
static inline void static inline void
set_normalized_timespec (struct timespec *ts, time_t sec, long nsec) set_normalized_timespec (struct timespec *ts, time_t sec, long nsec)
{ {
...@@ -143,7 +133,7 @@ do_settimeofday (struct timeval *tv) ...@@ -143,7 +133,7 @@ do_settimeofday (struct timeval *tv)
* Discover what correction gettimeofday would have done, and then undo * Discover what correction gettimeofday would have done, and then undo
* it! * it!
*/ */
nsec -= (*gettimeoffset)(); nsec -= time_interpolator_get_offset();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
...@@ -155,7 +145,7 @@ do_settimeofday (struct timeval *tv) ...@@ -155,7 +145,7 @@ do_settimeofday (struct timeval *tv)
time_status |= STA_UNSYNC; time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT; time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT;
(*reset_wall_time_hook)(); time_interpolator_reset();
} }
write_sequnlock_irq(&xtime_lock); write_sequnlock_irq(&xtime_lock);
clock_was_set(); clock_was_set();
...@@ -170,7 +160,7 @@ do_gettimeofday (struct timeval *tv) ...@@ -170,7 +160,7 @@ do_gettimeofday (struct timeval *tv)
seq = read_seqbegin(&xtime_lock); seq = read_seqbegin(&xtime_lock);
{ {
old = last_nsec_offset; old = last_nsec_offset;
offset = (*gettimeoffset)(); offset = time_interpolator_get_offset();
sec = xtime.tv_sec; sec = xtime.tv_sec;
nsec = xtime.tv_nsec; nsec = xtime.tv_nsec;
} }
...@@ -308,16 +298,17 @@ ia64_cpu_local_tick (void) ...@@ -308,16 +298,17 @@ ia64_cpu_local_tick (void)
void __init void __init
ia64_init_itm (void) ia64_init_itm (void)
{ {
unsigned long platform_base_freq, itc_freq, drift; unsigned long platform_base_freq, itc_freq;
struct pal_freq_ratio itc_ratio, proc_ratio; struct pal_freq_ratio itc_ratio, proc_ratio;
long status; long status, platform_base_drift, itc_drift;
/* /*
* According to SAL v2.6, we need to use a SAL call to determine the platform base * According to SAL v2.6, we need to use a SAL call to determine the platform base
* frequency and then a PAL call to determine the frequency ratio between the ITC * frequency and then a PAL call to determine the frequency ratio between the ITC
* and the base frequency. * and the base frequency.
*/ */
status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM, &platform_base_freq, &drift); status = ia64_sal_freq_base(SAL_FREQ_BASE_PLATFORM,
&platform_base_freq, &platform_base_drift);
if (status != 0) { if (status != 0) {
printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status)); printk(KERN_ERR "SAL_FREQ_BASE_PLATFORM failed: %s\n", ia64_sal_strerror(status));
} else { } else {
...@@ -330,6 +321,7 @@ ia64_init_itm (void) ...@@ -330,6 +321,7 @@ ia64_init_itm (void)
printk(KERN_ERR printk(KERN_ERR
"SAL/PAL failed to obtain frequency info---inventing reasonable values\n"); "SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
platform_base_freq = 100000000; platform_base_freq = 100000000;
platform_base_drift = -1; /* no drift info */
itc_ratio.num = 3; itc_ratio.num = 3;
itc_ratio.den = 1; itc_ratio.den = 1;
} }
...@@ -337,6 +329,7 @@ ia64_init_itm (void) ...@@ -337,6 +329,7 @@ ia64_init_itm (void)
printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n", printk(KERN_ERR "Platform base frequency %lu bogus---resetting to 75MHz!\n",
platform_base_freq); platform_base_freq);
platform_base_freq = 75000000; platform_base_freq = 75000000;
platform_base_drift = -1;
} }
if (!proc_ratio.den) if (!proc_ratio.den)
proc_ratio.den = 1; /* avoid division by zero */ proc_ratio.den = 1; /* avoid division by zero */
...@@ -344,11 +337,17 @@ ia64_init_itm (void) ...@@ -344,11 +337,17 @@ ia64_init_itm (void)
itc_ratio.den = 1; /* avoid division by zero */ itc_ratio.den = 1; /* avoid division by zero */
itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den; itc_freq = (platform_base_freq*itc_ratio.num)/itc_ratio.den;
if (platform_base_drift != -1)
itc_drift = platform_base_drift*itc_ratio.num/itc_ratio.den;
else
itc_drift = -1;
local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ; local_cpu_data->itm_delta = (itc_freq + HZ/2) / HZ;
printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, " printk(KERN_INFO "CPU %d: base freq=%lu.%03luMHz, ITC ratio=%lu/%lu, "
"ITC freq=%lu.%03luMHz\n", smp_processor_id(), "ITC freq=%lu.%03luMHz+/-%ldppm\n", smp_processor_id(),
platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000, platform_base_freq / 1000000, (platform_base_freq / 1000) % 1000,
itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000); itc_ratio.num, itc_ratio.den, itc_freq / 1000000, (itc_freq / 1000) % 1000,
itc_drift);
local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den; local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
local_cpu_data->itc_freq = itc_freq; local_cpu_data->itc_freq = itc_freq;
...@@ -356,6 +355,12 @@ ia64_init_itm (void) ...@@ -356,6 +355,12 @@ ia64_init_itm (void)
local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT) local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
+ itc_freq/2)/itc_freq; + itc_freq/2)/itc_freq;
if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
itc_interpolator.frequency = local_cpu_data->itc_freq;
itc_interpolator.drift = itc_drift;
register_time_interpolator(&itc_interpolator);
}
/* Setup the CPU local timer tick */ /* Setup the CPU local timer tick */
ia64_cpu_local_tick(); ia64_cpu_local_tick();
} }
...@@ -369,9 +374,6 @@ static struct irqaction timer_irqaction = { ...@@ -369,9 +374,6 @@ static struct irqaction timer_irqaction = {
void __init void __init
time_init (void) time_init (void)
{ {
update_wall_time_hook = ia64_update_wall_time;
reset_wall_time_hook = ia64_reset_wall_time;
register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction); register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
efi_gettimeofday(&xtime); efi_gettimeofday(&xtime);
ia64_init_itm(); ia64_init_itm();
......
...@@ -20,68 +20,45 @@ ...@@ -20,68 +20,45 @@
extern unsigned long sn_rtc_cycles_per_second; extern unsigned long sn_rtc_cycles_per_second;
static volatile unsigned long last_wall_rtc; static volatile unsigned long last_wall_rtc;
/**
* gettimeoffset - number of nsecs elapsed since &xtime was last updated
*
* This function is used by do_gettimeofday() to determine the number
* of nsecs that have elapsed since the last update to &xtime. On SN
* this is accomplished using the RTC built in to each Hub chip; each
* is guaranteed to be synchronized by the PROM, so a local read will
* suffice (GET_RTC_COUNTER() does this for us). A snapshot of the RTC
* value is taken every time wall_jiffies is updated by the
* update_wall_time_hook (sn2_update_wall_time) which means we don't
* have to adjust for lost jiffies ticks or anything like that.
*/
static volatile long rtc_offset;
static long rtc_nsecs_per_cycle; static long rtc_nsecs_per_cycle;
static long rtc_per_timer_tick; static long rtc_per_timer_tick;
unsigned long static unsigned long
sn_gettimeoffset(void) getoffset(void)
{ {
long current_rtc, elapsed_rtc, old, new_offset; return (long) (GET_RTC_COUNTER() - last_wall_rtc)*rtc_nsecs_per_cycle;
do {
old = rtc_offset;
current_rtc = GET_RTC_COUNTER();
/*
* Need to address wrapping here!
*/
elapsed_rtc = (long)(current_rtc - last_wall_rtc);
new_offset = max(elapsed_rtc, old);
} while (cmpxchg(&rtc_offset, old, new_offset) != old);
return new_offset * rtc_nsecs_per_cycle;
} }
void sn2_update_wall_time(long delta_nsec) static void
update(long delta_nsec)
{ {
ia64_update_wall_time(delta_nsec);
rtc_offset -= min(rtc_offset, rtc_per_timer_tick);
last_wall_rtc = GET_RTC_COUNTER(); last_wall_rtc = GET_RTC_COUNTER();
} }
void sn2_reset_wall_time(void) static void
reset(void)
{ {
ia64_reset_wall_time();
rtc_offset = 0;
last_wall_rtc = GET_RTC_COUNTER(); last_wall_rtc = GET_RTC_COUNTER();
} }
static struct time_interpolator sn2_interpolator = {
.get_offset = getoffset,
.update = update,
.reset = reset
};
void __init void __init
sn_timer_init(void) sn_timer_init(void)
{ {
sn2_interpolator.frequency = sn_rtc_cycles_per_second;
sn2_interpolator.drift = -1; /* unknown */
register_time_interpolator(&sn2_interpolator);
rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ; rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ;
rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second; rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second;
last_wall_rtc = GET_RTC_COUNTER(); last_wall_rtc = GET_RTC_COUNTER();
update_wall_time_hook = sn2_update_wall_time;
reset_wall_time_hook = sn2_reset_wall_time;
gettimeoffset = sn_gettimeoffset;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment