我正在將設備驅動程序從QNX移植到Linux。在QNX中,舊驅動程序使用帶有無限循環的pthread來監視中斷的發生,而不是註冊真正的中斷處理程序。爲了演示使用register_irq()而不是專用的輪詢線程的功效,我在Linux中編寫了兩個驅動程序。下面顯示了每個代碼的相關代碼,問題在底部。Linux外部事件處理 - IRQ與輪詢kthread
IRQ
編寫處理
irqreturn_t timing_interrupt_handler(int irq, void *dev_id) {
u32 test;
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if (test & (1 << 2)) {
/* clear interrupt status */
iowrite32(0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if (test & 0x01)
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
return IRQ_HANDLED;
}
註冊的處理程序
rc = request_irq(irq_line, timing_interrupt_handler,
IRQF_SHARED, "timing", timing_card);
if (rc) {
printk(KERN_ALERT "Failed to register irq %d\n", irq_line);
return rc;
}
輪詢線程
編寫線程函數
int poll_irq(void *data) {
u32 test;
/* until module unload */
while (!kthread_should_stop()) {
/* read device interrupt command/status register */
test = ioread32(timing_card[3].base);
/* sanity check that the device reported the interrupt */
if (test & (1 << 2)) {
/* clear interrupt status */
iowrite32(0x0d, timing_card[3].base);
/* toggle digital output line */
test = ioread32(timing_card[2].base);
if (test & 0x01)
iowrite32(test & ~0x1, timing_card[2].base);
else
iowrite32(test | 0x1, timing_card[2].base);
}
else
usleep_range(9, 11);
}
return 0;
}
開始線程
kthread = kthread_create(poll_irq, 0x0, "poll_IRQ_test");
wake_up_process(kthread);
問題
當我把兩條曲線在示波器上 - 一個監控卡的數字輸入(這會觸發中斷)和一個監控該卡的數字輸出(這將對中斷做出反應)我可以測量事件的反應時間。
第一個「正確」的方法,註冊一個IRQ,大約需要80微秒。
第二種方法,運行無限線程大約需要15-30微秒。
什麼給?第一個好處是它不會浪費太多的處理能力,但爲什麼響應時間如此劇烈呢?真的有這個輪詢線程有多糟糕?如何才能調查並最終證明輪詢線程對CPU造成的額外損失?
謝謝你的時間!
最佳
斯科特
是的。請參閱http://lwn.net/images/pdf/LDD3/ch17.pdf「接收中斷緩解」部分,其中討論了網絡驅動程序。 –