Linux 内核 s390 架构 PCI 子系统指南:命令行参数、debugfs/sysfs 接口与枚举热插拔机制
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
导读
本文基于 Linux 内核源码树中 Documentation/arch/s390/pci.rst 展开,系统讲解 s390(IBM Z / z/Architecture)平台上 PCI 子系统的三大核心内容:内核命令行参数(nomio、norid)与 s390 调试特性(s390dbf)的用法、面向 zPCI 功能的 sysfs/debugfs 属性接口语义,以及 PCI 地址(DDDD:BB:dd.f)的枚举与热插拔规则。读完本文,你将掌握如何在 s390 平台上定位、解读和调试 zPCI 功能,理解 FID/UID/RID 等平台特有标识的差异,并能依据源码定位每个属性的实现位置,为实际排障与运维提供直接依据。
S/390 PCI 背景:zPCI 与通用 PCI 的差异
s390 平台的 PCI 实现被称为 zPCI(z/Architecture PCI)。与传统 x86/ARM 平台不同,s390 的 PCI 硬件由 IBM Z 机器的 Channel Subsystem 与 PCI 桥(PCI bridge)共同管理,Linux 侧通过zpci驱动(源码位于 arch/s390/pci/)与固件交互。它遵循通用的 Linux PCI 核心框架(drivers/pci/),但在枚举、中断、DMA 和功能标识上引入了大量平台特有概念:
- FID(Function ID):机器级唯一的功能标识符;
- UID(User-defined Identifier):分区(LPAR)、KVM guest 或 z/VM guest 实例内可配置的标识;
- RID(Requester ID):PCI 规范定义的请求者 ID,用于组成
DDDD:BB:dd.f地址中的 bus/device/function 部分; - PFGID/PFT:PCI 功能组 ID 与功能类型,用于描述功能的归类与用途。
这些概念贯穿下文所有接口条目,理解它们之间的区别是正确解读 sysfs 输出的前提。
命令行参数
s390 PCI 子系统支持通过内核命令行(boot parameters)调整平台行为。参数解析在 arch/s390/pci/pci.c 的pcibios_setup()中完成,该函数针对每个以pci.为前缀或直接传入的 PCI 选项字符串逐一匹配:
| 参数 | 效果 | 源码处理 |
|---|---|---|
nomio | 不使用 PCI Mapped I/O(MIO)指令 | clear_machine_feature(MFEATURE_PCI_MIO)清除机器 MIO 特性位 |
norid | 忽略 RID 字段,强制每个 PCI 功能使用独立的 PCI domain | 置位s390_pci_no_rid,影响后续 domain/bus 分配 |
off | 禁用 s390 PCI 探测(s390_pci_probe = 0) | 关闭整个 zPCI 子系统 |
force_floating | 强制使用浮点中断(floating interrupts) | 置位s390_pci_force_floating |
nomio:关闭 MIO 指令
MIO(PCI Mapped I/O)是 s390 平台提供的一种 PCI MMIO 访问加速指令(如LPD/LPSD等),可减少 PCI 访问的指令开销。当硬件或虚拟化环境不支持 MIO,或驱动与 MIO 存在兼容性问题时,可在内核命令行追加pci=nomio(或直接nomio)禁用。源码中通过清除MFEATURE_PCI_MIO机器特性位实现,随后zpci_use_mio()判断将返回 false,对应的设备 sysfs 属性mio_enabled会显示为0(见 arch/s390/pci/pci_sysfs.c)。
norid:忽略 RID,强制单功能单 domain
RID(Requester ID)是 PCI 规范中用于标识请求者的字段。默认情况下,s390 平台会尽量利用平台暴露的 RID 来构造DDDD:BB:dd.f地址;而norid参数强制忽略 RID,此时每个 PCI 功能独立占用一个 PCI domain(详见下文"枚举与热插拔"一节)。在 arch/s390/pci/pci_bus.c 中,多功能根总线的判定条件即为:
return !s390_pci_no_rid && zdev->rid_available && !zdev->vfn;即只有在"未设置norid"且"RID 可用"且"不是虚拟功能"时,才会把多个功能组织到同一个多功能总线中。
debugfs 条目:s390dbf 调试视图
s390 平台的调试特性(s390 debug feature,简称 s390dbf)为各子系统提供环形缓冲式调试日志。zPCI 在 arch/s390/pci/pci_debug.c 的zpci_debug_init()中注册了两个调试视图:
| 注册名 | 页数 | 视图类型 | 用途 |
|---|---|---|---|
pci_msg | 8 页 | debug_sprintf_view | PCI 事件处理(机器检查处理、全局功能设置如 UID Checking)的消息日志 |
pci_error | 2 页 | debug_hex_ascii_view | 错误日志(十六进制 ASCII 视图) |
对应地在 sysfs 中出现形如/sys/kernel/debug/s390dbf/pci_*/的目录(debugfs 需挂载,通常位于/sys/kernel/debug)。常见示例:
/sys/kernel/debug/s390dbf/pci_msg/sprintf以可读文本保存 PCI 事件处理过程中的消息,例如机器检查(machine check)处理、UID Checking 等全局功能的开关记录。
/sys/kernel/debug/s390dbf/pci_error/hex_ascii以十六进制 ASCII 视图保存错误日志。
调整日志级别
s390dbf 的日志级别范围为 0~6(数字越大越详细)。可通过向对应视图的level文件写入数字动态调整:
# 将 pci_msg 的日志级别调高到 6(最详细) echo 6 > /sys/kernel/debug/s390dbf/pci_msg/level # 将 pci_error 的日志级别调回默认的 3 echo 3 > /sys/kernel/debug/s390dbf/pci_error/level源码中初始化时两者均被设置为级别 3(debug_set_level(pci_debug_msg_id, 3))。关于 s390dbf 的完整用法(视图类型、级别语义、flush/hex_ascii等文件),请参阅 Documentation/arch/s390/s390dbf.rst。
sysfs 条目:zPCI 功能属性
zPCI 设备属性通过 arch/s390/pci/pci_sysfs.c 中的zpci_attr()宏批量生成——该宏基于struct zpci_dev的成员字段生成只读_show函数与DEVICE_ATTR_RO属性。下面按文档顺序逐一说明。
插槽目录 /sys/bus/pci/slots/XXXXXXXX
s390 平台使用 PCI 功能的FID(函数标识符)作为插槽名,格式为 8 位十六进制数字(小写、不足前补 0),即文档中的XXXXXXXX:
/sys/bus/pci/slots/0000003a/该插槽目录内含 s390 特有的插槽属性:
uid:该插槽可配置的用户定义标识符(UID),格式0x%x(见 pci_sysfs.c 的zpci_uid_slot_show(),读取的是zdev->uid)。与设备属性中的uid含义一致。
同时,物理功能(PF)若当前支撑着虚拟功能(VF),则必须先移除全部 VF 才能下电该 PF:
# 关闭 SR-IOV:移除全部 VF(DDDD:BB:dd.f 为 PF 的 PCI 地址) echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvfn个 VF 对应写入n,0表示移除全部 VF;只有 VF 全部移除后,PF 插槽的power属性才允许下电。
设备属性 /sys/bus/pci/devices/DDDD:BB:dd.f/
每个 zPCI 设备目录下提供下列 s390 特有属性(均来自 pci_sysfs.c 的宏展开,格式与成员对应关系如下表):
| 属性 | 输出格式 | 对应zpci_dev成员 | 语义 |
|---|---|---|---|
function_id | 0x%08x | fid | zPCI 功能标识符(FID),32 位十六进制,机器内唯一(KVM 提供虚拟 FID 时除外),跨分区也不重复 |
function_handle | 0x%08x | fh | 底层句柄(FH),32 位十六进制;可能在 PCI 事件或使能/禁用功能时变化甚至失效 |
pchid | 0x%04x | pchid | 16 位十六进制,编码功能在机器上的模型相关位置 |
pfgid | 0x%02x | pfgid | PCI 功能组 ID:功能相同的组共用;组定义了中断、IOMMU、IOTLB 与 DMA 特性 |
vfn | 0x%04x | vfn | 虚拟功能号:VF 为 1~N,PF 为 0 |
pft | 0x%02x | pft | PCI 功能类型(s390 特有,见下) |
port | %d(十进制) | port | 功能所依附的物理端口;VF 与父 PF 共享端口;0 表示该类型不适用 |
fidparm | 0x%02x | fidparm | 平台提供的 8 位功能参数,含义随 pft 而定;如 NETH VF 为 0x01 表示支持混杂模式 |
uid | 0x%x | uid | 用户定义标识符(UID),32 位十六进制,实例级配置 |
uid_is_unique | %d(0/1) | 全局zpci_unique_uid | UID Checking 是否开启的每设备指示 |
segment0~segment3 | 0x%02x | pfip[0..3] | 隔离段(对应物理通路),段差异越大隔离越强 |
mio_enabled | %d(0/1) | zpci_use_mio(zdev) | 当前功能是否启用 MIO 指令 |
PFT 功能类型取值
pft是 s390 特有的、面向使用模型的分类,比 PCI 规范的 class/vendor/device ID 更贴近用途。相同pft的功能可能由不同硬件实现,且同一硬件在不同使用模型下可能呈现不同pft(例如 NETD 与 NETH 的 VF 可能由同一硬件实现,区别在于其父 PF 由用户管理还是平台管理)。当前定义的取值如下:
| 值 | 名称 | 含义 |
|---|---|---|
0x00 | UNC | 未分类(Unclassified) |
0x02 | ROCE | RoCE Express |
0x05 | ISM | Internal Shared Memory(内部共享内存) |
0x0a | ROC2 | RoCE Express 2 |
0x0b | NVMe | NVMe 存储 |
0x0c | NETH | Network Express hybrid |
0x0d | CNW | Cloud Network Adapter |
0x0f | NETD | Network Express direct |
UID 与 UID Checking
uid是 32 位十六进制、按实例(分区 / KVM guest / z/VM guest 配置)定义的用户标识。开启 UID Checking 后,平台保证实例内 UID 唯一——同一实例内不会同时看到两个同 UID 的功能。与 FID 不同,同一机器不同分区内的 UID 可以相同,这使得多个分区可以按 UID 命名空间构建完全一致的 PCI 配置。
uid_is_unique(设备级)与/sys/firmware/clp/uid_checking(全局)共同反映 UID Checking 状态:前者逐设备指示"该 UID 在本 Linux 实例内保证唯一",后者即使在没有配置任何 PCI 功能时也可查询全局开关状态。两者的内核实现都读取全局变量zpci_unique_uid(见 pci_sysfs.c)。
pfip/segmentX:隔离段
segment0~segment3(对应pfip[0..3])描述功能与物理通路的对应关系,决定功能间的隔离程度:段差异越大,功能间隔离越强。这些段信息来源于平台固件下发的 PFIP(PCI Function Identification Parameters)。
枚举与热插拔
PCI 地址构成
s390 的 PCI 地址为四段式DDDD:BB:dd.f:
DDDD:domain(域)BB:bus(总线号)dd:device(设备号)f:function(功能号)
无 RID / 隔离 VF 的情况
当平台不暴露 RID、使用pci=norid参数、或使用"隔离虚拟功能"(Isolated VF,虽含 RID 信息但其父 PF 不在同一 PCI 配置中)时:
- 每个 domain 中只有一个功能(单功能域);
- domain 号:若开启 UID Checking,取 zPCI 功能的 UID;否则动态生成,重启或热插拔后不稳定。
这与源码中zpci_bus_is_multifunction_root()(arch/s390/pci/pci_bus.c)的逻辑一致:无 RID 或norid时不会形成多功能根总线。
平台暴露 RID 且非隔离 VF 的情况
- 每个 domain 中仍只有一个 bus(
ZPCI_BUS_NR固定总线号,见zpci_bus_create_pci_bus()中的pci_create_root_bus(NULL, ZPCI_BUS_NR, ...),pci_bus.c); - 每条 bus 最多可容纳 256 个 PCI 功能(对应
dd.f共 8 位,即 device 5 位 + function 3 位); - 同一拓扑内所有功能的 domain 号,取该拓扑中
devfn最低的那个已配置功能所属的 domain; - 由 SR-IOV 能力 PF 生成的 VF,只有在使能 SR-IOV 后才可见。
RID 的devfn部分通过掩码ZPCI_RID_MASK_DEVFN从 RID 中提取并赋给zdev->devfn(见 pci_bus.c 与 pci_iov.c):
zdev->devfn = zdev->rid & ZPCI_RID_MASK_DEVFN;而 domain 的分配则由zpci_alloc_domain((u16)fr->uid)决定——在多功能场景下以根功能(root function)的 UID 作为 domain 号(pci_bus.c)。这一行为解释了文档中"domain 来自最低 devfn 的配置功能"以及"UID Checking 开启时 domain 来自 UID"的表述。
热插拔操作要点
s390 的热插拔通过插槽接口完成:/sys/bus/pci/slots/XXXXXXXX/(XXXXXXXX为 FID)。配合通用 PCI 接口可实现 VF 的动态创建/移除:
# 查看某 PF 下当前 VF 数 cat /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf # 创建 4 个 VF echo 4 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf # 移除全部 VF(PF 才能下电) echo 0 > /sys/bus/pci/devices/DDDD:BB:dd.f/sriov_numvf此外,pci_sysfs.c 还提供了recover可写属性(recover_store()):向设备目录下的recover写入内容可触发设备恢复流程(pci_stop_and_remove_bus_device()→zpci_disable_device()→zpci_reenable_device()),用于在设备异常后重新使能;实现中特意通过sysfs_break_active_protection()避免与插槽下电路径的潜在死锁。以及report_error二进制属性(BIN_ATTR(report_error, S_IWUSR, ...),pci_sysfs.c),用于向固件上报用户定义错误记录(经sclp_pci_report())。
排障速查:从接口到结论
| 场景 | 查看接口 | 预期结论 |
|---|---|---|
| 判断功能是否启用 MIO | cat /sys/bus/pci/devices/DDDD:BB:dd.f/mio_enabled | 1表示启用,0表示未启用(可能因nomio) |
| 判断 UID Checking 全局状态 | cat /sys/firmware/clp/uid_checking | 1开启、0关闭 |
| 判断某功能 UID 是否保证唯一 | cat .../uid_is_unique | 1唯一(UID Checking 生效) |
| 查看功能类型 | cat .../pft | 对照 PFT 取值表 |
| 追踪事件处理消息 | cat /sys/kernel/debug/s390dbf/pci_msg/sprintf | 查看机器检查、UID Checking 等日志 |
| 追踪错误 | cat /sys/kernel/debug/s390dbf/pci_error/hex_ascii | 十六进制错误日志 |
总结
s390 平台的 PCI 子系统在通用 PCI 框架之上叠加了 zPCI 特有的标识体系(FID/UID/RID/PFT)与管理接口:命令行参数nomio/norid分别控制 MIO 指令使用与 domain 组织方式;s390dbf 的pci_msg、pci_error视图承担事件与错误日志;sysfs 属性完整暴露了功能的 FID、FH、PFGID、PFT、端口、UID、隔离段等平台信息;枚举规则则由 RID 可用性与 UID Checking 共同决定 domain/bus/device/function 的构成。所有接口均有 arch/s390/pci/ 下的源码实现可查证,建议读者结合 Documentation/arch/s390/s390dbf.rst 与 pci.c 继续深入。
【免费下载链接】linuxLinux kernel source tree项目地址: https://gitcode.com/GitHub_Trending/li/linux
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考