diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-02-05 15:18:19 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2007-02-05 15:18:19 -0500 |
commit | d54853ef8cb17296ac7bce9c77430fb7c80532d0 (patch) | |
tree | 649e14d532e17231225a042a7c9a3d9207ad91ee /arch/s390/lib/delay.c | |
parent | c1821c2e9711adc3cd298a16b7237c92a2cee78d (diff) |
[S390] ETR support.
This patch adds support for clock synchronization to an external time
reference (ETR). The external time reference sends an oscillator
signal and a synchronization signal every 2^20 microseconds to keep
the TOD clocks of all connected servers in sync. For availability
two ETR units can be connected to a machine. If the clock deviates
for more than the sync-check tolerance all cpus get a machine check
that indicates that the clock is out of sync. For the lovely details
how to get the clock back in sync see the code below.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/lib/delay.c')
-rw-r--r-- | arch/s390/lib/delay.c | 48 |
1 files changed, 34 insertions, 14 deletions
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index 027c4742a001..02854449b74b 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * arch/s390/kernel/delay.c | 2 | * arch/s390/lib/delay.c |
3 | * Precise Delay Loops for S390 | 3 | * Precise Delay Loops for S390 |
4 | * | 4 | * |
5 | * S390 version | 5 | * S390 version |
@@ -13,10 +13,8 @@ | |||
13 | 13 | ||
14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | 16 | #include <linux/timex.h> | |
17 | #ifdef CONFIG_SMP | 17 | #include <linux/irqflags.h> |
18 | #include <asm/smp.h> | ||
19 | #endif | ||
20 | 18 | ||
21 | void __delay(unsigned long loops) | 19 | void __delay(unsigned long loops) |
22 | { | 20 | { |
@@ -31,17 +29,39 @@ void __delay(unsigned long loops) | |||
31 | } | 29 | } |
32 | 30 | ||
33 | /* | 31 | /* |
34 | * Waits for 'usecs' microseconds using the tod clock, giving up the time slice | 32 | * Waits for 'usecs' microseconds using the TOD clock comparator. |
35 | * of the virtual PU inbetween to avoid congestion. | ||
36 | */ | 33 | */ |
37 | void __udelay(unsigned long usecs) | 34 | void __udelay(unsigned long usecs) |
38 | { | 35 | { |
39 | uint64_t start_cc; | 36 | u64 end, time, jiffy_timer = 0; |
37 | unsigned long flags, cr0, mask, dummy; | ||
38 | |||
39 | local_irq_save(flags); | ||
40 | if (raw_irqs_disabled_flags(flags)) { | ||
41 | jiffy_timer = S390_lowcore.jiffy_timer; | ||
42 | S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); | ||
43 | __ctl_store(cr0, 0, 0); | ||
44 | dummy = (cr0 & 0xffff00e0) | 0x00000800; | ||
45 | __ctl_load(dummy , 0, 0); | ||
46 | mask = psw_kernel_bits | PSW_MASK_WAIT | PSW_MASK_EXT; | ||
47 | } else | ||
48 | mask = psw_kernel_bits | PSW_MASK_WAIT | | ||
49 | PSW_MASK_EXT | PSW_MASK_IO; | ||
50 | |||
51 | end = get_clock() + ((u64) usecs << 12); | ||
52 | do { | ||
53 | time = end < S390_lowcore.jiffy_timer ? | ||
54 | end : S390_lowcore.jiffy_timer; | ||
55 | set_clock_comparator(time); | ||
56 | trace_hardirqs_on(); | ||
57 | __load_psw_mask(mask); | ||
58 | local_irq_disable(); | ||
59 | } while (get_clock() < end); | ||
40 | 60 | ||
41 | if (usecs == 0) | 61 | if (raw_irqs_disabled_flags(flags)) { |
42 | return; | 62 | __ctl_load(cr0, 0, 0); |
43 | start_cc = get_clock(); | 63 | S390_lowcore.jiffy_timer = jiffy_timer; |
44 | do { | 64 | } |
45 | cpu_relax(); | 65 | set_clock_comparator(S390_lowcore.jiffy_timer); |
46 | } while (((get_clock() - start_cc)/4096) < usecs); | 66 | local_irq_restore(flags); |
47 | } | 67 | } |