Linux 内核 s390 架构 PCI 子系统指南:命令行参数、debugfs/sysfs 接口与枚举热插拔机制
2026/9/13 15:33:08 网站建设 项目流程

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 子系统的三大核心内容:内核命令行参数(nomionorid)与 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_msg8 页debug_sprintf_viewPCI 事件处理(机器检查处理、全局功能设置如 UID Checking)的消息日志
pci_error2 页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_numvf

n个 VF 对应写入n0表示移除全部 VF;只有 VF 全部移除后,PF 插槽的power属性才允许下电。

设备属性 /sys/bus/pci/devices/DDDD:BB:dd.f/

每个 zPCI 设备目录下提供下列 s390 特有属性(均来自 pci_sysfs.c 的宏展开,格式与成员对应关系如下表):

属性输出格式对应zpci_dev成员语义
function_id0x%08xfidzPCI 功能标识符(FID),32 位十六进制,机器内唯一(KVM 提供虚拟 FID 时除外),跨分区也不重复
function_handle0x%08xfh底层句柄(FH),32 位十六进制;可能在 PCI 事件或使能/禁用功能时变化甚至失效
pchid0x%04xpchid16 位十六进制,编码功能在机器上的模型相关位置
pfgid0x%02xpfgidPCI 功能组 ID:功能相同的组共用;组定义了中断、IOMMU、IOTLB 与 DMA 特性
vfn0x%04xvfn虚拟功能号:VF 为 1~N,PF 为 0
pft0x%02xpftPCI 功能类型(s390 特有,见下)
port%d(十进制)port功能所依附的物理端口;VF 与父 PF 共享端口;0 表示该类型不适用
fidparm0x%02xfidparm平台提供的 8 位功能参数,含义随 pft 而定;如 NETH VF 为 0x01 表示支持混杂模式
uid0x%xuid用户定义标识符(UID),32 位十六进制,实例级配置
uid_is_unique%d(0/1)全局zpci_unique_uidUID Checking 是否开启的每设备指示
segment0segment30x%02xpfip[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 由用户管理还是平台管理)。当前定义的取值如下:

名称含义
0x00UNC未分类(Unclassified)
0x02ROCERoCE Express
0x05ISMInternal Shared Memory(内部共享内存)
0x0aROC2RoCE Express 2
0x0bNVMeNVMe 存储
0x0cNETHNetwork Express hybrid
0x0dCNWCloud Network Adapter
0x0fNETDNetwork 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:隔离段

segment0segment3(对应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())。

排障速查:从接口到结论

场景查看接口预期结论
判断功能是否启用 MIOcat /sys/bus/pci/devices/DDDD:BB:dd.f/mio_enabled1表示启用,0表示未启用(可能因nomio
判断 UID Checking 全局状态cat /sys/firmware/clp/uid_checking1开启、0关闭
判断某功能 UID 是否保证唯一cat .../uid_is_unique1唯一(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_msgpci_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),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询