国产精品久久久久影院,成人午夜福利视频,国产精品久久久久高潮,国产精品 欧美 亚洲 制服,国产精品白浆无码流出

Linux中斷體系結(jié)構(gòu)

發(fā)布者:SparklingRiver最新更新時間:2024-11-05 來源: cnblogs關(guān)鍵字:Linux  中斷  體系結(jié)構(gòu) 手機看文章 掃描二維碼
隨時隨地手機看文章

1.中斷處理體系結(jié)構(gòu)


Linux內(nèi)核將所有中斷統(tǒng)一編號,使用一個irq_desc結(jié)構(gòu)數(shù)組來描述這些中斷。


數(shù)組聲明在/linux/kernel/irq/handle.c中,其中#define NR_IRQS 128,定義在/linux/include/asm/irq.h中


 1 /*

 2  * Linux has a controller-independent interrupt architecture.

 3  * Every controller has a 'controller-template', that is used

 4  * by the main code to do the right thing. Each driver-visible

 5  * interrupt source is transparently wired to the appropriate

 6  * controller. Thus drivers need not be aware of the

 7  * interrupt-controller.

 8  *

 9  * The code is designed to be easily extended with new/different

10  * interrupt controllers, without having to do assembly magic or

11  * having to touch the generic code.

12  *

13  * Controller mappings for all interrupt sources:

14  */

15 struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {

16     [0 ... NR_IRQS-1] = {

17         .status = IRQ_DISABLED,

18         .chip = &no_irq_chip,

19         .handle_irq = handle_bad_irq,

20         .depth = 1,

21         .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),

22 #ifdef CONFIG_SMP

23         .affinity = CPU_MASK_ALL

24 #endif

25     }

26 };


irq_desc結(jié)構(gòu)的數(shù)據(jù)類型在/linuxinclude/linux/irq.h中定義,


 1 struct irq_desc {

 2     irq_flow_handler_t    handle_irq;

 3     struct irq_chip        *chip;

 4     struct msi_desc        *msi_desc;

 5     void            *handler_data;

 6     void            *chip_data;

 7     struct irqaction    *action;    /* IRQ action list */

 8     unsigned int        status;        /* IRQ status */

 9 

10     unsigned int        depth;        /* nested irq disables */

11     unsigned int        wake_depth;    /* nested wake enables */

12     unsigned int        irq_count;    /* For detecting broken IRQs */

13     unsigned int        irqs_unhandled;

14     spinlock_t        lock;

15 #ifdef CONFIG_SMP

16     cpumask_t        affinity;

17     unsigned int        cpu;

18 #endif

19 #if defined(CONFIG_GENERIC_PENDING_IRQ) || defined(CONFIG_IRQBALANCE)

20     cpumask_t        pending_mask;

21 #endif

22 #ifdef CONFIG_PROC_FS

23     struct proc_dir_entry    *dir;

24 #endif

25     const char        *name;

26 } ____cacheline_internodealigned_in_smp;


handle_irq是這個或這組中斷的處理函數(shù)入口。發(fā)生中斷時,總?cè)肟诤瘮?shù)asm_do_IRQ將根據(jù)中斷號調(diào)用相應(yīng)irq_desc數(shù)組項中handle_irq.


typedef    void fastcall (*irq_flow_handler_t)(unsigned int irq,                struct irq_desc *desc);

handle_irq使用chip結(jié)構(gòu)中的函數(shù)清除、屏蔽或者重新使能中斷,還要調(diào)用用戶在action鏈表中注冊的中斷處理函數(shù)。irq_chip結(jié)構(gòu)類型也是在include/linux/irq.h中定義,其中的成員大多用于操作底層硬件,比如設(shè)置寄存器以屏蔽中斷,使能中斷,清除中斷等。注意這里的成員name會出現(xiàn)在/proc/interrupts中。


struct irq_chip {

    const char    *name;

    unsigned int    (*startup)(unsigned int irq);

    void        (*shutdown)(unsigned int irq);

    void        (*enable)(unsigned int irq);

    void        (*disable)(unsigned int irq);


    void        (*ack)(unsigned int irq);

    void        (*mask)(unsigned int irq);

    void        (*mask_ack)(unsigned int irq);

    void        (*unmask)(unsigned int irq);

    void        (*eoi)(unsigned int irq);


    void        (*end)(unsigned int irq);

    void        (*set_affinity)(unsigned int irq, cpumask_t dest);

