日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Exynos4412 中断处理流程详解

發(fā)布時間:2023/12/9 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Exynos4412 中断处理流程详解 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

?Linux 中,當(dāng)外設(shè)觸發(fā)中斷后,大體處理流程如下:

a -- 具體CPU architecture相關(guān)的模塊會進(jìn)行現(xiàn)場保護(hù),然后調(diào)用machine driver對應(yīng)的中斷處理handler;

b -- machine driver對應(yīng)的中斷處理handler中會根據(jù)硬件的信息獲取HW interrupt ID,并且通過irq domain模塊翻譯成IRQ number;

c -- ?調(diào)用該IRQ number 對應(yīng)的high level irq event handler,在這個high level的handler中,會通過和interupt controller交互,進(jìn)行中斷處理的flow control(處理中斷的嵌套、搶占等),當(dāng)然最終會遍歷該中斷描述符的IRQ action list,調(diào)用外設(shè)的specific handler來處理該中斷;

d -- 具體CPU architecture相關(guān)的模塊會進(jìn)行現(xiàn)場恢復(fù);

? ? ?

? ? ? ? 總結(jié)下來,整個過程可以分為三部分:1、硬件處理部分;2、匯編處理部分;3、C 處理部分;

? ? ? ?下面我們來追蹤一下代碼,了解當(dāng)中斷發(fā)生時,Linux 是如何處理的,前面的一些中斷初始化部分就不再這里詳述了,下面開始具體分析:


一、硬件處理部分

? ? ? ??當(dāng)一切準(zhǔn)備好之后,一旦打開處理器的全局中斷就可以處理來自外設(shè)的各種中斷事件了。

? ? ? ? 當(dāng)外設(shè)(SOC內(nèi)部或者外部都可以)檢測到了中斷事件,就會通過interrupt requestion line上的電平或者邊沿(上升沿或者下降沿或者both)通知到該外設(shè)連接到的那個中斷控制器,而中斷控制器就會在多個處理器中選擇一個,并把該中斷通過IRQ(或者FIQ,本文不討論FIQ的情況)分發(fā)給該processor。

? ? ? ? ARM處理器感知到了中斷事件后,會進(jìn)行下面一系列的動作(硬件處理部分):

1、切換處理器模式

? ? ? ?修改 CPSR 寄存器中的 M[4:0],切換處理器模式位?IRQ Mode(這里M[4:0] 所添值為 10010);

2、保護(hù)現(xiàn)場

? ? ??保存發(fā)生中斷時,CPSR值與PC值(為恢復(fù)現(xiàn)場做準(zhǔn)備);這里要注意,此時中斷可能發(fā)生在 usr mode (用戶空間),也可能發(fā)生在 SVC mode(內(nèi)核空間);

3、mask IRQ exception

? ? ??關(guān)閉IRQ中斷,也就是設(shè)定CPSR.I = 1;

4、設(shè)定PC值為IRQ exception vector

? ? ? ?實現(xiàn)向異常向量表的跳轉(zhuǎn),ARM處理器會跳轉(zhuǎn)到IRQ的exception?vector地址,到這硬件所做的工作就結(jié)束了,下面就是軟件行為了。


? ? ???軟件處理部分流程如下:



? ? ? ?可以看到 Vetor_irq 是匯編部分入口點,而Asm_do_irq 是C 部分入口點,下面分析Vetor_irq 向 Asm_do_irq 跳轉(zhuǎn)過程


二、匯編部分

? ? ? ? 前面硬件部分結(jié)束后,跳轉(zhuǎn)到相應(yīng)的異常中斷處理程序處執(zhí)行,對于ARMv7向量表普遍是0xFFFF0018 ,而對于低向量PC=0x00000018 ??

? ? ? ? 假設(shè)在用戶空間時,產(chǎn)生了外部硬件中斷,這個時候的會跳轉(zhuǎn)到異常向量表,向量表(vector table)的代碼如下

【arch/arm/kernel/entry-armv.S】

