Vendor ID 与 Device ID 寄存器详解

好,咱们今天来聊聊 PCIe 配置空间里最基础、也最重要的两个寄存器——Vendor ID 和 Device ID。说它们基础,是因为每个 PCIe 设备都得有;说重要,是因为操作系统和驱动全靠这两个 ID 来认设备。我刚开始接触 PCIe 时,觉得这俩就是两个数字嘛,后来踩过坑才明白,它们背后牵扯的东西真不少。

它们长什么样?

打开任意一个 PCIe 设备的配置空间,偏移 0x00 处是 Vendor ID,偏移 0x02 处是 Device ID。每个都是 16 位,小端序存储。打个比方:你读到的 0x8086 是 Intel,0x10EC 是 Realtek。其实读起来很简单,用 lspci -n 就能看到十六进制编号。

小技巧:我自己调试时习惯用 setpci -s 01:00.0 VENDOR_ID.L 直接读原始值,比看 lspci 输出更直观。

Vendor ID:谁造的?

Vendor ID 由 PCI-SIG 分配,全球唯一。每个厂家只能有一个。比如 Intel 是 0x8086,AMD 是 0x1022。我曾遇到过一个 FPGA 原型验证项目,同事把 Vendor ID 写成了 0x0000——结果操作系统根本不认,驱动加载失败。这是 PCIe 规范里保留的非法值,千万别碰。

厂家Vendor ID常见产品
Intel0x8086CPU内置PCIe控制器、网卡
AMD0x1022锐龙平台芯片组
NVIDIA0x10DEGPU、NVLink
Realtek0x10EC有线网卡、声卡
Broadcom0x14E4无线网卡、交换机

避坑:我曾经在一款定制 FPGA 卡上,因为设计时没注意字节序,把 Vendor ID 写成了 0x8680(高低字节颠倒),结果 lspci 显示成 0x8680 而不是 0x8086。驱动自然不匹配,排查了两天才找到问题。所以一定要确认 endianness。

Device ID:具体型号?

Device ID 由厂商自己定义,与 Vendor ID 组合唯一标识一个设备。比如 Intel 的 I210 网卡 Device ID 是 0x1533,NVIDIA 的 RTX 3080 是 0x2206。同一个网络控制器可能有多代产品,Device ID 会递增或跳跃,驱动就靠这个匹配。

嗯,这里要注意:Device ID 和 Revision ID 不同。Revision ID 是步进版本,不影响驱动匹配。我见过硬件工程师搞混这两个,导致驱动加载时明明看到相同 VID/DID 却报错——结果是 Revision 被错误地改成了别的值。

驱动怎么用它们?

Linux 内核里,驱动通过 pci_device_id 表来声明自己支持的设备。举个例子:

static const struct pci_device_id mydrv_ids[] = {
    { PCI_DEVICE(0x10EC, 0x8168) },  // Realtek RTL8168 网卡
    { PCI_DEVICE(0x8086, 0x153B) },  // Intel I217 网卡
    { 0, }
};

系统枚举时,会把 Vendor ID + Device ID 作为 key,遍历所有驱动注册的 ID 表,找到匹配就绑定驱动。如果 ID 写错了,要么驱动不加载,要么加载了错误的驱动——设备直接挂掉。

核心逻辑:操作系统靠 VID:DID 对设备进行分类和驱动分配,这两个寄存器的值一旦出错,整个链路都跑不起来。

我个人习惯在写驱动前先用 lspci -vnn 确认设备的 VID:DID,再对着内核源码的 ID 表检查,避免低级错误。

系统枚举流程

下面这张图展示了从设备上电到驱动匹配的完整路径,你可以看到 Vendor ID / Device ID 的位置。

PCIe 设备枚举与驱动匹配流程 PCIe 设备上电 配置空间初始化 Root 扫描设备 读取偏移 0x00 Vendor ID 分配 BDF 总线/设备/功能号 系统记录 pci_dev 结构体 驱动匹配 遍历 pci_device_id 表 驱动加载 probe() 调用 关键点 ▪ Vendor ID + Device ID 是驱动匹配的“钥匙” ▪ 任何一位出错都导致设备无法正常使用

你看,从设备上电开始,Root Complex 扫描到有效 Vendor ID(非 0xFFFF)后,就分配 BDF,然后把 VID:DID 填进系统设备列表。接着内核遍历驱动表,找到匹配项就加载驱动。如果 VID:DID 被填错或丢失,后面的步骤全白费。

实战建议

  • 读寄存器别只看 lspci:用 setpci -s <bdf> 0.L 读取前4字节,对比小端序显示与你定义的值是否一致。
  • 新板卡验证第一件事:上电后先确认 Vendor ID 不是 0xFFFF(无设备)也不是 0x0000(非法)。我每次拿到新样片都会这么测。
  • 模拟工具里提前配好:很多验证环境容易忽略这两个寄存器,结果驱动一直报错——回头才发现 DID 根本没更新。

曾经踩过的坑:有一次我给 FPGA 原型卡写了个自定义 Device ID 0xDEAD,刚好和某个古董网卡冲突。Linux 内核自动绑了那个古董网卡的驱动,结果 probe 失败。最后我只好在驱动里用 PCI_DEVICE(0x10EE, 0xDEAD) 强制匹配,才算解决。所以 Device ID 最好申请专属值,别乱编。

好了,关于 Vendor ID 和 Device ID 就讲到这儿。这两个寄存器虽然简单,却是整个 PCIe 设备识别的基石。你下次调板子时,不妨先看看它们对不对。