aboutsummaryrefslogtreecommitdiffstats
path: root/arch/ia64
diff options
context:
space:
mode:
authorTony Luck <tony.luck@intel.com>2007-07-20 14:22:30 -0400
committerTony Luck <tony.luck@intel.com>2007-07-20 14:22:30 -0400
commit0aa366f351d044703e25c8425e508170e80d83b1 (patch)
tree485040cbef6157b9bcb2e7b1b85920d1e391ab68 /arch/ia64
parent5bae7ac9feba925fd0099057f6b23d7be80b7b41 (diff)
[IA64] Convert to generic timekeeping/clocksource
This is a merge of Peter Keilty's initial patch (which was revived by Bob Picco) for this with Hidetoshi Seto's fixes and scaling improvements. Acked-by: Bob Picco <bob.picco@hp.com> Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'arch/ia64')
-rw-r--r--arch/ia64/Kconfig6
-rw-r--r--arch/ia64/configs/bigsur_defconfig2
-rw-r--r--arch/ia64/configs/gensparse_defconfig2
-rw-r--r--arch/ia64/configs/sim_defconfig2
-rw-r--r--arch/ia64/configs/sn2_defconfig2
-rw-r--r--arch/ia64/configs/tiger_defconfig2
-rw-r--r--arch/ia64/configs/zx1_defconfig2
-rw-r--r--arch/ia64/defconfig2
-rw-r--r--arch/ia64/kernel/asm-offsets.c35
-rw-r--r--arch/ia64/kernel/cyclone.c46
-rw-r--r--arch/ia64/kernel/fsys.S179
-rw-r--r--arch/ia64/kernel/fsyscall_gtod_data.h23
-rw-r--r--arch/ia64/kernel/time.c96
-rw-r--r--arch/ia64/sn/kernel/sn2/timer.c29
14 files changed, 286 insertions, 142 deletions
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index 616c96e73483..36c7b9682aa6 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -62,7 +62,11 @@ config GENERIC_CALIBRATE_DELAY
62 bool 62 bool
63 default y 63 default y
64 64
65config TIME_INTERPOLATION 65config GENERIC_TIME
66 bool
67 default y
68
69config GENERIC_TIME_VSYSCALL
66 bool 70 bool
67 default y 71 default y
68 72
diff --git a/arch/ia64/configs/bigsur_defconfig b/arch/ia64/configs/bigsur_defconfig
index 90e9c2e61bf4..9eb48c0927b0 100644
--- a/arch/ia64/configs/bigsur_defconfig
+++ b/arch/ia64/configs/bigsur_defconfig
@@ -85,7 +85,7 @@ CONFIG_MMU=y
85CONFIG_SWIOTLB=y 85CONFIG_SWIOTLB=y
86CONFIG_RWSEM_XCHGADD_ALGORITHM=y 86CONFIG_RWSEM_XCHGADD_ALGORITHM=y
87CONFIG_GENERIC_CALIBRATE_DELAY=y 87CONFIG_GENERIC_CALIBRATE_DELAY=y
88CONFIG_TIME_INTERPOLATION=y 88CONFIG_GENERIC_TIME=y
89CONFIG_EFI=y 89CONFIG_EFI=y
90CONFIG_GENERIC_IOMAP=y 90CONFIG_GENERIC_IOMAP=y
91CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y 91CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/gensparse_defconfig b/arch/ia64/configs/gensparse_defconfig
index 0d29aa2066b3..3a9ed951db08 100644
--- a/arch/ia64/configs/gensparse_defconfig
+++ b/arch/ia64/configs/gensparse_defconfig
@@ -86,7 +86,7 @@ CONFIG_MMU=y
86CONFIG_SWIOTLB=y 86CONFIG_SWIOTLB=y
87CONFIG_RWSEM_XCHGADD_ALGORITHM=y 87CONFIG_RWSEM_XCHGADD_ALGORITHM=y
88CONFIG_GENERIC_CALIBRATE_DELAY=y 88CONFIG_GENERIC_CALIBRATE_DELAY=y
89CONFIG_TIME_INTERPOLATION=y 89CONFIG_GENERIC_TIME=y
90CONFIG_EFI=y 90CONFIG_EFI=y
91CONFIG_GENERIC_IOMAP=y 91CONFIG_GENERIC_IOMAP=y
92CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y 92CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sim_defconfig b/arch/ia64/configs/sim_defconfig
index d9146c31ea13..c420d9f3df98 100644
--- a/arch/ia64/configs/sim_defconfig
+++ b/arch/ia64/configs/sim_defconfig
@@ -86,7 +86,7 @@ CONFIG_MMU=y
86CONFIG_SWIOTLB=y 86CONFIG_SWIOTLB=y
87CONFIG_RWSEM_XCHGADD_ALGORITHM=y 87CONFIG_RWSEM_XCHGADD_ALGORITHM=y
88CONFIG_GENERIC_CALIBRATE_DELAY=y 88CONFIG_GENERIC_CALIBRATE_DELAY=y
89CONFIG_TIME_INTERPOLATION=y 89CONFIG_GENERIC_TIME=y
90CONFIG_EFI=y 90CONFIG_EFI=y
91CONFIG_GENERIC_IOMAP=y 91CONFIG_GENERIC_IOMAP=y
92CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y 92CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
diff --git a/arch/ia64/configs/sn2_defconfig b/arch/ia64/configs/sn2_defconfig
index 64e951de4e57..4c9ffc47bc7a 100644
--- a/arch/ia64/configs/sn2_defconfig
+++ b/arch/ia64/configs/sn2_defconfig
@@ -93,7 +93,7 @@ CONFIG_SWIOTLB=y
93CONFIG_RWSEM_XCHGADD_ALGORITHM=y 93CONFIG_RWSEM_XCHGADD_ALGORITHM=y
94CONFIG_GENERIC_FIND_NEXT_BIT=y 94CONFIG_GENERIC_FIND_NEXT_BIT=y
95CONFIG_GENERIC_CALIBRATE_DELAY=y 95CONFIG_GENERIC_CALIBRATE_DELAY=y
96CONFIG_TIME_INTERPOLATION=y 96CONFIG_GENERIC_TIME=y
97CONFIG_DMI=y 97CONFIG_DMI=y
98CONFIG_EFI=y 98CONFIG_EFI=y
99CONFIG_GENERIC_IOMAP=y 99CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/configs/tiger_defconfig b/arch/ia64/configs/tiger_defconfig
index a1446931b401..e208747d5de4 100644
--- a/arch/ia64/configs/tiger_defconfig
+++ b/arch/ia64/configs/tiger_defconfig
@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
98# CONFIG_ARCH_HAS_ILOG2_U64 is not set 98# CONFIG_ARCH_HAS_ILOG2_U64 is not set
99CONFIG_GENERIC_FIND_NEXT_BIT=y 99CONFIG_GENERIC_FIND_NEXT_BIT=y
100CONFIG_GENERIC_CALIBRATE_DELAY=y 100CONFIG_GENERIC_CALIBRATE_DELAY=y
101CONFIG_TIME_INTERPOLATION=y 101CONFIG_GENERIC_TIME=y
102CONFIG_DMI=y 102CONFIG_DMI=y
103CONFIG_EFI=y 103CONFIG_EFI=y
104CONFIG_GENERIC_IOMAP=y 104CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/configs/zx1_defconfig b/arch/ia64/configs/zx1_defconfig
index 1c7955c16358..4a060fc39934 100644
--- a/arch/ia64/configs/zx1_defconfig
+++ b/arch/ia64/configs/zx1_defconfig
@@ -96,7 +96,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
96# CONFIG_ARCH_HAS_ILOG2_U64 is not set 96# CONFIG_ARCH_HAS_ILOG2_U64 is not set
97CONFIG_GENERIC_FIND_NEXT_BIT=y 97CONFIG_GENERIC_FIND_NEXT_BIT=y
98CONFIG_GENERIC_CALIBRATE_DELAY=y 98CONFIG_GENERIC_CALIBRATE_DELAY=y
99CONFIG_TIME_INTERPOLATION=y 99CONFIG_GENERIC_TIME=y
100CONFIG_DMI=y 100CONFIG_DMI=y
101CONFIG_EFI=y 101CONFIG_EFI=y
102CONFIG_GENERIC_IOMAP=y 102CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/defconfig b/arch/ia64/defconfig
index 90bd9601cdde..461f8ee738fb 100644
--- a/arch/ia64/defconfig
+++ b/arch/ia64/defconfig
@@ -98,7 +98,7 @@ CONFIG_RWSEM_XCHGADD_ALGORITHM=y
98# CONFIG_ARCH_HAS_ILOG2_U64 is not set 98# CONFIG_ARCH_HAS_ILOG2_U64 is not set
99CONFIG_GENERIC_FIND_NEXT_BIT=y 99CONFIG_GENERIC_FIND_NEXT_BIT=y
100CONFIG_GENERIC_CALIBRATE_DELAY=y 100CONFIG_GENERIC_CALIBRATE_DELAY=y
101CONFIG_TIME_INTERPOLATION=y 101CONFIG_GENERIC_TIME=y
102CONFIG_DMI=y 102CONFIG_DMI=y
103CONFIG_EFI=y 103CONFIG_EFI=y
104CONFIG_GENERIC_IOMAP=y 104CONFIG_GENERIC_IOMAP=y
diff --git a/arch/ia64/kernel/asm-offsets.c b/arch/ia64/kernel/asm-offsets.c
index 2236fabbb3c6..0aebc6f79e95 100644
--- a/arch/ia64/kernel/asm-offsets.c
+++ b/arch/ia64/kernel/asm-offsets.c
@@ -7,6 +7,7 @@
7#define ASM_OFFSETS_C 1 7#define ASM_OFFSETS_C 1
8 8
9#include <linux/sched.h> 9#include <linux/sched.h>
10#include <linux/clocksource.h>
10 11
11#include <asm-ia64/processor.h> 12#include <asm-ia64/processor.h>
12#include <asm-ia64/ptrace.h> 13#include <asm-ia64/ptrace.h>
@@ -15,6 +16,7 @@
15#include <asm-ia64/mca.h> 16#include <asm-ia64/mca.h>
16 17
17#include "../kernel/sigframe.h" 18#include "../kernel/sigframe.h"
19#include "../kernel/fsyscall_gtod_data.h"
18 20
19#define DEFINE(sym, val) \ 21#define DEFINE(sym, val) \
20 asm volatile("\n->" #sym " %0 " #val : : "i" (val)) 22 asm volatile("\n->" #sym " %0 " #val : : "i" (val))
@@ -256,17 +258,24 @@ void foo(void)
256 BLANK(); 258 BLANK();
257 259
258 /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */ 260 /* used by fsys_gettimeofday in arch/ia64/kernel/fsys.S */
259 DEFINE(IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET, offsetof (struct time_interpolator, addr)); 261 DEFINE(IA64_GTOD_LOCK_OFFSET,
260 DEFINE(IA64_TIME_INTERPOLATOR_SOURCE_OFFSET, offsetof (struct time_interpolator, source)); 262 offsetof (struct fsyscall_gtod_data_t, lock));
261 DEFINE(IA64_TIME_INTERPOLATOR_SHIFT_OFFSET, offsetof (struct time_interpolator, shift)); 263 DEFINE(IA64_GTOD_WALL_TIME_OFFSET,
262 DEFINE(IA64_TIME_INTERPOLATOR_NSEC_OFFSET, offsetof (struct time_interpolator, nsec_per_cyc)); 264 offsetof (struct fsyscall_gtod_data_t, wall_time));
263 DEFINE(IA64_TIME_INTERPOLATOR_OFFSET_OFFSET, offsetof (struct time_interpolator, offset)); 265 DEFINE(IA64_GTOD_MONO_TIME_OFFSET,
264 DEFINE(IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET, offsetof (struct time_interpolator, last_cycle)); 266 offsetof (struct fsyscall_gtod_data_t, monotonic_time));
265 DEFINE(IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET, offsetof (struct time_interpolator, last_counter)); 267 DEFINE(IA64_CLKSRC_MASK_OFFSET,
266 DEFINE(IA64_TIME_INTERPOLATOR_JITTER_OFFSET, offsetof (struct time_interpolator, jitter)); 268 offsetof (struct fsyscall_gtod_data_t, clk_mask));
267 DEFINE(IA64_TIME_INTERPOLATOR_MASK_OFFSET, offsetof (struct time_interpolator, mask)); 269 DEFINE(IA64_CLKSRC_MULT_OFFSET,
268 DEFINE(IA64_TIME_SOURCE_CPU, TIME_SOURCE_CPU); 270 offsetof (struct fsyscall_gtod_data_t, clk_mult));
269 DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64); 271 DEFINE(IA64_CLKSRC_SHIFT_OFFSET,
270 DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32); 272 offsetof (struct fsyscall_gtod_data_t, clk_shift));
271 DEFINE(IA64_TIMESPEC_TV_NSEC_OFFSET, offsetof (struct timespec, tv_nsec)); 273 DEFINE(IA64_CLKSRC_MMIO_OFFSET,
274 offsetof (struct fsyscall_gtod_data_t, clk_fsys_mmio));
275 DEFINE(IA64_CLKSRC_CYCLE_LAST_OFFSET,
276 offsetof (struct fsyscall_gtod_data_t, clk_cycle_last));
277 DEFINE(IA64_ITC_JITTER_OFFSET,
278 offsetof (struct itc_jitter_data_t, itc_jitter));
279 DEFINE(IA64_ITC_LASTCYCLE_OFFSET,
280 offsetof (struct itc_jitter_data_t, itc_lastcycle));
272} 281}
diff --git a/arch/ia64/kernel/cyclone.c b/arch/ia64/kernel/cyclone.c
index e00b21514f7c..2fd96d9062a1 100644
--- a/arch/ia64/kernel/cyclone.c
+++ b/arch/ia64/kernel/cyclone.c
@@ -3,6 +3,7 @@
3#include <linux/time.h> 3#include <linux/time.h>
4#include <linux/errno.h> 4#include <linux/errno.h>
5#include <linux/timex.h> 5#include <linux/timex.h>
6#include <linux/clocksource.h>
6#include <asm/io.h> 7#include <asm/io.h>
7 8
8/* IBM Summit (EXA) Cyclone counter code*/ 9/* IBM Summit (EXA) Cyclone counter code*/
@@ -18,13 +19,21 @@ void __init cyclone_setup(void)
18 use_cyclone = 1; 19 use_cyclone = 1;
19} 20}
20 21
22static void __iomem *cyclone_mc;
21 23
22struct time_interpolator cyclone_interpolator = { 24static cycle_t read_cyclone(void)
23 .source = TIME_SOURCE_MMIO64, 25{
24 .shift = 16, 26 return (cycle_t)readq((void __iomem *)cyclone_mc);
25 .frequency = CYCLONE_TIMER_FREQ, 27}
26 .drift = -100, 28
27 .mask = (1LL << 40) - 1 29static struct clocksource clocksource_cyclone = {
30 .name = "cyclone",
31 .rating = 300,
32 .read = read_cyclone,
33 .mask = (1LL << 40) - 1,
34 .mult = 0, /*to be caluclated*/
35 .shift = 16,
36 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
28}; 37};
29 38
30int __init init_cyclone_clock(void) 39int __init init_cyclone_clock(void)
@@ -44,13 +53,15 @@ int __init init_cyclone_clock(void)
44 offset = (CYCLONE_CBAR_ADDR); 53 offset = (CYCLONE_CBAR_ADDR);
45 reg = (u64*)ioremap_nocache(offset, sizeof(u64)); 54 reg = (u64*)ioremap_nocache(offset, sizeof(u64));
46 if(!reg){ 55 if(!reg){
47 printk(KERN_ERR "Summit chipset: Could not find valid CBAR register.\n"); 56 printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
57 " register.\n");
48 use_cyclone = 0; 58 use_cyclone = 0;
49 return -ENODEV; 59 return -ENODEV;
50 } 60 }
51 base = readq(reg); 61 base = readq(reg);
52 if(!base){ 62 if(!base){
53 printk(KERN_ERR "Summit chipset: Could not find valid CBAR value.\n"); 63 printk(KERN_ERR "Summit chipset: Could not find valid CBAR"
64 " value.\n");
54 use_cyclone = 0; 65 use_cyclone = 0;
55 return -ENODEV; 66 return -ENODEV;
56 } 67 }
@@ -60,7 +71,8 @@ int __init init_cyclone_clock(void)
60 offset = (base + CYCLONE_PMCC_OFFSET); 71 offset = (base + CYCLONE_PMCC_OFFSET);
61 reg = (u64*)ioremap_nocache(offset, sizeof(u64)); 72 reg = (u64*)ioremap_nocache(offset, sizeof(u64));
62 if(!reg){ 73 if(!reg){
63 printk(KERN_ERR "Summit chipset: Could not find valid PMCC register.\n"); 74 printk(KERN_ERR "Summit chipset: Could not find valid PMCC"
75 " register.\n");
64 use_cyclone = 0; 76 use_cyclone = 0;
65 return -ENODEV; 77 return -ENODEV;
66 } 78 }
@@ -71,7 +83,8 @@ int __init init_cyclone_clock(void)
71 offset = (base + CYCLONE_MPCS_OFFSET); 83 offset = (base + CYCLONE_MPCS_OFFSET);
72 reg = (u64*)ioremap_nocache(offset, sizeof(u64)); 84 reg = (u64*)ioremap_nocache(offset, sizeof(u64));
73 if(!reg){ 85 if(!reg){
74 printk(KERN_ERR "Summit chipset: Could not find valid MPCS register.\n"); 86 printk(KERN_ERR "Summit chipset: Could not find valid MPCS"
87 " register.\n");
75 use_cyclone = 0; 88 use_cyclone = 0;
76 return -ENODEV; 89 return -ENODEV;
77 } 90 }
@@ -82,7 +95,8 @@ int __init init_cyclone_clock(void)
82 offset = (base + CYCLONE_MPMC_OFFSET); 95 offset = (base + CYCLONE_MPMC_OFFSET);
83 cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32)); 96 cyclone_timer = (u32*)ioremap_nocache(offset, sizeof(u32));
84 if(!cyclone_timer){ 97 if(!cyclone_timer){
85 printk(KERN_ERR "Summit chipset: Could not find valid MPMC register.\n"); 98 printk(KERN_ERR "Summit chipset: Could not find valid MPMC"
99 " register.\n");
86 use_cyclone = 0; 100 use_cyclone = 0;
87 return -ENODEV; 101 return -ENODEV;
88 } 102 }
@@ -93,7 +107,8 @@ int __init init_cyclone_clock(void)
93 int stall = 100; 107 int stall = 100;
94 while(stall--) barrier(); 108 while(stall--) barrier();
95 if(readl(cyclone_timer) == old){ 109 if(readl(cyclone_timer) == old){
96 printk(KERN_ERR "Summit chipset: Counter not counting! DISABLED\n"); 110 printk(KERN_ERR "Summit chipset: Counter not counting!"
111 " DISABLED\n");
97 iounmap(cyclone_timer); 112 iounmap(cyclone_timer);
98 cyclone_timer = 0; 113 cyclone_timer = 0;
99 use_cyclone = 0; 114 use_cyclone = 0;
@@ -101,8 +116,11 @@ int __init init_cyclone_clock(void)
101 } 116 }
102 } 117 }
103 /* initialize last tick */ 118 /* initialize last tick */
104 cyclone_interpolator.addr = cyclone_timer; 119 cyclone_mc = cyclone_timer;
105 register_time_interpolator(&cyclone_interpolator); 120 clocksource_cyclone.fsys_mmio = cyclone_timer;
121 clocksource_cyclone.mult = clocksource_hz2mult(CYCLONE_TIMER_FREQ,
122 clocksource_cyclone.shift);
123 clocksource_register(&clocksource_cyclone);
106 124
107 return 0; 125 return 0;
108} 126}
diff --git a/arch/ia64/kernel/fsys.S b/arch/ia64/kernel/fsys.S
index 3f926c2dc708..44841971f077 100644
--- a/arch/ia64/kernel/fsys.S
+++ b/arch/ia64/kernel/fsys.S
@@ -147,12 +147,11 @@ ENTRY(fsys_set_tid_address)
147 FSYS_RETURN 147 FSYS_RETURN
148END(fsys_set_tid_address) 148END(fsys_set_tid_address)
149 149
150/* 150#if IA64_GTOD_LOCK_OFFSET !=0
151 * Ensure that the time interpolator structure is compatible with the asm code 151#error fsys_gettimeofday incompatible with changes to struct fsyscall_gtod_data_t
152 */ 152#endif
153#if IA64_TIME_INTERPOLATOR_SOURCE_OFFSET !=0 || IA64_TIME_INTERPOLATOR_SHIFT_OFFSET != 2 \ 153#if IA64_ITC_JITTER_OFFSET !=0
154 || IA64_TIME_INTERPOLATOR_JITTER_OFFSET != 3 || IA64_TIME_INTERPOLATOR_NSEC_OFFSET != 4 154#error fsys_gettimeofday incompatible with changes to struct itc_jitter_data_t
155#error fsys_gettimeofday incompatible with changes to struct time_interpolator
156#endif 155#endif
157#define CLOCK_REALTIME 0 156#define CLOCK_REALTIME 0
158#define CLOCK_MONOTONIC 1 157#define CLOCK_MONOTONIC 1
@@ -179,126 +178,124 @@ ENTRY(fsys_gettimeofday)
179 // r11 = preserved: saved ar.pfs 178 // r11 = preserved: saved ar.pfs
180 // r12 = preserved: memory stack 179 // r12 = preserved: memory stack
181 // r13 = preserved: thread pointer 180 // r13 = preserved: thread pointer
182 // r14 = address of mask / mask 181 // r14 = address of mask / mask value
183 // r15 = preserved: system call number 182 // r15 = preserved: system call number
184 // r16 = preserved: current task pointer 183 // r16 = preserved: current task pointer
185 // r17 = wall to monotonic use 184 // r17 = (not used)
186 // r18 = time_interpolator->offset 185 // r18 = (not used)
187 // r19 = address of wall_to_monotonic 186 // r19 = address of itc_lastcycle
188 // r20 = pointer to struct time_interpolator / pointer to time_interpolator->address 187 // r20 = struct fsyscall_gtod_data (= address of gtod_lock.sequence)
189 // r21 = shift factor 188 // r21 = address of mmio_ptr
190 // r22 = address of time interpolator->last_counter 189 // r22 = address of wall_time or monotonic_time
191 // r23 = address of time_interpolator->last_cycle 190 // r23 = address of shift / value
192 // r24 = adress of time_interpolator->offset 191 // r24 = address mult factor / cycle_last value
193 // r25 = last_cycle value 192 // r25 = itc_lastcycle value
194 // r26 = last_counter value 193 // r26 = address clocksource cycle_last
195 // r27 = pointer to xtime 194 // r27 = (not used)
196 // r28 = sequence number at the beginning of critcal section 195 // r28 = sequence number at the beginning of critcal section
197 // r29 = address of seqlock 196 // r29 = address of itc_jitter
198 // r30 = time processing flags / memory address 197 // r30 = time processing flags / memory address
199 // r31 = pointer to result 198 // r31 = pointer to result
200 // Predicates 199 // Predicates
201 // p6,p7 short term use 200 // p6,p7 short term use
202 // p8 = timesource ar.itc 201 // p8 = timesource ar.itc
203 // p9 = timesource mmio64 202 // p9 = timesource mmio64
204 // p10 = timesource mmio32 203 // p10 = timesource mmio32 - not used
205 // p11 = timesource not to be handled by asm code 204 // p11 = timesource not to be handled by asm code
206 // p12 = memory time source ( = p9 | p10) 205 // p12 = memory time source ( = p9 | p10) - not used
207 // p13 = do cmpxchg with time_interpolator_last_cycle 206 // p13 = do cmpxchg with itc_lastcycle
208 // p14 = Divide by 1000 207 // p14 = Divide by 1000
209 // p15 = Add monotonic 208 // p15 = Add monotonic
210 // 209 //
211 // Note that instructions are optimized for McKinley. McKinley can process two 210 // Note that instructions are optimized for McKinley. McKinley can
212 // bundles simultaneously and therefore we continuously try to feed the CPU 211 // process two bundles simultaneously and therefore we continuously
213 // two bundles and then a stop. 212 // try to feed the CPU two bundles and then a stop.
214 tnat.nz p6,p0 = r31 // branch deferred since it does not fit into bundle structure 213 //
214 // Additional note that code has changed a lot. Optimization is TBD.
215 // Comments begin with "?" are maybe outdated.
216 tnat.nz p6,p0 = r31 // ? branch deferred to fit later bundle
215 mov pr = r30,0xc000 // Set predicates according to function 217 mov pr = r30,0xc000 // Set predicates according to function
216 add r2 = TI_FLAGS+IA64_TASK_SIZE,r16 218 add r2 = TI_FLAGS+IA64_TASK_SIZE,r16
217 movl r20 = time_interpolator 219 movl r20 = fsyscall_gtod_data // load fsyscall gettimeofday data address
218 ;; 220 ;;
219 ld8 r20 = [r20] // get pointer to time_interpolator structure 221 movl r29 = itc_jitter_data // itc_jitter
220 movl r29 = xtime_lock 222 add r22 = IA64_GTOD_WALL_TIME_OFFSET,r20 // wall_time
221 ld4 r2 = [r2] // process work pending flags 223 ld4 r2 = [r2] // process work pending flags
222 movl r27 = xtime 224 ;;
223 ;; // only one bundle here 225(p15) add r22 = IA64_GTOD_MONO_TIME_OFFSET,r20 // monotonic_time
224 ld8 r21 = [r20] // first quad with control information 226 add r21 = IA64_CLKSRC_MMIO_OFFSET,r20
227 add r19 = IA64_ITC_LASTCYCLE_OFFSET,r29
225 and r2 = TIF_ALLWORK_MASK,r2 228 and r2 = TIF_ALLWORK_MASK,r2
226(p6) br.cond.spnt.few .fail_einval // deferred branch 229(p6) br.cond.spnt.few .fail_einval // ? deferred branch
227 ;; 230 ;;
228 add r10 = IA64_TIME_INTERPOLATOR_ADDRESS_OFFSET,r20 231 add r26 = IA64_CLKSRC_CYCLE_LAST_OFFSET,r20 // clksrc_cycle_last
229 extr r3 = r21,32,32 // time_interpolator->nsec_per_cyc
230 extr r8 = r21,0,16 // time_interpolator->source
231 cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled 232 cmp.ne p6, p0 = 0, r2 // Fallback if work is scheduled
232(p6) br.cond.spnt.many fsys_fallback_syscall 233(p6) br.cond.spnt.many fsys_fallback_syscall
233 ;; 234 ;;
234 cmp.eq p8,p12 = 0,r8 // Check for cpu timer 235 // Begin critical section
235 cmp.eq p9,p0 = 1,r8 // MMIO64 ? 236.time_redo:
236 extr r2 = r21,24,8 // time_interpolator->jitter 237 ld4.acq r28 = [r20] // gtod_lock.sequence, Must take first
237 cmp.eq p10,p0 = 2,r8 // MMIO32 ? 238 ;;
238 cmp.ltu p11,p0 = 2,r8 // function or other clock 239 and r28 = ~1,r28 // And make sequence even to force retry if odd
239(p11) br.cond.spnt.many fsys_fallback_syscall
240 ;; 240 ;;
241 setf.sig f7 = r3 // Setup for scaling of counter 241 ld8 r30 = [r21] // clocksource->mmio_ptr
242(p15) movl r19 = wall_to_monotonic 242 add r24 = IA64_CLKSRC_MULT_OFFSET,r20
243(p12) ld8 r30 = [r10] 243 ld4 r2 = [r29] // itc_jitter value
244 cmp.ne p13,p0 = r2,r0 // need jitter compensation? 244 add r23 = IA64_CLKSRC_SHIFT_OFFSET,r20
245 extr r21 = r21,16,8 // shift factor 245 add r14 = IA64_CLKSRC_MASK_OFFSET,r20
246 ;; 246 ;;
247.time_redo: 247 ld4 r3 = [r24] // clocksource mult value
248 .pred.rel.mutex p8,p9,p10 248 ld8 r14 = [r14] // clocksource mask value
249 ld4.acq r28 = [r29] // xtime_lock.sequence. Must come first for locking purposes 249 cmp.eq p8,p9 = 0,r30 // use cpu timer if no mmio_ptr
250 ;; 250 ;;
251 and r28 = ~1,r28 // Make sequence even to force retry if odd 251 setf.sig f7 = r3 // Setup for mult scaling of counter
252(p8) cmp.ne p13,p0 = r2,r0 // need itc_jitter compensation, set p13
253 ld4 r23 = [r23] // clocksource shift value
254 ld8 r24 = [r26] // get clksrc_cycle_last value
255(p9) cmp.eq p13,p0 = 0,r30 // if mmio_ptr, clear p13 jitter control
252 ;; 256 ;;
257 .pred.rel.mutex p8,p9
253(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!! 258(p8) mov r2 = ar.itc // CPU_TIMER. 36 clocks latency!!!
254 add r22 = IA64_TIME_INTERPOLATOR_LAST_COUNTER_OFFSET,r20 259(p9) ld8 r2 = [r30] // MMIO_TIMER. Could also have latency issues..
255(p9) ld8 r2 = [r30] // readq(ti->address). Could also have latency issues.. 260(p13) ld8 r25 = [r19] // get itc_lastcycle value
256(p10) ld4 r2 = [r30] // readw(ti->address) 261 ;; // ? could be removed by moving the last add upward
257(p13) add r23 = IA64_TIME_INTERPOLATOR_LAST_CYCLE_OFFSET,r20 262 ld8 r9 = [r22],IA64_TIMESPEC_TV_NSEC_OFFSET // tv_sec
258 ;; // could be removed by moving the last add upward 263 ;;
259 ld8 r26 = [r22] // time_interpolator->last_counter 264 ld8 r8 = [r22],-IA64_TIMESPEC_TV_NSEC_OFFSET // tv_nsec
260(p13) ld8 r25 = [r23] // time interpolator->last_cycle 265(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
261 add r24 = IA64_TIME_INTERPOLATOR_OFFSET_OFFSET,r20 266 ;;
262(p15) ld8 r17 = [r19],IA64_TIMESPEC_TV_NSEC_OFFSET 267(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
263 ld8 r9 = [r27],IA64_TIMESPEC_TV_NSEC_OFFSET 268 sub r10 = r2,r24 // current_cycle - last_cycle
264 add r14 = IA64_TIME_INTERPOLATOR_MASK_OFFSET, r20 269 ;;
265 ;; 270(p6) sub r10 = r25,r24 // time we got was less than last_cycle
266 ld8 r18 = [r24] // time_interpolator->offset
267 ld8 r8 = [r27],-IA64_TIMESPEC_TV_NSEC_OFFSET // xtime.tv_nsec
268(p13) sub r3 = r25,r2 // Diff needed before comparison (thanks davidm)
269 ;;
270 ld8 r14 = [r14] // time_interpolator->mask
271(p13) cmp.gt.unc p6,p7 = r3,r0 // check if it is less than last. p6,p7 cleared
272 sub r10 = r2,r26 // current_counter - last_counter
273 ;;
274(p6) sub r10 = r25,r26 // time we got was less than last_cycle
275(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg 271(p7) mov ar.ccv = r25 // more than last_cycle. Prep for cmpxchg
276 ;; 272 ;;
273(p7) cmpxchg8.rel r3 = [r19],r2,ar.ccv
274 ;;
275(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful
276 ;;
277(p7) sub r10 = r3,r24 // then use new last_cycle instead
278 ;;
277 and r10 = r10,r14 // Apply mask 279 and r10 = r10,r14 // Apply mask
278 ;; 280 ;;
279 setf.sig f8 = r10 281 setf.sig f8 = r10
280 nop.i 123 282 nop.i 123
281 ;; 283 ;;
282(p7) cmpxchg8.rel r3 = [r23],r2,ar.ccv 284 // fault check takes 5 cycles and we have spare time
283EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare time 285EX(.fail_efault, probe.w.fault r31, 3)
284 xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter) 286 xmpy.l f8 = f8,f7 // nsec_per_cyc*(counter-last_counter)
285(p15) add r9 = r9,r17 // Add wall to monotonic.secs to result secs
286 ;; 287 ;;
287(p15) ld8 r17 = [r19],-IA64_TIMESPEC_TV_NSEC_OFFSET 288 // ? simulate tbit.nz.or p7,p0 = r28,0
288(p7) cmp.ne p7,p0 = r25,r3 // if cmpxchg not successful redo
289 // simulate tbit.nz.or p7,p0 = r28,0
290 getf.sig r2 = f8 289 getf.sig r2 = f8
291 mf 290 mf
292 add r8 = r8,r18 // Add time interpolator offset
293 ;; 291 ;;
294 ld4 r10 = [r29] // xtime_lock.sequence 292 ld4 r10 = [r20] // gtod_lock.sequence
295(p15) add r8 = r8, r17 // Add monotonic.nsecs to nsecs 293 shr.u r2 = r2,r23 // shift by factor
296 shr.u r2 = r2,r21 294 ;; // ? overloaded 3 bundles!
297 ;; // overloaded 3 bundles!
298 // End critical section.
299 add r8 = r8,r2 // Add xtime.nsecs 295 add r8 = r8,r2 // Add xtime.nsecs
300 cmp4.ne.or p7,p0 = r28,r10 296 cmp4.ne p7,p0 = r28,r10
301(p7) br.cond.dpnt.few .time_redo // sequence number changed ? 297(p7) br.cond.dpnt.few .time_redo // sequence number changed, redo
298 // End critical section.
302 // Now r8=tv->tv_nsec and r9=tv->tv_sec 299 // Now r8=tv->tv_nsec and r9=tv->tv_sec
303 mov r10 = r0 300 mov r10 = r0
304 movl r2 = 1000000000 301 movl r2 = 1000000000
@@ -308,19 +305,19 @@ EX(.fail_efault, probe.w.fault r31, 3) // This takes 5 cycles and we have spare
308.time_normalize: 305.time_normalize:
309 mov r21 = r8 306 mov r21 = r8
310 cmp.ge p6,p0 = r8,r2 307 cmp.ge p6,p0 = r8,r2
311(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting some time 308(p14) shr.u r20 = r8, 3 // We can repeat this if necessary just wasting time
312 ;; 309 ;;
313(p14) setf.sig f8 = r20 310(p14) setf.sig f8 = r20
314(p6) sub r8 = r8,r2 311(p6) sub r8 = r8,r2
315(p6) add r9 = 1,r9 // two nops before the branch. 312(p6) add r9 = 1,r9 // two nops before the branch.
316(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod 313(p14) setf.sig f7 = r3 // Chances for repeats are 1 in 10000 for gettod
317(p6) br.cond.dpnt.few .time_normalize 314(p6) br.cond.dpnt.few .time_normalize
318 ;; 315 ;;
319 // Divided by 8 though shift. Now divide by 125 316 // Divided by 8 though shift. Now divide by 125
320 // The compiler was able to do that with a multiply 317 // The compiler was able to do that with a multiply
321 // and a shift and we do the same 318 // and a shift and we do the same
322EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles 319EX(.fail_efault, probe.w.fault r23, 3) // This also costs 5 cycles
323(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it... 320(p14) xmpy.hu f8 = f8, f7 // xmpy has 5 cycles latency so use it
324 ;; 321 ;;
325 mov r8 = r0 322 mov r8 = r0
326(p14) getf.sig r2 = f8 323(p14) getf.sig r2 = f8
diff --git a/arch/ia64/kernel/fsyscall_gtod_data.h b/arch/ia64/kernel/fsyscall_gtod_data.h
new file mode 100644
index 000000000000..490dab55fba3
--- /dev/null
+++ b/arch/ia64/kernel/fsyscall_gtod_data.h
@@ -0,0 +1,23 @@
1/*
2 * (c) Copyright 2007 Hewlett-Packard Development Company, L.P.
3 * Contributed by Peter Keilty <peter.keilty@hp.com>
4 *
5 * fsyscall gettimeofday data
6 */
7
8struct fsyscall_gtod_data_t {
9 seqlock_t lock;
10 struct timespec wall_time;
11 struct timespec monotonic_time;
12 cycle_t clk_mask;
13 u32 clk_mult;
14 u32 clk_shift;
15 void *clk_fsys_mmio;
16 cycle_t clk_cycle_last;
17} __attribute__ ((aligned (L1_CACHE_BYTES)));
18
19struct itc_jitter_data_t {
20 int itc_jitter;
21 cycle_t itc_lastcycle;
22} __attribute__ ((aligned (L1_CACHE_BYTES)));
23
diff --git a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
index 3486fe7d6e65..627785c48ea9 100644
--- a/arch/ia64/kernel/time.c
+++ b/arch/ia64/kernel/time.c
@@ -19,6 +19,7 @@
19#include <linux/interrupt.h> 19#include <linux/interrupt.h>
20#include <linux/efi.h> 20#include <linux/efi.h>
21#include <linux/timex.h> 21#include <linux/timex.h>
22#include <linux/clocksource.h>
22 23
23#include <asm/machvec.h> 24#include <asm/machvec.h>
24#include <asm/delay.h> 25#include <asm/delay.h>
@@ -28,6 +29,16 @@
28#include <asm/sections.h> 29#include <asm/sections.h>
29#include <asm/system.h> 30#include <asm/system.h>
30 31
32#include "fsyscall_gtod_data.h"
33
34static cycle_t itc_get_cycles(void);
35
36struct fsyscall_gtod_data_t fsyscall_gtod_data = {
37 .lock = SEQLOCK_UNLOCKED,
38};
39
40struct itc_jitter_data_t itc_jitter_data;
41
31volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */ 42volatile int time_keeper_id = 0; /* smp_processor_id() of time-keeper */
32 43
33#ifdef CONFIG_IA64_DEBUG_IRQ 44#ifdef CONFIG_IA64_DEBUG_IRQ
@@ -37,11 +48,16 @@ EXPORT_SYMBOL(last_cli_ip);
37 48
38#endif 49#endif
39 50
40static struct time_interpolator itc_interpolator = { 51static struct clocksource clocksource_itc = {
41 .shift = 16, 52 .name = "itc",
42 .mask = 0xffffffffffffffffLL, 53 .rating = 350,
43 .source = TIME_SOURCE_CPU 54 .read = itc_get_cycles,
55 .mask = 0xffffffffffffffff,
56 .mult = 0, /*to be caluclated*/
57 .shift = 16,
58 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
44}; 59};
60static struct clocksource *itc_clocksource;
45 61
46static irqreturn_t 62static irqreturn_t
47timer_interrupt (int irq, void *dev_id) 63timer_interrupt (int irq, void *dev_id)
@@ -210,8 +226,6 @@ ia64_init_itm (void)
210 + itc_freq/2)/itc_freq; 226 + itc_freq/2)/itc_freq;
211 227
212 if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) { 228 if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
213 itc_interpolator.frequency = local_cpu_data->itc_freq;
214 itc_interpolator.drift = itc_drift;
215#ifdef CONFIG_SMP 229#ifdef CONFIG_SMP
216 /* On IA64 in an SMP configuration ITCs are never accurately synchronized. 230 /* On IA64 in an SMP configuration ITCs are never accurately synchronized.
217 * Jitter compensation requires a cmpxchg which may limit 231 * Jitter compensation requires a cmpxchg which may limit
@@ -223,15 +237,50 @@ ia64_init_itm (void)
223 * even going backward) if the ITC offsets between the individual CPUs 237 * even going backward) if the ITC offsets between the individual CPUs
224 * are too large. 238 * are too large.
225 */ 239 */
226 if (!nojitter) itc_interpolator.jitter = 1; 240 if (!nojitter)
241 itc_jitter_data.itc_jitter = 1;
227#endif 242#endif
228 register_time_interpolator(&itc_interpolator);
229 } 243 }
230 244
231 /* Setup the CPU local timer tick */ 245 /* Setup the CPU local timer tick */
232 ia64_cpu_local_tick(); 246 ia64_cpu_local_tick();
247
248 if (!itc_clocksource) {
249 /* Sort out mult/shift values: */
250 clocksource_itc.mult =
251 clocksource_hz2mult(local_cpu_data->itc_freq,
252 clocksource_itc.shift);
253 clocksource_register(&clocksource_itc);
254 itc_clocksource = &clocksource_itc;
255 }
233} 256}
234 257
258static cycle_t itc_get_cycles()
259{
260 u64 lcycle, now, ret;
261
262 if (!itc_jitter_data.itc_jitter)
263 return get_cycles();
264
265 lcycle = itc_jitter_data.itc_lastcycle;
266 now = get_cycles();
267 if (lcycle && time_after(lcycle, now))
268 return lcycle;
269
270 /*
271 * Keep track of the last timer value returned.
272 * In an SMP environment, you could lose out in contention of
273 * cmpxchg. If so, your cmpxchg returns new value which the
274 * winner of contention updated to. Use the new value instead.
275 */
276 ret = cmpxchg(&itc_jitter_data.itc_lastcycle, lcycle, now);
277 if (unlikely(ret != lcycle))
278 return ret;
279
280 return now;
281}
282
283
235static struct irqaction timer_irqaction = { 284static struct irqaction timer_irqaction = {
236 .handler = timer_interrupt, 285 .handler = timer_interrupt,
237 .flags = IRQF_DISABLED | IRQF_IRQPOLL, 286 .flags = IRQF_DISABLED | IRQF_IRQPOLL,
@@ -307,3 +356,34 @@ ia64_setup_printk_clock(void)
307 if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) 356 if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT))
308 ia64_printk_clock = ia64_itc_printk_clock; 357 ia64_printk_clock = ia64_itc_printk_clock;
309} 358}
359
360void update_vsyscall(struct timespec *wall, struct clocksource *c)
361{
362 unsigned long flags;
363
364 write_seqlock_irqsave(&fsyscall_gtod_data.lock, flags);
365
366 /* copy fsyscall clock data */
367 fsyscall_gtod_data.clk_mask = c->mask;
368 fsyscall_gtod_data.clk_mult = c->mult;
369 fsyscall_gtod_data.clk_shift = c->shift;
370 fsyscall_gtod_data.clk_fsys_mmio = c->fsys_mmio;
371 fsyscall_gtod_data.clk_cycle_last = c->cycle_last;
372
373 /* copy kernel time structures */
374 fsyscall_gtod_data.wall_time.tv_sec = wall->tv_sec;
375 fsyscall_gtod_data.wall_time.tv_nsec = wall->tv_nsec;
376 fsyscall_gtod_data.monotonic_time.tv_sec = wall_to_monotonic.tv_sec
377 + wall->tv_sec;
378 fsyscall_gtod_data.monotonic_time.tv_nsec = wall_to_monotonic.tv_nsec
379 + wall->tv_nsec;
380
381 /* normalize */
382 while (fsyscall_gtod_data.monotonic_time.tv_nsec >= NSEC_PER_SEC) {
383 fsyscall_gtod_data.monotonic_time.tv_nsec -= NSEC_PER_SEC;
384 fsyscall_gtod_data.monotonic_time.tv_sec++;
385 }
386
387 write_sequnlock_irqrestore(&fsyscall_gtod_data.lock, flags);
388}
389
diff --git a/arch/ia64/sn/kernel/sn2/timer.c b/arch/ia64/sn/kernel/sn2/timer.c
index 56a88b6df4b4..19e25d2b64fc 100644
--- a/arch/ia64/sn/kernel/sn2/timer.c
+++ b/arch/ia64/sn/kernel/sn2/timer.c
@@ -11,6 +11,7 @@
11#include <linux/sched.h> 11#include <linux/sched.h>
12#include <linux/time.h> 12#include <linux/time.h>
13#include <linux/interrupt.h> 13#include <linux/interrupt.h>
14#include <linux/clocksource.h>
14 15
15#include <asm/hw_irq.h> 16#include <asm/hw_irq.h>
16#include <asm/system.h> 17#include <asm/system.h>
@@ -22,11 +23,21 @@
22 23
23extern unsigned long sn_rtc_cycles_per_second; 24extern unsigned long sn_rtc_cycles_per_second;
24 25
25static struct time_interpolator sn2_interpolator = { 26static void __iomem *sn2_mc;
26 .drift = -1, 27
27 .shift = 10, 28static cycle_t read_sn2(void)
28 .mask = (1LL << 55) - 1, 29{
29 .source = TIME_SOURCE_MMIO64 30 return (cycle_t)readq(sn2_mc);
31}
32
33static struct clocksource clocksource_sn2 = {
34 .name = "sn2_rtc",
35 .rating = 300,
36 .read = read_sn2,
37 .mask = (1LL << 55) - 1,
38 .mult = 0,
39 .shift = 10,
40 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
30}; 41};
31 42
32/* 43/*
@@ -47,9 +58,11 @@ ia64_sn_udelay (unsigned long usecs)
47 58
48void __init sn_timer_init(void) 59void __init sn_timer_init(void)
49{ 60{
50 sn2_interpolator.frequency = sn_rtc_cycles_per_second; 61 sn2_mc = RTC_COUNTER_ADDR;
51 sn2_interpolator.addr = RTC_COUNTER_ADDR; 62 clocksource_sn2.fsys_mmio = RTC_COUNTER_ADDR;
52 register_time_interpolator(&sn2_interpolator); 63 clocksource_sn2.mult = clocksource_hz2mult(sn_rtc_cycles_per_second,
64 clocksource_sn2.shift);
65 clocksource_register(&clocksource_sn2);
53 66
54 ia64_udelay = &ia64_sn_udelay; 67 ia64_udelay = &ia64_sn_udelay;
55} 68}