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)被使能了。
上一篇:Linux異常處理體系結(jié)構(gòu)
下一篇:u-boot.bin生成過程分析
推薦閱讀最新更新時間:2025-07-04 13:27






設(shè)計資源 培訓(xùn) 開發(fā)板 精華推薦
- Microchip 升級數(shù)字信號控制器(DSC)產(chǎn)品線 推出PWM 分辨率和 ADC 速度業(yè)界領(lǐng)先的新器件
- 意法半導(dǎo)體STM32MP23x:突破成本限制的工業(yè)AI應(yīng)用核心
- 意法半導(dǎo)體推出用于匹配遠距離無線微控制器STM32WL33的集成的匹配濾波芯片
- ESP32開發(fā)板連接TFT顯示屏ST7789跳坑記
- 如何讓ESP32支持analogWrite函數(shù)
- LGVL配合FreeType為可變字體設(shè)置字重-ESP32篇
- 使用樹莓派進行 ESP32 Jtag 調(diào)試
- ESP32怎么在SPIFFS里面存儲html,css,js文件,以及網(wǎng)頁和arduino的通訊
- ESP32 freeRTOS使用測試
- 適用于汽車應(yīng)用的 LT3973HMSE-3.3 3.3V 降壓轉(zhuǎn)換器的典型應(yīng)用
- R_08_V30基于IPS2電機換向傳感器的設(shè)計
- 使用 Microchip Technology 的 PIC16C782 的參考設(shè)計
- 使用 LT1054CSW 基本型電壓逆變器 / 穩(wěn)壓器的典型應(yīng)用
- 使用 LTC3637EDHC 4V 至 76V 輸入至 1.8V 超級電容器充電器的典型應(yīng)用
- 儀表用 ADC 驅(qū)動器
- EN6310QA 1A PowerSoC 電壓模式同步 PWM 降壓與集成電感器的典型應(yīng)用
- STEVAL-ISV012V1,使用 L6924D 高達 5 W 太陽能電池充電器的演示板,用于單節(jié)鋰離子和鋰聚合物電池
- 適用于汽車應(yīng)用的 A5974D 正降壓-升壓穩(wěn)壓器的典型應(yīng)用電路
- 使用 NXP Semiconductors 的 TDA2582Q 的參考設(shè)計
- 方案分享 | ARXML 規(guī)則下 ECU 總線通訊與 ADTF 測試方案
- 車載SerDes產(chǎn)業(yè)起飛!國產(chǎn)新品密集炸場
- 出貨量激增1.34倍! 5G車規(guī)模組成標配,三大廠商新品同臺競技
- 6月新能源市場:零跑創(chuàng)新高;比亞迪海外突破;理想滑坡
- 基于中科芯車規(guī)MCU的LED矩陣大燈應(yīng)用方案
- 蘋果被判侵犯3G專利,需向西班牙公司TOT賠償1.1億美元
- 從設(shè)計概念到 FPGA 原型僅需數(shù)分鐘,印度 InCore 完成 SoC Generator 平臺硅驗證
- 消息稱因難尋客戶,三星推遲美國芯片工廠的完工時間
- BOE(京東方)聯(lián)合榮耀打造榮耀Magic V5 以領(lǐng)先LTPO技術(shù)打造行業(yè)新標桿
- 華為ADS 4發(fā)布:多傳感器融合,提升自動駕駛安全性
- 又一日本運營商宣布重啟華為手機銷售
- 博通或要收購安全軟件公司賽門鐵克
- 國產(chǎn)MCU汽車前裝車身控制領(lǐng)域芯突破,賽騰微出貨量超百萬
- 日制裁韓國 或?qū)е耰Phone減產(chǎn)
- 蘋果神秘13英寸MacBook Pro曝光:型號A2159,或配32GB內(nèi)存
- 瘋狂的MLCC再添IPO新廠,韋爾股份子公司擬收購OV1.9826%股權(quán)
- 赴港IPO之路再起波折!小米被訴侵犯標準必要專利,索賠5000萬
- ?HTC宣布制造部門裁員1500人,員工數(shù)量將不足5000人
- 聯(lián)芯集成負債比率趨七成!為避免更多挖角,和艦IPO細節(jié)曝光
- 榮耀 “嚇人技術(shù)”升級,IoT生態(tài)及新零售戰(zhàn)略曝光
- 【一起學(xué)習(xí)器件指標】你敢說說你見過哪些電感不
- 轉(zhuǎn)帖:辦公室里的22條潛規(guī)則
- 蘋果因降頻門事件致歉消費者并降低更換電池價格
- 逆變器輸出正弦波,那么怎么測這個輸出電壓的諧波,波形畸變呢
- DAC0832與LM324的輸出問題,畢業(yè)設(shè)計,急需高手指教?。?!
- EEWORLD大學(xué)堂----Stellaris 浮點單元第一部分
- 電源中PWM控制開關(guān)的頻率問題
- 【TI首屆低功耗設(shè)計大賽】之談?wù)凩aunchpad的blink程序
- 【MSP430 編譯器使用經(jīng)驗】[一]關(guān)于IAR的仿真器鏈接問題
- TI DSP的選型、開發(fā)工具選擇及設(shè)計支持