微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM Linux中断机制分析

ARM Linux中断机制分析

时间:11-09 来源:互联网 点击:

系统的处理

/*

* this macro assumes that irqstat (r6) and base (r5) are

* preserved from get_irqnr_and_base above

*/

ALT_SMP(test_for_ipi r0, r6, r5, lr)//这里是从寄存器中读取ipi标志

ALT_UP_B(9997f)

movne r1, sp

adrne lr, BSYM(1b)//同理,这里也是将返回地址设置为ALT_SMP的第二条指令,构造成一个循环

bne do_IPI//只要存在IPI就调用do_IPI,并循环直到处理完所有IPI

#ifdef CONFIG_LOCAL_TIMERS//同理,这里循环处理多核系统中的本地时钟中断。

test_for_ltirq r0, r6, r5, lr

movne r0, sp

adrne lr, BSYM(1b)

bne do_local_timer

#endif

#endif

9997:

.endm

2.2.6 get_irqnr_preamble

get_irqnr_preamble用于获得中断状态寄存器基地址,特定于CPU,这里CPU用的是tegra,其定义如下

/* arch/arm/mach-tegra/include/mach/entry-macro.S

/* Uses the GIC interrupt controller built into the cpu */

#define ICTRL_BASE (IO_CPU_VIRT + 0x40100)// #define IO_CPU_VIRT 0xFE000000

.macroget_irqnr_preamble, base, tmp

movw \base, #(ICTRL_BASE & 0x0000ffff)

movt \base, #((ICTRL_BASE & 0xffff0000) >> 16)

.endm


2.2.7 get_irqnr_and_base

get_irqnr_and_base用来获取中断号。

/* arch/arm/mach-tegra/include/mach/entry-macro.S

.macro get_irqnr_and_base, irqnr, irqstat, base, tmp

ldr \irqnr, [\base, #0x20] @ EVT_IRQ_STS

cmp \irqnr, #0x80

.endm

get_irqnr_preamble和get_irqnr_and_base两个宏由machine级的代码定义,目的就是从中断控制器中获得IRQ编号,紧接着就调用asm_do_IRQ,从这个函数开始,中断程序进入C代码中,传入的参数是IRQ编号和寄存器结构指针,

2.2.8 asm_do_IRQ

图4 asm_do_IRQ流程图

asm_do_IRQ是ARM处理硬件中断的核心函数,第一个参数指定了硬中断的中断号,第二个参数是寄存器备份组成的一个结构体,保存了中断发生时的模式对应的寄存器的值,在中断返回时使用。

linux/arch/arm/kernel/irq.c

asmlinkage void __exception_irq_entry

asm_do_IRQ(unsigned int irq, struct pt_regs *regs)

{

struct pt_regs *old_regs = set_irq_regs(regs);//获得寄存器值

irq_enter();

/*

* Some hardware gives randomly wrong interrupts. Rather

* than crashing, do something sensible.

*/

if (unlikely(irq >= nr_irqs)) {

if (printk_ratelimit())

printk(KERN_WARNING "Bad IRQ%u\n", irq);

ack_bad_irq(irq);

} else {

generic_handle_irq(irq);

}

/* AT91 specific workaround */

irq_finish(irq);

irq_exit();

set_irq_regs(old_regs);

}

2.2.9 irq_enter

irq_enter是更新一些系统的统计信息,同时在__irq_enter宏中禁止了进程的抢占。虽然在产生IRQ时,ARM会自动把CPSR中的I位置位,禁止新的IRQ请求,直到中断控制转到相应的流控层后才通过local_irq_enable()打开。那为何还要禁止抢占?这是因为要考虑中断嵌套的问题,一旦流控层或驱动程序主动通过local_irq_enable打开了IRQ,而此时该中断还没处理完成,新的irq请求到达,这时代码会再次进入irq_enter,在本次嵌套中断返回时,内核不希望进行抢占调度,而是要等到最外层的中断处理完成后才做出调度动作,所以才有了禁止抢占这一处理。

linux/kernel/softirq.c

voidirq_enter(void)

{

int cpu = smp_processor_id();

rcu_irq_enter();

if (idle_cpu(cpu) && !in_interrupt()) {

/* Prevent raise_softirq from needlessly waking up ksoftirqd

* here, as softirq will be serviced on return from interrupt.*/

local_bh_disable();

tick_check_idle(cpu);

_local_bh_enable();

}

__irq_enter();

}

#define __irq_enter() \

do { \

account_system_vtime(current); \

add_preempt_count(HARDIRQ_OFFSET); \

trace_hardirq_enter(); \

} while (0)

2.2.10 generic_handle_irq

~/include /linux/Irqdesc.h

/*

* Architectures call this to let the generic IRQ layer

* handle an interrupt. If the descriptor is attached to an

* irqchip-style controller then we call the ->handle_irq() handler,

* and it calls __do_IRQ() if its attached to an irqtype-style controller.

*/

static inline void generic_handle_irq_desc(unsigned int irq,struct irq_desc *desc)

{

desc->handle_irq(irq, desc);//调用该irq注册的函数处理,该函数在注册中断时填写irq_desc结构体时指定。

}// handle_irq是

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top