Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -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();
+4 −2
Original line number Diff line number Diff line
@@ -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. */
+14 −0
Original line number Diff line number Diff line
@@ -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 */