气质,源于心灵的自信!
全部博文(204)
分类: LINUX
2012-08-18 17:48:50
代码分析是基于android4.03的内核
start_kernel(void) //Main.c (init)
early_irq_init();
setup_arch(&command_line);
handle_arch_irq = mdesc->handle_irq;
void __init early_trap_init(void) //拷贝中断向量表到0xffff0000
{
................
unsigned long vectors = CONFIG_VECTORS_BASE; //0xffff0000
extern char __vectors_start[], __vectors_end[];
.................
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
...........................
}
下面看下中断向量表的位置://entry-armv.S (arch\arm\kernel)
.globl __vectors_start
__vectors_start:
ARM( swi SYS_ERROR0 ) //复位时CPU执行该指令
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//普通中断的irq跳转位置
W(b) vector_fiq + stubs_offset
.globl __vectors_end
__vectors_end:
下面看下具体跳转后的函数vector_irq:
.globl __stubs_start
__stubs_start:
vector_stub irq, IRQ_MODE, 4//vector_stub展开后就是vector_irq
.long __irq_usr @ 0 (USR_26 / USR_32)
.......................
.long __irq_svc @ 3 (SVC_26 / SVC_32)
....................................
__stubs_end:
其中vector_stub是一个宏:
.macro vector_stub, name, mode, correction=0
.align 5
展开后入下:
vector_irq:
sub lr, lr, 4
stmia sp, {r0, lr} @ save r0, lr
mrs lr, spsr
str lr, [sp, #8] @ save spsr
mrs r0, cpsr
eor r0, r0, #(\mode ^ SVC_MODE | PSR_ISETSTATE)
msr spsr_cxsf, r0
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_irq)
最后跳转到__irq_svc函数处(假如跳转到该分支):
__irq_svc:
svc_entry //保存进程的上下文
................
irq_handler //跳转到irq_handler 处理函数
.............
ENDPROC(__irq_svc)
其中Irq_handler是一个宏:
.macro irq_handler
ldr r1, =handle_arch_irq //多核处理函数
mov r0, sp
adr lr, BSYM(9997f)
ldr pc, [r1]//执行该处理函数
.endm.endm
MACHINE_START(MSM8X60, " MSM8X60 ")
.map_io = msm8x60_map_io,
.reserve = msm8x60_reserve,
.init_irq = msm8x60_init_irq,
.handle_irq = gic_handle_irq,//该处理函数在板级初始化中定义
.init_machine = msm8x60_surf_init,
.timer = &msm_timer,
.init_early = msm8x60_charm_init_early,
MACHINE_END
下面分析该处理函数:
asmlinkage void __exception_irq_entry gic_handle_irq(struct pt_regs *regs)
{
u32 irqstat, irqnr;
struct gic_chip_data *gic = &gic_data[0];
void __iomem *cpu_base = gic_data_cpu_base(gic);
do {
irqstat = readl_relaxed(cpu_base + GIC_CPU_INTACK);//读取中断状态寄存器
irqnr = irqstat & ~0x1c00;//取出中断号
if (likely(irqnr > 15 && irqnr < 1021)) {
irqnr = irq_domain_to_irq(&gic->domain, irqnr);
handle_IRQ(irqnr, regs);//如果中断号大于15,小于1021则走handle_IRQ
continue;
}
if (irqnr < 16) {//如果小于16则周handle_IPI
writel_relaxed(irqstat, cpu_base + GIC_CPU_EOI);//清除中断
handle_IPI(irqnr, regs);
continue;
}
break;
} while (1);
}
其中handle_IRQ()
handle_IRQ(unsigned int irq, struct pt_regs *regs)
generic_handle_irq(irq);
generic_handle_irq_desc(irq, desc);//#define irq_to_desc(irq) (&irq_desc[irq])
desc->handle_irq(irq, desc);//调用该中断的处理函数
handle_IPI(irqnr, regs);
void handle_IPI(int ipinr, struct pt_regs *regs)
{
...............
switch (ipinr) {
case IPI_CPU_START://睡眠唤醒的中断处理
/* Wake up from WFI/WFE using SGI */
break;
case IPI_TIMER:
ipi_timer();
break;
/*各个中断的处理函数*/
}
................
}
下面跟踪下设置中断的处理函数:desc->handle_irq(irq, desc);
postcore_initcall(msm_gpio_init);
msm_gpio_init(void)//Gpio-v2.c (arch\arm\mach-msm)
msm_gpio_probe();
irq_set_chip_and_handler(irq, &msm_gpio_irq_chip, handle_level_irq);
irq_set_chip_and_handler_name(irq, chip, handle, NULL);
irq_set_chip(irq, chip);
desc->irq_data.chip = chip;
__irq_set_handler(irq, handle, 0, name);
desc->handle_irq = handle;
desc->name = name;
irq_startup(desc);
desc->irq_data.chip->irq_startup(&desc->irq_data);
irq_enable(desc);
desc->irq_data.chip->irq_enable(&desc->irq_data);
handle_level_irq函数如下:
handle_level_irq(unsigned int irq, struct irq_desc *desc)
handle_irq_event(desc);
handle_irq_event_percpu(desc, action);//action = desc->action;
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
{
unsigned int irq = desc->irq_data.irq;
do {
..........
action->handler(irq, action->dev_id);//依次执行action链表的handler函数
................
action = action->next;
} while (action);
}
则也是中断的执行过程,调用用户注册的中断函数。
下面看下用户注册中断的过程:
1、初始化中断架构,在start_kernel函数中调用
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {
[0 ... NR_IRQS-1] = {
.handle_irq = handle_bad_irq,
.depth = 1,
.lock = __RAW_SPIN_LOCK_UNLOCKED(irq_desc->lock),
}
};
int __init early_irq_init(void)
{
..............
desc = irq_desc;
count = ARRAY_SIZE(irq_desc);
for (i = 0; i < count; i++) {
....................
desc_set_defaults(i, &desc[i], node, NULL);
}
....................
}
2、申请中断,以msm72k_otg为例:
static int __init msm_otg_probe(struct platform_device *pdev)
ret = request_irq(dev->irq, msm_otg_irq, IRQF_SHARED,"msm_otg", dev);
request_threaded_irq(irq, handler, NULL, flags, name, dev);
{
struct irqaction *action;
struct irq_desc *desc;
desc = irq_to_desc(irq);
/*分配一个action,并用传进来的参数初始化*/
action = kzalloc(sizeof(struct irqaction), GFP_KERNEL);
action->handler = handler;
action->thread_fn = thread_fn;
action->flags = irqflags;
action->name = devname;
action->dev_id = dev_id;//dev id在free irq的时候用上,根据该id从action链表中去除对应id的action
__setup_irq(irq, desc, action);//把该action挂到对应描述符的action链表上
return retval;
}
static int __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
{
struct irqaction *old, **old_ptr;
old_ptr = &desc->action;
old = *old_ptr;
if (old) {//如果为共享中断
/* add new interrupt at end of irq queue */
do {
thread_mask |= old->thread_mask;
old_ptr = &old->next;
old = *old_ptr;
} while (old);
shared = 1;
}
if (!shared) {
/*如果不是共享中断,则设置一些特性*/
} else if (new->flags & IRQF_TRIGGER_MASK) {
/* 共享中断的进一步设置*/
}
/*加入action链表*/
new->irq = irq;
*old_ptr = new;
return 0;
}
3、注册后就可以响应的中断函数啦!
static irqreturn_t msm_otg_irq(int irq, void *data)
{
.......................
if (work) {
wake_lock(&dev->wlock);
/*调度work继续处理*/
queue_work(dev->wq, &dev->sm_work);
}
}