Linux获取pci设备的厂商号、设备号、class号

  要描述一个pci设备,就需要知道设备的厂商号(venderId)、设备号(devId)和class号。那么,在Linux系统中,如何获取这三个数据呢?
  既然是一个pci设备,那么首先就得知道BDF——该pci设备在OS中的唯一标识符。以网卡举例,我们可以通过ethtool来得到BDF。其中,bus-info对应的信息就是BDF。

# ethtool -i p12p1
driver: ixgbe
version: 4.0.1-k
firmware-version: 0x800003e1
bus-info: 0000:11:00.0
supports-statistics: yes
supports-test: yes
supports-eeprom-access: yes
supports-register-dump: yes
supports-priv-flags: no

厂商号和设备号

  可通过lspci命令获取pci设备的厂商号和设备号。

# lspci -n -s 11:00.0
11:00.0 0200: 8086:1528 (rev 01)

  其中,8086就是厂商号,1528就是设备号。

# lspci | grep 11:00.0                                                            
11:00.0 Ethernet controller: Intel Corporation Ethernet Controller 10-Gigabit X540-AT2 (rev 01)

  当然,也可以通过上面的方法直接使用lspci命令来查看该设备的基础信息。上面可以看出,这是一个intel的网卡设备,X540网卡。

class号

  一个完整的class号应该包含三个部分:Device class、Device subclass和Program interface,每个部分占2个16进制数字,一个类型的设备,他们的class号是一样的。其实,在上面的lspci命令中已经获取到了部分的class号。下面实例的0200就是class号的前两部分Device class和Device subclass,只是没有Program interface这一部分。要查询完整的class号,可以通过在线网站pci-ids来查询。

# lspci -n -s 11:00.0
11:00.0 0200: 8086:1528 (rev 01)

无Program interface情况

  还是以上面的网卡为例,我们已经知道这是个网卡控制器(Ethernet controller)。那么我们就在网页的Jump一栏中输入关键字“Ethernet controller”,就会直接跳转该项。由于该项没有Program interface,因此,最终的class号就是020000。

有Program interface情况

  再以三星的ssd磁盘为例。

# lspci | grep Samsung
01:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
0c:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
10:00.0 Non-Volatile memory controller: Samsung Electronics Co Ltd Device a802 (rev 01)
# lspci -n -s 01:00.0
01:00.0 0108: 144d:a802 (rev 01)

  在pci-ids查询关键字“Non-Volatile memory controller”,进入该项后,了解到该项的Device class和Device subclass为0108。同时,我们还发现该项有两个Program Interface。由于这个ssd是NVMe总线的,所以该ssd的最终class号就是010802。
这里写图片描述
ps:lspci -D:显示设备的厂商号、设备号、Class号。但这个Class号只是前半部分,还缺少后半部分。

