Complete IRQ handling flow on ARM Linux:
Once ARM core receives interrupt, it stops execution in current context. From there on the sequence of events:
- disables IRQ
- copies CPSR to SPSR
- copies current PC to LR
- switches to IRQ mode
- places the interrupt vector table address into PC
- jumps to vector handler code
- if interrupt occurred while processor was in supervisor mode, processor will switch to supervisor mode
- irq_svc saves the registers on kernel stack, the registers(r0-r12)
- next step is to identify irq number
- jumps to asm_do_IRQ
- calls handle_level_irq or handle_simple_irq or handle_edge_irq
- calls our ISR routine
- once ISR is completed, irq_svc will return and restore processor state by restoring registers(r0-r12), pc, cpsr
The first 6 steps is done by ARM core, not by Linux. Other steps are done by Linux. Refer to the figure below.
When interrupt is detected:
- __irq_svc - arch/arm/kernel/entry-armv.S
- asm_do_IRQ - arch/arm/kernel/irq.c
- handle_IRQ - arch/arm/kernel/irq.c
- generic_handle_irq - kernel/irq/irqdesc.c
- generic_handle_irq_desc - include/linux/irqdesc.h
- desc->handle_irq
In arch/arm/mach-ka2000/irq.c, ka2000_irq_init(),
irq_set_handler() is called.
In kernel/irq/chip.c, __irq_set_handler(),
desc->handle_irq = handle
handle can be: handle_edge_irq, handle_level_irq or handle_simple_irq. So the call to
Therefore, desc->handle_irq will jump to one of these.
For ARM Linux, the interrupt vector table is in arch/arm/kernel/entry-armv.S:
.globl __vectors_start
__vectors_start:
ARM( swi SYS_ERROR0 )
THUMB( svc #0 )
THUMB( nop )
W(b) vector_und + stubs_offset
W(ldr) pc, .LCvswi + stubs_offset
W(b) vector_pabt + stubs_offset
W(b) vector_dabt + stubs_offset
W(b) vector_addrexcptn + stubs_offset
W(b) vector_irq + stubs_offset
W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
For ARM Linux, the vector handler code that runs in IRQ mode and switches to SVC mode.
.macro vector_stub, name, mode, correction=0
.align 5
vector_\name:
.if \correction
sub lr, lr, #\correction
.endif
@
@ Save r0, lr_<exception> (parent PC) and spsr_<exception>
@ (parent CPSR)
@
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr
@
@ Prepare for SVC32 mode. IRQs remain disabled.
@
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0
@
@ the branch table must immediately follow this code
@
and lr, lr, #0x0f
THUMB( adr r0, 1f )
THUMB( ldr lr, [r0, lr, lsl #2] )
mov r0, sp
ARM( ldr lr, [pc, lr, lsl #2] )
movs pc, lr @ branch to handler in SVC mode
ENDPROC(vector_\name)
.align
2
@ handler addresses follow this label
1:
.endm
A practical problem encounter in USB debugging. Linux will hang after USB controller is initialised and USB irq 32 is unmasked, when USB cable is plugged.
1.
The vector handler code will call __irq_svc,
which call arch_irq_handler_default (arch/arm/include/asm/entry-macro-multi.S),
which will call get_irqnr_and_base
(arch/arm/mach-ka2000/include/mach/entry-macro.S).
2.
Look at get_irqnr_and_base (the code is attached
below). For usb irq32, it is the first bit of the interrupt pending 2 register.
The macro is entered, it branch to 6f, then branch to 4b, the condition is
fulfilled, so branch to 7f. Then macro is exited with zero flag set to 1. After
that, the “bne asm_do_IRQ” will not be executed, because the condition does not
fulfil, and Linux is stuck in that macro.
.macro arch_irq_handler_default
get_irqnr_and_base r0,
r2, r6, lr
……
bne asm_do_IRQ
…..
.endm
.endm
3.
To fix the Linux interrupt stuck issue, add a line before the macro exit.
The purpose is to set the zero flag to 0.
.macro get_irqnr_and_base,
irqnr, irqstat, base, tmp
ldr \irqstat, [\base, #0x18] @ interrupt pending 1
mov \tmp, #0
mov \irqnr, #0
teq \irqstat, #0
beq 6f
4:
teq \irqstat, #1
beq 7f
5:
mov \irqstat, \irqstat, lsr #1
teq \irqstat, #1
addne \irqnr, #1
bne 5b
add \irqnr, #1
teq \irqstat,
#0
@irqstat=1
bne 7f
6:
ldr \irqstat, [\base, #0x1c] @ interrupt pending 2
cmp \irqstat, #0
movne
\tmp, #32
bne 4b
7:
add \irqnr, \tmp
teq \irqstat, #0
.endm
No comments:
Post a Comment