• Thomas Gleixner's avatar
    m68k: Simplify low level interrupt handling code · 09f90f66
    Thomas Gleixner authored
    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: default avatarThomas Gleixner <tglx@linutronix.de>
    Tested-by: default avatarMichael Schmitz <schmitz@biophys.uni-duesseldorf.de>
    Acked-by: default avatarGeert 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
    09f90f66
entry.S 9.02 KB