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 | 常见产品 |
|---|---|---|
| Intel | 0x8086 | CPU内置PCIe控制器、网卡 |
| AMD | 0x1022 | 锐龙平台芯片组 |
| NVIDIA | 0x10DE | GPU、NVLink |
| Realtek | 0x10EC | 有线网卡、声卡 |
| Broadcom | 0x14E4 | 无线网卡、交换机 |
避坑:我曾经在一款定制 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 的位置。
你看,从设备上电开始,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 设备识别的基石。你下次调板子时,不妨先看看它们对不对。