[cpp]?view plaincopy
  • __vectors_start:---------------〉在中斷向量表被拷貝后,該地址就是0xffff0000.????
  • ?ARM(?swi?SYS_ERROR0?)????
  • ?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----------〉當(dāng)外部中斷產(chǎn)生時,pc直接指向這個地址。????
  • W(b)?vector_fiq?+?stubs_offset????
  • .globl?__vectors_end????
  • 1、IRQ mode中的處理 (vector table --- > vector_irq )

    ? ? ? IRQ mode的處理都在vector_irq中,vector_stub是一個宏,定義如下:

    [cpp]?view plaincopy
  • /*??
  • ?*?Vector?stubs.??
  • ?*??
  • ?*?This?code?is?copied?to?0xffff0200?so?we?can?use?branches?in?the??
  • ?*?vectors,?rather?than?ldr's.??Note?that?this?code?must?not??
  • ?*?exceed?0x300?bytes.??
  • ?*??
  • ?*?Common?stub?entry?macro:??
  • ?*???Enter?in?IRQ?mode,?spsr?=?SVC/USR?CPSR,?lr?=?SVC/USR?PC??
  • ?*??
  • ?*?SP?points?to?a?minimal?amount?of?processor-private?memory,?the?address??
  • ?*?of?which?is?copied?into?r0?for?the?mode?specific?abort?handler.??
  • ?*/????
  • ????.macro??vector_stub,?name,?mode,?correction=0????
  • ????.align??5????
  • ????
  • vector_\name:????
  • ????.if?\correction????
  • ????sub?lr,?lr,?#\correction??//因為硬件處理器是將當(dāng)前指令的下兩條指令的地址存儲在lr寄存器中,所以這里需要減4,讓他指向被中斷指令的下一條,這樣當(dāng)中斷被恢復(fù)時,可以繼續(xù)被中斷的指令繼續(xù)執(zhí)行。????
  • ????.endif????//需要注意的是,這個時候的lr寄存器,已經(jīng)是irq模式下的私有寄存器了,在中斷產(chǎn)生時,硬件處理器已經(jīng)自動為他賦了值。????
  • ????
  • ????@????
  • ????@?Save?r0,?lr_<exception>?(parent?PC)?and?spsr_<exception>????
  • ????@?(parent?CPSR)????
  • ????@????
  • ????stmia???sp,?{r0,?lr}????????@?save?r0,?lr//保存r0和lr寄存器,即被中斷的下一條指令????
  • ????mrs?lr,?spsr????
  • ????str?lr,?[sp,?#8]????????@?save?spsr????
  • ????
  • ????@????
  • ????@?Prepare?for?SVC32?mode.??IRQs?remain?disabled.//準(zhǔn)備從中斷模式切換到管理模式,不同的模式,對應(yīng)各自不同的堆棧。????
  • ????@????
  • ????mrs?r0,?cpsr????????
  • ????eor?r0,?r0,?#(\mode?^?SVC_MODE?|?PSR_ISETSTATE)????
  • ????msr?spsr_cxsf,?r0????
  • ????
  • ????@????
  • ????@?the?branch?table?must?immediately?follow?this?code????
  • ????@????
  • ????and?lr,?lr,?#0x0f???????????//獲取被中斷前,處理器所處的模式????
  • ?THUMB(?adr?r0,?1f??????????)????
  • ?THUMB(?ldr?lr,?[r0,?lr,?lsl?#2]????)????
  • ????mov?r0,?sp??//讓r0寄存器指向中斷模式下堆棧的基地址????
  • ?ARM(???ldr?lr,?[pc,?lr,?lsl?#2]????)????
  • ????movs????pc,?lr??????????@?branch?to?handler?in?SVC?mode,同時將中斷模式下的spsr_irq(irq私有的)賦值給cpsr(該寄存器所有模式共享)????
  • ENDPROC(vector_\name)??
  • 從這可以看出 vector_stub 的使用方法:

    ? ? ???vector_stub, name, mode, correction=0

    上面這段究竟做了些什么呢?

    (1)我們期望在棧上保存發(fā)生中斷時候的硬件現(xiàn)場(HW context),這里就包括ARM的core register。上一章我們已經(jīng)了解到,當(dāng)發(fā)生IRQ中斷的時候,lr中保存了發(fā)生中斷的PC+4,如果減去4的話,得到的就是發(fā)生中斷那一點的PC值。

    (2)當(dāng)前是IRQ mode,SP_irq在初始化的時候已經(jīng)設(shè)定(12個字節(jié))。在irq mode的stack上,依次保存了發(fā)生中斷那一點的r0值、PC值以及CPSR值(具體操作是通過spsr進(jìn)行的,其實硬件已經(jīng)幫我們保存了CPSR到SPSR中了)。為何要保存r0值?因為隨后的代碼要使用r0寄存器,因此我們要把r0放到棧上,只有這樣才能完完全全恢復(fù)硬件現(xiàn)場。

    (3)可憐的IRQ mode稍縱即逝,這段代碼就是準(zhǔn)備將ARM推送到SVC mode。如何準(zhǔn)備?其實就是修改SPSR的值,SPSR不是CPSR,不會引起processor mode的切換(畢竟這一步只是準(zhǔn)備而已)。

    (4)很多異常處理的代碼返回的時候都是使用了stack相關(guān)的操作,這里沒有。“movs pc, lr ”指令除了字面上意思(把lr的值付給pc),還有一個
    隱含的操作(movs中‘s’的含義):把SPSR copy到CPSR,從而實現(xiàn)了模式的切換

    這里有個問題:中斷為什么必須進(jìn)入svc模式

    一個最重要原因是:如果一個中斷模式(例如從usr進(jìn)入irq模式,在irq模式中)中重新允許了中斷,并且在這個中斷例程中使用了BL指令調(diào)用子程序,BL指令會自動將子程序返回地址保存到當(dāng)前模式的sp(即r14_irq)中,這個地址隨后會被在當(dāng)前模式下產(chǎn)生的中斷所破壞,因為產(chǎn)生中斷時CPU會將當(dāng)前模式的PC保存到r14_irq,這樣就把剛剛保存的子程序返回地址沖掉。為了避免這種情況,中斷例程應(yīng)該切換到SVC或者系統(tǒng)模式,這樣的話,BL指令可以使用r14_svc來保存子程序的返回地址


    2、vector table --- > vector_irq ?---> vector _stub

    對于IRQ Mode 則?vector_stub, irq, IRQ_MODE, 4? ?

    [cpp]?view plaincopy
  • __stubs_start:????
  • /*??
  • ?*?Interrupt?dispatcher??
  • ?*/????
  • vector_stub?irq,?IRQ_MODE,?4??//減去4,確保返回發(fā)生中斷之后的那條指令??
  • ????
  • ????
  • .long?__irq_usr@??0??(USR_26?/?USR_32)??//從用戶態(tài)進(jìn)入中斷的處理函數(shù)?base?address?+?0???
  • .long?__irq_invalid@??1??(FIQ_26?/?FIQ_32)????
  • .long?__irq_invalid@??2??(IRQ_26?/?IRQ_32)????
  • .long?__irq_svc@??3??(SVC_26?/?SVC_32)??//從SVC進(jìn)入中斷的處理函數(shù)?base?address?+?12??
  • .long?__irq_invalid@??4????
  • .long?__irq_invalid@??5????
  • .long?__irq_invalid@??6????
  • .long?__irq_invalid@??7????
  • .long?__irq_invalid@??8????
  • .long?__irq_invalid@??9????
  • .long?__irq_invalid@??a????
  • .long?__irq_invalid@??b????
  • .long?__irq_invalid@??c????
  • .long?__irq_invalid@??d????
  • .long?__irq_invalid@??e????
  • .long?__irq_invalid@??f????
  • 這里根據(jù)被中斷時,處理器模式的不同,分別跳轉(zhuǎn)到__irq_usr和__irq_svc兩個分支。


    3、vector table --- > vector_irq ?---> vector _stub --->?__irq_usr

    在這里我們以__irq_usr為例來說明:

    [cpp]?view plaincopy
  • __irq_usr:????
  • ????usr_entry???????//進(jìn)行中斷前的硬件上下文的保存????
  • ????kuser_cmpxchg_check????
  • ????irq_handler????
  • ????get_thread_info?tsk//獲取被中斷的用戶進(jìn)程或內(nèi)核線程所對應(yīng)的內(nèi)核棧所對應(yīng)的thread?info結(jié)構(gòu)。????
  • ????mov?why,?#0????
  • ????b???ret_to_user_from_irq//恢復(fù)被中斷時的上下文,然后繼續(xù)被中斷的進(jìn)程或線程的執(zhí)行????
  • ?UNWIND(.fnend??????)????
  • ENDPROC(__irq_usr)??

  • 4、vector table --- > vector_irq ?---> vector _stub --->?__irq_usr ---> usr_entry

    usr_entry展開如下: [cpp]?view plaincopy
  • .macro??usr_entry????
  • UNWIND(.fnstart?)????
  • UNWIND(.cantunwind??)???@?don't?unwind?the?user?space????
  • sub?sp,?sp,?#S_FRAME_SIZE???//?#S_FRAME_SIZE的值為72????
  • ARM(????stmib???sp,?{r1?-?r12}??)??????//盡管當(dāng)前是處于管理模式,但由于svc和usr的r0-r12是公共的,所以相當(dāng)于保存用戶模式的r1-r12寄存器????
  • THUMB(??stmia???sp,?{r0?-?r12}??)????
  • ????
  • ldmia???r0,?{r3?-?r5}??????????//將之前保存在中斷模式堆棧中的r0_usr,lr,spsr分別存儲到r3-r5中????
  • add?r0,?sp,?#S_PC???????@?here?for?interlock?avoidance?#S_PC=60????
  • mov?r6,?#-1?????????@??""??""?????""????????""????
  • ????
  • str?r3,?[sp]????????@?save?the?"real"?r0?copied????
  • ????????????????@?from?the?exception?stack????
  • ????
  • @????
  • @?We?are?now?ready?to?fill?in?the?remaining?blanks?on?the?stack:????
  • @????
  • @??r4?-?lr_<exception>,?already?fixed?up?for?correct?return/restart????
  • @??r5?-?spsr_<exception>????
  • @??r6?-?orig_r0?(see?pt_regs?definition?in?ptrace.h)????
  • @????
  • @?Also,?separately?save?sp_usr?and?lr_usr????
  • @????
  • stmia???r0,?{r4?-?r6}????
  • ARM(????stmdb???r0,?{sp,?lr}^???????????)//保存用戶模式下的sp_usr,lr_usr????
  • THUMB(??store_user_sp_lr?r0,?r1,?S_SP?-?S_PC????)????
  • ????
  • @????
  • @?Enable?the?alignment?trap?while?in?kernel?mode????
  • @????
  • alignment_trap?r0????
  • ????
  • @????
  • @?Clear?FP?to?mark?the?first?stack?frame????
  • @????
  • zero_fp????
  • ????
  • ifdef?CONFIG_IRQSOFF_TRACER????
  • bl??trace_hardirqs_off????
  • endif????
  • .endm????
  • ? ? ? 代碼執(zhí)行到這里的時候,ARM處理已經(jīng)切換到了【SVC mode】。一旦進(jìn)入SVC mode,ARM處理器看到的寄存器已經(jīng)發(fā)生變化,這里的sp已經(jīng)變成了sp_svc了。因此,后續(xù)的壓棧操作都是壓入了發(fā)生中斷那一刻的進(jìn)程的(或者內(nèi)核線程)內(nèi)核棧(svc mode棧)。

    ? ? ?此時的管理模式的內(nèi)核棧分布如下:

    ? ? ? ?需要說明的是:上圖中的lr_irq即為用戶模式下被中斷指令的下一條指令,spsr_irq即為用戶模式下被中斷時的cpsr寄存器。


    5、vector table --- > vector_irq ?---> vector _stub --->?__irq_usr ---> (usr_entry ?--->?irq_handler )

    ? ? ? ?usr_entry 結(jié)束后,會執(zhí)行 irq_handler

    irq_handler的實現(xiàn)過程?arch\arm\kernel\entry-armv.S

    [cpp]?view plaincopy
  • .macro?irq_handler??
  • ??????????????get_irqnr_preamble?r5,?lr??
  • ??????????????@在include/asm/arch-s3c2410/entry-macro.s中定義了宏get_irqnr_preamble為空操作,什么都不做??
  • ??????????????1:?get_irqnr_and_base?r0,?r6,?r5,?lr?@判斷中斷號,通過R0返回,3.5節(jié)有實現(xiàn)過程???
  • ??????????????movne?r1,?sp??
  • ??????????????@??
  • ??????????????@?routine?called?with?r0?=?irq?number,?r1?=?struct?pt_regs?*??
  • ??????????????@??
  • ??????????????adrne?lr,?1b??
  • ??????????????bne?asm_do_IRQ?@進(jìn)入中斷處理。???
  • ???????……???
  • ??????????????.endm??
  • 可以看到?bne asm_do_IRQ @進(jìn)入中斷處理 ?淚奔~~o(>_<)o ~~ 終于到了asm_do_IRQ

    可以看到整個跳轉(zhuǎn)過程:

    vector table --- >?vector_irq??--->vector_stub, irq, IRQ_MODE, 4?--->?__irq_usr?---> usr_entry ?--->?irq_handler?--->asm_do_IRQ?



    三、C語言處理部分

    1、?asm_do_IRQ

    ? ? ? ??asm_do_IRQ實現(xiàn)過程,arch/arm/kernel/irq.c?

    [cpp]?view plaincopy
  • ?*?asm_do_IRQ?is?the?interface?to?be?used?from?assembly?code.??
  • ?*/??
  • asmlinkage?void?__exception_irq_entry??
  • asm_do_IRQ(unsigned?int?irq,?struct?pt_regs?*regs)??
  • {??
  • ????handle_IRQ(irq,?regs);??
  • }??
  • [cpp]?view plaincopy
  • <span?style="font-family:?Arial,?Helvetica,?sans-serif;">其中關(guān)鍵一步handle_IRQ(irq,?regs)</span>??
  • 2、handle_IRQ(irq, regs)

    [cpp]?view plaincopy
  • /*?
  • ?*?handle_IRQ?handles?all?hardware?IRQ's.??Decoded?IRQs?should?
  • ?*?not?come?via?this?function.??Instead,?they?should?provide?their?
  • ?*?own?'handler'.??Used?by?platform?code?implementing?C-based?1st?
  • ?*?level?decoding.?
  • ?*/??
  • void?handle_IRQ(unsigned?int?irq,?struct?pt_regs?*regs)??
  • {??
  • ????struct?pt_regs?*old_regs?=?set_irq_regs(regs);??
  • ??
  • ????irq_enter();??
  • ??
  • ????/*?
  • ?????*?Some?hardware?gives?randomly?wrong?interrupts.??Rather?
  • ?????*?than?crashing,?do?something?sensible.?
  • ?????*/??
  • ????if?(unlikely(irq?>=?nr_irqs))?{??
  • ????????if?(printk_ratelimit())??
  • ????????????printk(KERN_WARNING?"Bad?IRQ%u\n",?irq);??
  • ????????ack_bad_irq(irq);??
  • ????}?else?{??
  • ????????generic_handle_irq(irq);??
  • ????}??
  • ??
  • ????irq_exit();??
  • ????set_irq_regs(old_regs);??
  • }??
  • 主要調(diào)用generic_handle_irq(irq)


    3、generic_handle_irq(irq)

    [cpp]?view plaincopy
  • include/linux/irq.h??
  • static?inline?void?generic_handle_irq_desc(unsigned?int?irq,?struct?irq_desc?*desc)??
  • {??
  • #ifdef?CONFIG_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??
  • }??
  • ??
  • static?inline?void?generic_handle_irq(unsigned?int?irq)??
  • {??
  • ????????generic_handle_irq_desc(irq,?irq_to_desc(irq));??
  • }??
  • generic_handle_irq調(diào)用前面定義的generic_handle_irq_desc


    4、generic_handle_irq_des

    [cpp]?view plaincopy
  • static?inline?void?generic_handle_irq_desc(unsigned?int?irq,?struct?irq_desc?*desc)??
  • ??
  • desc->handle_irq(irq,?desc);??
  • 而 generic_handle_irq_desc也沒做什么,調(diào)用desc——>handle_irq</strong>,這個函數(shù)就是irq_desc中的成員


    5、irq_desc結(jié)構(gòu)體 ??? ?

    ? ? ? ?Linux內(nèi)核將所有中斷統(tǒng)一編號,使用irq_desc結(jié)構(gòu)來描述中斷:每個數(shù)組項對應(yīng)一個中斷(也可能是一組中斷,它們使用共同的中斷號),里面記錄了中斷的名稱,中斷狀態(tài),中斷標(biāo)記,并提供硬件訪問函數(shù)(清除,屏蔽,使能中斷),提供了這個中斷的處理函數(shù)的入口,通過它可以調(diào)用用戶注冊的中斷處理函數(shù)

    [cpp]?view plaincopy
  • include/linux/irq.h??
  • {??
  • ????.........??
  • ??
  • ????irq_flow_handler_t?handle_irq;???//當(dāng)前的中斷處理函數(shù)入口??
  • ????struct?irq_chip?*chip;???????//底層的硬件訪問??
  • ??????
  • ????..........??
  • ??
  • ????struct?irqaction?*action;?//用戶提供的中斷處理函數(shù)鏈表??
  • ????unsigned?int?status;?//IRQ狀態(tài)??
  • ??
  • ????...........??
  • ??
  • ????const?char?*name;?????//中斷名稱??
  • }?____cacheline_internodealigned_in_smp;??
  • ? ? Handle_irq是這個或者這組中斷的處理函數(shù)入口

    ? ? 這里調(diào)用desc->handle_irq分為倆種情況,一是單獨的中斷號的,一是共享中斷號的,倆者的區(qū)別在于后者需要先判斷是共享中斷的中的哪一個然后再真正的去調(diào)用handle_irq,所以我這里分析一下單獨中斷號的處理流程,共享中斷也是一樣可以分析。

    ? ? ? ? 我們分析一個具體的,以外部中斷為例

    [cpp]?view plaincopy
  • for?(irqno?=?IRQ_EINT0;?irqno?<=?IRQ_EINT3;?irqno++)?{??
  • ???????????????irqdbf("registering?irq?%d?(ext?int)\n",?irqno);??
  • ???????????????set_irq_chip(irqno,?&s3c_irq_eint0t4);??
  • ???????????????set_irq_handler(irqno,?handle_edge_irq);??
  • ???????????????set_irq_flags(irqno,?IRQF_VALID);??
  • ????????}??
  • ? ? ? ?上面代碼我們看到,set_irq_handler的值是handler_edge_irq ,這里是處理邊沿觸發(fā)的中斷函數(shù),當(dāng)然還有電平觸發(fā)方式的中斷(handler_level_irq),繼續(xù)看代碼 [cpp]?view plaincopy
  • kernel/irq/chip.c??
  • void??
  • handle_edge_irq(unsigned?int?irq,?struct?irq_desc?*desc)??
  • {??
  • ????????spin_lock(&desc->lock);?????????上鎖??
  • ???
  • ????????desc->status?&=?~(IRQ_REPLAY?|?IRQ_WAITING);???
  • ???
  • ????????/*?
  • ?????????*?If?we're?currently?running?this?IRQ,?or?its?disabled,?
  • ?????????*?we?shouldn't?process?the?IRQ.?Mark?it?pending,?handle?
  • ?????????*?the?necessary?masking?and?go?out?
  • ?????????*/??
  • ????????if?(unlikely((desc->status?&?(IRQ_INPROGRESS?|?IRQ_DISABLED))?||???判斷??
  • ???????????????????!desc->action))?{??
  • ???????????????desc->status?|=?(IRQ_PENDING?|?IRQ_MASKED);??
  • ???????????????mask_ack_irq(desc,?irq);???屏蔽并清除中斷??
  • ???????????????goto?out_unlock;??
  • ????????}??
  • ????????kstat_incr_irqs_this_cpu(irq,?desc);?中斷統(tǒng)計計數(shù)??
  • ???
  • ????????/*?Start?handling?the?irq?*/??
  • ????????if?(desc->chip->ack)??????應(yīng)答中斷??
  • ???????????????desc->chip->ack(irq);??
  • ???
  • ????????/*?Mark?the?IRQ?currently?in?progress.*/??
  • ????????desc->status?|=?IRQ_INPROGRESS;???標(biāo)記中斷狀態(tài)??
  • ???
  • ????????do?{??
  • ???????????????struct?irqaction?*action?=?desc->action;??
  • ???????????????irqreturn_t?action_ret;??
  • ???
  • ???????????????if?(unlikely(!action))?{??
  • ???????????????????????desc->chip->mask(irq);??
  • ???????????????????????goto?out_unlock;??
  • ???????????????}??
  • ???
  • ???????????????/*?
  • ????????????????*?When?another?irq?arrived?while?we?were?handling?
  • ????????????????*?one,?we?could?have?masked?the?irq.?
  • ????????????????*?Renable?it,?if?it?was?not?disabled?in?meantime.?
  • ????????????????*/??
  • ???????????????if?(unlikely((desc->status?&??
  • ??????????????????????????????(IRQ_PENDING?|?IRQ_MASKED?|?IRQ_DISABLED))?==??
  • ?????????????????????????????(IRQ_PENDING?|?IRQ_MASKED)))?{??
  • ???????????????????????desc->chip->unmask(irq);??
  • ???????????????????????desc->status?&=?~IRQ_MASKED;??
  • ???????????????}??
  • ???
  • ???????????????desc->status?&=?~IRQ_PENDING;??
  • ???????????????spin_unlock(&desc->lock);??
  • ???????????????action_ret?=?handle_IRQ_event(irq,?action);??處理中斷,最重要的函數(shù),注意參數(shù),action這個參數(shù)將聯(lián)系到我們的用戶中斷處理函數(shù)??
  • ???????????????if?(!noirqdebug)??
  • ???????????????????????note_interrupt(irq,?desc,?action_ret);??
  • ???????????????spin_lock(&desc->lock);??
  • ???
  • ????????}?while?((desc->status?&?(IRQ_PENDING?|?IRQ_DISABLED))?==?IRQ_PENDING);??
  • ???
  • ????????desc->status?&=?~IRQ_INPROGRESS;??
  • out_unlock:??
  • ????????spin_unlock(&desc->lock);??
  • }??
  • 進(jìn)行追蹤handle_IRQ_event()

    [cpp]?view plaincopy
  • kernel/irq/handle.c??
  • ???????????????trace_irq_handler_entry(irq,?action);??
  • ???????????????ret?=?action->handler(irq,?action->dev_id);??
  • ???????????????trace_irq_handler_exit(irq,?action,?ret);??
  • ? ? ? ?調(diào)用action中的handler,我們注冊中斷的時候注意任務(wù)就是構(gòu)造一個irqaction結(jié)構(gòu)并添加到irq_desc中的irqaction鏈表中的指針action下面。現(xiàn)在處理中斷中我們就看到了調(diào)用了我們自己的中斷處理函數(shù)來處理中斷了。至此中斷處理流程就結(jié)束了


    總結(jié)軟件部分:

    asm_do_IRQ --> handle_IRQ(irq, regs)--> generic_handle_irq(irq) --> generic_handle_irq_desc --> (desc—>handle_irq ) -->handle_level_irq --> handle_irq_event--->?action->handler(irq, action->dev_id)

    總結(jié)

    以上是生活随笔為你收集整理的Exynos4412 中断处理流程详解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。