# lspci -Q -s 0c:00.1
0c:00.1 Class 0200: Device 8086:1528 (rev 01)
<think>好的,用户想了解如何在Linux内核中获取设备PCIe地址。我需要先回忆一下相关的知识点,确保自己理解正确,然后分步骤解释清楚。 首先,块设备通常指的是硬盘、SSD等存储设备,它们在系统中可能通过PCIe总线连接。要获取它们的PCIe地址,可能需要从设备层次结构入手。Linux系统中,设备的信息通常通过sysfs文件系统暴露,路径大概是/sys/block/<设备>/device或者更下层的PCI设备信息。 接下来,可能需要将块设备(比如sda)关联到其对应的SCSI主机控制器,再找到对应的PCI设备。这里涉及到设备树的结构,块设备属于某个SCSI主机,而该主机控制器可能是一个PCI设备。因此,步骤可能包括查找块设备的主设备号,找到对应的hostX目录,然后追踪到PCI设备的sysfs路径。 另外,使用命令工具如lspci可能会辅助确认设备PCI信息,但用户的问题是关于内核中如何获取,可能需要编程方法或者查看sysfs中的链接信息。例如,使用udevadm命令可以查询设备的属性,包括PCI地址。但内核中具体如何操作,可能需要解析sysfs中的符链接,比如从/sys/block/sda/device链接到hostX下的PCI设备路径,然后读取vendor和device信息,或者直接查看uevent文件中的内容。 需要注意的是,不同的块设备类型(比如NVMe和SATA)可能有不同的路径结构。NVMe设备通常直接关联到PCI设备,而SATA设备可能需要通过ATA控制器再到PCI。因此,在解释时需要区分不同情况,或者给出通用的方法。 可能还需要提到如何通过读取sysfs中的文件,比如/sys/block/sda/device/../vendor和device文件,来获取PCI商和设备ID,但这可能不够直接对应PCIe地址(即BDF,总线-设备-功能)。正确的做法应该是找到对应的PCI设备目录,其中的文件如uevent可能包含BDF信息,或者通过lspci的输出来匹配。 总结步骤可能包括:1. 找到块设备在sysfs中的路径;2. 向上遍历设备树找到关联的PCI设备;3. 从PCI设备的目录中获取BDF信息。具体命令可能包括使用readlink查看符链接,结合ls -l逐层查找,或者使用udevadm info查询属性。 需要确保步骤准确,避免错误。例如,使用ls -l /sys/block/sda/device查看符链接的目标,逐层进入hostX目录,再找到对应的PCI设备目录,其中会有address文件或者通过uevent获取PCI地址。或者,直接使用udevadm info -q path -n /dev/sda获取设备路径,然后解析其中的PCI部分。 最后,可能给出一个示例命令链,例如:使用readlink找到设备路径,用grep和sed提取PCI地址,或者结合lspci和grep来定位。例如: udevadm info -q path -n /dev/nvme0n1 | grep -oP '([0-9a-f]{4}:[0-9a-f]{2}:[0-9a-f]{2}\.[0-9a-f])' 这样可以得到PCIe的BDF。需要验证这个命令是否有效,可能根据不同的设备类型调整。 同时,要提醒用户注意不同设备类型的差异,比如NVMe和SATA在sysfs中的路径结构可能不同,因此具体步骤可能需要调整。确保用户理解这些步骤可能需要根据实际情况进行变通。</think>在Linux内核中,获取设备PCIe地址(即PCI总线-设备-功能,BDF格式如`0000:3b:00.0`)需要从设备树层级逐层向上追溯。以下是具体步骤和原理: --- ### 1. **理解设备层级关系** 块设备(如`/dev/sda`或`/dev/nvme0n1`)通常通过以下路径连接到PCIe设备: ``` 块设备 → SCSI/NVMe子系统 → 主机控制器(Host Controller) → PCIe设备 ``` --- ### 2. **通过sysfs遍历设备树** Linux通过`sysfs`(挂载在`/sys`)暴露设备信息。以NVMe设备为例: ```bash # 假设设备为 /dev/nvme0n1 $ ls -l /sys/block/nvme0n1/device # 输出会指向PCI设备路径,例如: # device -> ../../../0000:3b:00.0 ``` 此处`0000:3b:00.0`即为PCIe地址。 --- ### 3. **通用方法:使用`udevadm`查询** 通过`udevadm`工具直接获取设备属性: ```bash $ udevadm info -q path -n /dev/nvme0n1 # 输出示例:/devices/pci0000:3a/0000:3a:00.0/0000:3b:00.0/nvme/nvme0/nvme0n1 # 提取PCIe地址 $ udevadm info -q path -n /dev/nvme0n1 | grep -oP '([0-9a-f]{4}:[0-9a-f]{2}:[0-9a-f]{2}\.[0-9a-f])' # 输出:0000:3b:00.0 ``` --- ### 4. **手动解析sysfs符链接** 对于SATA设备(如`/dev/sda`): ```bash # 找到设备关联的SCSI主机控制器 $ readlink /sys/block/sda/device # 示例输出:../../../host2/target2:0:0/2:0:0:0 # 向上查找PCI设备路径 $ ls -l /sys/class/scsi_host/host2/device # 输出示例:device -> ../../../0000:3b:00.0 ``` --- ### 5. **通过`lspci`验证** 使用`lspci`列出所有PCI设备,结合设备信息匹配: ```bash $ lspci -nn | grep -i "storage controller" # 示例输出:3b:00.0 Non-Volatile memory controller [0108]: Samsung Electronics Co Ltd NVMe SSD Controller [144d:a808] ``` --- ### 6. **内核代码中的关键结构** 在内核开发中,可通过以下路径获取PCI设备: 1. **块设备对象**:`struct gendisk` → `struct device` 2. **向上遍历设备树**:使用`device_find_child()`或`dev_to_pci_dev()`定位PCI设备。 3. **提取BDF**:从`struct pci_dev`中读取`bus->number`, `devfn`等字段。 --- ### 注意事项 - **设备类型差异**:NVMe设备直接关联PCIe地址,而SATA设备需通过SCSI和AHCI控制器间接关联。 - **虚拟设备**:虚拟块设备(如`/dev/vda`)可能无物理PCIe地址。 - **多路径设备**:需追溯到实际物理控制器。 通过以上方法,可准确获取设备对应的PCIe地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值