1. 注冊線程化中斷處理函數
devmem_request_threaded_irq
是 Linux 內核中的一個函數,用于請求并注冊一個線程化的中斷處理程序。這個函數允許開發者注冊一個中斷處理函數,這個函數會在中斷發生時被調用,從而實現相應的中斷處理邏輯。它通過 devm
機制分配資源,這意味著在設備的生命周期結束時,資源會自動釋放,無需手動進行釋放,這有助于避免資源泄漏問題。
函數原型如下:
int devm_request_threaded_irq(struct device *dev, unsigned int irq,irq_handler_t handler, irq_handler_t thread_fn,unsigned long irqflags, const char *devname,void *dev_id);static inline int __must_check
devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id)
{return devm_request_threaded_irq(dev, irq, handler, NULL, irqflags,devname, dev_id);
}
參數說明:
dev
: 指向表示設備的struct device
結構體的指針。irq
: 中斷號,表示要請求和注冊的中斷線路。handler
: 中斷處理程序的主處理函數,它在中斷發生時執行。thread_fn
: 線程處理函數,它在中斷上下文之外以線程化的方式執行,通常用于執行一些比較耗時的操作。irqflags
: 中斷標志,用于指定中斷處理的屬性和行為。devname
: 設備名稱,用于標識中斷請求的設備。dev_id
: 設備標識符,可以是設備結構體或其他設備特定的標識符。
使用 devmem_request_threaded_irq
可以提高中斷處理的效率,特別是在處理高頻率中斷時,因為它允許將耗時的中斷處理邏輯移到一個線程中執行,而不是在中斷上下文中直接處理,這樣可以減少中斷處理時間,提高系統響應速度。
2.為什么要注冊一個線程化的中斷處理函數?
注冊一個線程化的中斷處理函數主要是為了提高系統的實時性能和響應性,特別是在實時或嵌入式系統中。線程化中斷處理函數與普通中斷處理函數的主要區別在于它們的執行環境和處理方式。
-
執行環境:普通中斷處理函數(也稱為中斷服務例程,ISR)在中斷上下文中執行,這個上下文是不可搶占的,意味著一旦中斷發生,CPU會立即暫停當前執行的任務去處理中斷,直到ISR執行完畢。這種方式雖然響應速度快,但如果ISR執行時間過長,會阻塞其他中斷和任務的執行,影響系統實時性。
-
處理方式:線程化的中斷處理函數將中斷處理分為兩部分:快速的硬件中斷處理程序(Fast hardware ISR)和線程中斷處理程序(Threaded IRQ handler)。硬件ISR負責快速響應中斷,執行必要的硬件操作,如確認中斷源、禁用中斷源等,然后喚醒線程化的中斷處理函數。線程化的中斷處理函數在獨立的線程上下文中運行,可以被搶占,允許其他高優先級任務在必要時搶占執行,從而減少對系統實時性的影響。
-
優勢:線程化中斷處理程序的主要優勢在于它們可以被搶占,允許系統在必要時調度其他任務,從而提高系統的響應性和實時性能。此外,線程化中斷處理程序可以在線程上下文中使用內核API,如互斥鎖等,簡化了驅動程序的設計和同步。
-
適用場景:線程化中斷處理程序適用于那些需要快速響應但處理過程可能較長的中斷,如網絡數據包處理。通過將耗時的處理邏輯移到線程中,可以減少中斷上下文的執行時間,降低對系統實時性的影響。
-
實現方式:在Linux內核中,可以通過
request_threaded_irq
函數來注冊線程化的中斷處理函數。這個函數允許指定一個硬件ISR和一個線程化的中斷處理函數,硬件ISR在中斷發生時快速響應,而線程化的中斷處理函數在獨立的線程中執行。
總的來說,線程化中斷處理函數通過將中斷處理邏輯分散到不同的執行環境,有助于提高系統的實時性能和響應性,特別是在需要處理大量或復雜中斷任務的場景中。
3. request_irq 申請中斷
request_irq
是 Linux 內核中用于注冊中斷處理程序的函數。它允許設備驅動程序請求一個中斷號(IRQ),并提供一個中斷處理函數(handler),當指定的中斷發生時,內核將調用這個處理函數。這個函數通常用于需要處理硬件中斷的設備驅動程序中。
函數原型如下:
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id);
參數說明:
irq
: 指定要分配的中斷號。handler
: 中斷處理函數指針,當中斷發生時,系統將調用這個函數。irqflags
: 中斷處理的屬性,可以指定快速中斷、中斷共享等屬性。devname
: 設備名稱,用于標識中斷請求的設備。dev_id
: 設備標識符,可以是設備結構體或其他設備特定的標識符,用于在共享中斷中區分不同的設備。
使用 request_irq
時,如果返回值是0,則表示申請成功;如果申請不成功,則返回的值非零,一般為負數,可能的取值包括 -EINVAL
表示中斷號無效或處理函數指針為NULL,-EBUSY
表示中斷已經被占用且不能共享。
此外,request_irq
函數在 2.4 內核和 2.6 內核中都使用,但在 2.6 內核中,需要包含的頭文件是 #include <linux/interrupt.h>
。在 2.4 內核中,需要包含的頭文件是 #include <linux/sched.h>
。
request_irq
函數的作用是申請使用 IRQ 并注冊中斷處理程序。當 CPU 接收到中斷請求后,可以根據中斷號通過 irq_desc[]
找到該設備的中斷服務程序。
在共享中斷的情況下,dev_id
參數是必需的,并且 dev_id
的值必須唯一。這有助于在共享中斷線上區分不同的設備。
request_irq()函數可能會導致睡眠,因此不能在中斷上下文或者其他禁止睡眠的代碼段中使用 。
與request_irq() 函數相比request_threaded_irq() 函數僅多了一個入參thread_fn ,thread_fn()為在線程中運行的函數。
Appendix.
irqflags:中斷標志,可以在文件 include/linux/interrupt.h 里面查看所有的中斷標志,這里我們介紹幾個常用的中斷標志。
標志 | 描述 |
---|---|
IRQF_SHARED | 多個設備共享一個中斷線,共享的所有中斷都必須指定此標志。如果使用共享中斷的話,request_irq 函數的 dev 參數就是唯一區分他們的標志 |
IRQF_ONESHOT | 單次中斷,中斷執行一次就結束 |
IRQF_TRIGGER_NONE | 無觸發 |
IRQF_TRIGGER_RISING | 上升沿觸發 |
IRQF_TRIGGER_FALLING | 下降沿觸發 |
IRQF_TRIGGER_HIGH | 高電平觸發 |
IRQF_TRIGGER_LOW | 低電平觸發 |
返回值: | 0 中斷申請成功,其他負值 中斷申請失敗,如果返回-EBUSY 的話表示中斷已經被申請了。 |