裝置驅動程式與核心模組

註冊中斷(registering an IRQ)

/ I-R-Q, 'eye-ar-cue' /

裝置常常無法立刻告訴你它準備好了——網路封包何時到就何時到、按鍵在無法預測的時刻被按下。與其讓 CPU 不斷地問「你好了沒?」,裝置會發出中斷:一個硬體信號,把 CPU 從它正在做的事拉開,去執行一個特別的處理常式。註冊中斷就是驅動程式告訴核心「當中斷線 N 觸發時,呼叫我的函式」。

在 Linux 中,驅動程式呼叫 request_irq(irq, handler, flags, name, dev_id)。irq 是裝置使用的中斷編號;handler 是觸發時要執行的函式;dev_id 是會被傳回的識別記號,讓共享的處理常式能找到自己的資料。從那時起,每當裝置發出信號,核心就切換進中斷情境並呼叫你的處理常式。關鍵在於:中斷處理常式(往往)在中斷被停用的情況下執行、不能睡眠,而且必須快——它應該只做最少的事(向裝置確認、抓取資料),並把較慢的工作延遲給稍後在較寬鬆情境執行的下半部(softirq、tasklet 或 workqueue)。這就是上半部/下半部的切分:上半部是極小的緊急處理常式,下半部是延後的其餘部分。處理常式若這個中斷屬於它的裝置就回傳 IRQ_HANDLED,否則回傳 IRQ_NONE(這對共享線很重要)。

這之所以重要,是因為中斷是裝置取得關注而不浪費 CPU 去輪詢的方式,而把處理常式的紀律弄對,對一個反應靈敏的系統至關重要。兩個誠實的提醒:緩慢或會睡眠的中斷處理常式可能凍結機器,因為它以高於任何行程的優先權執行,並可能擋住其他中斷。此外,數個裝置可以共享一條 IRQ 線,所以共享的處理常式必須檢查自己裝置的狀態暫存器,並在中斷不是給它的時候回傳 IRQ_NONE,否則它會把別的裝置的中斷吞掉。

static irqreturn_t my_isr(int irq, void *dev_id) { if (!(read_status() & MY_IRQ_BIT)) // 不是我的裝置? return IRQ_NONE; // (共享線) ack_device(); // 只做最少的事 schedule_work(&bottom_half); // 把其餘延後 return IRQ_HANDLED; } // request_irq(irq, my_isr, IRQF_SHARED, "mydev", dev);

一個上半部處理常式:確認這真的是我們的中斷、向裝置確認、延後慢工作、回傳 HANDLED 或 NONE。

中斷處理常式在中斷情境中執行:它不可睡眠、必須快,而在共享線上若中斷不是它的,必須回傳 IRQ_NONE——否則它會偷走別的裝置的中斷。

又称
request_irqinterrupt handler registration中斷處理常式註冊