aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:46:25 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-04-17 01:47:05 -0400
commit5a62b192196af9a798e2f2f4c6a1324e7edf2f4b (patch)
tree0aa96ba3153b257000be22e49befbde2b5bd6917 /arch/s390
parentd7b906897e9caae452947e33674df0a2d6f7e10f (diff)
[S390] Convert s390 to GENERIC_CLOCKEVENTS.
This way we get rid of s390's NO_IDLE_HZ and use the generic dynticks variant instead. In addition we get high resolution timers for free. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/Kconfig24
-rw-r--r--arch/s390/kernel/process.c4
-rw-r--r--arch/s390/kernel/s390_ext.c9
-rw-r--r--arch/s390/kernel/setup.c2
-rw-r--r--arch/s390/kernel/time.c256
-rw-r--r--arch/s390/lib/delay.c14
6 files changed, 92 insertions, 217 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig
index da6ea64cc34d..f6a68e178fc5 100644
--- a/arch/s390/Kconfig
+++ b/arch/s390/Kconfig
@@ -43,6 +43,9 @@ config GENERIC_HWEIGHT
43config GENERIC_TIME 43config GENERIC_TIME
44 def_bool y 44 def_bool y
45 45
46config GENERIC_CLOCKEVENTS
47 def_bool y
48
46config GENERIC_BUG 49config GENERIC_BUG
47 bool 50 bool
48 depends on BUG 51 depends on BUG
@@ -73,6 +76,8 @@ menu "Base setup"
73 76
74comment "Processor type and features" 77comment "Processor type and features"
75 78
79source "kernel/time/Kconfig"
80
76config 64BIT 81config 64BIT
77 bool "64 bit kernel" 82 bool "64 bit kernel"
78 help 83 help
@@ -487,25 +492,6 @@ config APPLDATA_NET_SUM
487 492
488source kernel/Kconfig.hz 493source kernel/Kconfig.hz
489 494
490config NO_IDLE_HZ
491 bool "No HZ timer ticks in idle"
492 help
493 Switches the regular HZ timer off when the system is going idle.
494 This helps z/VM to detect that the Linux system is idle. VM can
495 then "swap-out" this guest which reduces memory usage. It also
496 reduces the overhead of idle systems.
497
498 The HZ timer can be switched on/off via /proc/sys/kernel/hz_timer.
499 hz_timer=0 means HZ timer is disabled. hz_timer=1 means HZ
500 timer is active.
501
502config NO_IDLE_HZ_INIT
503 bool "HZ timer in idle off by default"
504 depends on NO_IDLE_HZ
505 help
506 The HZ timer is switched off in idle by default. That means the
507 HZ timer is already disabled at boot time.
508
509config S390_HYPFS_FS 495config S390_HYPFS_FS
510 bool "s390 hypervisor file system support" 496 bool "s390 hypervisor file system support"
511 select SYS_HYPERVISOR 497 select SYS_HYPERVISOR
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index eb768ce88672..df033249f6b1 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -36,6 +36,7 @@
36#include <linux/module.h> 36#include <linux/module.h>
37#include <linux/notifier.h> 37#include <linux/notifier.h>
38#include <linux/utsname.h> 38#include <linux/utsname.h>
39#include <linux/tick.h>
39#include <asm/uaccess.h> 40#include <asm/uaccess.h>
40#include <asm/pgtable.h> 41#include <asm/pgtable.h>
41#include <asm/system.h> 42#include <asm/system.h>
@@ -167,9 +168,10 @@ static void default_idle(void)
167void cpu_idle(void) 168void cpu_idle(void)
168{ 169{
169 for (;;) { 170 for (;;) {
171 tick_nohz_stop_sched_tick();
170 while (!need_resched()) 172 while (!need_resched())
171 default_idle(); 173 default_idle();
172 174 tick_nohz_restart_sched_tick();
173 preempt_enable_no_resched(); 175 preempt_enable_no_resched();
174 schedule(); 176 schedule();
175 preempt_disable(); 177 preempt_disable();
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c
index 3a8772d3baea..947d8c74403b 100644
--- a/arch/s390/kernel/s390_ext.c
+++ b/arch/s390/kernel/s390_ext.c
@@ -120,12 +120,9 @@ void do_extint(struct pt_regs *regs, unsigned short code)
120 old_regs = set_irq_regs(regs); 120 old_regs = set_irq_regs(regs);
121 irq_enter(); 121 irq_enter();
122 s390_idle_check(); 122 s390_idle_check();
123 if (S390_lowcore.int_clock >= S390_lowcore.jiffy_timer) 123 if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator)
124 /** 124 /* Serve timer interrupts first. */
125 * Make sure that the i/o interrupt did not "overtake" 125 clock_comparator_work();
126 * the last HZ timer interrupt.
127 */
128 account_ticks(S390_lowcore.int_clock);
129 kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++; 126 kstat_cpu(smp_processor_id()).irqs[EXTERNAL_INTERRUPT]++;
130 index = ext_hash(code); 127 index = ext_hash(code);
131 for (p = ext_int_hash[index]; p; p = p->next) { 128 for (p = ext_int_hash[index]; p; p = p->next) {
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 22040d087d8a..7141147e6b63 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -428,7 +428,7 @@ setup_lowcore(void)
428 lc->io_new_psw.mask = psw_kernel_bits; 428 lc->io_new_psw.mask = psw_kernel_bits;
429 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler; 429 lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;
430 lc->ipl_device = S390_lowcore.ipl_device; 430 lc->ipl_device = S390_lowcore.ipl_device;
431 lc->jiffy_timer = -1LL; 431 lc->clock_comparator = -1ULL;
432 lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE; 432 lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
433 lc->async_stack = (unsigned long) 433 lc->async_stack = (unsigned long)
434 __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE; 434 __alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 925f9dc0b0a0..17c4de9e1b6b 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -30,7 +30,7 @@
30#include <linux/timex.h> 30#include <linux/timex.h>
31#include <linux/notifier.h> 31#include <linux/notifier.h>
32#include <linux/clocksource.h> 32#include <linux/clocksource.h>
33 33#include <linux/clockchips.h>
34#include <asm/uaccess.h> 34#include <asm/uaccess.h>
35#include <asm/delay.h> 35#include <asm/delay.h>
36#include <asm/s390_ext.h> 36#include <asm/s390_ext.h>
@@ -57,9 +57,9 @@
57 57
58static ext_int_info_t ext_int_info_cc; 58static ext_int_info_t ext_int_info_cc;
59static ext_int_info_t ext_int_etr_cc; 59static ext_int_info_t ext_int_etr_cc;
60static u64 init_timer_cc;
61static u64 jiffies_timer_cc; 60static u64 jiffies_timer_cc;
62static u64 xtime_cc; 61
62static DEFINE_PER_CPU(struct clock_event_device, comparators);
63 63
64/* 64/*
65 * Scheduler clock - returns current time in nanosec units. 65 * Scheduler clock - returns current time in nanosec units.
@@ -95,162 +95,40 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
95#define s390_do_profile() do { ; } while(0) 95#define s390_do_profile() do { ; } while(0)
96#endif /* CONFIG_PROFILING */ 96#endif /* CONFIG_PROFILING */
97 97
98/* 98void clock_comparator_work(void)
99 * Advance the per cpu tick counter up to the time given with the
100 * "time" argument. The per cpu update consists of accounting
101 * the virtual cpu time, calling update_process_times and calling
102 * the profiling hook. If xtime is before time it is advanced as well.
103 */
104void account_ticks(u64 time)
105{ 99{
106 __u32 ticks; 100 struct clock_event_device *cd;
107 __u64 tmp;
108
109 /* Calculate how many ticks have passed. */
110 if (time < S390_lowcore.jiffy_timer)
111 return;
112 tmp = time - S390_lowcore.jiffy_timer;
113 if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */
114 ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
115 S390_lowcore.jiffy_timer +=
116 CLK_TICKS_PER_JIFFY * (__u64) ticks;
117 } else if (tmp >= CLK_TICKS_PER_JIFFY) {
118 ticks = 2;
119 S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
120 } else {
121 ticks = 1;
122 S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
123 }
124
125#ifdef CONFIG_SMP
126 /*
127 * Do not rely on the boot cpu to do the calls to do_timer.
128 * Spread it over all cpus instead.
129 */
130 write_seqlock(&xtime_lock);
131 if (S390_lowcore.jiffy_timer > xtime_cc) {
132 __u32 xticks;
133 tmp = S390_lowcore.jiffy_timer - xtime_cc;
134 if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
135 xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
136 xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY;
137 } else {
138 xticks = 1;
139 xtime_cc += CLK_TICKS_PER_JIFFY;
140 }
141 do_timer(xticks);
142 }
143 write_sequnlock(&xtime_lock);
144#else
145 do_timer(ticks);
146#endif
147
148 while (ticks--)
149 update_process_times(user_mode(get_irq_regs()));
150 101
102 S390_lowcore.clock_comparator = -1ULL;
103 set_clock_comparator(S390_lowcore.clock_comparator);
104 cd = &__get_cpu_var(comparators);
105 cd->event_handler(cd);
151 s390_do_profile(); 106 s390_do_profile();
152} 107}
153 108
154#ifdef CONFIG_NO_IDLE_HZ
155
156#ifdef CONFIG_NO_IDLE_HZ_INIT
157int sysctl_hz_timer = 0;
158#else
159int sysctl_hz_timer = 1;
160#endif
161
162/*
163 * Stop the HZ tick on the current CPU.
164 * Only cpu_idle may call this function.
165 */
166static void stop_hz_timer(void)
167{
168 unsigned long flags;
169 unsigned long seq, next;
170 __u64 timer, todval;
171 int cpu = smp_processor_id();
172
173 if (sysctl_hz_timer != 0)
174 return;
175
176 cpu_set(cpu, nohz_cpu_mask);
177
178 /*
179 * Leave the clock comparator set up for the next timer
180 * tick if either rcu or a softirq is pending.
181 */
182 if (rcu_needs_cpu(cpu) || local_softirq_pending()) {
183 cpu_clear(cpu, nohz_cpu_mask);
184 return;
185 }
186
187 /*
188 * This cpu is going really idle. Set up the clock comparator
189 * for the next event.
190 */
191 next = next_timer_interrupt();
192 do {
193 seq = read_seqbegin_irqsave(&xtime_lock, flags);
194 timer = ((__u64) next) - ((__u64) jiffies) + jiffies_64;
195 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
196 todval = -1ULL;
197 /* Be careful about overflows. */
198 if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) {
199 timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
200 if (timer >= jiffies_timer_cc)
201 todval = timer;
202 }
203 set_clock_comparator(todval);
204}
205
206/* 109/*
207 * Start the HZ tick on the current CPU. 110 * Fixup the clock comparator.
208 * Only cpu_idle may call this function.
209 */ 111 */
210static void start_hz_timer(void) 112static void fixup_clock_comparator(unsigned long long delta)
211{ 113{
212 if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) 114 /* If nobody is waiting there's nothing to fix. */
115 if (S390_lowcore.clock_comparator == -1ULL)
213 return; 116 return;
214 account_ticks(get_clock()); 117 S390_lowcore.clock_comparator += delta;
215 set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION); 118 set_clock_comparator(S390_lowcore.clock_comparator);
216 cpu_clear(smp_processor_id(), nohz_cpu_mask);
217}
218
219static int nohz_idle_notify(struct notifier_block *self,
220 unsigned long action, void *hcpu)
221{
222 switch (action) {
223 case S390_CPU_IDLE:
224 stop_hz_timer();
225 break;
226 case S390_CPU_NOT_IDLE:
227 start_hz_timer();
228 break;
229 }
230 return NOTIFY_OK;
231} 119}
232 120
233static struct notifier_block nohz_idle_nb = { 121static int s390_next_event(unsigned long delta,
234 .notifier_call = nohz_idle_notify, 122 struct clock_event_device *evt)
235};
236
237static void __init nohz_init(void)
238{ 123{
239 if (register_idle_notifier(&nohz_idle_nb)) 124 S390_lowcore.clock_comparator = get_clock() + delta;
240 panic("Couldn't register idle notifier"); 125 set_clock_comparator(S390_lowcore.clock_comparator);
126 return 0;
241} 127}
242 128
243#endif 129static void s390_set_mode(enum clock_event_mode mode,
244 130 struct clock_event_device *evt)
245/*
246 * Set up per cpu jiffy timer and set the clock comparator.
247 */
248static void setup_jiffy_timer(void)
249{ 131{
250 /* Set up clock comparator to next jiffy. */
251 S390_lowcore.jiffy_timer =
252 jiffies_timer_cc + (jiffies_64 + 1) * CLK_TICKS_PER_JIFFY;
253 set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
254} 132}
255 133
256/* 134/*
@@ -259,7 +137,26 @@ static void setup_jiffy_timer(void)
259 */ 137 */
260void init_cpu_timer(void) 138void init_cpu_timer(void)
261{ 139{
262 setup_jiffy_timer(); 140 struct clock_event_device *cd;
141 int cpu;
142
143 S390_lowcore.clock_comparator = -1ULL;
144 set_clock_comparator(S390_lowcore.clock_comparator);
145
146 cpu = smp_processor_id();
147 cd = &per_cpu(comparators, cpu);
148 cd->name = "comparator";
149 cd->features = CLOCK_EVT_FEAT_ONESHOT;
150 cd->mult = 16777;
151 cd->shift = 12;
152 cd->min_delta_ns = 1;
153 cd->max_delta_ns = LONG_MAX;
154 cd->rating = 400;
155 cd->cpumask = cpumask_of_cpu(cpu);
156 cd->set_next_event = s390_next_event;
157 cd->set_mode = s390_set_mode;
158
159 clockevents_register_device(cd);
263 160
264 /* Enable clock comparator timer interrupt. */ 161 /* Enable clock comparator timer interrupt. */
265 __ctl_set_bit(0,11); 162 __ctl_set_bit(0,11);
@@ -270,8 +167,6 @@ void init_cpu_timer(void)
270 167
271static void clock_comparator_interrupt(__u16 code) 168static void clock_comparator_interrupt(__u16 code)
272{ 169{
273 /* set clock comparator for next tick */
274 set_clock_comparator(S390_lowcore.jiffy_timer + CPU_DEVIATION);
275} 170}
276 171
277static void etr_reset(void); 172static void etr_reset(void);
@@ -316,8 +211,9 @@ static struct clocksource clocksource_tod = {
316 */ 211 */
317void __init time_init(void) 212void __init time_init(void)
318{ 213{
214 u64 init_timer_cc;
215
319 init_timer_cc = reset_tod_clock(); 216 init_timer_cc = reset_tod_clock();
320 xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
321 jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; 217 jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
322 218
323 /* set xtime */ 219 /* set xtime */
@@ -342,10 +238,6 @@ void __init time_init(void)
342 /* Enable TOD clock interrupts on the boot cpu. */ 238 /* Enable TOD clock interrupts on the boot cpu. */
343 init_cpu_timer(); 239 init_cpu_timer();
344 240
345#ifdef CONFIG_NO_IDLE_HZ
346 nohz_init();
347#endif
348
349#ifdef CONFIG_VIRT_TIMER 241#ifdef CONFIG_VIRT_TIMER
350 vtime_init(); 242 vtime_init();
351#endif 243#endif
@@ -699,53 +591,49 @@ static int etr_aib_follows(struct etr_aib *a1, struct etr_aib *a2, int p)
699} 591}
700 592
701/* 593/*
702 * The time is "clock". xtime is what we think the time is. 594 * The time is "clock". old is what we think the time is.
703 * Adjust the value by a multiple of jiffies and add the delta to ntp. 595 * Adjust the value by a multiple of jiffies and add the delta to ntp.
704 * "delay" is an approximation how long the synchronization took. If 596 * "delay" is an approximation how long the synchronization took. If
705 * the time correction is positive, then "delay" is subtracted from 597 * the time correction is positive, then "delay" is subtracted from
706 * the time difference and only the remaining part is passed to ntp. 598 * the time difference and only the remaining part is passed to ntp.
707 */ 599 */
708static void etr_adjust_time(unsigned long long clock, unsigned long long delay) 600static unsigned long long etr_adjust_time(unsigned long long old,
601 unsigned long long clock,
602 unsigned long long delay)
709{ 603{
710 unsigned long long delta, ticks; 604 unsigned long long delta, ticks;
711 struct timex adjust; 605 struct timex adjust;
712 606
713 /* 607 if (clock > old) {
714 * We don't have to take the xtime lock because the cpu
715 * executing etr_adjust_time is running disabled in
716 * tasklet context and all other cpus are looping in
717 * etr_sync_cpu_start.
718 */
719 if (clock > xtime_cc) {
720 /* It is later than we thought. */ 608 /* It is later than we thought. */
721 delta = ticks = clock - xtime_cc; 609 delta = ticks = clock - old;
722 delta = ticks = (delta < delay) ? 0 : delta - delay; 610 delta = ticks = (delta < delay) ? 0 : delta - delay;
723 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); 611 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
724 init_timer_cc = init_timer_cc + delta;
725 jiffies_timer_cc = jiffies_timer_cc + delta;
726 xtime_cc = xtime_cc + delta;
727 adjust.offset = ticks * (1000000 / HZ); 612 adjust.offset = ticks * (1000000 / HZ);
728 } else { 613 } else {
729 /* It is earlier than we thought. */ 614 /* It is earlier than we thought. */
730 delta = ticks = xtime_cc - clock; 615 delta = ticks = old - clock;
731 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY); 616 delta -= do_div(ticks, CLK_TICKS_PER_JIFFY);
732 init_timer_cc = init_timer_cc - delta; 617 delta = -delta;
733 jiffies_timer_cc = jiffies_timer_cc - delta;
734 xtime_cc = xtime_cc - delta;
735 adjust.offset = -ticks * (1000000 / HZ); 618 adjust.offset = -ticks * (1000000 / HZ);
736 } 619 }
620 jiffies_timer_cc += delta;
737 if (adjust.offset != 0) { 621 if (adjust.offset != 0) {
738 printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n", 622 printk(KERN_NOTICE "etr: time adjusted by %li micro-seconds\n",
739 adjust.offset); 623 adjust.offset);
740 adjust.modes = ADJ_OFFSET_SINGLESHOT; 624 adjust.modes = ADJ_OFFSET_SINGLESHOT;
741 do_adjtimex(&adjust); 625 do_adjtimex(&adjust);
742 } 626 }
627 return delta;
743} 628}
744 629
630static struct {
631 int in_sync;
632 unsigned long long fixup_cc;
633} etr_sync;
634
745static void etr_sync_cpu_start(void *dummy) 635static void etr_sync_cpu_start(void *dummy)
746{ 636{
747 int *in_sync = dummy;
748
749 etr_enable_sync_clock(); 637 etr_enable_sync_clock();
750 /* 638 /*
751 * This looks like a busy wait loop but it isn't. etr_sync_cpus 639 * This looks like a busy wait loop but it isn't. etr_sync_cpus
@@ -753,7 +641,7 @@ static void etr_sync_cpu_start(void *dummy)
753 * __udelay will stop the cpu on an enabled wait psw until the 641 * __udelay will stop the cpu on an enabled wait psw until the
754 * TOD is running again. 642 * TOD is running again.
755 */ 643 */
756 while (*in_sync == 0) { 644 while (etr_sync.in_sync == 0) {
757 __udelay(1); 645 __udelay(1);
758 /* 646 /*
759 * A different cpu changes *in_sync. Therefore use 647 * A different cpu changes *in_sync. Therefore use
@@ -761,14 +649,14 @@ static void etr_sync_cpu_start(void *dummy)
761 */ 649 */
762 barrier(); 650 barrier();
763 } 651 }
764 if (*in_sync != 1) 652 if (etr_sync.in_sync != 1)
765 /* Didn't work. Clear per-cpu in sync bit again. */ 653 /* Didn't work. Clear per-cpu in sync bit again. */
766 etr_disable_sync_clock(NULL); 654 etr_disable_sync_clock(NULL);
767 /* 655 /*
768 * This round of TOD syncing is done. Set the clock comparator 656 * This round of TOD syncing is done. Set the clock comparator
769 * to the next tick and let the processor continue. 657 * to the next tick and let the processor continue.
770 */ 658 */
771 setup_jiffy_timer(); 659 fixup_clock_comparator(etr_sync.fixup_cc);
772} 660}
773 661
774static void etr_sync_cpu_end(void *dummy) 662static void etr_sync_cpu_end(void *dummy)
@@ -783,8 +671,8 @@ static void etr_sync_cpu_end(void *dummy)
783static int etr_sync_clock(struct etr_aib *aib, int port) 671static int etr_sync_clock(struct etr_aib *aib, int port)
784{ 672{
785 struct etr_aib *sync_port; 673 struct etr_aib *sync_port;
786 unsigned long long clock, delay; 674 unsigned long long clock, old_clock, delay, delta;
787 int in_sync, follows; 675 int follows;
788 int rc; 676 int rc;
789 677
790 /* Check if the current aib is adjacent to the sync port aib. */ 678 /* Check if the current aib is adjacent to the sync port aib. */
@@ -799,9 +687,9 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
799 * successfully synced the clock. smp_call_function will 687 * successfully synced the clock. smp_call_function will
800 * return after all other cpus are in etr_sync_cpu_start. 688 * return after all other cpus are in etr_sync_cpu_start.
801 */ 689 */
802 in_sync = 0; 690 memset(&etr_sync, 0, sizeof(etr_sync));
803 preempt_disable(); 691 preempt_disable();
804 smp_call_function(etr_sync_cpu_start,&in_sync,0,0); 692 smp_call_function(etr_sync_cpu_start, NULL, 0, 0);
805 local_irq_disable(); 693 local_irq_disable();
806 etr_enable_sync_clock(); 694 etr_enable_sync_clock();
807 695
@@ -809,6 +697,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
809 __ctl_set_bit(14, 21); 697 __ctl_set_bit(14, 21);
810 __ctl_set_bit(0, 29); 698 __ctl_set_bit(0, 29);
811 clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32; 699 clock = ((unsigned long long) (aib->edf2.etv + 1)) << 32;
700 old_clock = get_clock();
812 if (set_clock(clock) == 0) { 701 if (set_clock(clock) == 0) {
813 __udelay(1); /* Wait for the clock to start. */ 702 __udelay(1); /* Wait for the clock to start. */
814 __ctl_clear_bit(0, 29); 703 __ctl_clear_bit(0, 29);
@@ -817,16 +706,17 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
817 /* Adjust Linux timing variables. */ 706 /* Adjust Linux timing variables. */
818 delay = (unsigned long long) 707 delay = (unsigned long long)
819 (aib->edf2.etv - sync_port->edf2.etv) << 32; 708 (aib->edf2.etv - sync_port->edf2.etv) << 32;
820 etr_adjust_time(clock, delay); 709 delta = etr_adjust_time(old_clock, clock, delay);
821 setup_jiffy_timer(); 710 etr_sync.fixup_cc = delta;
711 fixup_clock_comparator(delta);
822 /* Verify that the clock is properly set. */ 712 /* Verify that the clock is properly set. */
823 if (!etr_aib_follows(sync_port, aib, port)) { 713 if (!etr_aib_follows(sync_port, aib, port)) {
824 /* Didn't work. */ 714 /* Didn't work. */
825 etr_disable_sync_clock(NULL); 715 etr_disable_sync_clock(NULL);
826 in_sync = -EAGAIN; 716 etr_sync.in_sync = -EAGAIN;
827 rc = -EAGAIN; 717 rc = -EAGAIN;
828 } else { 718 } else {
829 in_sync = 1; 719 etr_sync.in_sync = 1;
830 rc = 0; 720 rc = 0;
831 } 721 }
832 } else { 722 } else {
@@ -834,7 +724,7 @@ static int etr_sync_clock(struct etr_aib *aib, int port)
834 __ctl_clear_bit(0, 29); 724 __ctl_clear_bit(0, 29);
835 __ctl_clear_bit(14, 21); 725 __ctl_clear_bit(14, 21);
836 etr_disable_sync_clock(NULL); 726 etr_disable_sync_clock(NULL);
837 in_sync = -EAGAIN; 727 etr_sync.in_sync = -EAGAIN;
838 rc = -EAGAIN; 728 rc = -EAGAIN;
839 } 729 }
840 local_irq_enable(); 730 local_irq_enable();
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index 70f2a862b670..eae21a8ac72d 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -34,7 +34,7 @@ void __delay(unsigned long loops)
34 */ 34 */
35void __udelay(unsigned long usecs) 35void __udelay(unsigned long usecs)
36{ 36{
37 u64 end, time, jiffy_timer = 0; 37 u64 end, time, old_cc = 0;
38 unsigned long flags, cr0, mask, dummy; 38 unsigned long flags, cr0, mask, dummy;
39 int irq_context; 39 int irq_context;
40 40
@@ -43,8 +43,8 @@ void __udelay(unsigned long usecs)
43 local_bh_disable(); 43 local_bh_disable();
44 local_irq_save(flags); 44 local_irq_save(flags);
45 if (raw_irqs_disabled_flags(flags)) { 45 if (raw_irqs_disabled_flags(flags)) {
46 jiffy_timer = S390_lowcore.jiffy_timer; 46 old_cc = S390_lowcore.clock_comparator;
47 S390_lowcore.jiffy_timer = -1ULL - (4096 << 12); 47 S390_lowcore.clock_comparator = -1ULL;
48 __ctl_store(cr0, 0, 0); 48 __ctl_store(cr0, 0, 0);
49 dummy = (cr0 & 0xffff00e0) | 0x00000800; 49 dummy = (cr0 & 0xffff00e0) | 0x00000800;
50 __ctl_load(dummy , 0, 0); 50 __ctl_load(dummy , 0, 0);
@@ -55,8 +55,8 @@ void __udelay(unsigned long usecs)
55 55
56 end = get_clock() + ((u64) usecs << 12); 56 end = get_clock() + ((u64) usecs << 12);
57 do { 57 do {
58 time = end < S390_lowcore.jiffy_timer ? 58 time = end < S390_lowcore.clock_comparator ?
59 end : S390_lowcore.jiffy_timer; 59 end : S390_lowcore.clock_comparator;
60 set_clock_comparator(time); 60 set_clock_comparator(time);
61 trace_hardirqs_on(); 61 trace_hardirqs_on();
62 __load_psw_mask(mask); 62 __load_psw_mask(mask);
@@ -65,10 +65,10 @@ void __udelay(unsigned long usecs)
65 65
66 if (raw_irqs_disabled_flags(flags)) { 66 if (raw_irqs_disabled_flags(flags)) {
67 __ctl_load(cr0, 0, 0); 67 __ctl_load(cr0, 0, 0);
68 S390_lowcore.jiffy_timer = jiffy_timer; 68 S390_lowcore.clock_comparator = old_cc;
69 } 69 }
70 if (!irq_context) 70 if (!irq_context)
71 _local_bh_enable(); 71 _local_bh_enable();
72 set_clock_comparator(S390_lowcore.jiffy_timer); 72 set_clock_comparator(S390_lowcore.clock_comparator);
73 local_irq_restore(flags); 73 local_irq_restore(flags);
74} 74}