Linux驅動技術(六) _內核中斷

来源:http://www.cnblogs.com/xiaojiang1025/archive/2017/02/14/6388603.html
-Advertisement-
Play Games

在硬體上,中斷源可以通過中斷控制器向CPU提交中斷,進而引發中斷處理程式的執行,不過這種硬體中斷體系每一種CPU都不一樣,而Linux作為操作系統,需要同時支持這些中斷體系,如此一來,Linux中就提出了 軟中斷 的概念,也有人叫 內核中斷 ,其本質就是使用統一的方式對不同硬體中斷體系中的中斷號進行 ...


在硬體上,中斷源可以通過中斷控制器向CPU提交中斷,進而引發中斷處理程式的執行,不過這種硬體中斷體系每一種CPU都不一樣,而Linux作為操作系統,需要同時支持這些中斷體系,如此一來,Linux中就提出了軟中斷的概念,也有人叫內核中斷,其本質就是使用統一的方式對不同硬體中斷體系中的中斷號進行再映射,在操作系統中操作的中斷號都是這些映射過的軟中斷號。就是下圖中的irq_num

中斷映射原理

Linux內核中定義了名為irq_desc的中斷常式描述符表來描述中斷服務常式,每一個irq_desc對象數組中的下標就是軟中斷號。其中的struct irqaction對象描述了這個中斷服務常式的中斷的具體信息。

//include/linux/irqdesc.h
 40 struct irq_desc {
 41         struct irq_data         irq_data;
 42         unsigned int __percpu   *kstat_irqs;
 43         irq_flow_handler_t      handle_irq;
 44 #ifdef CONFIG_IRQ_PREFLOW_FASTEOI
 45         irq_preflow_handler_t   preflow_handler;
 46 #endif
 47         struct irqaction        *action;        /* IRQ action list */
 48         unsigned int            status_use_accessors;
 49         unsigned int            core_internal_state__do_not_mess_with_it;
 50         unsigned int            depth;          /* nested irq disables */
 51         unsigned int            wake_depth;     /* nested wake enables */
 52         unsigned int            irq_count;      /* For detecting broken IRQs */
 53         unsigned long           last_unhandled; /* Aging timer for unhandled count */
 54         unsigned int            irqs_unhandled;
 55         raw_spinlock_t          lock;
 56         struct cpumask          *percpu_enabled;
 57 #ifdef CONFIG_SMP
 58         const struct cpumask    *affinity_hint;
 59         struct irq_affinity_notify *affinity_notify;
 60 #ifdef CONFIG_GENERIC_PENDING_IRQ
 61         cpumask_var_t           pending_mask;
 62 #endif
 63 #endif
 64         unsigned long           threads_oneshot;
 65         atomic_t                threads_active;
 66         wait_queue_head_t       wait_for_threads;
 67 #ifdef CONFIG_PROC_FS
 68         struct proc_dir_entry   *dir;
 69 #endif
 70         int                     parent_irq;
 71         struct module           *owner;
 72         const char              *name;
 73 } ____cacheline_internodealigned_in_smp;
 74 
 76 extern struct irq_desc irq_desc[NR_IRQS];  //NR_IRQS表示中斷源的數目
//linux/interrupt.h
104 //一個irq action的描述結構
105 struct irqaction {           
106         irq_handler_t           handler;
107         void                    *dev_id;
108         void __percpu           *percpu_dev_id;
109         struct irqaction        *next;
110         irq_handler_t           thread_fn;
111         struct task_struct      *thread;
112         unsigned int            irq;
113         unsigned int            flags;
114         unsigned long           thread_flags;
115         unsigned long           thread_mask;
116         const char              *name;
117         struct proc_dir_entry   *dir;
118 } ____cacheline_internodealigned_in_smp;

struct irqaction
--105-->handler: 中斷處理函數
--106-->name: 設備名
--107-->dev_id: 設備識別id
--109-->next: 指向下一個irqaction的指針
--110-->irq: 硬體中斷號!!!
--113-->flags:IRQF_DISABLED .etc
--110-->thread_fn: 線程中斷的中斷處理函數
--111-->thread: 線程中斷的線程指針
--114-->thread_flags: 與@thread關聯的flags
--115-->thread_mask: 追蹤@thread activity的位掩碼
--116-->dir: 指向proc/irq/NN/name的入口指針

