[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>
This commit is contained in:
parent
3a95e8eb34
commit
934b2857cc
3 changed files with 20 additions and 4 deletions
|
@ -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();
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue