PCIe: 使用python访问PCIe进行debug
扫描二维码
随时随地手机看文章
当进行问题定位时,我们通常会使用setpci命令和lspci命令发起PCIe的cfg请求对PCIe的配置空间寄存器进行访问。经常进行PCIe问题定位的朋友可能会有自己的一套检查方案,例如检查某些寄存器是否存在异常,通过脚本输出相关打印,从而快速发现问题。而此时使用python调用setpci和lspci命令并且按自己期望的格式输出打印将会极大提高debug效率。
本文描述如何通过python调用setpci命令对PCIe的配置空间寄存器进行访问。
脚本如下
#!/usr/bin/env python3import subprocess # 导入subprocess模块,用于执行系统命令import os # 导入os模块,用于访问环境变量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}")
脚本执行结果如下:
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
如打印描述:脚本执行的命令是setpci -s 15:00.0 0x10.L、setpci -s 15:00.0 0x14.L和setpci -s 15:00.0 ECAP0019+08.L。在terminal直接执行如上命令结果如下:
[]e000000c[]0000021f[]00000000[]
python脚本使用的关键语句如下
1. cmd = f"setpci -s {bdf} {str(addr)}.{ws}"
这是一个**f-string格式化字符串**,用于动态构建
setpci命令(PCIe配置空间读取工具的命令)。各部分含义:
{str(addr)}:将addr(例如代码中的"0x10"、"0x14")转换为字符串,代表配置空间的偏移地址(十六进制)。{ws}:由setpci_width函数返回的宽度标识(L表示4字节,W表示2字节,B表示1字节),用于指定读取的数据长度。setpci:Linux系统中用于读取/修改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字节数据”。
2. out = subprocess.check_output(cmd, shell=True).decode("ASCII").strip()
这行代码通过
subprocess模块执行上述构建的cmd命令,并处理输出结果:subprocess.check_output(cmd, shell=True):执行cmd命令(shell=True表示通过shell解析命令),并返回命令的标准输出(字节流)。若命令执行失败(返回非0状态码),会抛出CalledProcessError异常。.decode("ASCII"):将命令输出的字节流(bytes类型)转换为ASCII编码的字符串(str类型),便于后续处理。.strip():去除字符串首尾的空白字符(包括换行符\n、空格等)。例如,setpci命令的原始输出可能带有换行符(如"e000000c\n"),strip()后会变为纯数据字符串"e000000c"。最终
out变量的值为命令输出的纯数据字符串(例如"e000000c"或"0000021f"),用于后续转换为整数。
注意事项
再调用pcie_cfg_rd功能时,addr需要加上双引号表示字符格式是字符串,因为setpci命令支持两种地址访问。直接地址访问,例如0x10,0x14等等。间接地址访问是以能力结构描述符加偏移量的形式体现,例如ECAP0019+08。