    int        (*retrigger)(unsigned int irq);

    int        (*set_type)(unsigned int irq, unsigned int flow_type);

    int        (*set_wake)(unsigned int irq, unsigned int on);


    /* Currently used only by UML, might disappear one day.*/

#ifdef CONFIG_IRQ_RELEASE_METHOD

    void        (*release)(unsigned int irq, void *dev_id);

#endif

    /*

     * For compatibility, ->typename is copied into ->name.

     * Will disappear.

     */

    const char    *typename;

};


irq_desc結(jié)構(gòu)中的irqaction結(jié)構(gòu)類型在include/linux/iterrupt.h中定義。用戶注冊的每個中斷處理函數(shù)用一個irqaction結(jié)構(gòu)來表示,一個中斷比如共享中斷可以有多個處理函數(shù),它們的irqaction結(jié)構(gòu)鏈接成一個鏈表,以action為表頭。irqation結(jié)構(gòu)在linux/include/linux/interrupt.h中定義如下:


typedef irqreturn_t (*irq_handler_t)(int, void *);


struct irqaction {

    irq_handler_t handler;

    unsigned long flags;

    cpumask_t mask;

    const char *name;

    void *dev_id;

    struct irqaction *next;

    int irq;

    struct proc_dir_entry *dir;

};


irq_desc結(jié)構(gòu)數(shù)組、它的成員“struct irq_chip *chip” 'struct irqaction *action',這3種數(shù)據(jù)結(jié)構(gòu)構(gòu)成了中斷處理體系的框架。下圖中描述了Linxu中斷處理體系結(jié)構(gòu)的關(guān)系圖:

中斷處理流程如下

(1)發(fā)生中斷時,CPU執(zhí)行異常向量vector_irq的代碼

(2)在vector_irq里面,最終會調(diào)用中斷處理的總?cè)肟诤瘮?shù)asm_do_IRQ

(3)asm_do_IRQ根據(jù)中斷號調(diào)用irq_desc數(shù)組項中的handle_irq。

(4)handle_irq會使用chip成員中的函數(shù)來設(shè)置硬件,比如清除中斷、禁止中斷、重新使能中斷等

(5)handle_irq逐個調(diào)用用戶在aciton鏈表中注冊的處理函數(shù)

   中斷體系結(jié)構(gòu)的初始化就是構(gòu)造這些數(shù)據(jù)結(jié)構(gòu),比如irq_desc數(shù)組項中的handle_irq、chip等成員;用戶注冊中斷時就是構(gòu)造action鏈表;用戶卸載中斷時就是從action鏈表中去除不需要的項。

 

2.中斷處理體系結(jié)構(gòu)的初始化

init_IRQ函數(shù)被用來初始化中斷處理體系結(jié)構(gòu),代碼在arch/arm/kernel/irq.c中


void __init init_IRQ(void)

{

    int irq;


    for (irq = 0; irq < NR_IRQS; irq++)

        irq_desc[irq].status |= IRQ_NOREQUEST | IRQ_NOPROBE;


#ifdef CONFIG_SMP

    bad_irq_desc.affinity = CPU_MASK_ALL;

    bad_irq_desc.cpu = smp_processor_id();

#endif

    init_arch_irq();

}


下面簡單分析下init_arch_irq();的獲取過程及調(diào)用順序


1 /*

2 init_arch_irq()的由來

3 定義一個空函數(shù)指針void (*init_arch_irq)(void) __initdata = NULL;

4 */

5 asmlinkage void __init start_kernel(void)

6     -->setup_arch(&command_line);

7         -->init_arch_irq = mdesc->init_irq;

8     -->init_IRQ();    

9         -->init_arch_irq()//即mdesc->init_irq=s3c24xx_init_irq


上述machine_desc結(jié)構(gòu)在/linux/arch/arm/mach-s3c2410/mach-bast.c如下宏中獲得,后面會分析machine_desc結(jié)構(gòu)。


MACHINE_START(BAST, 'Simtec-BAST')

    //Maintainer: Ben Dooks  

    .phys_io    = S3C2410_PA_UART,

    .io_pg_offst    = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,

    .boot_params    = S3C2410_SDRAM_PA + 0x100,

    .map_io        = bast_map_io,

    .init_irq    = s3c24xx_init_irq,

    .init_machine    = bast_init,

    .timer        = &s3c24xx_timer,

