[S390] nohz/sclp: disable timer on synchronous waits.

sclp_sync_wait wait synchronously for an sclp interrupt and disables
timer interrupts. However on the irq enter paths there is an extra
check if a timer interrupt would be due and calls the timer callback.
This would schedule softirqs in the wrong context.
So introduce local_tick_enable/disable which prevents this.

Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c
index eae21a8..fc6ab60 100644
--- a/arch/s390/lib/delay.c
+++ b/arch/s390/lib/delay.c
@@ -43,7 +43,7 @@
 		local_bh_disable();
 	local_irq_save(flags);
 	if (raw_irqs_disabled_flags(flags)) {
-		old_cc = S390_lowcore.clock_comparator;
+		old_cc = local_tick_disable();
 		S390_lowcore.clock_comparator = -1ULL;
 		__ctl_store(cr0, 0, 0);
 		dummy = (cr0 & 0xffff00e0) | 0x00000800;
@@ -65,7 +65,7 @@
 
 	if (raw_irqs_disabled_flags(flags)) {
 		__ctl_load(cr0, 0, 0);
-		S390_lowcore.clock_comparator = old_cc;
+		local_tick_enable(old_cc);
 	}
 	if (!irq_context)
 		_local_bh_enable();
diff --git a/drivers/s390/char/sclp.c b/drivers/s390/char/sclp.c
index 3c8b25e..1fd8f21 100644
--- a/drivers/s390/char/sclp.c
+++ b/drivers/s390/char/sclp.c
@@ -399,6 +399,7 @@
 void
 sclp_sync_wait(void)
 {
+	unsigned long long old_tick;
 	unsigned long flags;
 	unsigned long cr0, cr0_sync;
 	u64 timeout;
@@ -419,11 +420,12 @@
 	if (!irq_context)
 		local_bh_disable();
 	/* Enable service-signal interruption, disable timer interrupts */
+	old_tick = local_tick_disable();
 	trace_hardirqs_on();
 	__ctl_store(cr0, 0, 0);
 	cr0_sync = cr0;
+	cr0_sync &= 0xffff00a0;
 	cr0_sync |= 0x00000200;
-	cr0_sync &= 0xFFFFF3AC;
 	__ctl_load(cr0_sync, 0, 0);
 	__raw_local_irq_stosm(0x01);
 	/* Loop until driver state indicates finished request */
@@ -439,9 +441,9 @@
 	__ctl_load(cr0, 0, 0);
 	if (!irq_context)
 		_local_bh_enable();
+	local_tick_enable(old_tick);
 	local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(sclp_sync_wait);
 
 /* Dispatch changes in send and receive mask to registered listeners. */
diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
index 4b7cb96..89ec705 100644
--- a/include/asm-s390/hardirq.h
+++ b/include/asm-s390/hardirq.h
@@ -34,4 +34,18 @@
 
 void clock_comparator_work(void);
 
+static inline unsigned long long local_tick_disable(void)
+{
+	unsigned long long old;
+
+	old = S390_lowcore.clock_comparator;
+	S390_lowcore.clock_comparator = -1ULL;
+	return old;
+}
+
+static inline void local_tick_enable(unsigned long long comp)
+{
+	S390_lowcore.clock_comparator = comp;
+}
+
 #endif /* __ASM_HARDIRQ_H */