2.4 timer_interrupt/gettimeoffset machvec
PATCH 1/1 2.4 timer_interrupt/gettimeoffset machvec
Hi,
On systems with a drifting ITC, such as the SGI SN2, the current implementation of timer_interrupt() and gettimeoffset() wont work as they rely heavily on ar.itc.
On SN2 this has been solved by using the synchronized RTC in the system, which results a different implementation of the two above mentioned functions.
To get around this I suggest we change gettimeoffset() and timer_intererupt() to be machvec's.
Patch against a not too old Bjorn-2.4 kernel attached. Tested on DIG.
Cheers,
Jes
arch/ia64/kernel/time.c +7 -6
@@ -33,7 +33,7 @@#endif -static void +void do_profile (unsigned long ip) {extern unsigned long prof_cpu_mask;
@@ -61,8 +61,8 @@* Return the number of micro-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 ) +unsigned long +__ia64_gettimeoffset (void ) {unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;unsigned long now, last_tick;
@@ -146,8 +146,8 @@ tv->tv_usec = usec; } -static void -timer_interrupt (int irq,void *dev_id,struct pt_regs *regs) +void +__ia64_timer_interrupt (int irq,void *dev_id,struct pt_regs *regs) {unsigned long new_itm;
@@ -284,7 +284,7 @@ }static struct irqaction timer_irqaction = { - handler: timer_interrupt, + handler:NULL , flags:SA_INTERRUPT , name:"timer" };
@@ -292,6 +294,7 @@void __init time_init (void ) { + timer_irqaction.handler = platform_timer_interrupt;register_percpu_irq (IA64_TIMER_VECTOR , &timer_irqaction);efi_gettimeofday ((struct timeval *) &xtime);ia64_init_itm ();
arch/ia64/sn/kernel/setup.c +3 -0
@@ -76,6 +76,7 @@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;
@@ -313,6 +314,8 @@* Turn off "floating-point assist fault" warnings by default. */ current->thread.flags |=IA64_THREAD_FPEMU_NOPRINT ; + +sn_timer_init (); }/**
arch/ia64/sn/kernel/sn2/Makefile +1 -1
@@ -42,6 +42,6 @@ O_TARGET = sn2.o -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 include $(TOPDIR)/Rules.make
arch/ia64/sn/kernel/sn2/timer.c +176 -0
176 lines not on this page · raw message
include/asm-ia64/machvec.h +17 -1
@@ -64,6 +64,8 @@typedef void ia64_mv_outb_t (unsigned char ,unsigned long );typedef void ia64_mv_outw_t (unsigned short ,unsigned long );typedef void ia64_mv_outl_t (unsigned int ,unsigned long ); +typedef unsigned long ia64_mv_gettimeoffset_t (void ); +typedef void ia64_mv_timer_interrupt_t (int ,void *,struct pt_regs *);extern void machvec_noop (void );
@@ -115,6 +117,8 @@# define platform_outb ia64_mv.outb# define platform_outw ia64_mv.outw# define platform_outl ia64_mv.outl +# define platform_gettimeoffset ia64_mv.gettimeoffset +# define platform_timer_interrupt ia64_mv.timer_interrupt# endif struct ia64_machine_vector {
@@ -151,6 +155,8 @@ia64_mv_outb_t *outb;ia64_mv_outw_t *outw;ia64_mv_outl_t *outl; +ia64_mv_gettimeoffset_t *gettimeoffset; +ia64_mv_timer_interrupt_t *timer_interrupt; };#define MACHVEC_INIT (name) \
@@ -187,7 +193,9 @@ platform_inl, \ platform_outb, \ platform_outw, \ - platform_outl \ + platform_outl, \ + platform_gettimeoffset, \ + platform_timer_interrupt \ }extern struct ia64_machine_vector ia64_mv;
@@ -211,6 +219,8 @@extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported; +extern ia64_mv_gettimeoffset_t __ia64_gettimeoffset; +extern void __ia64_timer_interrupt (int ,void *,struct pt_regs *);/* * Define default versions so we can extend machvec for new platforms without having
@@ -309,5 +319,11 @@#ifndef platform_outl# define platform_outl __ia64_outl#endif +#ifndef platform_gettimeoffset +# define platform_gettimeoffset __ia64_gettimeoffset +#endif +#ifndef platform_timer_interrupt +# define platform_timer_interrupt __ia64_timer_interrupt +#endif #endif /* _ASM_IA64_MACHVEC_H */
include/asm-ia64/machvec_sn2.h +4 -0
@@ -59,6 +59,8 @@extern ia64_mv_pci_dma_sync_single sn_pci_dma_sync_single;extern ia64_mv_pci_dma_sync_sg sn_pci_dma_sync_sg;extern ia64_mv_pci_dma_supported sn_pci_dma_supported; +extern ia64_mv_gettimeoffset_t sn_gettimeoffset; +extern ia64_mv_timer_interrupt_t sn_timer_interrupt;/* * This stuff has dual use!
@@ -95,5 +97,7 @@#define platform_pci_dma_sync_single sn_pci_dma_sync_single#define platform_pci_dma_sync_sg sn_pci_dma_sync_sg#define platform_pci_dma_supported sn_pci_dma_supported +#define platform_gettimeoffset sn_gettimeoffset +#define platform_timer_interrupt sn_timer_interrupt#endif /* _ASM_IA64_MACHVEC_SN2_H */
include/asm-ia64/sn/clksupport.h +3 -3
@@ -38,7 +38,7 @@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 @@#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,7 @@#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))#endif /* CONFIG_IA64_SGI_SN1 */ - +#define SN_RTC_PER_ITC_SHIFT 34#define GET_RTC_COUNTER () (*RTC_COUNTER_ADDR)#define rtc_time () GET_RTC_COUNTER()
include/asm-ia64/timex.h +2 -0
@@ -24,4 +24,6 @@#define vxtime_lock () do {} while (0)#define vxtime_unlock () do {} while (0) +#define gettimeoffset () platform_gettimeoffset() +#endif /* _ASM_IA64_TIMEX_H */
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jes Sorensen
Jes> Hi, On systems with a drifting ITC, such as the SGI SN2, the Jes> current implementation of timer_interrupt() and gettimeoffset() Jes> wont work as they rely heavily on ar.itc.
Jes> On SN2 this has been solved by using the synchronized RTC in Jes> the system, which results a different implementation of the two Jes> above mentioned functions.
Jes> To get around this I suggest we change gettimeoffset() and Jes> timer_intererupt() to be machvec's.
I suspect we're better off in the long term making gettimeoffset() a function pointer. I can certainly imagine platforms where multiple interpolation sources are available and depending on parameters (e.g., long-term stability or overhead), one might want to choose one or another.
The motivation for changing timer_interrupt() seems suspect to me. The timer interupt is generated PER CPU, so there is no drift issue at all (in fact, we intentionally _skew_ things at boot time to reduce the likelihood of getting all timer interrupts at the same time).
--david
Quoted 5 lines · David Mosberger
I suspect we're better off in the long term making
gettimeoffset()a function pointer. I can certainly imagine platforms where multiple interpolation sources are available and depending on parameters (e.g., long-term stability or overhead), one might want to choose one or another.
I agree, since it'll probably refer to a platform specific RTC.
Quoted 4 lines
The motivation for changing
timer_interrupt()seems suspect to me. The timer interupt is generated PER CPU, so there is no drift issue at all (in fact, we intentionally _skew_ things at boot time to reduce the likelihood of getting all timer interrupts at the same time).
The problem is that we want high resolution gettimeofday, which means that we need to know how long its been since wall time was updated when gettimeoffset is called. We do that right now by snapshoting the RTC in timer_interrupt...
Jesse
Quoted 6 lines
Quoted 6 lines
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jesse Barnes
The motivation for changing
timer_interrupt()seems suspect to me. The timer interupt is generated PER CPU, so there is no drift issue at all (in fact, we intentionally _skew_ things at boot time to reduce the likelihood of getting all timer interrupts at the same time).
Jesse> The problem is that we want high resolution gettimeofday, which means Jesse> that we need to know how long its been since wall time was updated Jesse> when gettimeoffset is called. We do that right now by snapshoting the Jesse> RTC in timer_interrupt...
Clearly you need to establish the relationship between the external clock and time-of-day somewhere, but I'm not so sure this should be done in the arch-specific timer interrupt handler. I suspect you really want to do it where the time-of-day gets updated. Also, I think this should be treated much more as a driver issue rather than a platform-issue (suppose someone plugged in an adapter card providing a low-latency, atomic accurracy & high precision lock, you'd presumably want to be able to use that card in favor of whatever other hardware might be there.
--david
Quoted 2 lines · David Mosberger
Also, I think this should be treated much more as a driver issue rather than a platform-issue
In general, I like the idea. It's really three peices of HW
involved: the RTC, the interval timer, and high resolution support.
The RTC is/has a driver in most cases it seems.
The interval timer gets started very early (bogomips) by arch code. A seperate driver could work here which "claims" the (per CPU) interval timer, registers the timer interrupt handler, and syncronizes the multiple timers. But someone would need to unravel dependencies and fix the init sequence accordingly. Sounds like a pretty ugly task.
(Occasionally I try to figure out a timer problem that shows up on some SMP parisc-linux boxes and then give up in the morass of interactions.)
The high resolution support is typically based on a cycle counter in the CPU - very arch specific. But that probably doesn't need to change (much) or become a driver.
Quoted 4 lines
(suppose someone plugged in an adapter card providing a low-latency, atomic accurracy & high precision lock, you'd presumably want to be able to use that card in favor of whatever other hardware might be there.
yup.
thanks,
grant
Quoted 4 lines · David Mosberger
Clearly you need to establish the relationship between the external clock and time-of-day somewhere, but I'm not so sure this should be done in the arch-specific timer interrupt handler. I suspect you really want to do it where the time-of-day gets updated. Also, I
I'd like for it to be there too. Jes and I discussed this on irc and I think he's going to take a stab at it.
Quoted 5 lines
think this should be treated much more as a driver issue rather than a platform-issue (suppose someone plugged in an adapter card providing a low-latency, atomic accurracy & high precision lock, you'd presumably want to be able to use that card in favor of whatever other hardware might be there.
Agreed. It would be nice to have that kind of flexibility.
Thanks,
Jesse
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
"David" = David Mosberger <[email protected]> writes:
On Tue, 8 Apr 2003 14:49:25 -0700, Jesse Barnes <[email protected]> said:
Jesse> The problem is that we want high resolution gettimeofday, which Jesse> means that we need to know how long its been since wall time Jesse> was updated when gettimeoffset is called. We do that right now Jesse> by snapshoting the RTC in timer_interrupt...
David> Clearly you need to establish the relationship between the David> external clock and time-of-day somewhere, but I'm not so sure David> this should be done in the arch-specific timer interrupt David> handler. I suspect you really want to do it where the David> time-of-day gets updated. Also, I think this should be treated David> much more as a driver issue rather than a platform-issue David> (suppose someone plugged in an adapter card providing a David> low-latency, atomic accurracy & high precision lock, you'd David> presumably want to be able to use that card in favor of David> whatever other hardware might be there.
Hi David,
Here is an attempt to do just that using the SN2 RTC timer by providing a hook one can plug into where wall time is updated. This patch is against Bjorn's tree as of a little while ago and leaves the old concept in place for the ITC codepath - not sure if we want to try and convert that over.
Comments? If you think this is a better solution, I'll go ahead and forward port it to 2.5 as well.
Cheers,
Jes
arch/ia64/kernel/time.c +5 -2
@@ -61,8 +61,8 @@* Return the number of micro-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 ) +unsigned long +__ia64_gettimeoffset (void ) {unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;unsigned long now, last_tick;
@@ -102,6 +102,9 @@ tv->tv_sec--; } +if (update_wall_time_plug) +update_wall_time_plug (); + xtime = *tv; time_adjust =0 ;/* stop active adjtime() */ time_status |=STA_UNSYNC ;
arch/ia64/sn/kernel/setup.c +3 -48
69 lines not on this page · raw message
arch/ia64/sn/kernel/sn2/Makefile +1 -1
@@ -42,6 +42,6 @@ O_TARGET = sn2.o -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 include $(TOPDIR)/Rules.make
arch/ia64/sn/kernel/sn2/timer.c +83 -0
83 lines not on this page · raw message
include/asm-ia64/machvec.h +9 -1
@@ -63,6 +63,7 @@typedef void ia64_mv_outb_t (unsigned char ,unsigned long );typedef void ia64_mv_outw_t (unsigned short ,unsigned long );typedef void ia64_mv_outl_t (unsigned int ,unsigned long ); +typedef unsigned long ia64_mv_gettimeoffset_t (void );extern void machvec_noop (void );
@@ -113,6 +114,7 @@# define platform_outb ia64_mv.outb# define platform_outw ia64_mv.outw# define platform_outl ia64_mv.outl +# define platform_gettimeoffset ia64_mv.gettimeoffset# endif struct ia64_machine_vector {
@@ -148,6 +150,7 @@ia64_mv_outb_t *outb;ia64_mv_outw_t *outw;ia64_mv_outl_t *outl; +ia64_mv_gettimeoffset_t *gettimeoffset; };#define MACHVEC_INIT (name) \
@@ -183,7 +186,8 @@ platform_inl, \ platform_outb, \ platform_outw, \ - platform_outl \ + platform_outl, \ + platform_gettimeoffset \ }extern struct ia64_machine_vector ia64_mv;
@@ -206,6 +210,7 @@extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported; +extern ia64_mv_gettimeoffset_t __ia64_gettimeoffset;/* * Define default versions so we can extend machvec for new platforms without having
@@ -301,5 +306,8 @@#ifndef platform_outl# define platform_outl __ia64_outl#endif +#ifndef platform_gettimeoffset +# define platform_gettimeoffset __ia64_gettimeoffset +#endif #endif /* _ASM_IA64_MACHVEC_H */
include/asm-ia64/machvec_sn2.h +2 -0
@@ -58,6 +58,7 @@extern ia64_mv_pci_dma_sync_single sn_pci_dma_sync_single;extern ia64_mv_pci_dma_sync_sg sn_pci_dma_sync_sg;extern ia64_mv_pci_dma_supported sn_pci_dma_supported; +extern ia64_mv_gettimeoffset_t sn_gettimeoffset;/* * This stuff has dual use!
@@ -93,5 +94,6 @@#define platform_pci_dma_sync_single sn_pci_dma_sync_single#define platform_pci_dma_sync_sg sn_pci_dma_sync_sg#define platform_pci_dma_supported sn_pci_dma_supported +#define platform_gettimeoffset sn_gettimeoffset#endif /* _ASM_IA64_MACHVEC_SN2_H */
include/asm-ia64/sn/clksupport.h +3 -3
@@ -38,7 +38,7 @@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 @@#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,7 @@#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))#endif /* CONFIG_IA64_SGI_SN1 */ - +#define SN_RTC_PER_ITC_SHIFT 34#define GET_RTC_COUNTER () (*RTC_COUNTER_ADDR)#define rtc_time () GET_RTC_COUNTER()
include/asm-ia64/timex.h +2 -0
@@ -24,4 +24,6 @@#define vxtime_lock () do {} while (0)#define vxtime_unlock () do {} while (0) +#define gettimeoffset () platform_gettimeoffset() +#endif /* _ASM_IA64_TIMEX_H */
include/linux/timex.h +6 -0
@@ -286,6 +286,12 @@extern long pps_errcnt;/* calibration errors */ extern long pps_stbcnt;/* stability limit exceeded */ +/* +* Call-back for high precision timer sources to snapshot every time +* wall_jiffies is updated. +*/ +extern void (*update_wall_time_plug)(void ); +#endif /* KERNEL */ #endif /* LINUX_TIMEX_H */
kernel/timer.c +11 -0
@@ -514,6 +514,14 @@ }/* +* Hook for using external high precision timers for the system clock. +* On systems where the CPU clock isn't synchronized between CPUs, +* it is necessary to use an external source such as an RTC to obtain +* precision in gettimeofday(). +*/ +void (*update_wall_time_plug)(void ) =NULL ; + +/* * Using a loop looks inefficient, but "ticks" is * usually just one (we shouldn't be losing ticks, * we're doing this this way mainly for interrupt
@@ -522,6 +530,9 @@*/ static void update_wall_time (unsigned long ticks) { +if (update_wall_time_plug) +update_wall_time_plug (); + do { ticks--; update_wall_time_one_tick();
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line
Quoted 1 line · Jes Sorensen
Jes> Here is an attempt to do just that using the SN2 RTC timer by Jes> providing a hook one can plug into where wall time is updated. This Jes> patch is against Bjorn's tree as of a little while ago and leaves the Jes> old concept in place for the ITC codepath - not sure if we want to try Jes> and convert that over.
Jes> Comments? If you think this is a better solution, I'll go ahead and Jes> forward port it to 2.5 as well.
I thought we agreed that gettimeoffset() should just be a function pointer? Also, in 2.5, there is already a "clock_was_set()" call-back (for the POSIX timers). Perhaps that should be considered.
--david
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
"David" = David Mosberger <[email protected]> writes:
On 17 Apr 2003 19:02:26 -0400, Jes Sorensen <[email protected]> said:
Jes> Comments? If you think this is a better solution, I'll go ahead Jes> and forward port it to 2.5 as well.
David> I thought we agreed that gettimeoffset() should just be a David> function pointer? Also, in 2.5, there is already a David> "clock_was_set()" call-back (for the POSIX timers). Perhaps David> that should be considered.
Is there a real difference between using a plain function pointer and a machvec? Admittedly I have just been considering machvec's as function pointers with a fancy name, however I'll be happy to change it to a regular function pointer instead.
I'll take a look at clock_was_set().
Thanks,
Jes
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
Quoted 3 lines
"David" = David Mosberger <[email protected]> writes:
On 17 Apr 2003 19:02:26 -0400, Jes Sorensen <[email protected]> said:
Jes> Comments? If you think this is a better solution, I'll go ahead Jes> and forward port it to 2.5 as well.
David> I thought we agreed that gettimeoffset() should just be a David> function pointer? Also, in 2.5, there is already a David> "clock_was_set()" call-back (for the POSIX timers). Perhaps David> that should be considered.
Hi David,
I had a look at clock_was_set() and it really serves a different purpose, which is to wake up sleeping tasks waiting for the clock. Being called outside the xtime_lock points means that in a preemptive kernel this would fail for us.
Anyway here is a new version of the patch, all traces of machvec's are gone ;-) Anything else you'd like me to change?
Cheers,
Jes
arch/ia64/kernel/time.c +8 -2
@@ -26,6 +26,9 @@extern rwlock_t xtime_lock;extern unsigned long wall_jiffies;extern unsigned long last_time_offset; +unsigned long __ia64_gettimeoffset (void ); + +unsigned long (*gettimeoffset)(void ) = &__ia64_gettimeoffset;#ifdef CONFIG_IA64_DEBUG_IRQ
@@ -61,8 +64,8 @@* Return the number of micro-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 ) +unsigned long +__ia64_gettimeoffset (void ) {unsigned long elapsed_cycles, lost = jiffies - wall_jiffies;unsigned long now, last_tick;
@@ -102,6 +105,9 @@ tv->tv_sec--; } +if (update_wall_time_plug) +update_wall_time_plug (); + xtime = *tv; time_adjust =0 ;/* stop active adjtime() */ time_status |=STA_UNSYNC ;
arch/ia64/sn/kernel/setup.c +3 -48
69 lines not on this page · raw message
arch/ia64/sn/kernel/sn2/Makefile +1 -1
@@ -42,6 +42,6 @@ O_TARGET = sn2.o -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 include $(TOPDIR)/Rules.make
arch/ia64/sn/kernel/sn2/timer.c +85 -0
85 lines not on this page · raw message
include/asm-ia64/sn/clksupport.h +3 -3
@@ -38,7 +38,7 @@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 @@#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,7 @@#define RTC_INT_ENABLED_B_ADDR ((clkreg_t*)LOCAL_MMR_ADDR(SH_RTC))#endif /* CONFIG_IA64_SGI_SN1 */ - +#define SN_RTC_PER_ITC_SHIFT 34#define GET_RTC_COUNTER () (*RTC_COUNTER_ADDR)#define rtc_time () GET_RTC_COUNTER()
include/asm-ia64/timex.h +2 -0
@@ -24,4 +24,6 @@#define vxtime_lock () do {} while (0)#define vxtime_unlock () do {} while (0) +extern unsigned long (*gettimeoffset)(void ); +#endif /* _ASM_IA64_TIMEX_H */
include/linux/timex.h +6 -0
@@ -286,6 +286,12 @@extern long pps_errcnt;/* calibration errors */ extern long pps_stbcnt;/* stability limit exceeded */ +/* +* Call-back for high precision timer sources to snapshot every time +* wall_jiffies is updated. +*/ +extern void (*update_wall_time_plug)(void ); +#endif /* KERNEL */ #endif /* LINUX_TIMEX_H */
kernel/timer.c +11 -0
@@ -514,6 +514,14 @@ }/* +* Hook for using external high precision timers for the system clock. +* On systems where the CPU clock isn't synchronized between CPUs, +* it is necessary to use an external source such as an RTC to obtain +* precision in gettimeofday(). +*/ +void (*update_wall_time_plug)(void ) =NULL ; + +/* * Using a loop looks inefficient, but "ticks" is * usually just one (we shouldn't be losing ticks, * we're doing this this way mainly for interrupt
@@ -522,6 +530,9 @@*/ static void update_wall_time (unsigned long ticks) { +if (update_wall_time_plug) +update_wall_time_plug (); + do { ticks--; update_wall_time_one_tick();