Commit 934b2857 authored by Heiko Carstens's avatar Heiko Carstens Committed by Martin Schwidefsky

[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: default avatarHeiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 3a95e8eb
...@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs) ...@@ -43,7 +43,7 @@ void __udelay(unsigned long usecs)
local_bh_disable(); local_bh_disable();
local_irq_save(flags); local_irq_save(flags);
if (raw_irqs_disabled_flags(flags)) { if (raw_irqs_disabled_flags(flags)) {
old_cc = S390_lowcore.clock_comparator; old_cc = local_tick_disable();
S390_lowcore.clock_comparator = -1ULL; S390_lowcore.clock_comparator = -1ULL;
__ctl_store(cr0, 0, 0); __ctl_store(cr0, 0, 0);
dummy = (cr0 & 0xffff00e0) | 0x00000800; dummy = (cr0 & 0xffff00e0) | 0x00000800;
...@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs) ...@@ -65,7 +65,7 @@ void __udelay(unsigned long usecs)
if (raw_irqs_disabled_flags(flags)) { if (raw_irqs_disabled_flags(flags)) {
__ctl_load(cr0, 0, 0); __ctl_load(cr0, 0, 0);
S390_lowcore.clock_comparator = old_cc; local_tick_enable(old_cc);
} }
if (!irq_context) if (!irq_context)
_local_bh_enable(); _local_bh_enable();
......
...@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies) ...@@ -399,6 +399,7 @@ sclp_tod_from_jiffies(unsigned long jiffies)
void void
sclp_sync_wait(void) sclp_sync_wait(void)
{ {
unsigned long long old_tick;
unsigned long flags; unsigned long flags;
unsigned long cr0, cr0_sync; unsigned long cr0, cr0_sync;
u64 timeout; u64 timeout;
...@@ -419,11 +420,12 @@ sclp_sync_wait(void) ...@@ -419,11 +420,12 @@ sclp_sync_wait(void)
if (!irq_context) if (!irq_context)
local_bh_disable(); local_bh_disable();
/* Enable service-signal interruption, disable timer interrupts */ /* Enable service-signal interruption, disable timer interrupts */
old_tick = local_tick_disable();
trace_hardirqs_on(); trace_hardirqs_on();
__ctl_store(cr0, 0, 0); __ctl_store(cr0, 0, 0);
cr0_sync = cr0; cr0_sync = cr0;
cr0_sync &= 0xffff00a0;
cr0_sync |= 0x00000200; cr0_sync |= 0x00000200;
cr0_sync &= 0xFFFFF3AC;
__ctl_load(cr0_sync, 0, 0); __ctl_load(cr0_sync, 0, 0);
__raw_local_irq_stosm(0x01); __raw_local_irq_stosm(0x01);
/* Loop until driver state indicates finished request */ /* Loop until driver state indicates finished request */
...@@ -439,9 +441,9 @@ sclp_sync_wait(void) ...@@ -439,9 +441,9 @@ sclp_sync_wait(void)
__ctl_load(cr0, 0, 0); __ctl_load(cr0, 0, 0);
if (!irq_context) if (!irq_context)
_local_bh_enable(); _local_bh_enable();
local_tick_enable(old_tick);
local_irq_restore(flags); local_irq_restore(flags);
} }
EXPORT_SYMBOL(sclp_sync_wait); EXPORT_SYMBOL(sclp_sync_wait);
/* Dispatch changes in send and receive mask to registered listeners. */ /* Dispatch changes in send and receive mask to registered listeners. */
......
...@@ -34,4 +34,18 @@ typedef struct { ...@@ -34,4 +34,18 @@ typedef struct {
void clock_comparator_work(void); 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 */ #endif /* __ASM_HARDIRQ_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment