5. 通过 sysfs 访问 PCI 设备资源¶
sysfs,通常挂载在 /sys,提供了对支持它的平台上的 PCI 资源的访问。例如,一个给定的总线可能看起来像这样
/sys/devices/pci0000:17
|-- 0000:17:00.0
| |-- class
| |-- config
| |-- device
| |-- enable
| |-- irq
| |-- local_cpus
| |-- remove
| |-- resource
| |-- resource0
| |-- resource1
| |-- resource2
| |-- revision
| |-- rom
| |-- subsystem_device
| |-- subsystem_vendor
| `-- vendor
`-- ...
最顶层的元素描述了 PCI 域和总线号。在本例中,域号为 0000,总线号为 17(两个值都是十六进制)。此总线在插槽 0 中包含一个单功能设备。为了方便起见,重复了域和总线号。在设备目录下有几个文件,每个文件都有自己的功能。
文件
功能
class
PCI 类 (ascii, 只读)
config
PCI 配置空间 (二进制,读写)
device
PCI 设备 (ascii, 只读)
enable
设备是否启用 (ascii, 读写)
irq
IRQ 号 (ascii, 只读)
local_cpus
附近的 CPU 掩码 (cpumask, 只读)
remove
从内核列表中删除设备 (ascii, 只写)
resource
PCI 资源主机地址 (ascii, 只读)
resource0..N
PCI 资源 N,如果存在 (二进制,mmap,读写[1])
resource0_wc..N_wc
PCI WC 映射资源 N,如果可预取 (二进制,mmap)
revision
PCI 修订 (ascii, 只读)
rom
PCI ROM 资源,如果存在 (二进制,只读)
subsystem_device
PCI 子系统设备 (ascii, 只读)
subsystem_vendor
PCI 子系统供应商 (ascii, 只读)
vendor
PCI 供应商 (ascii, 只读)
ro - read only file
rw - file is readable and writable
wo - write only file
mmap - file is mmapable
ascii - file contains ascii text
binary - file contains binary data
cpumask - file contains a cpumask type
只读文件是信息性的,对它们的写入将被忽略,但 “rom” 文件除外。可写文件可用于对设备执行操作(例如,更改配置空间、分离设备)。可 mmap 的文件可以通过文件偏移量 0 的 mmap 访问,并可用于从用户空间进行实际的设备编程。请注意,某些平台不支持某些资源的 mmapping,因此请务必检查任何尝试 mmap 的返回值。其中最值得注意的是 I/O 端口资源,它们还提供读/写访问权限。
“enable” 文件提供一个计数器,指示设备已启用的次数。如果 “enable” 文件当前返回 “4”,并且向其中回显 “1”,则它将返回 “5”。向其中回显 “0” 将减少计数。但是,即使它返回到 0,某些初始化也可能不会被逆转。
“rom” 文件比较特殊,因为它提供了对设备 ROM 文件的只读访问权限(如果可用)。但是,默认情况下它是禁用的,因此应用程序应在尝试读取调用之前向该文件写入字符串 “1” 以启用它,并在访问后通过向该文件写入 “0” 来禁用它。请注意,必须启用设备才能成功返回 ROM 读取数据。如果驱动程序未绑定到设备,可以使用上面记录的 “enable” 文件启用它。
“remove” 文件用于删除 PCI 设备,方法是向该文件写入一个非零整数。这不涉及任何类型的热插拔功能,例如关闭设备电源。设备将从内核的 PCI 设备列表中删除,其 sysfs 目录将被删除,并且该设备将从连接到它的任何驱动程序中删除。不允许删除 PCI 根总线。
5.1. 通过 sysfs 访问传统资源¶
如果底层平台支持,sysfs 中还会提供传统的 I/O 端口和 ISA 内存资源。它们位于 PCI 类层次结构中,例如
/sys/class/pci_bus/0000:17/
|-- bridge -> ../../../devices/pci0000:17
|-- cpuaffinity
|-- legacy_io
`-- legacy_mem
legacy_io 文件是一个读/写文件,应用程序可以使用它来执行传统的端口 I/O。应用程序应打开该文件,寻址到所需的端口(例如 0x3e8),并读取或写入 1、2 或 4 个字节。legacy_mem 文件应使用与所需内存偏移量对应的偏移量进行 mmap,例如,VGA 帧缓冲区的偏移量为 0xa0000。然后,应用程序可以简单地取消引用返回的指针(当然,在检查错误后)以访问传统内存空间。
5.2. 在新平台上支持 PCI 访问¶
为了支持如上所述的 PCI 资源映射,Linux 平台代码应理想地定义 ARCH_GENERIC_PCI_MMAP_RESOURCE 并使用该功能的通用实现。为了支持 /proc/bus/pci 中文件的 mmap() 的历史接口,平台也可以设置 HAVE_PCI_MMAP。
或者,设置了 HAVE_PCI_MMAP 的平台可以提供他们自己的 pci_mmap_resource_range() 实现,而不是定义 ARCH_GENERIC_PCI_MMAP_RESOURCE。
支持 PCI 资源写组合映射的平台必须定义 arch_can_pci_mmap_wc(),当允许写组合时,该函数在运行时应评估为非零值。支持 I/O 资源映射的平台类似地定义 arch_can_pci_mmap_io()。
传统资源受 HAVE_PCI_LEGACY 定义的保护。希望支持传统功能的平台应定义它并提供 pci_legacy_read、pci_legacy_write 和 pci_mmap_legacy_page_range 函数。