MACHINE_END


對于S3C2440開發(fā)板,這個函數(shù)就是s3c24xx_init_irq,移植machine_desc結(jié)構(gòu)中的init_irq成員就指向這個函數(shù)s3c24xx_init_irq函數(shù)在arch/arm/plat-s3c24xx/irq.c中定義,它為所有中斷設(shè)置了芯片相關(guān)的數(shù)據(jù)結(jié)構(gòu)(irq_desc[irq].chip),設(shè)置了處理函數(shù)入口(irq_desc[irq].handle_irq)。


以外部中斷EINT4-EINT23為例,用來設(shè)置它們的代碼如下:


void __init s3c24xx_init_irq(void)

{

    ...

    

    for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {

        irqdbf('registering irq %d (extended s3c irq)n', irqno);

        set_irq_chip(irqno, &s3c_irqext_chip);

        set_irq_handler(irqno, handle_edge_irq);

        set_irq_flags(irqno, IRQF_VALID);

    }

    ...    

    

}


set_irq_chip函數(shù)的作用就是“irq_desc[irno].chip = &s3c_irqext_chip”,以后就可能通過irq_desc[irqno].chip結(jié)構(gòu)中的函數(shù)指針設(shè)置這些外部中斷的觸發(fā)方式(電平觸發(fā),邊沿觸發(fā)),使能中斷,禁止中斷。


set_irq_chip函數(shù)的作用就是“irq_desc[irno].handler_irq = handle_edge_irq”,設(shè)置這些中斷的處理函數(shù)入口為handle_edge_irq。發(fā)生中斷時handle_edge_irq函數(shù)會調(diào)用用戶注冊的具體處理函數(shù);


set_irq_flags設(shè)置中斷標志為“IRQF_VALID”,表示可以使用它們。


init_IRQ函數(shù)執(zhí)行完后,irq_desc數(shù)組項的chip,handl_irq成員都被設(shè)置。


3.用戶注冊中斷過程分析


調(diào)用/linux/kernel/irq/manage.c中的request_irq函數(shù)。


int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)

    -->struct irqaction *action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);

    -->action->handler = handler;

    -->action->flags = irqflags;

    -->cpus_clear(action->mask);

    -->action->name = devname;

    -->action->next = NULL;

    -->action->dev_id = dev_id;

    -->retval = setup_irq(irq, action);

        -->request_irq函數(shù)根據(jù)中斷號找到irq_desc數(shù)組項,然后在它的action鏈表添加一個表

        -->irq_chip_set_defaults(desc->chip);//chip成員在init_IRQ()中已經(jīng)設(shè)置,這里設(shè)置其中還沒有設(shè)置的。

        -->設(shè)置中斷觸發(fā)方式

        -->啟動中斷


3.1將新建的irqaction結(jié)構(gòu)鏈入irq_desc[irq]結(jié)構(gòu)的action鏈表中


這有兩種可能。如果action鏈表為空,則直接鏈入;否則先判斷新建的irqaction結(jié)構(gòu)和鏈表中的irqaction結(jié)構(gòu)所表示的中斷類型是否一致,即是否都聲明為'可共享的'(IRQF_SHARED)、是否都使用相同的觸發(fā)方式,如果一致,則將新建的irqation結(jié)構(gòu)鏈入。

3.2設(shè)置irq_desc[irq]結(jié)構(gòu)中chip成員的還沒設(shè)置的指針


讓它們指向一些默認函數(shù)。chip成員在init_IRQ函數(shù)初始化中斷體系結(jié)構(gòu)的時候已經(jīng)設(shè)置了,這里只是設(shè)置其中還沒設(shè)置的指針這通過irq_chip_set_defaults函數(shù)來完成,它在kernel/irq/chip.c中定義


3.3設(shè)置中斷的觸發(fā)方式


如果requestt_irq傳入的irqflags參數(shù)表示中斷的觸發(fā)方式為高低電平觸發(fā)/邊沿觸發(fā),則調(diào)用irq_desc[irq]結(jié)構(gòu)中的chip-.set_type成員函數(shù)來進行設(shè)置:設(shè)置引腳功能為外部中斷,設(shè)置中斷觸發(fā)方式。


3.4啟動中斷


