最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

深入分析Linux中斷子系統(tǒng)之通用框架處理

2022-12-20 21:26 作者:補給站Linux內(nèi)核  | 我要投稿

說明:

  1. Kernel版本:4.14

  2. ARM64處理器,Contex-A53,雙核

  3. 使用工具:Source Insight 3.5, Visio

1. 概述

《Linux中斷子系統(tǒng)(一)-中斷控制器及驅(qū)動分析》講到了底層硬件GIC驅(qū)動,以及Arch-Specific的中斷代碼,本文將研究下通用的中斷處理的過程,屬于硬件無關(guān)層。當(dāng)然,我還是建議你看一下上篇文章。

這篇文章會解答兩個問題:

  1. 用戶是怎么使用中斷的(中斷注冊)?

  2. 外設(shè)觸發(fā)中斷信號時,最終是怎么調(diào)用到中斷handler的(中斷處理)?

2. 數(shù)據(jù)結(jié)構(gòu)分析

先來看一下總的數(shù)據(jù)結(jié)構(gòu),核心是圍繞著struct irq_desc來展開:

圖片
  • Linux內(nèi)核的中斷處理,圍繞著中斷描述符結(jié)構(gòu)struct irq_desc展開,內(nèi)核提供了兩種中斷描述符組織形式:

    1. 打開CONFIG_SPARSE_IRQ宏(中斷編號不連續(xù)),中斷描述符以radix-tree來組織,用戶在初始化時進行動態(tài)分配,然后再插入radix-tree中;

    2. 關(guān)閉CONFIG_SPARSE_IRQ宏(中斷編號連續(xù)),中斷描述符以數(shù)組的形式組織,并且已經(jīng)分配好;

    3. 不管哪種形式,都可以通過linux irq號來找到對應(yīng)的中斷描述符;

  • 圖的左側(cè)灰色部分,主要在中斷控制器驅(qū)動中進行初始化設(shè)置,包括各個結(jié)構(gòu)中函數(shù)指針的指向等,其中struct irq_chip用于對中斷控制器的硬件操作,struct irq_domain與中斷控制器對應(yīng),完成的工作是硬件中斷號到Linux irq的映射;

  • 圖的上側(cè)灰色部分,中斷描述符的創(chuàng)建(這里指CONFIG_SPARSE_IRQ),主要在獲取設(shè)備中斷信息的過程中完成的,從而讓設(shè)備樹中的中斷能與具體的中斷描述符irq_desc匹配;

  • 圖中剩余部分,在設(shè)備申請注冊中斷的過程中進行設(shè)置,比如struct irqactionhandler的設(shè)置,這個用于指向我們設(shè)備驅(qū)動程序中的中斷處理函數(shù)了;

中斷的處理主要有以下幾個功能模塊:

  1. 硬件中斷號到Linux irq中斷號的映射,并創(chuàng)建好irq_desc中斷描述符;

  2. 中斷注冊時,先獲取設(shè)備的中斷號,根據(jù)中斷號找到對應(yīng)的irq_desc,并將設(shè)備的中斷處理函數(shù)添加到irq_desc中;

  3. 設(shè)備觸發(fā)中斷信號時,根據(jù)硬件中斷號得到Linux irq中斷號,找到對應(yīng)的irq_desc,最終調(diào)用到設(shè)備的中斷處理函數(shù);

上述的描述比較簡單,更詳細的過程,往下看吧。


【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【749907784】整理了一些個人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦?。。。ê曨l教程、電子書、實戰(zhàn)項目及代碼)? ??

3. 流程分析

3.1 中斷注冊

這一次,讓我們以問題的方式來展開:先來讓我們回答第一個問題:用戶是怎么使用中斷的?

  1. 熟悉設(shè)備驅(qū)動的同學(xué)應(yīng)該都清楚,經(jīng)常會在驅(qū)動程序中調(diào)用request_irq()接口或者request_threaded_irq()接口來注冊設(shè)備的中斷處理函數(shù);

  2. request_irq()/request_threaded_irq接口中,都需要用到irq,也就是中斷號,那么這個中斷號是從哪里來的呢?它是Linux irq,它又是如何映射到具體的硬件設(shè)備的中斷號的呢?

先來看第二個問題:設(shè)備硬件中斷號到Linux irq中斷號的映射

