新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > ARM-Linux s3c2440 之中斷分析(三)

        ARM-Linux s3c2440 之中斷分析(三)

        作者: 時間:2016-11-19 來源:網絡 收藏
        Linux通過以下函數來注冊中斷以及中斷相關的入口函數handle,只有先注冊IRQ,才能正常使用。

        本文引用地址:http://www.104case.com/article/201611/318130.htm
        1. intset_irq_chip(unsignedintirq,structirq_chip*chip)
        2. staticinlinevoidset_irq_handler(unsignedintirq,irq_flow_handler_thandle)
        3. staticinlinevoidset_irq_chained_handler(unsignedintirq,irq_flow_handler_thandle)

        實現的代碼如下:


        1. for(irqno=IRQ_EINT4t7;irqno<=IRQ_ADCPARENT;irqno++){
        2. /*setallthes3c2410internalirqs*/
        3. switch(irqno){
        4. /*dealwiththespecialIRQs(cascaded)*/
        5. caseIRQ_EINT4t7:
        6. caseIRQ_EINT8t23:
        7. caseIRQ_UART0:
        8. caseIRQ_UART1:
        9. caseIRQ_UART2:
        10. caseIRQ_ADCPARENT:
        11. set_irq_chip(irqno,&s3c_irq_level_chip);
        12. set_irq_handler(irqno,handle_level_irq);//電平觸發型
        13. break;
        14. caseIRQ_RESERVED6:
        15. caseIRQ_RESERVED24:
        16. /*noIRQhere*/
        17. break;
        18. default:
        19. //irqdbf("registeringirq%d(s3cirq)n",irqno);
        20. set_irq_chip(irqno,&s3c_irq_chip);
        21. set_irq_handler(irqno,handle_edge_irq);//邊緣觸發型
        22. set_irq_flags(irqno,IRQF_VALID);
        23. }
        24. /*級聯中斷的注冊*/
        25. set_irq_chained_handler(IRQ_EINT4t7,s3c_irq_demux_extint4t7);
        26. set_irq_chained_handler(IRQ_EINT8t23,s3c_irq_demux_extint8);
        27. set_irq_chained_handler(IRQ_UART0,s3c_irq_demux_uart0);
        28. set_irq_chained_handler(IRQ_UART1,s3c_irq_demux_uart1);
        29. set_irq_chained_handler(IRQ_UART2,s3c_irq_demux_uart2);
        30. set_irq_chained_handler(IRQ_ADCPARENT,s3c_irq_demux_adc);
        31. /*externalinterrupts*/
        32. for(irqno=IRQ_EINT0;irqno<=IRQ_EINT3;irqno++){
        33. irqdbf("registeringirq%d(extint)n",irqno);
        34. set_irq_chip(irqno,&s3c_irq_eint0t4);
        35. set_irq_handler(irqno,handle_edge_irq);
        36. set_irq_flags(irqno,IRQF_VALID);
        37. }
        38. for(irqno=IRQ_EINT4;irqno<=IRQ_EINT23;irqno++){
        39. irqdbf("registeringirq%d(extendeds3cirq)n",irqno);
        40. set_irq_chip(irqno,&s3c_irqext_chip);
        41. set_irq_handler(irqno,handle_edge_irq);
        42. set_irq_flags(irqno,IRQF_VALID);
        43. }
        44. /*registertheuartinterrupts*/
        45. irqdbf("s3c2410:registeringexternalinterruptsn");
        46. for(irqno=IRQ_S3CUART_RX0;irqno<=IRQ_S3CUART_ERR0;irqno++){
        47. irqdbf("registeringirq%d(s3cuart0irq)n",irqno);
        48. set_irq_chip(irqno,&s3c_irq_uart0);
        49. set_irq_handler(irqno,handle_level_irq);
        50. set_irq_flags(irqno,IRQF_VALID);
        51. }
        52. for(irqno=IRQ_S3CUART_RX1;irqno<=IRQ_S3CUART_ERR1;irqno++){
        53. irqdbf("registeringirq%d(s3cuart1irq)n",irqno);
        54. set_irq_chip(irqno,&s3c_irq_uart1);
        55. set_irq_handler(irqno,handle_level_irq);
        56. set_irq_flags(irqno,IRQF_VALID);
        57. }
        58. for(irqno=IRQ_S3CUART_RX2;irqno<=IRQ_S3CUART_ERR2;irqno++){
        59. irqdbf("registeringirq%d(s3cuart2irq)n",irqno);
        60. set_irq_chip(irqno,&s3c_irq_uart2);
        61. set_irq_handler(irqno,handle_level_irq);
        62. set_irq_flags(irqno,IRQF_VALID);
        63. }
        64. for(irqno=IRQ_TC;irqno<=IRQ_ADC;irqno++){//具體注冊IRQ_TC、IRQ_ADC
        65. irqdbf("registeringirq%d(s3cadcirq)n",irqno);
        66. set_irq_chip(irqno,&s3c_irq_adc);
        67. set_irq_handler(irqno,handle_edge_irq);
        68. set_irq_flags(irqno,IRQF_VALID);
        69. }

        從以上代碼中可以看出,注冊中斷主要是注冊中斷服務程序入口。Linux中將所有的中斷號用一個stuctirq_desc數據結構進行統一管理,每個中斷號或者一組中斷號(如級聯的中斷),對應一個structirq_desc, 所以根據相應的中斷號,可以獲取對應的中斷描述結構irq_desc:


        1. structirq_desc*desc=irq_to_desc(irq);
        2. irq_desc數據結構如下:
        3. structirq_desc{
        4. unsignedintirq;//中斷號
        5. irq_flow_handler_thandle_irq;//系統中斷處理的入口函數
        6. structirq_chip*chip;//對應的irq_chip結構,定義了與中斷處理有關的函數
        7. structirqaction*action;//用戶的中斷處理函數,調用request_irq時添加
        8. unsignedintstatus;//IRQ的狀態
        9. spinlock_tlock;
        10. constchar*name;
        11. }____cacheline_internodealigned_in_smp;

        irq_chip結構定義了各種中斷相關的處理行為,如開啟或禁止中斷以及中斷服務完成的之后對相關的中斷寄存器進行處理。關于電平觸發型和邊緣型觸發中斷入口函數可以從irq_chip結構中的看出只有ack函數的處理不同:


        1. structirq_chips3c_irq_level_chip={
        2. .name="s3c-level",
        3. .ack=s3c_irq_maskack,
        4. .mask=s3c_irq_mask,
        5. .unmask=s3c_irq_unmask,
        6. .set_wake=s3c_irq_wake
        7. };
        8. structirq_chips3c_irq_chip={
        9. .name="s3c",
        10. .ack=s3c_irq_ack,
        11. .mask=s3c_irq_mask,
        12. .unmask=s3c_irq_unmask,
        13. .set_wake=s3c_irq_wake
        14. };

        在s3cirq_maskack中多了以下代碼:

        mask = __raw_readl(S3C2410_INTMSK);

        __raw_writel(mask|bitval, S3C2410_INTMSK);

        實現的功能是,屏蔽相應的中斷。

        在early_trap_init()中已經進行了中斷(異常)向量的初始化,將異常向量表從物理地址0x00000000拷貝到虛擬0xffff0000的虛擬地址處。異常向量在arch/arm/kernel/entry-armv.S中定義:


        1. .globl__vectors_start
        2. rs_start:
        3. swiSYS_ERROR0
        4. bvector_und+stubs_offset
        5. ldrpc,.LCvswi+stubs_offset
        6. bvector_pabt+stubs_offset
        7. bvector_dabt+stubs_offset
        8. bvector_addrexcptn+stubs_offset
        9. bvector_irq+stubs_offset
        10. bvector_fiq+stubs_offset
        11. .globl__vectors_end

        那么當有中斷產生時:

        1. /*
        2. *Interrupthandling.Preservesr7,r8,r9
        3. */
        4. .macroirq_handler
        5. get_irqnr_preambler5,lr
        6. 1:get_irqnr_and_baser0,r6,r5,lr
        7. movner1,sp
        8. @
        9. @routinecalledwithr0=irqnumber,r1=structpt_regs*
        10. @
        11. adrnelr,1b
        12. bneasm_do_IRQ//跳轉到這里中斷的總入口函數

        這里的asm_do_IRQ對應arch/arm/kernel/irq.c中:


        1. asmlinkagevoid__exceptionasm_do_IRQ(unsignedintirq,structpt_regs*regs)

        所以這是Linux中所有中斷的總入口函數。asm_doIRQ()調用generic_handle_irq()再后調用

        generic_handle_irq_desc(),最后到各個irq_desc的處理。


        1. staticinlinevoidgeneric_handle_irq_desc(unsignedintirq,structirq_desc*desc)
        2. {
        3. #ifdefCONFIG_GENERIC_HARDIRQS_NO__DO_IRQ
        4. desc->handle_irq(irq,desc);
        5. #else
        6. if(likely(desc->handle_irq))
        7. desc->handle_irq(irq,desc);
        8. else
        9. __do_IRQ(irq);
        10. #endif
        11. }

        從總入口到用戶的中斷處理函數的流程:

        asm_do_IRQ() –-> generic_handle_irq() –->irq_dsc->handle() à handle_IRQ_event() à irq_des->action()

        最后對中斷處理流程進行簡單總結:

        (1)總入口函數asm_do_IRQ,獲取中斷號irq

        (2)asm_do_IRQ根據中斷號調用各中斷號所注冊的中斷入口函數irq_desc[irq]->handle_irq

        (3)最后在中斷入口函數中調用handle_IRQ_event()依次執行用戶的中斷處理函數action



        關鍵詞: ARMLinuxs3c2440中

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 汉中市| 正蓝旗| 隆尧县| 文登市| 津市市| 固原市| 沈丘县| 武威市| 鹿邑县| 杂多县| 武清区| 大田县| 米易县| 乡城县| 道真| 江川县| 宣威市| 久治县| 志丹县| 丰顺县| 淮安市| 乌拉特后旗| 定日县| 梁河县| 青田县| 玛曲县| 旺苍县| 抚松县| 云龙县| 新巴尔虎右旗| 布尔津县| 荆门市| 聂荣县| 新平| 诸暨市| 虞城县| 天等县| 米林县| 广南县| 贺兰县| 卓尼县|