irq: Consolidate do_softirq() arch overriden implementations
All arch overriden implementations of do_softirq() share the following common code: disable irqs (to avoid races with the pending check), check if there are softirqs pending, then execute __do_softirq() on a specific stack. Consolidate the common parts such that archs only worry about the stack switch. Acked-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@au1.ibm.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul Mackerras <paulus@au1.ibm.com> Cc: James Hogan <james.hogan@imgtec.com> Cc: James E.J. Bottomley <jejb@parisc-linux.org> Cc: Helge Deller <deller@gmx.de> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> Cc: David S. Miller <davem@davemloft.net> Cc: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
parent
ded7975475
commit
7d65f4a655
11 changed files with 93 additions and 197 deletions
|
@ -159,44 +159,30 @@ void irq_ctx_exit(int cpu)
|
|||
|
||||
extern asmlinkage void __do_softirq(void);
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct thread_info *curctx;
|
||||
union irq_ctx *irqctx;
|
||||
u32 *isp;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
curctx = current_thread_info();
|
||||
irqctx = softirq_ctx[smp_processor_id()];
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info));
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
curctx = current_thread_info();
|
||||
irqctx = softirq_ctx[smp_processor_id()];
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(struct thread_info));
|
||||
|
||||
asm volatile (
|
||||
"MOV D0.5,%0\n"
|
||||
"SWAP A0StP,D0.5\n"
|
||||
"CALLR D1RtP,___do_softirq\n"
|
||||
"MOV A0StP,D0.5\n"
|
||||
:
|
||||
: "r" (isp)
|
||||
: "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4",
|
||||
"D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP",
|
||||
"D0.5"
|
||||
);
|
||||
/*
|
||||
* Shouldn't happen, we returned above if in_interrupt():
|
||||
*/
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
asm volatile (
|
||||
"MOV D0.5,%0\n"
|
||||
"SWAP A0StP,D0.5\n"
|
||||
"CALLR D1RtP,___do_softirq\n"
|
||||
"MOV A0StP,D0.5\n"
|
||||
:
|
||||
: "r" (isp)
|
||||
: "memory", "cc", "D1Ar1", "D0Ar2", "D1Ar3", "D0Ar4",
|
||||
"D1Ar5", "D0Ar6", "D0Re0", "D1Re0", "D0.4", "D1RtP",
|
||||
"D0.5"
|
||||
);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -499,22 +499,9 @@ static void execute_on_irq_stack(void *func, unsigned long param1)
|
|||
*irq_stack_in_use = 1;
|
||||
}
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
__u32 pending;
|
||||
unsigned long flags;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
pending = local_softirq_pending();
|
||||
|
||||
if (pending)
|
||||
execute_on_irq_stack(__do_softirq, 0);
|
||||
|
||||
local_irq_restore(flags);
|
||||
execute_on_irq_stack(__do_softirq, 0);
|
||||
}
|
||||
#endif /* CONFIG_IRQSTACKS */
|
||||
|
||||
|
|
|
@ -593,7 +593,7 @@ void irq_ctx_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
static inline void do_softirq_onstack(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
struct thread_info *curtp, *irqtp;
|
||||
|
||||
|
@ -611,21 +611,6 @@ static inline void do_softirq_onstack(void)
|
|||
set_bits(irqtp->flags, &curtp->flags);
|
||||
}
|
||||
|
||||
void do_softirq(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (local_softirq_pending())
|
||||
do_softirq_onstack();
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
irq_hw_number_t virq_to_hw(unsigned int virq)
|
||||
{
|
||||
struct irq_data *irq_data = irq_get_irq_data(virq);
|
||||
|
|
|
@ -157,39 +157,29 @@ int arch_show_interrupts(struct seq_file *p, int prec)
|
|||
/*
|
||||
* Switch to the asynchronous interrupt stack for softirq execution.
|
||||
*/
|
||||
asmlinkage void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long flags, old, new;
|
||||
unsigned long old, new;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
/* Get current stack pointer. */
|
||||
asm volatile("la %0,0(15)" : "=a" (old));
|
||||
/* Check against async. stack address range. */
|
||||
new = S390_lowcore.async_stack;
|
||||
if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
|
||||
/* Need to switch to the async. stack. */
|
||||
new -= STACK_FRAME_OVERHEAD;
|
||||
((struct stack_frame *) new)->back_chain = old;
|
||||
|
||||
asm volatile(" la 15,0(%0)\n"
|
||||
" basr 14,%2\n"
|
||||
" la 15,0(%1)\n"
|
||||
: : "a" (new), "a" (old),
|
||||
"a" (__do_softirq)
|
||||
: "0", "1", "2", "3", "4", "5", "14",
|
||||
"cc", "memory" );
|
||||
} else {
|
||||
/* We are already on the async stack. */
|
||||
__do_softirq();
|
||||
}
|
||||
/* Get current stack pointer. */
|
||||
asm volatile("la %0,0(15)" : "=a" (old));
|
||||
/* Check against async. stack address range. */
|
||||
new = S390_lowcore.async_stack;
|
||||
if (((new - old) >> (PAGE_SHIFT + THREAD_ORDER)) != 0) {
|
||||
/* Need to switch to the async. stack. */
|
||||
new -= STACK_FRAME_OVERHEAD;
|
||||
((struct stack_frame *) new)->back_chain = old;
|
||||
asm volatile(" la 15,0(%0)\n"
|
||||
" basr 14,%2\n"
|
||||
" la 15,0(%1)\n"
|
||||
: : "a" (new), "a" (old),
|
||||
"a" (__do_softirq)
|
||||
: "0", "1", "2", "3", "4", "5", "14",
|
||||
"cc", "memory" );
|
||||
} else {
|
||||
/* We are already on the async stack. */
|
||||
__do_softirq();
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -149,47 +149,32 @@ void irq_ctx_exit(int cpu)
|
|||
hardirq_ctx[cpu] = NULL;
|
||||
}
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct thread_info *curctx;
|
||||
union irq_ctx *irqctx;
|
||||
u32 *isp;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
curctx = current_thread_info();
|
||||
irqctx = softirq_ctx[smp_processor_id()];
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_sp = current_stack_pointer;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
curctx = current_thread_info();
|
||||
irqctx = softirq_ctx[smp_processor_id()];
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_sp = current_stack_pointer;
|
||||
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *)((char *)irqctx + sizeof(*irqctx));
|
||||
|
||||
__asm__ __volatile__ (
|
||||
"mov r15, r9 \n"
|
||||
"jsr @%0 \n"
|
||||
/* switch to the softirq stack */
|
||||
" mov %1, r15 \n"
|
||||
/* restore the thread stack */
|
||||
"mov r9, r15 \n"
|
||||
: /* no outputs */
|
||||
: "r" (__do_softirq), "r" (isp)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
|
||||
);
|
||||
|
||||
/*
|
||||
* Shouldn't happen, we returned above if in_interrupt():
|
||||
*/
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
__asm__ __volatile__ (
|
||||
"mov r15, r9 \n"
|
||||
"jsr @%0 \n"
|
||||
/* switch to the softirq stack */
|
||||
" mov %1, r15 \n"
|
||||
/* restore the thread stack */
|
||||
"mov r9, r15 \n"
|
||||
: /* no outputs */
|
||||
: "r" (__do_softirq), "r" (isp)
|
||||
: "memory", "r0", "r1", "r2", "r3", "r4",
|
||||
"r5", "r6", "r7", "r8", "r9", "r15", "t", "pr"
|
||||
);
|
||||
}
|
||||
#else
|
||||
static inline void handle_one_irq(unsigned int irq)
|
||||
|
|
|
@ -698,30 +698,19 @@ void __irq_entry handler_irq(int pil, struct pt_regs *regs)
|
|||
set_irq_regs(old_regs);
|
||||
}
|
||||
|
||||
void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
void *orig_sp, *sp = softirq_stack[smp_processor_id()];
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
sp += THREAD_SIZE - 192 - STACK_BIAS;
|
||||
|
||||
local_irq_save(flags);
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
void *orig_sp, *sp = softirq_stack[smp_processor_id()];
|
||||
|
||||
sp += THREAD_SIZE - 192 - STACK_BIAS;
|
||||
|
||||
__asm__ __volatile__("mov %%sp, %0\n\t"
|
||||
"mov %1, %%sp"
|
||||
: "=&r" (orig_sp)
|
||||
: "r" (sp));
|
||||
__do_softirq();
|
||||
__asm__ __volatile__("mov %0, %%sp"
|
||||
: : "r" (orig_sp));
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
__asm__ __volatile__("mov %%sp, %0\n\t"
|
||||
"mov %1, %%sp"
|
||||
: "=&r" (orig_sp)
|
||||
: "r" (sp));
|
||||
__do_softirq();
|
||||
__asm__ __volatile__("mov %0, %%sp"
|
||||
: : "r" (orig_sp));
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HOTPLUG_CPU
|
||||
|
|
|
@ -1342,7 +1342,7 @@ bad_gs:
|
|||
.previous
|
||||
|
||||
/* Call softirq on interrupt stack. Interrupts are off. */
|
||||
ENTRY(call_softirq)
|
||||
ENTRY(do_softirq_own_stack)
|
||||
CFI_STARTPROC
|
||||
pushq_cfi %rbp
|
||||
CFI_REL_OFFSET rbp,0
|
||||
|
@ -1359,7 +1359,7 @@ ENTRY(call_softirq)
|
|||
decl PER_CPU_VAR(irq_count)
|
||||
ret
|
||||
CFI_ENDPROC
|
||||
END(call_softirq)
|
||||
END(do_softirq_own_stack)
|
||||
|
||||
#ifdef CONFIG_XEN
|
||||
zeroentry xen_hypervisor_callback xen_do_hypervisor_callback
|
||||
|
|
|
@ -149,35 +149,21 @@ void irq_ctx_init(int cpu)
|
|||
cpu, per_cpu(hardirq_ctx, cpu), per_cpu(softirq_ctx, cpu));
|
||||
}
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
void do_softirq_own_stack(void)
|
||||
{
|
||||
unsigned long flags;
|
||||
struct thread_info *curctx;
|
||||
union irq_ctx *irqctx;
|
||||
u32 *isp;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
curctx = current_thread_info();
|
||||
irqctx = __this_cpu_read(softirq_ctx);
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
|
||||
local_irq_save(flags);
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
|
||||
|
||||
if (local_softirq_pending()) {
|
||||
curctx = current_thread_info();
|
||||
irqctx = __this_cpu_read(softirq_ctx);
|
||||
irqctx->tinfo.task = curctx->task;
|
||||
irqctx->tinfo.previous_esp = current_stack_pointer;
|
||||
|
||||
/* build the stack frame on the softirq stack */
|
||||
isp = (u32 *) ((char *)irqctx + sizeof(*irqctx));
|
||||
|
||||
call_on_stack(__do_softirq, isp);
|
||||
/*
|
||||
* Shouldn't happen, we returned above if in_interrupt():
|
||||
*/
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
}
|
||||
|
||||
local_irq_restore(flags);
|
||||
call_on_stack(__do_softirq, isp);
|
||||
}
|
||||
|
||||
bool handle_irq(unsigned irq, struct pt_regs *regs)
|
||||
|
|
|
@ -87,24 +87,3 @@ bool handle_irq(unsigned irq, struct pt_regs *regs)
|
|||
generic_handle_irq_desc(irq, desc);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
extern void call_softirq(void);
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
{
|
||||
__u32 pending;
|
||||
unsigned long flags;
|
||||
|
||||
if (in_interrupt())
|
||||
return;
|
||||
|
||||
local_irq_save(flags);
|
||||
pending = local_softirq_pending();
|
||||
/* Switch to interrupt stack */
|
||||
if (pending) {
|
||||
call_softirq();
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
}
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <asm/irq.h>
|
||||
|
||||
/*
|
||||
* These correspond to the IORESOURCE_IRQ_* defines in
|
||||
|
@ -374,6 +375,16 @@ struct softirq_action
|
|||
|
||||
asmlinkage void do_softirq(void);
|
||||
asmlinkage void __do_softirq(void);
|
||||
|
||||
#ifdef __ARCH_HAS_DO_SOFTIRQ
|
||||
void do_softirq_own_stack(void);
|
||||
#else
|
||||
static inline void do_softirq_own_stack(void)
|
||||
{
|
||||
__do_softirq();
|
||||
}
|
||||
#endif
|
||||
|
||||
extern void open_softirq(int nr, void (*action)(struct softirq_action *));
|
||||
extern void softirq_init(void);
|
||||
extern void __raise_softirq_irqoff(unsigned int nr);
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/irq.h>
|
||||
|
||||
#include <asm/irq.h>
|
||||
/*
|
||||
- No shared variables, all the data are CPU local.
|
||||
- If a softirq needs serialization, let it serialize itself
|
||||
|
@ -283,7 +282,7 @@ asmlinkage void __do_softirq(void)
|
|||
tsk_restore_flags(current, old_flags, PF_MEMALLOC);
|
||||
}
|
||||
|
||||
#ifndef __ARCH_HAS_DO_SOFTIRQ
|
||||
|
||||
|
||||
asmlinkage void do_softirq(void)
|
||||
{
|
||||
|
@ -298,13 +297,12 @@ asmlinkage void do_softirq(void)
|
|||
pending = local_softirq_pending();
|
||||
|
||||
if (pending)
|
||||
__do_softirq();
|
||||
do_softirq_own_stack();
|
||||
|
||||
WARN_ON_ONCE(softirq_count());
|
||||
local_irq_restore(flags);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Enter an interrupt context.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue