4. USB4路由器配置空间访问

任务说明

USB4路由器在Linux中作为PCI设备暴露,其配置空间可通过两种方式访问:setpci命令直接读写,或通过sysfs的/sys/bus/pci/devices/接口读取。本案例定位USB4路由器设备,读取其厂商ID(Vendor ID)和设备ID(Device ID),并验证两种方式结果一致。

环境与依赖

  • Linux内核支持USB4/Thunderbolt(CONFIG_USB4)
  • pciutils包(提供setpci和lspci)
  • root权限(访问配置空间需要)

实现代码

#!/bin/bash
# usb4_cfgspace.sh - 访问USB4路由器配置空间,读取厂商ID和设备ID
set -euo pipefail

# 1. 定位USB4路由器:PCI class 0x0c0330 为USB4/Thunderbolt主机控制器
#    USB4路由器通常表现为PCI桥设备,class为0x060400
find_usb4_routers() {
    local dev
    for dev in /sys/bus/pci/devices/*; do
        [ -f "$dev/class" ] || continue
        local cls
        cls=$(cat "$dev/class" 2>/dev/null) || continue
        # 0x0c0330 = USB4 host controller, 0x060400 = PCI bridge (router)
        case "$cls" in
            0x0c0330|0x060400)
                # 进一步确认是USB4设备:检查是否有usb4相关属性
                if [ -d "$dev/usb4" ] || [ -e "$dev/removable" ]; then
                    echo "$dev"
                fi
                ;;
        esac
    done
}

# 2. 通过sysfs读取厂商ID和设备ID
read_via_sysfs() {
    local dev="$1"
    local vid did
    vid=$(cat "$dev/vendor" 2>/dev/null) || { echo "无法读取vendor"; return 1; }
    did=$(cat "$dev/device" 2>/dev/null) || { echo "无法读取device"; return 1; }
    echo "sysfs: vendor=$vid device=$did"
}

# 3. 通过setpci读取厂商ID和设备ID
#    配置空间偏移:0x00 = Vendor ID (16bit), 0x02 = Device ID (16bit)
read_via_setpci() {
    local bdf="$1"
    local vid did
    vid=$(setpci -s "$bdf" 0x00.w 2>/dev/null) || { echo "setpci读取vendor失败"; return 1; }
    did=$(setpci -s "$bdf" 0x02.w 2>/dev/null) || { echo "setpci读取device失败"; return 1; }
    echo "setpci: vendor=0x$vid device=0x$did"
}

# 主流程
main() {
    local routers
    routers=$(find_usb4_routers)
    if [ -z "$routers" ]; then
        echo "未找到USB4路由器设备"
        exit 1
    fi

    local dev bdf
    for dev in $routers; do
        bdf=$(basename "$dev")
        echo "=== USB4路由器: $bdf ==="
        read_via_sysfs "$dev"
        read_via_setpci "$bdf"
        echo ""
    done
}

main "$@"

运行方式

chmod +x usb4_cfgspace.sh
sudo ./usb4_cfgspace.sh

验证方法与通过条件

  1. 脚本输出每个USB4路由器的BDF地址(如0000:00:0d.0)。
  2. sysfs行与setpci行的vendor/device值应一致(注意格式:sysfs为0x8086,setpci输出为8086,需统一比较)。
  3. 用lspci -s <BDF> -n交叉验证:输出格式为<class>: <vendor>:<device>,其中vendor和device应与脚本读取值匹配。
  4. 若系统无USB4设备,脚本输出"未找到USB4路由器设备"并退出码1,属正常情况。

关键点

  • 配置空间偏移0x00为Vendor ID(16位),0x02为Device ID(16位),setpci的.w后缀表示16位读取。
  • sysfs路径/sys/bus/pci/devices/<BDF>/vendor和/device直接暴露这两个字段,无需root即可读取(但setpci需要root)。
  • USB4路由器可能以PCI桥(class 0x060400)形式出现,需结合usb4目录或removable属性进一步筛选。