您的位置:首页 > 编程语言

读代码细学内核中断机制-中断的响应

2012-08-11 18:03 141 查看
在内核中断初始化完成并且设备注册了响应的中断后,内核就可以响应相应的中断了。

首先要确定如果一个外设发出中断请求,它到底做了什么,设备是不能直接发出中断的,而是借助中断控制器,设备向中断控制器请求中断,这就是IRQ的来历。

对于龙芯1B处理器来说,中断控制器有四条输出线接在了处理器上,也就是四条中断线,INT0~INT3,每条中断线对应32个中断源,而中断控制器寄存器的位域也就跟这32个中断源一一对应。

每个设备控制器都有一条IRQ输出线和中断控制器寄存器的相应位相连,这样当相应设备控制器发出中断时,中断控制器寄存器相应位就置1,中断控制器就通过相应的中断输出线向内核发出中断,CP0协处理器寄存器cause寄存器的IP0~IP7相应位就置1。

内核响应中断就是跳转到事先设定好的异常向量入口,前面说过,对于龙芯1B内核是在0x80000180,首先读取cause寄存器中的例外码,确定是哪一种通用异常,然后跳转到exception_handler数组相应的处理函数中。对于中断就是数组的0号成员,处理函数是handler_int,执行handler_int,这个函数中是检查status寄存器的全局中断标志位IE是否置1,然后跳转到plat_irq_dispatch,这个函数就是中断的下发函数了,读取出status寄存器的IM0~IM7,读出cause寄存器的IP0~IP7,相与就得到具体是产生哪一种中断并且该中断也是被使能了。

asmlinkage void plat_irq_dispatch(struct pt_regs *regs)

{

// unsigned int pending = read_c0_cause() & read_c0_status() & ST0_IM;

unsigned int cause_reg = read_c0_cause() ;

unsigned int status_reg = read_c0_status() ;

unsigned volatile int cause = cause_reg & ST0_IM;

unsigned volatile int status = status_reg & ST0_IM;

unsigned int pending = cause & status;

uint64_t volatile counter1, counter2;

if (pending & CAUSEF_IP7) {

ll_timer_interrupt(MIPS_CPU_IRQ_BASE+7);

}

else if (pending & CAUSEF_IP2) {

sb2f_board_hw_irqdispatch(0);

}

else if (pending & CAUSEF_IP3) {

sb2f_board_hw_irqdispatch(1);

}

else if (pending & CAUSEF_IP4) {

sb2f_board_hw_irqdispatch(2);

}

else if (pending & CAUSEF_IP5) {

sb2f_board_hw_irqdispatch(3);

}

else if (pending & CAUSEF_IP6) {

sb2f_board_hw_irqdispatch(4);

} else {

spurious_interrupt();

}

}

从这个函数中可以看出INT0~INT3对应的是IP2~IP5,这个函数调用sb2f_board_hw_irqdispatch,读出相应中断线的ISR中断状态寄存器,计算出是哪一位被置1,然后计算出中断号,再调用do_IRQ函数。

void sb2f_board_hw_irqdispatch(int n)

{

int irq;

int intstatus = 0;

int status;

/* Receive interrupt signal, compute the irq */

status = read_c0_cause();

intstatus = (sb2f_board_hw0_icregs+n)->int_isr;



irq=ffs(intstatus);

// prom_printf("irq=%d,n=%d,realirq=%d\n",irq,n,n*32+irq-1);



if(!irq){

printk("Unknow interrupt status %x intstatus %x \n" , status, intstatus);

return;

}

else do_IRQ(n*32+irq-1);

}

do_IRQ函数
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: