《Linux Device Drivers》第十章 中斷處理——note

  • 概述:系統要及時的感知硬件的狀態,通常有兩種方式:一種是輪詢;一種是通過響應硬件中斷。前者會浪費處理器的時間,而後者不會。
  • 準備並口
    • 在沒有節設定產生中斷之前,並口是不會產生中斷的
    • 並口的標準規定設置端口2(px37a、0x27a或者其它端口)的第4位將啓用中斷報告,0×10
    • 當處於啓用中斷狀態,每當引腳10的電平發生從低到高改變時,並口就會產生一箇中斷
    • 引腳9是並口數據字節中的最高位
  • 安裝中斷處理例程
    • 中斷信號線是非常珍貴且有限的資源
    • 內核維護了一箇中斷信號線的註冊表,該註冊表類似於I/O端口的註冊表
    • 模塊在使用中斷前要先請求一箇中斷通道,然後在使用後釋放該通道
    • <linux/sched.h>
      • int request_irq(unsigned int irq, irqreturn_t (*handler) (int, void *, struct pt_regs *), unsigned long flags, const char *dev_name, void *dev_id);
        • 返回0表示申請成功
        • flags
          • SA_INTERRUPT
            • 表明這是一個“快速”的中斷處理例程
          • SA_SHIRQ
            • 表示中斷可以在設備之間共享
          • SA_SAMPLE_RANDOM
            • 指出產生的中斷能對/dev/random設備和/dev/urandom設備使用的熵池(entropy pool)有貢獻
      • void free_irq(unsigned int irq, void *dev_id);
      • int can_request_irq(unsigned int irq, unsigned long flags);
    • 使用request_irq的正確位置應該是在設備第一次打開、硬件被告知產生中斷之前
    • 調用free_irq的位置是最後一次關閉設備、硬件被告知不用再中斷處理器之後
    • /proc接口
      • /proc/interrupts
        • 不依賴體系結構
      • /proc/stat
        • 依賴體系結構
      • 當前x86體系結構上定義的中斷數量是224,可以從頭文件include/asm-386/irq.h中得到解釋
    • 自動檢測IRQ號
      • 內核幫助下的探測
        • <linux/interrupt.h>
          • unsigned long probe_irq_on(void);
          • int probe_irq_off(unsigned long);
      • DIY探測
    • 快速和慢速處理例程
      • 快速中斷執行時,當前處理器上的其他所有中斷都被禁止
      • x86平臺上中斷處理的內幕
        • arch/i386/kernel/irq.c
        • arch/i386/kernel/apic.c
        • arch/i386/kernel/entry.S
        • arch/i386/kernel/i8259.c
        • include/asm-i386/hw_irq.h
        • IRQ的探測是通過爲每個缺少中斷處理例程的IRQ設置IRQ_WAITING狀態位來完成的

  • 實現中斷處理例程
    • 中斷處理例程是在中斷時間內運行的,因此它的行爲會受到一些限制
      • 不能向用戶空間發送或者接收數據
      • 不能做作任何可能發生休眠的操作
      • 不能調用schdule函數
    • 將有關中斷接收到信息反饋給設備,並根據正在服務的中斷的不同含義對數據進行相應的讀或寫
      • 通常做清除接口卡上的一個位,大多數硬件設備在它們的“interrupt-pending(中斷掛起)”位被清除之前不會產生其他的中斷
    • 中斷處理例程的一個典型任務就是:如果中斷通知進程所等待的事件已經發生,比如新的數據到達,就會喚醒在該設備上休眠的進程
    • 處理例程的參數及返回值
      • int irq是中斷號
      • void *dev_id是一種客戶數據類型(即驅動程序可用的私有數據)
      • struct pt_reg *regs很少使用,它保存了處理器進入中斷代碼之前的處理器上下文快照
      • 中斷處理例程應該返回一個值,用來指明是否真正處理了一箇中斷,如果處理例程發現其設備的確需要處理,則應該返回IRQ_HANDLED,否則,返回值應該是IRQ_NONE
    • 啓用和禁用中斷
      • 有時設備驅動程序必須在一個時間段內阻塞中斷的發出,如擁有自旋鎖的時候阻塞中斷
      • 禁用單箇中斷
        • <asm/irq.h>
          • void disable_irq(int irq);
          • void disable_irq_nosync(int irq);
          • void enable_irq(int irq);
        • diables_irq不但會禁止給定的中斷,而且也會等待當前正在執行的中斷處理例程完成
        • 如果調用disable_irq的線程擁有任何中斷處理例程需要的資源(比如自旋鎖),則系統會死鎖
      • 禁用所有的中斷
        • <asm/system.h>
          • void local_irq_save(unsigned long falsg);
          • void local_irq_disable(void);
          • void local_irq_restore(unsigned long flags);
          • void local_irq_enable(void)
  • 頂半部和底半部
    • 頂半部,是實際響應中斷的例程,也就是用request_irq註冊的中斷例程
    • 底半部,是一個被頂半部調度,並在稍後更安全的時間內執行的例程
    • 當底半部處理例程執行時,所有的中斷都是打開的
    • 典型的情況是頂半部保存設備的數據到一個設備特定的緩衝區並調度它的底半部
    • tasklet
      • tasklet可以被多次調度運行,但tasklet的調度並不會累積
      • 如果驅動程序有多個tasklet,必須使用某種鎖機制來避免彼此間的衝突
      • tasklet可確保和第一次調度它們的函數運行在同樣的CPU上
      • 必須使用宏DECLARE_TASKLET聲明tasklet
        • DECLARE_TASKLET(name, function, data);
        • void do_tasklet(unsigned long);
        • DECLARE_TASKLET(test_tasklet, do_tasklet, 0);
        • tasklet_schedule($test_tasklet);
    • 工作隊列
      • 工作隊列函數運行在進程上下文中,因此可以必要時休眠
      • 不能從工作隊列向用戶空間複製數據
  • 中斷共享
    • PC上的IRQ信號燈線不能爲一個以上的設備服務
    • 現代硬件已經能譎詐中斷的共享了,PCI總線就要求外設可共享中斷
    • 安裝共享的處理例程
      • 共享的中斷也是通過request_irq安裝的,但是有兩處不同
        • 請求中斷時,必須指定flags參數中的SA_SHIRQ位
        • dev_id參數必須是唯一的,任何指向模塊地址空間的指針都可以使用,但dev_id不能設置成NULL
      • 請求一個共享中斷時,如果滿足下面條件之一,那麼request_irq就會成功
        • 中斷信號線空閒
        • 任何已經註冊了該中斷信號線的處理例程也標識了IRQ是共享的
      • 使用共享處理例程的驅動程序需要小心一件事情:不能使用enable_irq和disable_irq
    • 運行處理例程
      • 當內核收到中斷時,所有已註冊的處理例程都將被調用
      • 一個共享中斷處理例程必須能夠將要處理的中斷和其他設備產生的中斷區分開來
    • /proc接口和共享的中斷
      • 在系統上安裝共享的中斷處理例程不會對/proc/stat造成影響,它甚至不知道哪些處理例程是共享的,但是,/proc/interrupts會稍許改變
  • 中斷驅動的I/O
    • 如果與驅動程序管理的硬件之間的數據傳輸因爲某種原因被延遲的話,驅動程序作者就應該實現緩衝
    • 數據緩衝區有助於將數據的傳送和接收與系統調用write和read分離開來,從而提高系統的整體性能
    • 一個好的緩衝機制需要用中斷驅動的I/O
    • 要正確進行中斷驅動的數據傳輸,要求硬件 應該能按照下面的語義來產生中斷
      • 對於輸入來說,當新的數據已經到達並且處理器準備接收它時,設備就中斷處理器
      • 對於輸出來說,當設備準備好接收新數據或者對成功的數據傳送進行應答時,就要發出中斷
發佈了48 篇原創文章 · 獲贊 12 · 訪問量 1141萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章