[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:
Родитель
3a95e8eb34
Коммит
934b2857cc
|
@ -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)
|
||||||
|
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
__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 {
|
||||||
|
|
||||||
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 */
|
||||||
|
|
Загрузка…
Ссылка в новой задаче