如果irq_desc[irq]結(jié)構(gòu)中status成員沒有被指明IRQ_NOAUTOEN(表示注冊中斷時不要使用中斷),還要調(diào)用chip->startup或chip->enable來啟動中斷,所謂啟動中斷通常就是使用中斷。一般情況下,只有那些“可以自動使能的”中斷對應(yīng)的irq_desc[irq].status才會被指明為IRQ_NOAUTOEN,所以,無論哪種情況,執(zhí)行request_irq注冊中斷之后,這個中斷就已經(jīng)被使能了。

[1] [2]
關(guān)鍵字:Linux  中斷  體系結(jié)構(gòu) 引用地址:Linux中斷體系結(jié)構(gòu)

上一篇:Linux異常處理體系結(jié)構(gòu)
下一篇:u-boot.bin生成過程分析

推薦閱讀最新更新時間:2025-07-04 13:27

Linux中斷體系結(jié)構(gòu)
1.中斷處理體系結(jié)構(gòu) Linux內(nèi)核將所有中斷統(tǒng)一編號,使用一個irq_desc結(jié)構(gòu)數(shù)組來描述這些中斷。 數(shù)組聲明在/linux/kernel/irq/handle.c中,其中#define NR_IRQS 128,定義在/linux/include/asm/irq.h中 1 /* 2 * Linux has a controller-independent interrupt architecture. 3 * Every controller has a 'controller-template', that is used 4 * by the main code to do the rig
[單片機]
<font color='red'>Linux</font><font color='red'>中斷</font><font color='red'>體系結(jié)構(gòu)</font>
S3C2440的中斷體系結(jié)構(gòu)
概述 S3C2440A中的中斷控制器接受來自60個中斷源的請求。提供這些中斷源的可以是內(nèi)部外設(shè),如DMA控制器、UART、IIC等等。在這些中斷源中,UARTn、AC97和EINTn中斷對于中斷控制器而言是“或”關(guān)系(在這幾個源中還可以有中斷分支)。 當(dāng)從內(nèi)部外設(shè)和外部中斷請求引腳收到多個中斷請求時,中斷控制器在仲裁步驟后請求ARM920T內(nèi)核的FIQ或IRQ。 總流程圖如下: 程序狀態(tài)寄存器(PSR)的 F 位和 I 位 如果 ARM920T CPU 中的 PSR 的 F 位被置位為 1,CPU 不會接受來自中斷控制器的快中斷請求(FIQ)。同 樣的如果 PSR 的 I 位被置位為 1,CPU 不會接受來自中斷控制器
[單片機]
S3C2440的<font color='red'>中斷</font><font color='red'>體系結(jié)構(gòu)</font>
Linux驅(qū)動之按鍵驅(qū)動編寫(中斷方式)
1、查看原理圖,確定需要控制的IO端口 打開原理圖,確定需要控制的IO端口為GPF0、GPF2、GPG3、GPG11??梢钥吹剿闹袛嗵枮镮RQ_EINT0、IRQ_EINT2、IRQ_EINT11、IRQ_EINT19 2、查看芯片手冊,確定IO端口的寄存器地址,可以看到因為用了兩組GPIO端口,所以它的基地址分別為0x56000050、0x56000060。中斷方式的寄存器基地址為0x56000088、0x5600008c、0x56000090 3、編寫驅(qū)動代碼,編寫驅(qū)動代碼的步驟如下: 1)、編寫出口、入口函數(shù)。代碼如下,具體說明參考Linux驅(qū)動之LED驅(qū)動編寫 static int second_
[單片機]
<font color='red'>Linux</font>驅(qū)動之按鍵驅(qū)動編寫(<font color='red'>中斷</font>方式)
s3c2440中斷學(xué)習(xí)筆記
進入異常時cpu將做如下工作 1.將中斷時pc的值copy到lr(此時pc的值為中斷指令位置+8,所以返回的指令地址應(yīng)該是當(dāng)前pc值+4) 2.CPSR- SPSR_(irq)  (相當(dāng)于bl跳轉(zhuǎn)) 3.強制進入irq,ARM工作模式 4.跳轉(zhuǎn)到異常制定的指令位置 進入異常時應(yīng)該保護寄存器:stmdb sp!, { r0-r12,lr } 退出時恢復(fù)寄存器:    ldmia  sp!,  {r0-r12,pc}^   ^ :當(dāng) register list 中有pc寄存器時,表示執(zhí)行指令后spsr中的值自動復(fù)制到cpsr中,如果沒有pc寄存器是,^表示操作的是用戶模式下的寄存器,而不是當(dāng)前特權(quán)模式的寄存器,也就是說在特權(quán)模式下
[單片機]
s3c2440裸機-電阻觸摸屏-3-觸摸屏TSC初始化和中斷服務(wù)程序框架
1. ADC中斷產(chǎn)生流程 中斷源: 這里是ADC和TSC共用一個中斷源。 SRCPND表示哪個中斷源產(chǎn)生了中斷請求。 INTMODE:配置中斷模式 配置中斷屏蔽寄存器 中斷掛起寄存器(用來顯示當(dāng)前優(yōu)先級最高的、正在發(fā)生的中斷, 需要清除對應(yīng)位) 從SRCPND寄存器可以讀到ADC和TSC復(fù)用的同一個中斷源,那么如何區(qū)分呢? 可以從SUBSRCPND寄存器配置,如下: 當(dāng)bit 9被置1時,表示TSC中斷。那么我們需要打開subsrcmask寄存器 所以TSC中斷的產(chǎn)生流程如下: 2. TSC編程實現(xiàn)  ?、俪跏蓟疶
[單片機]
STM32串口空閑中斷的使用
今天完善了USART串口接收數(shù)據(jù)函數(shù)以及程序,在每個USART外設(shè)上都添加了串口空閑中斷函數(shù)。其步驟如下: 添加總線空閑中斷功能的優(yōu)點: a) 可以準確地判斷出串口數(shù)據(jù)是否接收完畢,不需要額外添加定時器作數(shù)據(jù)接收完畢超時檢測,不僅可以減少了TIM定時器外設(shè) 的使用,提高系統(tǒng)性能,而且可以增強程序的可讀性(因為使用TIM定時器做超時檢測時,需要在TIM定時器中斷函數(shù)中添加一個 USART_RX_Over的標識符,影響了程序的可讀性); 添加總線空閑中斷功能的需要注意的地方: a) 在使用串口空閑中斷時需要添加讀DR位(數(shù)據(jù)寄存器)空閑中斷變量,因為每次觸發(fā)串口空閑中斷時,需要讀取對應(yīng)USART的DR位(數(shù)據(jù)寄存器)才能清除
[單片機]
STM32串口空閑<font color='red'>中斷</font>的使用
STM32 中斷時間計算
定時中斷發(fā)生的時間T: T = (arr+1)*(psc+1)/72M T=1/f 32的tclk已知 我們可以直接用這個tclk 去除我們設(shè)定的分頻系數(shù)(psc+1) 也就是把tclk 分成了(psc+)份 這個分頻系數(shù)的范圍在1~65535 這樣得到tclk/(psc+1)也就得到了定時器最終的頻率 我們在倒過來 得到我們的周期(psc+1)/tclk 在乘上我們的裝載值 也就得到我們想要的時間了 例
[單片機]
STM32 <font color='red'>中斷</font>時間計算
msp432快速入門第六節(jié)之按鍵掃描和GPIO中斷操作
(一)按鍵掃描 (1)配置引腳 在按鍵掃描這一節(jié),僅需要配置好引腳即可,打開TI的GPIO驅(qū)動庫,可以看到GPIO設(shè)置函數(shù)H文件如下: 在這個函數(shù)上方有對函數(shù)的說明: 解釋為:該函數(shù)配置MSP432的GPIO引腳為輸入模式,沒有指明被配置的引腳是否被上拉或者下拉,當(dāng)然如果需要配置輸入上拉或者輸入下拉需要使用此函數(shù)配置: 在這里我們直接使用普通配置,配置引腳為輸入即可。 如下進行引腳初始化:(板載兩個按鍵,一左一右均可以使用,注意復(fù)位鍵是在上面的) //key pin init void Key_Init(void) { GPIO_setAsInputPinWithPullUpResistor(KEY_LEFT
[單片機]
msp432快速入門第六節(jié)之按鍵掃描和GPIO<font color='red'>中斷</font>操作
小廣播
設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦

最新單片機文章

 
EEWorld訂閱號

 
EEWorld服務(wù)號

 
汽車開發(fā)圈

 
機器人開發(fā)圈

電子工程世界版權(quán)所有 京ICP證060456號 京ICP備10001474號-1 電信業(yè)務(wù)審批[2006]字第258號函 京公網(wǎng)安備 11010802033920號 Copyright ? 2005-2025 EEWORLD.com.cn, Inc. All rights reserved