diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-08-01 16:39:11 +0200 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-08-01 16:39:30 +0200 |
commit | 934b2857cc576ae53c92a66e63fce7ddcfa74691 (patch) | |
tree | 4a8e261d16739624bb91ed9f56062ec5f7401227 | |
parent | 3a95e8eb34f595a0144adb6e5513d456319bd8a5 (diff) |
[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>
-rw-r--r-- | arch/s390/lib/delay.c | 4 | ||||
-rw-r--r-- | drivers/s390/char/sclp.c | 6 | ||||
-rw-r--r-- | include/asm-s390/hardirq.h | 14 |
3 files changed, 20 insertions, 4 deletions
diff --git a/arch/s390/lib/delay.c b/arch/s390/lib/delay.c index eae21a8ac72..fc6ab6094df 100644 --- a/arch/s390/lib/delay.c +++ b/arch/s390/lib/delay.c @@ -43,7 +43,7 @@ void __udelay(unsigned long usecs) 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 @@ void __udelay(unsigned long usecs) 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 3c8b25e6c34..1fd8f2193ed 100644 --- a/drivers/s390/char/sclp.c +++ b/drivers/s390/char/sclp.c @@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies) void sclp_sync_wait(void) { + unsigned long long old_tick; unsigned long flags; unsigned long cr0, cr0_sync; u64 timeout; @@ -419,11 +420,12 @@ sclp_sync_wait(void) 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 @@ sclp_sync_wait(void) __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 4b7cb964ff3..89ec7056da2 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -34,4 +34,18 @@ typedef struct { 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 */ |