linux/arch/m68k/kernel
Thomas Gleixner 09f90f6685 m68k: Simplify low level interrupt handling code
The low level interrupt entry code of m68k contains the following:

    add_preempt_count(HARDIRQ_OFFSET);

    do_IRQ();
	irq_enter();
	    add_preempt_count(HARDIRQ_OFFSET);
	handle_interrupt();    
	irq_exit();    
	    sub_preempt_count(HARDIRQ_OFFSET);
	    if (in_interrupt())
       	       return; <---- On m68k always taken!
	    if (local_softirq_pending())
       	       do_softirq();

    sub_preempt_count(HARDIRQ_OFFSET);
    if (in_hardirq())
       return;
    if (status_on_stack_has_interrupt_priority_mask > 0)
       return;
    if (local_softirq_pending())
       do_softirq();

    ret_from_exception:
	if (interrupted_context_is_kernel)
	   return:
	....

I tried to find a proper explanation for this, but the changelog is
sparse and there are no mails explaining it further. But obviously
this relates to the interrupt priority levels of the m68k and tries to
be extra clever with nested interrupts. Though this cleverness just
adds code bloat to the interrupt hotpath.

For the common case of non nested interrupts the code runs through two
extra conditionals to the only important one, which checks whether the
return is to kernel or user space.

For the nested case the checks for in_hardirq() and the priority mask
value on stack catch only the case where the nested interrupt happens
inside the hard irq context of the first interrupt. If the nested
interrupt happens while the first interrupt handles soft interrupts,
then these extra checks buy nothing. The nested interrupt will fall
through to the final kernel/user space return check at
ret_from_exception.

Changing the code flow in the following way:

    do_IRQ();
	irq_enter();
	    add_preempt_count(HARDIRQ_OFFSET);
	handle_interrupt();    
	irq_exit();    
	    sub_preempt_count(HARDIRQ_OFFSET);
	    if (in_interrupt())
       	       return;
	    if (local_softirq_pending())
       	       do_softirq();

    ret_from_exception:
	if (interrupted_context_is_kernel)
	   return:

makes the region protected by the hardirq count slightly smaller and
the softirq handling is invoked with a minimal deeper stack. But
otherwise it's completely functional equivalent and saves 104 bytes of
text in arch/m68k/kernel/entry.o.

This modification allows us further to get rid of the limitations
which m68k puts on the preempt_count layout, so we can make the
preempt count bits completely generic.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Michael Schmitz <schmitz@biophys.uni-duesseldorf.de>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Cc: Linux/m68k <linux-m68k@vger.kernel.org>
Cc: Andreas Schwab <schwab@linux-m68k.org>
Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1311112052360.30673@ionos.tec.linutronix.de
2013-11-13 20:21:46 +01:00
..
.gitignore
Makefile m68k: Sort out !CONFIG_MMU_SUN3 vs. CONFIG_HAS_DMA 2013-02-09 14:23:36 +01:00
asm-offsets.c lib: Move fonts from drivers/video/console/ to lib/fonts/ 2013-06-28 10:28:22 +02:00
dma.c
entry.S m68k: Simplify low level interrupt handling code 2013-11-13 20:21:46 +01:00
head.S m68k/mac: Fix unexpected interrupt with CONFIG_EARLY_PRINTK 2013-05-31 10:43:18 +02:00
ints.c m68k: Simplify low level interrupt handling code 2013-11-13 20:21:46 +01:00
irq.c
m68k_ksyms.c
module.c
module.lds
pcibios.c ARCH: drivers remove __dev* attributes. 2013-01-03 15:57:13 -08:00
process.c m68k: Use generic idle loop 2013-04-08 17:39:26 +02:00
ptrace.c
setup.c
setup_mm.c m68k/atari: ROM port ISA adapter support 2013-04-16 21:08:11 +02:00
setup_no.c m68knommu: Mark functions only called from setup_arch() __init 2013-08-26 16:51:13 +10:00
signal.c m68k/coldfire: flush cache when creating the signal stack frame 2013-08-26 16:51:13 +10:00
sun3-head.S
sys_m68k.c
syscalltable.S
time.c PTR_RET is now PTR_ERR_OR_ZERO(): Replace most. 2013-07-15 11:25:01 +09:30
traps.c dump_stack: consolidate dump_stack() implementations and unify their behaviors 2013-04-30 17:04:02 -07:00
vectors.c
vmlinux-nommu.lds
vmlinux-std.lds
vmlinux-sun3.lds
vmlinux.lds.S