Commit 14076de1 authored by Jes Sorensen's avatar Jes Sorensen Committed by David Mosberger

[PATCH] ia64: gettimeoffset hooks

Make it possible to plug in alternate time-offset sources, such as external
(e.g., chipset) timers or High-Performance Event Timer (HPET) etc. This
is needed on platforms where the cycle-counters on different CPUs may
drift apart from each other.
This patch contains the ia64-specific portion only.
parent 10a0ceef
......@@ -14,6 +14,7 @@
#include <asm/offsets.h>
#include <asm/percpu.h>
#include <asm/thread_info.h>
#include <asm/sal.h>
/*
* See Documentation/ia64/fsys.txt for details on fsyscalls.
......@@ -142,23 +143,30 @@ END(fsys_set_tid_address)
* we ought to either skip the ITC-based interpolation or run an ntp-like
* daemon to keep the ITCs from drifting too far apart.
*/
ENTRY(fsys_gettimeofday)
add r9=TI_FLAGS+IA64_TASK_SIZE,r16
movl r3=THIS_CPU(cpu_info)
mov.m r31=ar.itc // put time stamp into r31 (ITC) == now (35 cyc)
movl r19=xtime // xtime is a timespec struct
;;
#ifdef CONFIG_SMP
movl r10=__per_cpu_offset
movl r2=sal_platform_features
;;
ld8 r2=[r2]
movl r19=xtime // xtime is a timespec struct
ld8 r10=[r10] // r10 <- __per_cpu_offset[0]
movl r21=cpu_info__per_cpu
;;
add r10=r21, r10 // r10 <- &cpu_data(time_keeper_id)
tbit.nz p8,p0 = r2, IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT
(p8) br.spnt.many fsys_fallback_syscall
#else
;;
mov r10=r3
movl r19=xtime // xtime is a timespec struct
#endif
ld4 r9=[r9]
movl r17=xtime_lock
......
......@@ -17,6 +17,7 @@
#include <linux/time.h>
#include <linux/interrupt.h>
#include <linux/efi.h>
#include <linux/timex.h>
#include <asm/delay.h>
#include <asm/hw_irq.h>
......@@ -26,9 +27,14 @@
extern unsigned long wall_jiffies;
extern unsigned long last_nsec_offset;
static unsigned long __ia64_gettimeoffset (void);
unsigned long (*gettimeoffset)(void) = &__ia64_gettimeoffset;
u64 jiffies_64 = INITIAL_JIFFIES;
#define TIME_KEEPER_ID 0 /* smp_processor_id() of time-keeper */
#ifdef CONFIG_IA64_DEBUG_IRQ
unsigned long last_cli_ip;
......@@ -63,15 +69,14 @@ do_profile (unsigned long ip)
* Return the number of nano-seconds that elapsed since the last update to jiffy. The
* xtime_lock must be at least read-locked when calling this routine.
*/
static inline unsigned long
gettimeoffset (void)
static unsigned long
__ia64_gettimeoffset (void)
{
unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;
unsigned long now, last_tick;
# define time_keeper_id 0 /* smp_processor_id() of time-keeper */
last_tick = (cpu_data(time_keeper_id)->itm_next
- (lost + 1)*cpu_data(time_keeper_id)->itm_delta);
last_tick = (cpu_data(TIME_KEEPER_ID)->itm_next
- (lost + 1)*cpu_data(TIME_KEEPER_ID)->itm_delta);
now = ia64_get_itc();
if (unlikely((long) (now - last_tick) < 0)) {
......@@ -112,7 +117,7 @@ do_settimeofday (struct timeval *tv)
* Discover what correction gettimeofday would have done, and then undo
* it!
*/
nsec -= gettimeoffset();
nsec -= (*gettimeoffset)();
wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
......@@ -124,6 +129,9 @@ do_settimeofday (struct timeval *tv)
time_status |= STA_UNSYNC;
time_maxerror = NTP_PHASE_LIMIT;
time_esterror = NTP_PHASE_LIMIT;
if (update_wall_time_hook)
(*update_wall_time_hook)();
}
write_sequnlock_irq(&xtime_lock);
clock_was_set();
......@@ -138,7 +146,7 @@ do_gettimeofday (struct timeval *tv)
seq = read_seqbegin(&xtime_lock);
{
old = last_nsec_offset;
offset = gettimeoffset();
offset = (*gettimeoffset)();
sec = xtime.tv_sec;
nsec = xtime.tv_nsec;
}
......@@ -214,7 +222,7 @@ timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
#endif
new_itm += local_cpu_data->itm_delta;
if (smp_processor_id() == 0) {
if (smp_processor_id() == TIME_KEEPER_ID) {
/*
* Here we are in the timer irq handler. We have irqs locally
* disabled, but we don't know if the timer_bh is running on
......
......@@ -78,9 +78,9 @@ DEFINE_PER_CPU(struct pda_s, pda_percpu);
extern void bte_init_node (nodepda_t *, cnodeid_t);
extern void bte_init_cpu (void);
extern void sn_timer_init (void);
unsigned long sn_rtc_cycles_per_second;
unsigned long sn_rtc_usec_per_cyc;
partid_t sn_partid = -1;
char sn_system_serial_number_string[128];
......@@ -263,13 +263,6 @@ sn_setup(char **cmdline_p)
else
sn_rtc_cycles_per_second = ticks_per_sec;
#ifdef CONFIG_IA64_SGI_SN1
/* PROM has wrong value on SN1 */
sn_rtc_cycles_per_second = 990177;
#endif
sn_rtc_usec_per_cyc = ((1000000000UL<<IA64_NSEC_PER_CYC_SHIFT)
+ sn_rtc_cycles_per_second/2) / sn_rtc_cycles_per_second;
for (i=0;i<NR_CPUS;i++)
_sn_irq_desc[i] = _irq_desc;
......@@ -309,6 +302,8 @@ sn_setup(char **cmdline_p)
* Turn off "floating-point assist fault" warnings by default.
*/
current->thread.flags |= IA64_THREAD_FPEMU_NOPRINT;
sn_timer_init();
}
/**
......
......@@ -11,4 +11,4 @@
EXTRA_CFLAGS := -DLITTLE_ENDIAN
obj-y += cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o
obj-y += cache.o iomv.o ptc_deadlock.o sn2_smp.o sn_proc_fs.o timer.o
/*
* linux/arch/ia64/sn/kernel/sn2/timer.c
*
* Copyright (C) 2003 Silicon Graphics, Inc.
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/time.h>
#include <linux/interrupt.h>
#include <asm/hw_irq.h>
#include <asm/system.h>
#include <asm/sn/leds.h>
#include <asm/sn/clksupport.h>
extern unsigned long sn_rtc_cycles_per_second;
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_per_timer_tick;
unsigned long
sn_gettimeoffset(void)
{
long current_rtc, elapsed_rtc, old, new_offset;
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(void)
{
rtc_offset -= min(rtc_offset, rtc_per_timer_tick);
last_wall_rtc = GET_RTC_COUNTER();
}
void sn2_reset_wall_time(void)
{
rtc_offset = 0;
last_wall_rtc = GET_RTC_COUNTER();
}
void __init
sn_timer_init(void)
{
rtc_per_timer_tick = sn_rtc_cycles_per_second / HZ;
rtc_nsecs_per_cycle = 1000000000 / sn_rtc_cycles_per_second;
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;
}
......@@ -23,6 +23,18 @@
* (plus examples of platform error info structures from smariset @ Intel)
*/
#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT 0
#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT 1
#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT 2
#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT 3
#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1<<IA64_SAL_PLATFORM_FEATURE_BUS_LOCK_BIT)
#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT (1<<IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT_BIT)
#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT (1<<IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT_BIT)
#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT (1<<IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT_BIT)
#ifndef __ASSEMBLY__
#include <linux/spinlock.h>
#include <linux/efi.h>
......@@ -162,11 +174,6 @@ typedef struct ia64_sal_desc_memory {
u8 oem_reserved[8];
} ia64_sal_desc_memory_t;
#define IA64_SAL_PLATFORM_FEATURE_BUS_LOCK (1 << 0)
#define IA64_SAL_PLATFORM_FEATURE_IRQ_REDIR_HINT (1 << 1)
#define IA64_SAL_PLATFORM_FEATURE_IPI_REDIR_HINT (1 << 2)
#define IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT (1 << 3)
typedef struct ia64_sal_desc_platform_feature {
u8 type;
u8 feature_mask;
......@@ -790,4 +797,6 @@ ia64_sal_update_pal (u64 param_buf, u64 scratch_buf, u64 scratch_buf_size,
extern unsigned long sal_platform_features;
#endif /* __ASSEMBLY__ */
#endif /* _ASM_IA64_PAL_H */
......@@ -38,7 +38,7 @@ extern unsigned long sn_rtc_cycles_per_second;
extern nasid_t master_nasid;
#define RTC_MASK (0x007fffffffffffff)
#define RTC_MASK 0x007fffffffffffffUL
/* clocks are not synchronized yet on SN1 - used node 0 (problem if no NASID 0) */
#define RTC_COUNTER_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COUNTER))
#define RTC_COMPARE_A_ADDR ((clkreg_t*)REMOTE_HUB_ADDR(master_nasid, PI_RT_COMPARE_A))
......@@ -52,7 +52,7 @@ extern nasid_t master_nasid;
#include <asm/sn/sn2/addrs.h>
#include <asm/sn/sn2/shubio.h>
#include <asm/sn/sn2/shub_mmr.h>
#define RTC_MASK (SH_RTC_MASK)
#define RTC_MASK SH_RTC_MASK
#define RTC_COUNTER_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
#define RTC_COMPARE_A_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
#define RTC_COMPARE_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
......@@ -62,7 +62,6 @@ extern nasid_t master_nasid;
#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))
#endif /* CONFIG_IA64_SGI_SN1 */
#define GET_RTC_COUNTER() (*RTC_COUNTER_ADDR)
#define rtc_time() GET_RTC_COUNTER()
......
......@@ -25,4 +25,6 @@ get_cycles (void)
return ret;
}
extern unsigned long (*gettimeoffset)(void);
#endif /* _ASM_IA64_TIMEX_H */
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