圖片
  • 硬件設(shè)備的中斷信息都在設(shè)備樹device tree中進行了描述,在系統(tǒng)啟動過程中,這些信息都已經(jīng)加載到內(nèi)存中并得到了解析;

  • 驅(qū)動中通常會使用platform_get_irqirq_of_parse_and_map接口,去根據(jù)設(shè)備樹的信息去創(chuàng)建映射關(guān)系(硬件中斷號到linux irq中斷號映射);

  • 《Linux中斷子系統(tǒng)(一)-中斷控制器及驅(qū)動分析》提到過struct irq_domain用于完成映射工作,因此在irq_create_fwspec_mapping接口中,會先去找到匹配的irq domain,再去回調(diào)該irq domain中的函數(shù)集,通常irq domain都是在中斷控制器驅(qū)動中初始化的,以ARM GICV2為例,最終回調(diào)到gic_irq_domain_hierarchy_ops中的函數(shù);

  • 如果已經(jīng)創(chuàng)建好了映射,那么可以直接進行返回linux irq中斷號了,否則的話需要irq_domain_alloc_irqs來創(chuàng)建映射關(guān)系;

  • irq_domain_alloc_irqs完成兩個工作:

    1. 針對linux irq中斷號創(chuàng)建一個irq_desc中斷描述符;

    2. 調(diào)用domain->ops->alloc函數(shù)來完成映射,在ARM GICV2驅(qū)動中對應(yīng)gic_irq_domain_alloc函數(shù),這個函數(shù)很關(guān)鍵,所以下文介紹一下;

gic_irq_domain_alloc函數(shù)如下:

圖片
  • gic_irq_domain_translate:負責(zé)解析出設(shè)備樹中描述的中斷號和中斷觸發(fā)類型(邊緣觸發(fā)、電平觸發(fā)等);

  • gic_irq_domain_map:將硬件中斷號和linux中斷號綁定到一個結(jié)構(gòu)中,也就完成了映射,此外還綁定了irq_desc結(jié)構(gòu)中的其他字段,最重要的是設(shè)置了irq_desc->handle_irq的函數(shù)指針,這個最終是中斷響應(yīng)時往上執(zhí)行的入口,這個是關(guān)鍵,下文講述中斷處理過程時還會提到;

  • 根據(jù)硬件中斷號的范圍設(shè)置irq_desc->handle_irq的指針,共享中斷入口為handle_fasteoi_irq,私有中斷入口為handle_percpu_devid_irq;

上述函數(shù)執(zhí)行完成后,完成了兩大工作:

  1. 硬件中斷號與Linux中斷號完成映射,并為Linux中斷號創(chuàng)建了irq_desc中斷描述符;

  2. 數(shù)據(jù)結(jié)構(gòu)的綁定及初始化,關(guān)鍵的地方是設(shè)置了中斷處理往上執(zhí)行的入口;

再看第一個問題:中斷是怎么來注冊的?

設(shè)備驅(qū)動中,獲取到了irq中斷號后,通常就會采用request_irq/request_threaded_irq來注冊中斷,其中request_irq用于注冊普通處理的中斷,request_threaded_irq用于注冊線程化處理的中斷;

在講具體的注冊流程前,先看一下主要的中斷標志位:

圖片
  • request_irq也是調(diào)用request_threaded_irq,只是在傳參的時候,線程處理函數(shù)thread_fn函數(shù)設(shè)置成NULL;

  • 由于在硬件中斷號和Linux中斷號完成映射后,irq_desc已經(jīng)創(chuàng)建好,可以通過irq_to_desc接口去獲取對應(yīng)的irq_desc;

  • 創(chuàng)建irqaction,并初始化該結(jié)構(gòu)體中的各個字段,其中包括傳入的中斷處理函數(shù)賦值給對應(yīng)的字段;

  • __setup_irq用于完成中斷的相關(guān)設(shè)置,包括中斷線程化的處理:

    1. 中斷線程化用于減少系統(tǒng)關(guān)中斷的時間,增強系統(tǒng)的實時性;

    2. ARM64默認開啟了CONFIG_IRQ_FORCED_THREADING,引導(dǎo)參數(shù)傳入threadirqs時,則除了IRQF_NO_THREAD外的中斷,其他的都將強制線程化處理;

    3. 中斷線程化會為每個中斷都創(chuàng)建一個內(nèi)核線程,如果中斷進行共享,對應(yīng)irqaction將連接成鏈表,每個irqaction都有thread_mask位圖字段,當(dāng)所有共享中斷都處理完成后才能unmask中斷,解除中斷屏蔽;

3.2 中斷處理

當(dāng)完成中斷的注冊后,所有結(jié)構(gòu)的組織關(guān)系都已經(jīng)建立好,剩下的工作就是當(dāng)信號來臨時,進行中斷的處理工作。

