ARM-Linux s3c2440 之中斷分析(三)
- intset_irq_chip(unsignedintirq,structirq_chip*chip)
- staticinlinevoidset_irq_handler(unsignedintirq,irq_flow_handler_thandle)
- staticinlinevoidset_irq_chained_handler(unsignedintirq,irq_flow_handler_thandle)
實(shí)現(xiàn)的代碼如下:
- for(irqno=IRQ_EINT4t7;irqno<=IRQ_ADCPARENT;irqno++){
- /*setallthes3c2410internalirqs*/
- switch(irqno){
- /*dealwiththespecialIRQs(cascaded)*/
- caseIRQ_EINT4t7:
- caseIRQ_EINT8t23:
- caseIRQ_UART0:
- caseIRQ_UART1:
- caseIRQ_UART2:
- caseIRQ_ADCPARENT:
- set_irq_chip(irqno,&s3c_irq_level_chip);
- set_irq_handler(irqno,handle_level_irq);//電平觸發(fā)型
- break;
- caseIRQ_RESERVED6:
- caseIRQ_RESERVED24:
- /*noIRQhere*/
- break;
- default:
- //irqdbf("registeringirq%d(s3cirq)n",irqno);
- set_irq_chip(irqno,&s3c_irq_chip);
- set_irq_handler(irqno,handle_edge_irq);//邊緣觸發(fā)型
- set_irq_flags(irqno,IRQF_VALID);
- }
- /*級(jí)聯(lián)中斷的注冊(cè)*/
- set_irq_chained_handler(IRQ_EINT4t7,s3c_irq_demux_extint4t7);
- set_irq_chained_handler(IRQ_EINT8t23,s3c_irq_demux_extint8);
- set_irq_chained_handler(IRQ_UART0,s3c_irq_demux_uart0);
- set_irq_chained_handler(IRQ_UART1,s3c_irq_demux_uart1);
- set_irq_chained_handler(IRQ_UART2,s3c_irq_demux_uart2);
- set_irq_chained_handler(IRQ_ADCPARENT,s3c_irq_demux_adc);
- /*externalinterrupts*/
- for(irqno=IRQ_EINT0;irqno<=IRQ_EINT3;irqno++){
- irqdbf("registeringirq%d(extint)n",irqno);
- set_irq_chip(irqno,&s3c_irq_eint0t4);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_EINT4;irqno<=IRQ_EINT23;irqno++){
- irqdbf("registeringirq%d(extendeds3cirq)n",irqno);
- set_irq_chip(irqno,&s3c_irqext_chip);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- /*registertheuartinterrupts*/
- irqdbf("s3c2410:registeringexternalinterruptsn");
- for(irqno=IRQ_S3CUART_RX0;irqno<=IRQ_S3CUART_ERR0;irqno++){
- irqdbf("registeringirq%d(s3cuart0irq)n",irqno);
- set_irq_chip(irqno,&s3c_irq_uart0);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_S3CUART_RX1;irqno<=IRQ_S3CUART_ERR1;irqno++){
- irqdbf("registeringirq%d(s3cuart1irq)n",irqno);
- set_irq_chip(irqno,&s3c_irq_uart1);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_S3CUART_RX2;irqno<=IRQ_S3CUART_ERR2;irqno++){
- irqdbf("registeringirq%d(s3cuart2irq)n",irqno);
- set_irq_chip(irqno,&s3c_irq_uart2);
- set_irq_handler(irqno,handle_level_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
- for(irqno=IRQ_TC;irqno<=IRQ_ADC;irqno++){//具體注冊(cè)IRQ_TC、IRQ_ADC
- irqdbf("registeringirq%d(s3cadcirq)n",irqno);
- set_irq_chip(irqno,&s3c_irq_adc);
- set_irq_handler(irqno,handle_edge_irq);
- set_irq_flags(irqno,IRQF_VALID);
- }
從以上代碼中可以看出,注冊(cè)中斷主要是注冊(cè)中斷服務(wù)程序入口。Linux中將所有的中斷號(hào)用一個(gè)stuctirq_desc數(shù)據(jù)結(jié)構(gòu)進(jìn)行統(tǒng)一管理,每個(gè)中斷號(hào)或者一組中斷號(hào)(如級(jí)聯(lián)的中斷),對(duì)應(yīng)一個(gè)structirq_desc, 所以根據(jù)相應(yīng)的中斷號(hào),可以獲取對(duì)應(yīng)的中斷描述結(jié)構(gòu)irq_desc:
- structirq_desc*desc=irq_to_desc(irq);
- irq_desc數(shù)據(jù)結(jié)構(gòu)如下:
- structirq_desc{
- unsignedintirq;//中斷號(hào)
- …
- irq_flow_handler_thandle_irq;//系統(tǒng)中斷處理的入口函數(shù)
- structirq_chip*chip;//對(duì)應(yīng)的irq_chip結(jié)構(gòu),定義了與中斷處理有關(guān)的函數(shù)
- …
- structirqaction*action;//用戶(hù)的中斷處理函數(shù),調(diào)用request_irq時(shí)添加
- unsignedintstatus;//IRQ的狀態(tài)
- …
- spinlock_tlock;
- …
- constchar*name;
- }____cacheline_internodealigned_in_smp;
irq_chip結(jié)構(gòu)定義了各種中斷相關(guān)的處理行為,如開(kāi)啟或禁止中斷以及中斷服務(wù)完成的之后對(duì)相關(guān)的中斷寄存器進(jìn)行處理。關(guān)于電平觸發(fā)型和邊緣型觸發(fā)中斷入口函數(shù)可以從irq_chip結(jié)構(gòu)中的看出只有ack函數(shù)的處理不同:
- structirq_chips3c_irq_level_chip={
- .name="s3c-level",
- .ack=s3c_irq_maskack,
- .mask=s3c_irq_mask,
- .unmask=s3c_irq_unmask,
- .set_wake=s3c_irq_wake
- };
- structirq_chips3c_irq_chip={
- .name="s3c",
- .ack=s3c_irq_ack,
- .mask=s3c_irq_mask,
- .unmask=s3c_irq_unmask,
- .set_wake=s3c_irq_wake
- };
在s3cirq_maskack中多了以下代碼:
mask = __raw_readl(S3C2410_INTMSK);
__raw_writel(mask|bitval, S3C2410_INTMSK);
實(shí)現(xiàn)的功能是,屏蔽相應(yīng)的中斷。
在early_trap_init()中已經(jīng)進(jìn)行了中斷(異常)向量的初始化,將異常向量表從物理地址0x00000000拷貝到虛擬0xffff0000的虛擬地址處。異常向量在arch/arm/kernel/entry-armv.S中定義:
- .globl__vectors_start
- rs_start:
- swiSYS_ERROR0
- bvector_und+stubs_offset
- ldrpc,.LCvswi+stubs_offset
- bvector_pabt+stubs_offset
- bvector_dabt+stubs_offset
- bvector_addrexcptn+stubs_offset
- bvector_irq+stubs_offset
- bvector_fiq+stubs_offset
- .globl__vectors_end
那么當(dāng)有中斷產(chǎn)生時(shí):
- /*
- *Interrupthandling.Preservesr7,r8,r9
- */
- .macroirq_handler
- get_irqnr_preambler5,lr
- 1:get_irqnr_and_baser0,r6,r5,lr
- movner1,sp
- @
- @routinecalledwithr0=irqnumber,r1=structpt_regs*
- @
- adrnelr,1b
- bneasm_do_IRQ//跳轉(zhuǎn)到這里中斷的總?cè)肟诤瘮?shù)
這里的asm_do_IRQ對(duì)應(yīng)arch/arm/kernel/irq.c中:
- asmlinkagevoid__exceptionasm_do_IRQ(unsignedintirq,structpt_regs*regs)
所以這是Linux中所有中斷的總?cè)肟诤瘮?shù)。asm_doIRQ()調(diào)用generic_handle_irq()再后調(diào)用
generic_handle_irq_desc(),最后到各個(gè)irq_desc的處理。
- staticinlinevoidgeneric_handle_irq_desc(unsignedintirq,structirq_desc*desc)
- {
- #ifdefCONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
- desc->handle_irq(irq,desc);
- #else
- if(likely(desc->handle_irq))
- desc->handle_irq(irq,desc);
- else
- __do_IRQ(irq);
- #endif
- }
從總?cè)肟诘接脩?hù)的中斷處理函數(shù)的流程:
asm_do_IRQ() –-> generic_handle_irq() –->irq_dsc->handle() à handle_IRQ_event() à irq_des->action()
最后對(duì)中斷處理流程進(jìn)行簡(jiǎn)單總結(jié):
(1)總?cè)肟诤瘮?shù)asm_do_IRQ,獲取中斷號(hào)irq
(2)asm_do_IRQ根據(jù)中斷號(hào)調(diào)用各中斷號(hào)所注冊(cè)的中斷入口函數(shù)irq_desc[irq]->handle_irq
(3)最后在中斷入口函數(shù)中調(diào)用handle_IRQ_event()依次執(zhí)行用戶(hù)的中斷處理函數(shù)action
評(píng)論