raw_local_irq_save(x) //禁止所有中斷
raw_local_irq_enable    //取消禁止中斷

寫中斷處理程式

1. 編寫中斷處理函數

下麵這個就是中斷處理程式的原型,中斷發生後,內核會將軟中斷號和註冊時的data作為參數傳入。中斷處理程式ISR是在中斷發生時被調用的用來處理中斷的函數,不是進程上下文,在中斷期間運行,不能執行可能休眠的操作,不能同用戶空間交換數據,不能調用schedule()函數放棄調度
實現中斷處理有一個原則:儘可能快的處理並返回,冗長的計算處理工作應該交給tasklet或任務隊列在安全的時間內進行。此外,硬體系統中常使用共用中斷,即多個設備共用一根線。所以在中斷處理程式中要添加中斷識別代碼,通常就是讀取寄存器,看具體是哪個中斷被觸發了。

 88 typedef irqreturn_t (*irq_handler_t)(int, void *);   
irqreturn_t xxx_interrupt(int irq, void *dev_id)
{
    ...
    int status = read_irq_status(); /* 讀取相應的寄存器獲取中斷源 */
    if(!is_myirq(dev_id,status)){   /* 判斷是否是本設備中斷 */
        return IRQ_NONE;    
    }
    /* 中斷處理程式 */
    return IRQ_HANDLED
}

2. 註冊中斷處理函數

下麵這個就是註冊中斷的API,其中最重要的就是flags參數,它的取值在interrupt.h有定義,常用的有IRQF_DISABLEDIRQF_SHARED,前者表示中斷程式調用時屏蔽所有中斷,IRQF_SHARED表示多個設備共用中斷,即該中斷號可以被多個設備共用-SPI(另外兩種SGI,PPI),此外,還要"位或"上觸發方式,eg:IRQF_DISABLED|IRQF_TRIGGER_RISING

/**
 * @flags:中斷標誌位。
 * @dev_id通常用於共用中斷,用來標識是哪個設備觸發了中斷
 * @name 是中斷名稱,可以在/proc/interrupt中看到
 */
int requst_irq(unsigned int irq,irq_handler_t handler, unsigned long flags, const char *name,void * dev_id);

3. 釋放中斷處理函數

中斷號也是一種系統資源,使用完畢後要釋放,註意,free_irq的第二個參數應當與request_irq()中最後一個參數相同。

/**
 * free_irq - 釋放irq 
 */
void free_irq(unsigned int irqno,void * dev_id);

底半部

