中斷¶
- 2.5.2-rmk5
這是第一個包含一些主要架構特定子系統重大變革的核心。
首先,它包含對我們處理 MMU TLB 方式的一些相當大的更改。現在,每個 MMU TLB 變體都完全獨立處理 - 我們有 TLB v3、TLB v4(沒有寫緩衝)、TLB v4(有寫緩衝)以及最後的 TLB v4(有寫緩衝,帶有 I TLB 無效條目)。每個函式內部都有更多的彙編程式碼,主要是為了允許將來更靈活的 TLB 處理。
其次,是 IRQ 子系統。
2.5 核心將對 IRQ 的處理方式進行重大更改。不幸的是,這意味著所有訪問 irq_desc[] 陣列的機器型別(基本上是所有機器型別)都會崩潰,這意味著我們目前擁有的每種機器型別都會崩潰。
讓我們舉個例子。在帶有 Neponset 的 Assabet 上,我們有
GPIO25 IRR:2
SA1100 ------------> Neponset -----------> SA1111
IIR:1
-----------> USAR
IIR:0
-----------> SMC9196
當前的工作方式是,所有 SA1111 中斷都是相互排斥的 - 如果您正在處理來自 SA1111 的一箇中斷,並且另一箇中斷到來,您必須等待該中斷完成處理才能服務新的中斷。例如,SA1111 上的基於 IDE PIO 的中斷會排除所有其他 SA1111 和 SMC9196 中斷,直到它完成傳輸其多扇區資料,這可能需要很長時間。另請注意,由於我們在 SA1111 IRQ 處理程式中迴圈,因此 SA1111 IRQ 可以無限期地阻止 SMC9196 IRQ。
新方法帶來了一些新想法...
我們引入了“父”和“子”的概念。例如,對於 Neponset 處理程式,“父”是 GPIO25,“子”是 SA1111、SMC9196 和 USAR。
我們還引入了 IRQ “晶片” 的概念(主要是為了減少 irqdesc 陣列的大小)。這不必是真正的“IC”;事實上,SA11x0 IRQ 由兩個單獨的“晶片”結構處理,一個用於 GPIO0-10,另一個用於所有其餘部分。它只是各種操作的容器(也許這會更改為一個更好的名稱)。此結構具有以下操作
struct irqchip {
/*
* Acknowledge the IRQ.
* If this is a level-based IRQ, then it is expected to mask the IRQ
* as well.
*/
void (*ack)(unsigned int irq);
/*
* Mask the IRQ in hardware.
*/
void (*mask)(unsigned int irq);
/*
* Unmask the IRQ in hardware.
*/
void (*unmask)(unsigned int irq);
/*
* Re-run the IRQ
*/
void (*rerun)(unsigned int irq);
/*
* Set the type of the IRQ.
*/
int (*type)(unsigned int irq, unsigned int, type);
};
- ack
必需。對於由 do_level_IRQ 處理的 IRQ,可能與 mask 函式相同。
- mask
必需。
- unmask
必需。
- rerun
可選。如果您為所有使用此“irqchip”的 IRQ 使用 do_level_IRQ,則不需要。通常希望儘可能重新觸發硬體 IRQ。如果沒有,可以直接呼叫處理程式。
- type
可選。如果您不支援更改 IRQ 的型別,則它應該為空,以便人們可以檢測到他們是否無法設定 IRQ 型別。
對於每個 IRQ,我們保留以下資訊
“停用”深度(沒有
disable_irq()的enable_irq()s 的數量)指示我們可以對該 IRQ 執行的操作的標誌(valid、probe、noautounmask),與以前一樣
IRQ 的狀態(正在探測、啟用等)
chip
每個 IRQ 的處理程式
irqaction 結構列表
處理程式可以是 3 個標準處理程式之一 - “level”、“edge” 和 “simple”,或者如果您需要做一些特殊的事情,則可以使用您自己的特定處理程式。
“level” 處理程式是我們目前擁有的 - 它非常簡單。“edge” 知道這種 IRQ 實現的缺陷 - 您需要在處理硬體 IRQ 時保持啟用狀態,並且如果在處理過程中再次發生 IRQ,則應將進一步的 IRQ 事件排隊。“simple” 處理程式非常基本,不執行任何硬體操作,也不進行狀態跟蹤。這對於上面的 SMC9196 和 USAR 之類的東西很有用。
那麼,改變了什麼?¶
機器實現不得寫入 irqdesc 陣列。
用於操作 irqdesc 陣列的新函式。前 4 個函式預計僅對機器特定程式碼有用。建議僅由機器特定程式碼使用最後一個,但如果絕對必要,可以在驅動程式中使用。
- set_irq_chip(irq,chip)
設定用於處理此 IRQ 的 mask/unmask 方法
- set_irq_handler(irq,handler)
設定此 IRQ 的處理程式 (level, edge, simple)
- set_irq_chained_handler(irq,handler)
為此 IRQ 設定一個“chained”處理程式 - 自動啟用此 IRQ(例如,Neponset 和 SA1111 處理程式)。
- set_irq_flags(irq,flags)
設定 valid/probe/noautoenable 標誌。
- set_irq_type(irq,type)
設定啟用的 IRQ 邊沿/電平。這取代了 SA1111 INTPOL 操作和 set_GPIO_IRQ_edge() 函式。Type 應該是 <linux/irq.h> 中定義的 IRQ_TYPE_xxx 之一
set_GPIO_IRQ_edge() 已過時,應替換為 set_irq_type。
不推薦直接訪問 SA1111 INTPOL。改用 set_irq_type。
處理程式應透過正確的晶片特定函式執行任何必要的父 IRQ 確認。例如,如果 SA1111 直接連線到 SA1110 GPIO,則每次重新讀取 SA1111 IRQ 狀態時,都應確認 SA1110 IRQ。
對於任何沒有自己的 IRQ 啟用/停用控制元件的子項(例如,SMC9196),處理程式必須在呼叫子處理程式時遮蔽或確認父 IRQ,並且子處理程式應該是 “simple” 處理程式(而不是 “edge” 或 “level”)。處理程式完成後,應取消遮蔽父 IRQ,並且必須重新檢查所有子項的狀態以查詢待處理的事件。(有關詳細資訊,請參見 Neponset IRQ 處理程式)。
fixup_irq() 已消失,arch/arm/mach-*/include/mach/irq.h 也是如此
請注意,這不會解決所有問題 - 其中一些問題是基於硬體的。在同一父訊號(例如,neponset)上混合使用基於電平和基於邊沿的 IRQ 是一個軟體解決方案無法完全解決低 IRQ 延遲的領域。