5. Accessing PCI device resources through sysfs
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 中包含一个单一功能设备。为方便起见,复制了域和总线编号。 device目录下有几个文件,每个文件都有自己的功能。
| file | function |
|---|---|
| class | PCI class (ascii, ro) |
| config | PCI config space (binary, rw) |
| device | PCI device (ascii, ro) |
| enable | Whether the device is enabled (ascii, rw) |
| irq | IRQ number (ascii, ro) |
| local_cpus | nearby CPU mask (cpumask, ro) |
| remove | remove device from kernel’s list (ascii, wo) |
| resource | PCI resource host addresses (ascii, ro) |
| resource0..N | PCI resource N, if present (binary, mmap, rw1) |
| resource0_wc..N_wc | PCI WC map resource N, if prefetchable (binary, mmap) |
| revision | PCI revision (ascii, ro) |
| rom | PCI ROM resource, if present (binary, ro) |
| subsystem_device | PCI subsystem device (ascii, ro) |
| subsystem_vendor | PCI subsystem vendor (ascii, ro) |
| vendor | PCI vendor (ascii, ro) |
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
[1] rw for IORESOURCE_IO (I/O port) regions only
只读文件是信息性的,对它们的写入将被忽略,“rom”文件除外。 可写文件可用于在设备上执行操作(例如更改配置空间、分离设备)。 mmapable 文件可通过偏移量 0 处的文件 mmap 获得,并可用于从用户空间进行实际设备编程。 请注意,某些平台不支持某些资源的映射,因此请务必检查任何尝试的映射的返回值。 其中最值得注意的是 I/O 端口资源,它也提供读/写访问。
“enable”文件提供了一个计数器,指示设备已启用的次数。 如果“enable”文件当前返回“4”,并且回显“1”,则它将返回“5”。 回显“0”会减少计数。 但是,即使返回到 0,某些初始化也可能无法逆转。
“rom”文件的特殊之处在于它提供对设备 ROM 文件(如果可用)的只读访问。 但默认情况下它是禁用的,因此应用程序应在尝试读取调用之前将字符串“1”写入文件以启用它,并在访问后通过将“0”写入文件来禁用它。 请注意,必须启用设备才能读取 ROM 才能成功返回数据。 如果驱动程序未绑定到设备,则可以使用上面记录的“enable”文件来启用它。
“删除”文件用于通过向文件写入非零整数来删除 PCI 设备。 这不涉及任何类型的热插拔功能,例如 关闭设备电源。 该设备将从内核的 PCI 设备列表中删除,其 sysfs 目录也将被删除,并且该设备将从附加到它的任何驱动程序中删除。 不允许移除 PCI 根总线。
5.1. Accessing legacy resources through 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 文件应该使用与所需内存偏移量相对应的偏移量进行映射,例如 0xa0000 表示 VGA 帧缓冲区。 然后,应用程序可以简单地取消引用返回的指针(当然是在检查错误之后)来访问遗留内存空间。
5.2. Supporting PCI access on new platforms
为了支持如上所述的 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 函数。