PCIe: 使用python訪問PCIe進行debug
掃描二維碼
隨時隨地手機看文章
當進行問題定位時,我們通常會使用setpci命令和lspci命令發(fā)起PCIe的cfg請求對PCIe的配置空間寄存器進行訪問。經常進行PCIe問題定位的朋友可能會有自己的一套檢查方案,例如檢查某些寄存器是否存在異常,通過腳本輸出相關打印,從而快速發(fā)現問題。而此時使用python調用setpci和lspci命令并且按自己期望的格式輸出打印將會極大提高debug效率。
本文描述如何通過python調用setpci命令對PCIe的配置空間寄存器進行訪問。
腳本如下
#!/usr/bin/env python3import?subprocess ?# 導入subprocess模塊,用于執(zhí)行系統(tǒng)命令import?os ? ? ? ? ?# 導入os模塊,用于訪問環(huán)境變量def?pcie_cfg_rd(bdf, addr, n_bytes=4):? ? ws = setpci_width(n_bytes)? ??print(f"setpci -s?{bdf}?{str(addr)}.{ws}")? ? cmd =?f"setpci -s?{bdf}?{str(addr)}.{ws}"??? ? out = subprocess.check_output(cmd, shell=True).decode("ASCII").strip()? ??#out = subprocess.check_output(cmd, shell=True).decode("ASCII")? ? data =?int(out,?16)? ??print(f"out:{out:s}")? ??print(f"data:{data:x}")? ??return?data# setpci_width函數保持不變def?setpci_width(n_bytes):? ??if?n_bytes ==?4:? ? ? ??return?'L'? ??elif?n_bytes ==?2:? ? ? ??return?'W'? ??elif?n_bytes ==?1:? ? ? ??return?'B'? ??else:? ? ? ??raise?Exception(f"Illegal data width?{n_bytes}?bytes for setpci.")bdf="15:00.0"bar0_low_32b = pcie_cfg_rd(bdf,?"0x10")bar0_hig_32b = pcie_cfg_rd(bdf,?"0x14")ep_lane_err = pcie_cfg_rd(bdf,?"ECAP0019+08")print(f"bar0_low_32b:0x{bar0_low_32b:x}?bar0_hig_32b:0x{bar0_hig_32b:x}")
腳本執(zhí)行結果如下:
setpci?-s?15:00.0?0x10.Lout:e000000cdata:e000000csetpci?-s?15:00.0?0x14.Lout:0000021fdata:21fsetpci?-s?15:00.0?ECAP0019+08.Lout:00000000data:0bar0_low_32b:0xe000000c bar0_hig_32b:0x21f
如打印描述:腳本執(zhí)行的命令是setpci -s 15:00.0 0x10.L、setpci -s 15:00.0 0x14.L和setpci -s 15:00.0 ECAP0019+08.L。在terminal直接執(zhí)行如上命令結果如下:
[]e000000c[]0000021f[]00000000[]
python腳本使用的關鍵語句如下
1.?cmd = f"setpci -s {bdf} {str(addr)}.{ws}"
這是一個**f-string格式化字符串**,用于動態(tài)構建
setpci命令(PCIe配置空間讀取工具的命令)。各部分含義:
{str(addr)}:將addr(例如代碼中的"0x10"、"0x14")轉換為字符串,代表配置空間的偏移地址(十六進制)。{ws}:由setpci_width函數返回的寬度標識(L表示4字節(jié),W表示2字節(jié),B表示1字節(jié)),用于指定讀取的數據長度。setpci:Linux系統(tǒng)中用于讀取/修改PCIe設備配置空間的工具命令。-s {bdf}:-s參數指定目標PCIe設備的BDF地址(格式為域:總線:設備.功能),{bdf}會被變量bdf的值(例如代碼中的"15:00.0")替換,用于定位具體設備。{str(addr)}.{ws}:指定讀取配置空間的偏移地址和數據寬度:最終構建的命令示例:當
bdf="15:00.0"、addr="0x10"、ws="L"時,cmd的值為"setpci -s 15:00.0 0x10.L",表示“讀取PCIe設備15:00.0在配置空間偏移0x10處的4字節(jié)數據”。
2.?out = subprocess.check_output(cmd, shell=True).decode("ASCII").strip()
這行代碼通過
subprocess模塊執(zhí)行上述構建的cmd命令,并處理輸出結果:subprocess.check_output(cmd, shell=True):執(zhí)行cmd命令(shell=True表示通過shell解析命令),并返回命令的標準輸出(字節(jié)流)。若命令執(zhí)行失敗(返回非0狀態(tài)碼),會拋出CalledProcessError異常。.decode("ASCII"):將命令輸出的字節(jié)流(bytes類型)轉換為ASCII編碼的字符串(str類型),便于后續(xù)處理。.strip():去除字符串首尾的空白字符(包括換行符\n、空格等)。例如,setpci命令的原始輸出可能帶有換行符(如"e000000c\n"),strip()后會變?yōu)榧償祿址?/span>"e000000c"。最終
out變量的值為命令輸出的純數據字符串(例如"e000000c"或"0000021f"),用于后續(xù)轉換為整數。
注意事項
再調用pcie_cfg_rd功能時,addr需要加上雙引號表示字符格式是字符串,因為setpci命令支持兩種地址訪問。直接地址訪問,例如0x10,0x14等等。間接地址訪問是以能力結構描述符加偏移量的形式體現,例如ECAP0019+08。





