首頁 > 軟體

一種Linux下共用中斷的處理方法

2020-06-16 17:53:50

前段時間偵錯一款晶片的時候,碰到一個奇怪的問題:只要在板卡上插入一個PS2鍵盤,啟動核心時系統就可能會進入串列埠中斷函數去執行,過一會系統就panic不往下繼續執行。後來經過分析出現問題時的panic的堆疊,藉助EJTAG工具,讀到這個時候的串列埠的中斷狀態位,竟然發現串列埠並沒有真正產生中斷。那麼,串列埠本身沒有中斷,核心怎麼又會跑到串列埠的中斷服務函數去執行呢?

我們知道Linux的中斷可以分為I/O 中斷 、時鐘中斷和處理器核間中斷。其中I/O中斷是Linux 系統響應外部IO事件的重要方式。儘管不同的平台和體系結構實現的方法不一樣,但是都支援不同的裝置共用同一個中斷向量 。例如在PCI的匯流排結構中,幾個裝置可以共用同一個IRQ線,也即它們共用一個中斷號,各自的中斷服務例程掛在這個中斷號上。當CPU響應這個IRQ時,會逐一檢查掛在這個中斷向量上的例程,並且執行那些真正有中斷的例程。但是串列埠明顯不屬於PCI,不可能用到PCI的中斷線和中斷引腳暫存器,那又是什麼原因導致kernel panic呢?

帶著上面的這些問題,和硬體工程師和晶片設計的同事深入討論了各種可能性,最後結合晶片板卡原理圖,發現這個板子上的低速裝置都整合在晶片內部,這些低速裝置包括串列埠、LPC只是控制器、SPI控制、I2C控制器、NAND控制器等,其中CPU UART和LPC的中斷信號都路由到同一個CPU的中斷引腳。 具體的連線圖如下所顯:

通過上圖最左側的部分可以看到,CPU UART和CPU LPC控制器的中斷請求信號經過邏輯或後,輸出到了CPU 晶片內Interrupt Pending Bit2。一旦CPU檢測到任何一個Interrupt Pending位被設定起來,它就會根據約定的順序逐一查詢各個Interrupt Pending Bit,並且執行中斷路由到這個bit上的裝置驅動的中斷服務例程。

在老版本的板卡設計中,CPU LPC上沒有接任何裝置,當時沒有碰到前面提到的問題。後來,由於客戶的需求,板卡上CPU LPC埠上可以連線PS2 鍵盤和滑鼠,問題也隨之暴露。因此,我猜測問題的根源是由於沒有對共用IP2的連線到LPC上的裝置的中斷進行處理。按照這一思路,檢查了之前的中斷分發處理常式,發現果然在處理IP2時,只呼叫了do_irq(58)。參考核心中串列埠驅動的程式碼可以知道,第一個CPU UART的中斷號預設是58。因此在這種情況下一旦接入的PS2鍵盤或滑鼠發出中斷信號,現有的程式碼就會不分青紅皂白地去執行do_irq(58)。顯然,這不是期望的行為,需要查詢各自的中斷狀態位來檢測到底該響應那個裝置的中斷。在最新的Linux 4.2核心主幹分支裡,我們仍然可以找到這部分有待完善的程式碼:arch/mips/loongson64/loongson-3/irq.c:

void mach_irq_dispatch(unsigned int pending)

{

        if (pending & CAUSEF_IP7)

                do_IRQ(LOONGSON_TIMER_IRQ);

#if defined(CONFIG_SMP)

        else if (pending & CAUSEF_IP6)

                loongson3_ipi_interrupt(NULL);

#endif

        else if (pending & CAUSEF_IP3)

                ht_irqdispatch();

        else if (pending & CAUSEF_IP2)

                do_IRQ(LOONGSON_UART_IRQ);

        else {

                pr_err("%s : spurious interruptn", __func__);

                spurious_interrupt();

        }

}

另外,該晶片中LPC上的中斷信號是電平觸發,根據LPC設定暫存器的定義,當中斷完成之後,需要清除LPC SIRQ,這就需要新增響應的中斷ack和eoi等函數。與此相反的是,相容NS16550A的串列埠上的中斷是邊沿觸發,不需要程式去清除:當傳輸儲存暫存器為空時,串列埠的ISR的bit 1會被設定起來,一旦寫資料到傳輸儲存暫存器,這個bit就會被清掉;當接收FIFO中字元的個數達到trigger的水平時,ISR的bit 2會被設定起來,直到程式讀接收FIFO。

根據上面的兩點思路,修改了響應的程式碼,重新編譯核心,重新做了大量測試,沒有再復現前文提到的問題。通過這個例子,我們可以看到:除了PCI中斷這種共用中斷向量的機制之外,還有不同物理裝置的中斷信號路由到同一個中斷引腳但使用不同中斷號的情況。針對這種情況。工程師需要綜合晶片結構、硬體連線、中斷路由及核心中斷處理流程,全面考慮各種情況,給出完善、健壯的解決方案。但比較這兩者的異同之後,不難發現其實本質還是一樣的:不管中斷號是否一樣,任何路由到CPU內部中斷或者外部中斷控制器上的裝置,都應享用被服務的機會,不能遺漏。

本文永久更新連結地址http://www.linuxidc.com/Linux/2015-09/122568.htm


IT145.com E-mail:sddin#qq.com