diff options
author | Ingo Molnar <mingo@elte.hu> | 2009-05-07 05:17:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-05-07 05:17:34 -0400 |
commit | 44347d947f628060b92449702071bfe1d31dfb75 (patch) | |
tree | c6ed74610d5b3295df4296659f80f5feb94b28cc /arch/s390/kernel/time.c | |
parent | d94fc523f3c35bd8013f04827e94756cbc0212f4 (diff) | |
parent | 413f81eba35d6ede9289b0c8a920c013a84fac71 (diff) |
Merge branch 'linus' into tracing/core
Merge reason: tracing/core was on a .30-rc1 base and was missing out on
on a handful of tracing fixes present in .30-rc5-almost.
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r-- | arch/s390/kernel/time.c | 79 |
1 files changed, 52 insertions, 27 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index f72d41068dc2..ef596d020573 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -52,9 +52,6 @@ | |||
52 | #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) | 52 | #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) |
53 | #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) | 53 | #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) |
54 | 54 | ||
55 | /* The value of the TOD clock for 1.1.1970. */ | ||
56 | #define TOD_UNIX_EPOCH 0x7d91048bca000000ULL | ||
57 | |||
58 | /* | 55 | /* |
59 | * Create a small time difference between the timer interrupts | 56 | * Create a small time difference between the timer interrupts |
60 | * on the different cpus to avoid lock contention. | 57 | * on the different cpus to avoid lock contention. |
@@ -63,9 +60,10 @@ | |||
63 | 60 | ||
64 | #define TICK_SIZE tick | 61 | #define TICK_SIZE tick |
65 | 62 | ||
63 | u64 sched_clock_base_cc = -1; /* Force to data section. */ | ||
64 | |||
66 | static ext_int_info_t ext_int_info_cc; | 65 | static ext_int_info_t ext_int_info_cc; |
67 | static ext_int_info_t ext_int_etr_cc; | 66 | static ext_int_info_t ext_int_etr_cc; |
68 | static u64 sched_clock_base_cc; | ||
69 | 67 | ||
70 | static DEFINE_PER_CPU(struct clock_event_device, comparators); | 68 | static DEFINE_PER_CPU(struct clock_event_device, comparators); |
71 | 69 | ||
@@ -195,25 +193,15 @@ static void timing_alert_interrupt(__u16 code) | |||
195 | static void etr_reset(void); | 193 | static void etr_reset(void); |
196 | static void stp_reset(void); | 194 | static void stp_reset(void); |
197 | 195 | ||
198 | /* | 196 | unsigned long read_persistent_clock(void) |
199 | * Get the TOD clock running. | ||
200 | */ | ||
201 | static u64 __init reset_tod_clock(void) | ||
202 | { | 197 | { |
203 | u64 time; | 198 | struct timespec ts; |
204 | |||
205 | etr_reset(); | ||
206 | stp_reset(); | ||
207 | if (store_clock(&time) == 0) | ||
208 | return time; | ||
209 | /* TOD clock not running. Set the clock to Unix Epoch. */ | ||
210 | if (set_clock(TOD_UNIX_EPOCH) != 0 || store_clock(&time) != 0) | ||
211 | panic("TOD clock not operational."); | ||
212 | 199 | ||
213 | return TOD_UNIX_EPOCH; | 200 | tod_to_timeval(get_clock() - TOD_UNIX_EPOCH, &ts); |
201 | return ts.tv_sec; | ||
214 | } | 202 | } |
215 | 203 | ||
216 | static cycle_t read_tod_clock(void) | 204 | static cycle_t read_tod_clock(struct clocksource *cs) |
217 | { | 205 | { |
218 | return get_clock(); | 206 | return get_clock(); |
219 | } | 207 | } |
@@ -265,12 +253,13 @@ void update_vsyscall_tz(void) | |||
265 | */ | 253 | */ |
266 | void __init time_init(void) | 254 | void __init time_init(void) |
267 | { | 255 | { |
268 | sched_clock_base_cc = reset_tod_clock(); | 256 | struct timespec ts; |
257 | unsigned long flags; | ||
258 | cycle_t now; | ||
269 | 259 | ||
270 | /* set xtime */ | 260 | /* Reset time synchronization interfaces. */ |
271 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &xtime); | 261 | etr_reset(); |
272 | set_normalized_timespec(&wall_to_monotonic, | 262 | stp_reset(); |
273 | -xtime.tv_sec, -xtime.tv_nsec); | ||
274 | 263 | ||
275 | /* request the clock comparator external interrupt */ | 264 | /* request the clock comparator external interrupt */ |
276 | if (register_early_external_interrupt(0x1004, | 265 | if (register_early_external_interrupt(0x1004, |
@@ -278,17 +267,38 @@ void __init time_init(void) | |||
278 | &ext_int_info_cc) != 0) | 267 | &ext_int_info_cc) != 0) |
279 | panic("Couldn't request external interrupt 0x1004"); | 268 | panic("Couldn't request external interrupt 0x1004"); |
280 | 269 | ||
281 | if (clocksource_register(&clocksource_tod) != 0) | ||
282 | panic("Could not register TOD clock source"); | ||
283 | |||
284 | /* request the timing alert external interrupt */ | 270 | /* request the timing alert external interrupt */ |
285 | if (register_early_external_interrupt(0x1406, | 271 | if (register_early_external_interrupt(0x1406, |
286 | timing_alert_interrupt, | 272 | timing_alert_interrupt, |
287 | &ext_int_etr_cc) != 0) | 273 | &ext_int_etr_cc) != 0) |
288 | panic("Couldn't request external interrupt 0x1406"); | 274 | panic("Couldn't request external interrupt 0x1406"); |
289 | 275 | ||
276 | if (clocksource_register(&clocksource_tod) != 0) | ||
277 | panic("Could not register TOD clock source"); | ||
278 | |||
279 | /* | ||
280 | * The TOD clock is an accurate clock. The xtime should be | ||
281 | * initialized in a way that the difference between TOD and | ||
282 | * xtime is reasonably small. Too bad that timekeeping_init | ||
283 | * sets xtime.tv_nsec to zero. In addition the clock source | ||
284 | * change from the jiffies clock source to the TOD clock | ||
285 | * source add another error of up to 1/HZ second. The same | ||
286 | * function sets wall_to_monotonic to a value that is too | ||
287 | * small for /proc/uptime to be accurate. | ||
288 | * Reset xtime and wall_to_monotonic to sane values. | ||
289 | */ | ||
290 | write_seqlock_irqsave(&xtime_lock, flags); | ||
291 | now = get_clock(); | ||
292 | tod_to_timeval(now - TOD_UNIX_EPOCH, &xtime); | ||
293 | clocksource_tod.cycle_last = now; | ||
294 | clocksource_tod.raw_time = xtime; | ||
295 | tod_to_timeval(sched_clock_base_cc - TOD_UNIX_EPOCH, &ts); | ||
296 | set_normalized_timespec(&wall_to_monotonic, -ts.tv_sec, -ts.tv_nsec); | ||
297 | write_sequnlock_irqrestore(&xtime_lock, flags); | ||
298 | |||
290 | /* Enable TOD clock interrupts on the boot cpu. */ | 299 | /* Enable TOD clock interrupts on the boot cpu. */ |
291 | init_cpu_timer(); | 300 | init_cpu_timer(); |
301 | |||
292 | /* Enable cpu timer interrupts on the boot cpu. */ | 302 | /* Enable cpu timer interrupts on the boot cpu. */ |
293 | vtime_init(); | 303 | vtime_init(); |
294 | } | 304 | } |
@@ -1423,6 +1433,7 @@ static void *stp_page; | |||
1423 | static void stp_work_fn(struct work_struct *work); | 1433 | static void stp_work_fn(struct work_struct *work); |
1424 | static DEFINE_MUTEX(stp_work_mutex); | 1434 | static DEFINE_MUTEX(stp_work_mutex); |
1425 | static DECLARE_WORK(stp_work, stp_work_fn); | 1435 | static DECLARE_WORK(stp_work, stp_work_fn); |
1436 | static struct timer_list stp_timer; | ||
1426 | 1437 | ||
1427 | static int __init early_parse_stp(char *p) | 1438 | static int __init early_parse_stp(char *p) |
1428 | { | 1439 | { |
@@ -1454,10 +1465,16 @@ static void __init stp_reset(void) | |||
1454 | } | 1465 | } |
1455 | } | 1466 | } |
1456 | 1467 | ||
1468 | static void stp_timeout(unsigned long dummy) | ||
1469 | { | ||
1470 | queue_work(time_sync_wq, &stp_work); | ||
1471 | } | ||
1472 | |||
1457 | static int __init stp_init(void) | 1473 | static int __init stp_init(void) |
1458 | { | 1474 | { |
1459 | if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) | 1475 | if (!test_bit(CLOCK_SYNC_HAS_STP, &clock_sync_flags)) |
1460 | return 0; | 1476 | return 0; |
1477 | setup_timer(&stp_timer, stp_timeout, 0UL); | ||
1461 | time_init_wq(); | 1478 | time_init_wq(); |
1462 | if (!stp_online) | 1479 | if (!stp_online) |
1463 | return 0; | 1480 | return 0; |
@@ -1565,6 +1582,7 @@ static void stp_work_fn(struct work_struct *work) | |||
1565 | 1582 | ||
1566 | if (!stp_online) { | 1583 | if (!stp_online) { |
1567 | chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); | 1584 | chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); |
1585 | del_timer_sync(&stp_timer); | ||
1568 | goto out_unlock; | 1586 | goto out_unlock; |
1569 | } | 1587 | } |
1570 | 1588 | ||
@@ -1586,6 +1604,13 @@ static void stp_work_fn(struct work_struct *work) | |||
1586 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); | 1604 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); |
1587 | put_online_cpus(); | 1605 | put_online_cpus(); |
1588 | 1606 | ||
1607 | if (!check_sync_clock()) | ||
1608 | /* | ||
1609 | * There is a usable clock but the synchonization failed. | ||
1610 | * Retry after a second. | ||
1611 | */ | ||
1612 | mod_timer(&stp_timer, jiffies + HZ); | ||
1613 | |||
1589 | out_unlock: | 1614 | out_unlock: |
1590 | mutex_unlock(&stp_work_mutex); | 1615 | mutex_unlock(&stp_work_mutex); |
1591 | } | 1616 | } |