簡介
PCIe中有4種復位機制,早期的3種被稱為傳統復位(Conventional?Reset)。傳統復位中的前2種又稱為基本復位(Fundamental?Resets),分別為冷復位(Cold?Reset),暖復位(Warm?Reset)。第3種復位為熱復位(Hot?Reset)。第4種復位被稱為功能級復位(Function?Level?Reset),出現在PCIe?2.0規范中。
傳統復位
2.1.?基本復位
基本復位由硬件處理,并且是復位整個設備,重新初始化所有硬件的邏輯、端口狀態以及配置寄存器。唯一的例外是,有一組標識為"sticky"的寄存器位,因為要記錄復位過程中的錯誤,所以其配套有輔助電源(Vaux)。如果主電源和輔助電源同時關閉,那么Stick寄存器也會復位。
兩種基本復位的定義:
冷復位:啟動設備主電源或重啟設備主電源都會導致冷復位。
暖復位(可選):不關閉主電源下的觸發。規范沒有定義實現機制,廠商可自行選擇是否添加此功能,并設計具體觸發的機制,可以考慮通過檢測電源狀態來實現。
基本復位發生和退出時,正負電壓端阻抗必須滿足要求,發射端的阻抗和直流也必須滿足要求,詳見技術規范。
兩種基本復位方法:
-
通過輔助邊帶信號PERST#(PCI?Express?Reset)觸發。
-
如果未提供邊帶信號,則重啟電源時,組件或插槽會自動產生復位。
2.2.?PERST#?基本復位的產生
PERST#信號是邊帶信號,系統不一定設計有。芯片組可能提供PERST#信號,如下圖ICH對外提供PERST#信號。當POWERGOOD信號觸發時,ICH會發出PERST#信號。PERST#邊帶信號會接入所有PCIe設備。
當設備電源關閉,POWERGOOD信號觸發,然后產生PERST#信號,這是一個冷復位。(此時設備電源也會同時開啟)。
當設備電源開啟,系統可以通過其他方式產生PERST#信號以實現暖復位。
2.3.?自主復位的產生
設備在主電源接通時,應該自己產生復位信號,然后對設備進行本地復位。如果設備檢測到電源超出范圍,也必須生成自主復位。
2.4.?鏈路從低功耗喚醒
當設備的主要電源被關閉作為電源管理策略的一部分時,如果設備設計用于發出喚醒信號,它可能能夠請求恢復到完全供電狀態。當電源恢復時,設備必須進行復位。系統的電源控制器可以通過激活PERST#引腳向設備發送復位信號,但如果沒有這樣做,或者設備不支持PERST#,則設備必須在感知到主電源重新連接時自主生成其自己的基本復位。
2.5.?熱復位(帶內復位)
熱復位是通過在鏈路上發送特定的TS1消息來實現的。這些消息中的第5個符號的第0位被設置為1,以表示這是一個熱復位消息。這些消息將在所有通道上廣播,以確保所有鏈路鄰居都能夠接收到,并執行相應的操作以響應熱復位。一旦完成發送,發送器和接收器將進入特定的狀態以處理熱復位。這個過程有助于在高速數據鏈路中進行重置操作,以確保鏈路的正確性和穩定性。
軟件發起的熱復位是通過在橋接設備的配置寄存器中設置特定的位來實現的。這個位被稱為Secondary?Bus?Reset位。當此位被設置時,與該橋接設備相關聯的所有設備都將接收到復位信號,并進行自我復位。這種復位操作通常由具有橋接功能的設備(例如Root?Complex設備或交換機)執行,并且可以通過其控制寄存器進行觸發。交換機在接收到熱復位信號后將廣播給其下游端口,并要求所有下游設備進行復位。這確保了整個鏈路中的所有設備都可以正確地響應熱復位,并重新初始化其狀態。
如上圖,如果Root?Compex或Switch被軟件啟用了熱復位,那么Root?Compex或Switch會對其所有下端設備發生熱復位。
當熱復位接收器檢測到連續2個熱復位的TS1消息埋,它會進入Hot?Reset狀態并持續2ms,然后退出檢測狀態,上行端口和下行端口都會進行初始化,然后再進入檢測狀態,然后開始免鏈路的訓練。如果下游設備也是交換機或橋接器,它也會將Hot?Reset消息轉發給其下游端口。
2.6.?熱復位方法
2.6.1.?次級總線復位
上級橋接設備的Secondary?Bus?Reset位于配置空間的Bridge?Control寄存器中,可以通過軟件修改達到熱復位。軟件對Secondary?Bus?Reset寄存器先寫入0再寫入1,即發出TS1消息,連續2次。
2.6.2.?鏈路禁用
通過在下游設備的鏈路控制寄存器中設置Link?Disable位,軟件可以禁用鏈路。當禁用鏈路時,下游組件會收到禁用信號并執行相應的操作,這也會導致它們進行熱復位。禁用鏈路的操作將觸發下游端口進入Recovery?LTSSM狀態,并開始發送具有Disable位設置的TS1消息。需要注意的是,只有在禁用鏈路后,才能對下游端口進行控制。因此,Link?Disable位被保留給上行端口,例如終端設備或交換機上行端口。
Link?Control?Register寄存器位于PCI?Express?Capability的Offset?PXCAP?+?10h:?PXLC?–?PCI?Express?Link?Control。
當上行端口識別到帶有Disabled位設置的傳入TS1消息時,物理層會向鏈路層發送LinkUp=0(false)信號,并使所有通道進入電氣空閑狀態。在經過2毫秒的超時后,上行端口將進入Detect狀態,但下行端口將保持在Disabled?LTSSM狀態,直到被指示退出該狀態(例如通過清除Link?Disable位),因此鏈路將保持禁用狀態,并且在未被解除禁用之前不會嘗試進行訓練。
功能層級復位
3.1.?FLR
FLR(Function-Level?Reset)功能允許軟件僅重置多功能設備中的某一個功能,而無需對所有功能進行復位。為了確定是否支持FLR功能,軟件可以檢查設備能力寄存器中的Function-Level?Reset?Capability位。如果此位被設置,軟件可以通過設置設備控制寄存器中的Initiate?Function-Level?Reset位來啟動FLR操作。FLR的實現雖然推薦,但并非每個設備都支持該功能,因此在嘗試使用FLR之前,軟件應先確認設備是否支持該功能。
是否支持FLR,通過查看位于PCI?Express?Capability的Offset?PXCAP?+?4h:?PXDCAP?–?PCI?Express?Device?Capabilities。
設置FLR,通過設置于通過查看位于PCI?Express?Capability的Offset?PXCAP?+?8h:?PXDC?–?PCI?Express?Device?Control。
FLR重置功能的內部狀態和寄存器,使其處于靜止狀態,但不會影響任何sticky位、硬件初始化的位或鏈路特定的寄存器(如Captured?Power、ASPM?Control、Max_Payload_Size或Virtual?Channel寄存器)。如果已發送了一個未解除的Assert?INTx中斷消息,則必須發送相應的Deassert?INTx消息,除非該中斷由內部的另一個功能共享并且仍然處于已斷言狀態。當接收到FLR時,該功能的所有外部活動都需要停止。
3.2.?時間要求
-
與可能訪問該功能的其他軟件協調,確保在FLR期間不嘗試訪問該功能。
-
清除整個命令寄存器,使該功能處于靜止狀態。
-
確保先前請求的完成已通過輪詢設備狀態寄存器中的Transactions?Pending位進行返回,直到該位被清除或等待足夠長的時間以確保這些完成永遠不會被返回。多長時間足夠長呢?如果使用了完成超時,可以在發送FLR之前等待超時時間。如果禁用了完成超時,則至少等待100毫秒。
-
啟動FLR并等待100毫秒。
-
設置功能的配置寄存器,并使其能夠進行正常操作。
當FLR完成后,無論何時完成,都必須清除Transactions?Pending位。
3.3.?復位退出
在退出復位狀態后,鏈路訓練和初始化必須在20毫秒內開始。由于復位信號是異步的,設備可能在不同的時間退出復位狀態,但必須在此時間內開始進行訓練。
為了允許復位組件執行內部初始化,系統軟件必須在復位結束后至少等待100毫秒才能嘗試發送配置請求到它們。如果軟件在100毫秒等待時間之后向設備發起配置請求,但設備仍未完成自我初始化,它會返回帶有CRS狀態的完成。由于配置請求只能由CPU發起,因此完成將返回給根復雜性。作為響應,根復雜性可以自動重新發出配置請求,或者使失敗對軟件可見。規范還指出,如果啟用了CRS軟件可見性,則軟件應僅使用100毫秒的等待周期,否則可能會導致長時間超時或處理器停滯。
在復位后,設備被允許有1.0秒(-0%?/?+50%)的時間來做出對配置請求的正確響應。因此,在判斷一個無響應的設備是否損壞之前,系統必須小心等待那么長的時間。這個值繼承自PCI,這種長時間延遲的原因可能是一些設備將配置空間實現為本地存儲器,必須在配置軟件能夠正確查看之前進行初始化。它的初始化可能涉及從慢速串行EEPROM復制所需的信息,因此可能需要一些時間。
開發實踐
Linux下和Windows下的PCIe復位,均是通過操作Capacity?Register來實現的。Windows下操作Capacity?Register可以通過rw-everything或內核驅動WinIo來實現。以下具體方法使用Linux。
4.1.?傳統復位
能夠軟件操作的只有Hot?Reset。兩種Hot?Reset的方法都需要在上行設備上進行設置。
獲取上行設備路徑:
michael@ubuntu22:~$ readlink /sys/bus/pci/devices/0000:0f:00.0
../../../devices/pci0000:00/0000:00:02.2/0000:0f:00.0
# 上面的內容即是DBF設備的完整路徑,0000:00:02.2即是它的上行設備DBF
4.1.1.?Secondary?Bus?Reset
# 獲取Bridge Control寄存器
root@ubuntu22:~# setpci -s 00:02.2 3e.w
0012
root@ubuntu22:~# setpci -s 00:02.2 BRIDGE_CONTROL
0012
# 連續設置2個Reset, 0x52=0x12|0x40,即設置Secondary Bus Rset=1
root@ubuntu22:~# setpci -s 00:02.2 BRIDGE_CONTROL=0x52
root@ubuntu22:~# setpci -s 00:02.2 BRIDGE_CONTROL=0x52
# 還原
root@ubuntu22:~# setpci -s 00:02.2 BRIDGE_CONTROL=0x52
# 通知系統移除設備 /
root@ubuntu22:/home/michael# echo 1 > /sys/bus/pci/devices/0000:0f:00.0/remove
# Rescan
echo 1 > /sys/bus/pci/rescan
4.1.2.?Link?Disable?Rset
# 獲取Link Control Register
root@ubuntu22:~# setpci -s 00:02.2 CAP_EXP+10.b
40
# 連續設置2個Reset, 0x50=0x40|0x10,即設置Link Disable=1
root@ubuntu22:~# setpci -s 00:02.2 CAP_EXP+10.b=0x50
# 還原
sleep 1
root@ubuntu22:~# setpci -s 00:02.2 CAP_EXP+10.b=0x40
# 通知系統移除設備 /
root@ubuntu22:/home/michael# echo 1 > /sys/bus/pci/devices/0000:0f:00.0/remove
# Rescan
echo 1 > /sys/bus/pci/rescan
4.2. FLR
# 獲取PXDCAP寄存器查看是否支持FLR
root@ubuntu22:/home/michael# setpci -s 0f:00.0 CAP_EXP+4.L
112c8da1
# 28Bit為1,支持FLR
# 連續設置2個Reset, 0x50=0x40|0x10,即設置Link Disable=1
root@ubuntu22:~# setpci -s 00:02.2 CAP_EXP+10.b=0x50
# 還原
sleep 1
root@ubuntu22:~# setpci -s 00:02.2 CAP_EXP+10.b=0x40
# 通知系統移除設備 ? ? ? ? ? ? /
root@ubuntu22:/home/michael# echo 1 > /sys/bus/pci/devices/0000:0f:00.0/remove
# Rescan
echo 1 > /sys/bus/pci/rescan