当前位置:首页 > > 处芯积律

当进行问题定位时,我们通常会使用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直接执行如上命令结果如下:

[root@icxiaoge asic]# setpci -s 15:00.0 0x10.Le000000c[root@icxiaoge asic]# setpci -s 15:00.0 0x14.L0000021f[root@icxiaoge asic]# setpci -s 15:00.0 ECAP0019+08.L00000000[root@icxiaoge asic]

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"),用于后续转换为整数。

  1. 注意事项

再调用pcie_cfg_rd功能时,addr需要加上双引号表示字符格式是字符串,因为setpci命令支持两种地址访问。直接地址访问,例如0x10,0x14等等。间接地址访问是以能力结构描述符加偏移量的形式体现,例如ECAP0019+08。


本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除( 邮箱:macysun@21ic.com )。
关闭