沿一次回報保存錯誤證據
選擇步驟後,圖中對應的元件與下方解說會加上重點標示。完整圖與所有解說會持續顯示;也可用方向鍵切換步驟。
先走左上到右下的正常回報路徑,再看下方遮罩分支。DPC(Downstream Port Containment,下游連接埠隔離)在後文另行放大,不把兩條路徑畫成連續操作。
作者依本章案例繪製的證據關係圖。訊息來源識別與實體故障原因需依其他證據繼續判讀。
AER(Advanced Error Reporting,進階錯誤回報)提供錯誤狀態、回報控制及相關紀錄。本章先走正常的錯誤回報路徑,再解釋遮罩與 DPC 隔離如何改變軟體看到的資訊。
- DPC
- Downstream Port Containment,下游連接埠錯誤隔離
前情提要:Chapter 5 的交易識別用來解讀有效的 Header Log;Chapter 7 的通知概念用來理解 Root 端如何把事件交給軟體。
規格路線:Figure 6-1 的分類 → Status/Mask/Severity → Figure 6-3 的回報路徑 → Root 紀錄 → 保存與清除 → DPC 分支。
先核對結構版本及錯誤類別
本章的主要算例使用非 Flit、無 Prefix 的條件;不能因 Base 版本較新而改套別種 Capability 布局。
確認 AER Extended Capability 的版本與欄位布局,再依錯誤類型讀相關 Status。
- AER
- Advanced Error Reporting,進階錯誤回報
Base 6.0 §6.2.1–§6.2.3/Figure 6-1,pp.669–673;Figure 7-154/Table 7-134,p.1112。
沿控制條件判斷這次回報
這是本章特定錯誤案例的回報路徑;Unsupported Request、Advisory Non-Fatal 等另有規則。
在本例中依 Status、個別 Mask、Severity 與回報 Enable 追蹤訊息。被遮罩的狀態仍有自己的保存規則。
Base 6.0 §6.2.3.2.2、§6.2.6/Figure 6-3,pp.673、685;Figures 7-155–7-157,pp.1113–1117。
把來源端與 Root 紀錄配起來
回報的 Requester ID 是定位線索;只有 Log 非零,尚不足以確認它屬於這次事件。
保存 Root Error Status/Source ID,再回到來源 Function 的 Status 與有效紀錄;用 First Error Pointer 等欄位確認關聯。
Base 6.0 §7.8.4.7–§7.8.4.11/Figures 7-160–7-164,pp.1121–1127。
先保存,再處理清除與隔離分支
RW1C 表示讀取可得值、寫 1 清除相應狀態;清除前先保留需要的證據。DPC 的觸發與恢復依其專屬條件。
保存相關狀態、Header Log、控制值及時間資訊,再依 RW1C 等存取規則清除已處理狀態。接著比較啟用 DPC 時的不同觀察。
Base 6.0 §6.2.4.2/§6.2.7.1,pp.679–681、691;§6.2.11、§7.9.14,pp.694–697、1245–1254。
圖中元件
Root 端的回報紀錄
本圖從 Root 端通知連回來源 Function 的狀態與紀錄。
基本責任
錯誤分類、來源識別、有效紀錄與故障原因是沿途要核對的資訊,不能只用一個識別值概括。
1. 一個錯誤訊息,能告訴我們多少事情?
Correctable Error 表示協定可自行恢復的錯誤,仍可能降低效能;Uncorrectable Error 則影響功能,並分為 Non-Fatal 與 Fatal。Non-Fatal 不等於工作已成功,Fatal 也不是「一定已損壞某顆晶片」的硬體診斷。這些分類提供回報與處理政策所需的嚴重程度。
| 紀錄位置 | 回答的問題 | 證據限制 |
|---|---|---|
| Function 的 Device Status/AER Status | 這個 Function 記錄了哪類偵測結果? | 不保證訊息已送達,也不是事件次數。 |
| AER Mask/Severity/Device Control | 偵測時如何記錄與回報? | 事後讀值不一定等於事發當時設定。 |
| Root Error Status/Source ID | Root Port 收到哪些類別,第一個回報者是誰? | 回報者不一定是造成根本問題的元件。 |
| Header Log/First Error Pointer | 目前保存的錯誤對應哪個交易內容? | 有有效性、容量、封包模式與錯誤種類限制。 |
| DPC Status | 是否已隔離下游,觸發原因是什麼? | 不能替應用工作判定成功或復原完成。 |
Advanced Error Reporting(AER)是在基本錯誤回報之外,提供個別錯誤狀態、遮罩、嚴重程度與相關紀錄的 Extended Capability。即使沒有找到 AER,也不能直接說「裝置沒有任何錯誤回報能力」。
分類與回報模型
§6.2.1–§6.2.4(pp.669–679);Figure 6-1(p.670)整理分類。個別錯誤的處理與預設分類要再讀 Tables 6-4、6-5(pp.685–691),不能只從名稱猜行為。
2. Status 有兩個 bit,為什麼只回報一個錯誤?
先依 Chapter 2 的 Extended Capability 清單找 ID=0x0001,再用 Figure 7-154 解 Header。下面是 Endpoint 03:00.0 的快照;AER base 剛好是 0x100,不是固定位置。假設先前紀錄已清理、設定自事件前保持不變,期間沒有其他錯誤,且沿途的錯誤訊息轉送已正確啟用。
| 欄位與位置 | 值 | 閱讀入口 |
|---|---|---|
| Header,0x100,32 bits | 0x00020001 | Figure 7-154 |
| Uncorrectable Error Status,0x104,32 bits | 0x00044000 | Figure 7-155 |
| Uncorrectable Error Mask,0x108,32 bits | 0x00040000 | Figure 7-156 |
| Uncorrectable Error Severity,0x10C,32 bits | 0x00040000 | Figure 7-157 |
| Advanced Error Capabilities and Control,0x118,32 bits | 0x0000100E | Figure 7-160 |
| Device Control,PCIe base+0x08=0x78,16 bits | 0x2816 | Figure 7-25 |
Header 表示 ID=0x0001、Version=2、Next=0;即使讀的是 Base 6.0,也不能自行套用只適合較新 Capability/Flit 的佈局。本例沒有 Flit 或 Prefix,因此 Version=2 符合條件。
Status 的 bit 14=1 是 Completion Timeout;bit 18=1 是 Malformed TLP。Mask bit 18=1、bit 14=0,因此這兩個已記錄的錯誤中,只有 Completion Timeout 未被遮罩:0x00044000 & ~0x00040000 = 0x00004000。這個運算只挑出本例的未遮罩狀態,還不是完整的回報判定演算法。
- TLP
- Transaction Layer Packet,交易層封包
個別錯誤被 Mask 時,Status 仍可設起來;但不會為該次錯誤發出 Error Message,也不會把它存進 Header Log、TLP Prefix Log 或 First Error Pointer。不能把「Mask=1」解成「沒有發生」,也不能把 Severity=Fatal 解成「無論 Mask 為何都必須送出 Fatal 訊息」。
本例 Severity bit 14=0,Completion Timeout 被設定為 Non-Fatal;bit 18=1,Malformed TLP 被設定為 Fatal,但後者已 Mask。Device Control bit 1=1 允許 Non-Fatal 回報,所以在本例前提下,Completion Timeout 產生 ERR_NONFATAL。Device Control bit 2 也開啟 Fatal 回報,仍不會解除個別 Malformed TLP Mask。這是明確設定後的快照,不宣稱 Severity 值是重設預設值。
完整通知還要經過沿途 Bridge 的轉送條件、Root Port primary interface 的傳送允許,以及 Root 端的中斷設定。實際查詢時,從 Figure 6-3 沿來源到 Root 的路徑檢查;不能只讀 Endpoint 的一個 Enable 就結案。Unsupported Request、Advisory Non-Fatal 等類型另有規則,不宜把本例簡化式照搬過去。
Status → Mask → Severity → 回報路徑
Figures 7-154–7-157/Tables 7-134–7-137(pp.1112–1117);Figure 7-25/Table 7-21(pp.958–962)。Mask 行為見 §6.2.3.2.2(p.673),回報路徑見 §6.2.6/Figure 6-3(p.685)、§6.2.8.1(p.692);Advisory Non-Fatal 另見 §6.2.4.3(p.682)。
3. Header Log 看起來像封包,就能直接解碼嗎?
先檢查有效性。Advanced Error Capabilities and Control 的低五位為 0x0E,也就是 First Error Pointer(FEP)=14;它指向 Uncorrectable Error Status 的 bit 14。本例該 bit=1,因此 FEP 有效,對應 Completion Timeout。不是看到 Log 非零,就能認定它屬於目前關心的事件。
Completion Timeout 也不能一律期待有 Request Header。本例 bit 12=1,表示 Completion Timeout Prefix/Header Log Capable;Multiple Header Recording Capable/Enable bits 9、10 均為 0。再加上沒有 Flit/End-End Prefix,這才得到本例的四個 DWORD Log 容量與解讀前提。
| DWORD 讀取位置 | 讀值 | 由封包格式推出的內容 |
|---|---|---|
| 0x11C | 0x00000040 | 3 DW Memory Read Header,Length=64 DW。 |
| 0x120 | 0x030013FF | Requester ID=0x0300、Tag=0x13、First/Last DW BE 均為 0xF。 |
| 0x124 | 0x40001000 | Request 起始位址。 |
| 0x128 | 不解讀 | 本例是 12-byte Header,第四個 DWORD 未定義。 |
- DW
- Double Word,4 bytes的資料單位
因此這筆未如期完成的 Request 要讀 64 × 4=256 bytes,範圍為 0x40001000–0x400010FF。Header 顯示的是等待 Completion 的 Request,不是「超時回來的 Completion」。這個案例延用 Chapter 5 的交易欄位,不重教 TLP 全部格式。
Figure 7-161 特別規定 DWORD 讀取後的排列方式:封包 Header byte 0 位於第一個 Log DWORD 的 bits 31:24。上表已按 DWORD 數值解讀,不能再套一次普通 byte dump 的直覺而把位元組反轉。若是 Flit Mode,要改看 Logged TLP was Flit Mode、Header Log Size、Logged TLP Size,以及 Type/OHC,不能仍只拿前三個 DWORD 套本例。
- OHC
- Orthogonal Header Content,Flit模式的擴充標頭內容
這份 Log 可以定位某筆 Request 及其等待結果;它不能單獨證明原因在 Endpoint、Completer、Link、路由或平台。Masked 的 Malformed TLP 沒有本次 Header 紀錄,也不能把現在這份 MRd Header 逕自歸給它。
先驗證 FEP,再選 Header 格式
§6.2.4.2(pp.679–680)定義 FEP 有效性及多筆記錄;Figures 7-160、7-161/Tables 7-140、7-141(pp.1121–1123)定義能力、Log 格式與 byte 排列。Memory Request 格式見 §2.2.7、Figure 2-31(p.163),細部推導連回 Chapter 5。
4. Root Port 記錄 03:00.0,是否代表它就是故障來源?
先區分「送出錯誤訊息的 Function」與「造成根本問題的元件」。Root Error Source Identification 記錄第一個相應類別訊息的 Requester ID;例如 Endpoint 等不到讀取回覆而回報 Timeout,Root 看到 Endpoint 的 ID 並不奇怪。
| Root AER base=0x100 的位置 | 值 | 判讀 |
|---|---|---|
| Root Error Command,0x12C | 0x00000002 | 開啟 Non-Fatal 中斷回報。 |
| Root Error Status,0x130 | 0x00000024 | bit 2、bit 5=1;Multiple、Fatal、Correctable 均未設。 |
| Error Source Identification,0x134 | 0x03000000 | 高 16 bits=0x0300,是第一個 Uncorrectable 訊息的 Requester ID。 |
(0x03000000 >> 16) & 0xFFFF = 0x0300,依一般 BDF 編碼解為 03:00.0。本例 Root AER 的中斷向量編號設為 0,因此完整 Status 的高位沒有額外數值。Root primary interface 的傳送條件也已滿足;若要斷言 CPU 實際收到中斷,還要確認 MSI/MSI-X 或 INTx 的傳送與平台路由,不能只憑 0x24。
- BDF
- Bus/Device/Function,匯流排、裝置與功能識別
- MSI
- Message Signaled Interrupt,訊息中斷
- MSI-X
- Message Signaled Interrupts Extension,表格式訊息中斷
Root Error Status 的更新不受 Root Error Command 或 Root Control 的值控制,但仍有前述 primary interface 傳送允許條件。假如後來又收到另一個 Uncorrectable Message,Multiple bit 會設起來,第一個 Source ID 仍保留;這個欄位不是完整的回報者清單。
Root 端的圖表路徑
Figure 7-162/Table 7-142(pp.1123–1124)→ Figure 7-163/Table 7-143(pp.1124–1126)→ Figure 7-164/Table 7-144(pp.1126–1127)。先看類別有效狀態,再決定要讀 Source ID 的哪半邊。
5. 為什麼不能一開始就把所有 Status 寫 1 清掉?
因為清除不只是讓畫面乾淨。當軟體清掉 FEP 所指的錯誤時,硬體可能更新下一筆 Header 與 FEP;若先清除再讀 Log,就可能把兩個時間點的資料拼成同一個事件。
- 先記下管理對象、時間與當時設定;保存相關 AER Status、Mask、Severity、FEP、有效 Log,以及 Root/DPC 的對應證據。
- 依 FEP 與能力確認 Log 的格式及有效範圍;若資料可能並行變動,重新核對關聯,不能假定多個 Register 的讀取是原子快照。
- 完成該筆紀錄處理後,才對相應 RW1CS bit 寫 1。若啟用 Multiple Header Recording,依 FEP 逐筆處理,再重新讀狀態。
前兩步是作者整理的蒐證方式;第三步的硬體清除語意來自規格。Base 6.0 建議在多筆 Header 記錄啟用且 FEP 有效時,不要清除 FEP 以外的 Status bit;規格也列有確定沒有 Header 紀錄的 masked error 例外。它不是一條「所有錯誤情境都一次寫固定遮罩」的操作口訣。
另外,清 PCI Status 不會連帶清 AER Status,反方向也一樣。對照不同紀錄時,須記下是哪個 Register 在什麼時候被清除。
清除會改變哪些證據
§6.2.4.2(pp.679–681,含註腳 108)說明多筆記錄與清除順序;§6.2.7.1(p.691)說明 PCI Status 與 AER Status 的獨立性。
6. 如果啟用 DPC,為什麼 Root 可能看不到原本的 ERR_NONFATAL?
以下換成另一個事件案例。02:01.0 的 DPC Extended Capability 位於 0x300;這是一個 Switch Downstream Port,不使用 Root Port Extensions。Downstream Port Containment(DPC)可在觸發後停止下游 PCIe 流量,使問題先被限制在受影響的分支。
| 欄位與位置 | 值 | 由欄位得知的狀態 |
|---|---|---|
| Header,0x300,32 bits | 0x0001001D | ID=0x001D、Version=1、Next=0。 |
| DPC Control,0x306,16 bits | 0x000A | Trigger Enable=10b;Interrupt Enable=1。 |
| DPC Status,0x308,16 bits | 0x000B | Trigger Status=1;Reason=01b;Interrupt Status=1。 |
| DPC Error Source ID,0x30A,16 bits | 0x0300 | 觸發訊息的 Requester ID。 |
Trigger Enable=10b 表示 Port 自己偵測到未遮罩的 Uncorrectable Error,或收到 ERR_NONFATAL/ERR_FATAL 時可觸發。Reason=(0x000B >> 1) & 3 = 1,所以本次原因是收到 ERR_NONFATAL;此時 Source ID 才具有這裡要用的意義。若 Reason=00b 表示 Port 自己偵測到錯誤,就不能照用 Source ID 猜來源。
觸發 DPC 的這個 ERR_NONFATAL 會被 Port 丟棄,不再往上游轉送。DPC 可另外以中斷或 ERR_COR 通知管理者,但本例 DPC ERR_COR Enable=0,只啟用 DPC 中斷;中斷是否到達仍要看向量與平台設定。因此不能要求 Root AER 一定同時出現上一節的 0x24 快照。
清掉通知後,Link 為什麼還沒有回來?
Figure 7-300 把 DPC Trigger Status 放在 bit 0,DPC Interrupt Status 放在 bit 3。兩者都能寫入 1 清除,但作用不同:bit 3 處理中斷狀態;bit 0 維持隔離,清除後才允許 LTSSM離開 Disabled,回到 Detect 嘗試建立 Link。
- LTSSM
- Link Training and Status State Machine,鏈結訓練與狀態機
【模擬資料】以下資料為教學用途建立,不代表特定硬體或平台。延續上方獨立的 DPC 事件:02:01.0 已收到來自 03:00.0 的 ERR_NONFATAL,DPC Status 讀為 0x000B。本例選擇先保存證據、只清中斷,再等待解除隔離的條件。到 Switch 的上游管理路徑仍可用,軟體經由這條路徑讀寫 Port 的設定空間;本次停用的是 02:01.0 到 03:00.0 的 Link。假設過程中沒有新的 DPC 事件,也沒有其他軟體同時寫入這個 Register。
| 動作與位置 | DPC Interrupt Status,bit 3 | DPC Trigger Status,bit 0 | 後續行為 |
|---|---|---|---|
| 讀取 0x308,得到 0x000B | 1 | 1 | 已記錄中斷與隔離事件;Reason=01b。 |
| 保存證據後,以 16-bit 寫入 0x0008 到 0x308 | 清為 0 | 維持 1 | 本例再讀為 0x0003,Port 仍在 DPC。 |
| 符合釋放條件後,以 16-bit 寫入 0x0001 到 0x308 | 本例維持 0 | 清為 0 | 回到 Detect 嘗試訓練;Reason 已無效,不指定整個 Register 的固定讀值。 |
這裡刻意拆成兩次寫入,讓通知與隔離的差別容易看清楚;規格沒有要求每套軟體都採這個拆法。真正必須遵守的是釋放條件。也因此,不能把讀出的 0x000B 原樣寫回,當成只清中斷的操作:那會同時對 bit 3 與 bit 0 寫 1,連隔離也一起釋放。
下圖的等待分支接到 §6.2.11:軟體必須先讀到 Link Status 的 Data Link Layer Link Active=0,才能釋放 DPC;若過早清除,結果為 undefined(規格未定義)。本例是 Switch Downstream Port,DPC RP Busy 不適用;支援 RP Extensions 的 Root Port 則還須等待該 bit 為 0。
- LTSSM
- Link Training and Status State Machine,鏈結訓練與狀態機
隔離期間又來一筆 Memory Read,誰回覆?
接著讀 §2.9.3 Transaction Layer Behavior During Downstream Port Containment。假設 Root Complex 送來一筆新的、格式合法的 Memory Read,原本應由 02:01.0 轉送到 03:00.0 的 BAR;它在 Port 已處於 DPC 時才提交給下游傳送路徑。這筆 Request 由 Port 丟棄,並由 Port 產生錯誤 Completion(交易回覆)。
- BAR
- Base Address Register,基底位址暫存器
為了知道回覆哪種錯誤,回到 Figure 7-299/Table 7-263:本例 DPC Control=0x000A,bit 2 的 DPC Completion Control=0,因此回覆 Completer Abort(CA,完成端中止);若該 bit=1,才改回 Unsupported Request(UR,不支援的要求)。此 Completion 的 Completer ID 是 Downstream Port 02:01.0,因為這次由它終止 Request;前面 DPC Error Source ID 的 03:00.0 則是觸發隔離訊息的回報者。
在這個情境中收到 CA,是 Port 依 DPC 規則產生的結果,無法據此宣稱 Endpoint 已接受或執行該次讀取。若換成隔離前就已送出的 Request,且 DPC 使 Completion 無法回來,本例沒有 Root Port Extensions 的代回覆機制,Requester 仍可能遇到 Completion Timeout。新的 Request 如何被終止,與舊 Request 是否已完成,要分別追蹤。
解除隔離後,還有哪些恢復工作?
Table 7-264 說明,清除 DPC Trigger Status 後,Port 離開 DPC,LTSSM 必須回 Detect。這只是重新嘗試訓練;接著還要觀察 Link 與 Data Link 恢復,並依 §6.6.1 遵守 Conventional Reset(一般重設)之後首次 Configuration Read 的適用時序,才能繼續恢復設定與驅動程式。等待條件連回 Chapter 9,不在這裡重複全部 Reset 流程。
解除隔離也會改變紀錄的判讀條件:DPC Trigger Status=0 後,DPC Trigger Reason 已不再有效,應使用先前保存的快照分析本次事件。規格允許在釋放要求已滿足後清除 Trigger Status,不必等所有相關錯誤 Status 都變成 0;因此,清空整片錯誤紀錄並不是恢復的必要前提。裝置如何重建工作、處理先前在途資料及恢復應用服務,則仍須裝置、驅動與平台的恢復程序。
從欄位、隔離中的交易,到釋放條件
依據 PCI Express Base Specification Revision 6.0。Figure 7-300 DPC Status Register/Table 7-264、§7.9.14.4(PDF/印刷 pp.1252–1253)定位 Trigger Status、Interrupt Status、Reason 有效條件與適用的 RP Busy。接 §6.2.11 Downstream Port Containment (DPC)(p.694),閱讀必須等 Link Active=0 才可釋放的要求;DPC 中斷條件見 §6.2.11.1 DPC Interrupts(p.697)。隔離期間 Request 的處理依 §2.9.3 Transaction Layer Behavior During Downstream Port Containment(p.262),再回 Figure 7-299 DPC Control Register/Table 7-263、§7.9.14.3(pp.1250–1251)查 DPC Completion Control。訊息來源欄位依 Figure 7-301/Table 7-265、§7.9.14.5 DPC Error Source ID Register(pp.1253–1254)。釋放後首次設定存取依 §6.6.1 Conventional Reset(pp.721–723)。上述 PDF 與印刷頁碼相同;本例的軟體處理順序是作者示範。
7. 先保存,再逐項解讀錯誤
AER Status=0,是否足以證明從開機至今都沒有錯誤?
不足。紀錄可能已被清除或重設,部分欄位也取決於實作與偵測條件。應先確認蒐證時間範圍與清除紀錄。依據:§6.2.4.2、Table 7-135。
FEP=14,但 Status bit 14 已清除,仍可把 Header Log 當成最新 Timeout 嗎?
不可以。FEP 此時無效;Log 看起來合理並不能補足有效性條件。依據:§6.2.4.2、Table 7-140。
DPC Source ID=03:00.0,能否斷言 03:00.0 的硬體必須更換?
不能。先確認 Trigger Reason 允許解讀 Source ID;即使有效,也只識別觸發訊息的回報者。還需交易、相鄰元件與平台證據才能判斷原因。依據:Table 7-265。