Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1598693
  • 博文数量: 204
  • 博客积分: 2215
  • 博客等级: 大尉
  • 技术积分: 4427
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-06 08:03
个人简介

气质,源于心灵的自信!

文章存档

2018年(1)

2017年(1)

2016年(1)

2015年(18)

2014年(20)

2013年(30)

2012年(119)

2011年(14)

分类: 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 idfree irq的时候用上,根据该idaction链表中去除对应idaction

__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);

}

}

阅读(3137) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~