中斷不屬於進程上下文,所以不能被內核調度,如果進入了中斷處理函數,就只能將其執行完畢,不能被打斷,這樣帶來的一個問題是如果在中斷處理函數中執行耗時操作,就會極大的影響系統性能,為瞭解決這個問題,Linux內核中提出了中斷頂半部和`底半部(bottom half)的概念,對於耗時的中斷處理程式,將重要的、必要的操作放在頂半部執行,這部分和傳統的中斷概念一樣,一旦開始就必須執行完畢;將中斷處理程式中耗時的,不那麼緊要的操作放在底半部,防止整個中斷處理程式過多的占用系統資源。
Linux內核提供的3種中斷底半部機制:工作隊列,tasklet,軟中斷。其中軟中斷機制是內核底層的機制,包括定時器,非同步通知等很多機制都是基於軟中斷,開發者不應該直接操作,所以這裡僅討論前兩種

Tasklet

每個tasklet都和一個函數相關聯,當tasklet被運行時,該函數就被調用,並且tasklet可以調度自己。

//定義一個處理函數
void  my_tasklet_fcn(unsigned long){}

//定義一個tasklet結構my_tasklet,並與處理函數相關聯,
DECLARE_TASKLET(my_tasklet,my_tasklet_fcn,data);

//調度tasklet
tasklet_schedule(&my_tasklet);

工作隊列

工作隊列和tasklet類型,tasklet多運行於中斷上下文,而工作隊列多運行與進程上下文
此外,tasklet中不能睡眠,而工作隊列處理函數允許睡眠(正是由於它被當作內核線程被調度)

//定義一個工作隊列
struct work_queue my_wq;

//定義一個處理函數
void my_wq_fcn(unsigned long){}

//初始化工作隊列並將其與處理函數綁定
INIT_WORK(&my_wq,my_wq_fcn);

//調度工作隊列執行
schedule_work(&my_wq);
static irqreturn_t handler_t(int irq, void *dev)
{
    //top half
    schedule_work(&ws);
    return IRQ_HANDLED;
}

void work_func(struct work_struct *work)
{
    //bottom half
    ssleep(3);
}

static int __init demo_init(void)
{
    ...
    INIT_WORK(&ws, work_func);
    request_irq(irq, handler_t, IRQF_TRIGGER_RISING, "demo", NULL);
    ...
}

其他API

除了上述API,內核還提供了其他的中斷操作API,在內核代碼中被廣泛使用。

raw_local_irq_save(x)   //禁止所有中斷
raw_local_irq_enable    //取消禁止中斷

//下麵三個函數用於可編程中斷控制器,對所有CPU都有效
//屏蔽一個中斷
void disable_irq(int irq);  //立即返回
void disable_irq_nosync();  //等待目前中斷處理返程

//使能一個中斷
void enable_irq()




您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 昨天在修改欄位類型的時候引起了死鎖,我一般會使用REORG命令處理,在控制中心下 只需要執行 REORG TABLE TABLENAME 命令就可以, 但是在 RazorSQL 下執行此命令會報缺失字元,這是我們在前面加上一個過程 CALL SYSPROC.ADMIN_CMD('REORG TABL ...
  • update 表名 set 欄位 = replace(欄位,' ','') //去空格update 表名set 欄位 = replace(欄位,char(10),'') //去LFupdate 表名set 欄位 = replace(欄位,char(13),'') //去CRupdate 表名set ...
  • DATEADD 在向指定日期加上一段時間的基礎上,返回新的 datetime 值。語法 DATEADD ( datepart , number, date ) 參數 (1) datepart:是規定應嚮日期的哪一部分返回新值的參數。 下表列出了 Microsoft® SQL Server™ 識別的日 ...
  • 一.設置客戶端網路實用工具 點擊“開始”-“程式”,在“Microsoft SQL Server”菜單中選擇“客戶端網路實用工具”。 在“別名”選項中點擊“添加”。 在“伺服器別名”中,填入您網站功能變數名稱,在“網路庫”區域中點擊“TCP/IP”,在“連接參數”區域取消“動態決定埠”,指定“埠號”為2 ...
  • 等待分類與解決基本流程: 步驟1.定位問題 系統等待往往能直觀的反映出系統問題。通過一些常見的等待類型,同樣可以找到系統瓶頸,結合性能計數器往往定位更準確。 步驟1.定位問題 如:系統中存在大量IO類等待,那麼可能表示你的磁碟或記憶體是語句運行緩慢的原因,也是系統的瓶頸所在。 常見的等待類型 CXPA ...
  • 今天進行了InfluxDB和MySQL的對比測試,這裡記錄下結果,也方便我以後查閱。 操作系統: CentOS6.5_x64InfluxDB版本 : v1.1.0MySQL版本:v5.1.73CPU : Intel(R) Core(TM) i5-2320 CPU @ 3.00GHz記憶體 :12G硬碟 ...
  • 本文分三部步講解: 資料庫安裝,資料庫創建,創建表空間與用戶 資料庫安裝 首先到官方網站根據機器要求下載必要安裝包: http://www.oracle.com/technetwork/database/enterprise-edition/downloads/index.html win32_11 ...
  • 為VMware虛擬機內安裝的Ubuntu 16.04設置靜態IP地址NAT方式 為VMware虛擬機內安裝的Ubuntu 16.04設置靜態IP地址NAT方式 1.安裝環境 VMware 12 Ubuntu 16.04 x86_64 2.在VMware中,配置網路環境 VMware在預設安裝完成之後 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...