來回顧一下《Linux中斷子系統(tǒng)(一)-中斷控制器及驅(qū)動分析》中的Arch-specific處理流程:

圖片
  • 中斷收到之后,首先會跳轉(zhuǎn)到異常向量表的入口處,進而逐級進行回調(diào)處理,最終調(diào)用到generic_handle_irq來進行中斷處理。

generic_handle_irq處理如下圖:

圖片
  • generic_handle_irq函數(shù)最終會調(diào)用到desc->handle_irq(),這個也就是對應(yīng)到上文中在建立映射關(guān)系的過程中,調(diào)用irq_domain_set_info函數(shù),設(shè)置好了函數(shù)指針,也就是handle_fasteoi_irqhandle_percpu_devid_irq

  • handle_fasteoi_irq:處理共享中斷,并且遍歷irqaction鏈表,逐個調(diào)用action->handler()函數(shù),這個函數(shù)正是設(shè)備驅(qū)動程序調(diào)用request_irq/request_threaded_irq接口注冊的中斷處理函數(shù),此外如果中斷線程化處理的話,還會調(diào)用__irq_wake_thread()喚醒內(nèi)核線程;

  • handle_percpu_devid_irq:處理per-CPU中斷處理,在這個過程中會分別調(diào)用中斷控制器的處理函數(shù)進行硬件操作,該函數(shù)調(diào)用action->handler()來進行中斷處理;

來看看中斷線程化處理后的喚醒流程吧__handle_irq_event_percpu->__irq_wake_thread

圖片
  • __handle_irq_event_percpu->__irq_wake_thread將喚醒irq_thread中斷內(nèi)核線程;

  • irq_thread內(nèi)核線程,將根據(jù)是否為強制中斷線程化對函數(shù)指針handler_fn進行初始化,以便后續(xù)進行調(diào)用;

  • irq_thread內(nèi)核線程將while(!irq_wait_for_interrupt)循環(huán)進行中斷的處理,當(dāng)滿足條件時,執(zhí)行handler_fn,在該函數(shù)中最終調(diào)用action->thread_fn,也就是完成了中斷的處理;

  • irq_wait_for_interrupt函數(shù),將會判斷中斷線程的喚醒條件,如果滿足了,則將當(dāng)前任務(wù)設(shè)置成TASK_RUNNING狀態(tài),并返回0,這樣就能執(zhí)行中斷的處理,否則就調(diào)用schedule()進行調(diào)度,讓出CPU,并將任務(wù)設(shè)置成TASK_INTERRUPTIBLE可中斷睡眠狀態(tài);

3.3 總結(jié)

中斷的處理,總體來說可以分為兩部分來看:

  1. 從上到下:圍繞irq_desc中斷描述符建立好連接關(guān)系,這個過程就包括:中斷源信息的解析(設(shè)備樹),硬件中斷號到Linux中斷號的映射關(guān)系、irq_desc結(jié)構(gòu)的分配及初始化(內(nèi)部各個結(jié)構(gòu)的組織關(guān)系)、中斷的注冊(填充irq_desc結(jié)構(gòu),包括handler處理函數(shù))等,總而言之,就是完成靜態(tài)關(guān)系創(chuàng)建,為中斷處理做好準備;

  2. 從下到上,當(dāng)外設(shè)觸發(fā)中斷信號時,中斷控制器接收到信號并發(fā)送到處理器,此時處理器進行異常模式切換,并逐步從處理器架構(gòu)相關(guān)代碼逐級回調(diào)。如果涉及到中斷線程化,則還需要進行中斷內(nèi)核線程的喚醒操作,最終完成中斷處理函數(shù)的執(zhí)行。


原文作者:LoyenWang


深入分析Linux中斷子系統(tǒng)之通用框架處理的評論 (共 條)

分享到微博請遵守國家法律
东方市| 武宁县| 昌黎县| 万载县| 涞源县| 平塘县| 柞水县| 甘洛县| 炎陵县| 柘城县| 平邑县| 明光市| 江山市| 交城县| 城固县| 衡阳县| 无为县| 莆田市| 南部县| 德安县| 博罗县| 崇明县| 高要市| 朝阳市| 元阳县| 湖口县| 西华县| 财经| 天门市| 普兰店市| 措勤县| 南康市| 姚安县| 邳州市| 若尔盖县| 乌审旗| 驻马店市| 宣化县| 漾濞| 富阳市| 西华县|