lspci -vv -s 00:00
我在运行 Linux 的单板计算机上运行时得到了以下输出。
07:05.0 RAID bus controller: Adaptec AAC-RAID (Rocket) (rev 03)
Subsystem: Adaptec ASR-2230S + ASR-2230SLP PCI-X (Lancer)
Control: I/O- Mem+ BusMaster+ SpecCycle+ MemWINV+ VGASnoop-
ParErr- Stepping- SERR+ FastB2B-
Status: Cap+ 66MHz+ UDF- FastB2B- ParErr- DEVSEL=medium >TAbort- SERR-
Latency: 64 (250ns min, 250ns max), Cache Line Size: 64 bytes
Interrupt: pin A routed to IRQ 74
Region 0: Memory at f7a00000 (64-bit, non-prefetchable) [size=2M]
Region 2: Memory at f79ff000 (64-bit, non-prefetchable)
[Remaining output truncated]
以上只是示例输出,并不完全是我所得到的,但它包含感兴趣的项目。
我理解该命令的大部分输出lspci
,但是我希望有人能向我解释以 Region 开头的行...我在这里看到的 Region 行指定了什么类型的内存?我该如何访问它?问完这个问题后,我试图实现通过 PCI 总线连接的两台单板计算机之间的通信。我应该可以直接交谈。只有一个 PCI 仲裁器运行总线。这是我迄今为止所取得的成就……
我创建了一个用于出站 PCI 流量的 Linux 内核模块。基本上,它使用驱动程序 mmap 实现从用户空间(使用用户空间应用程序)一直向下映射。我写入 mmap 返回的位置,并且我实际上使用总线分析器看到了流量!现在,在另一台单板计算机上,我尝试读取 PCI 设备的 sysfs 资源,但只看到所有 FF,没有变化。
如果您能提供任何有关所有这些内存映射如何发生(包括 PCI)的建议或解释,我们将不胜感激。谢谢!
答案1
在 PCI/PCI-X/PCI-E 设备中,PCI 配置空间中有 BARs 寄存器。在 Linux 内核启动时,它会扫描 PCI 总线,找到所有 PCI 设备,包括 PCI-to-PCI 桥接器和 PCI 设备。然后内核会检查 PCI 设备的配置空间中有多少个 BAR。并通过向 BAR 寄存器写入 0xFFFFFFFF 来检查每个 BAR 需要多少内存空间以及内存空间类型。然后内核将内存空间资源分配给 PCI 设备。
在您的情况下,区域狮子显示 BAR 寄存器。
在各个设备驱动中都可以通过调用 pci_resource_start() 获取到 Linux 内核为各个 BAR 分配的物理基地址,然后调用 pci_iomap() 将物理基地址映射到内核虚拟地址,或者使用 remap_pfn_range() 为用户空间进程实现一个 mmap 方法将物理地址映射到用户空间进程虚拟地址。
答案2
设备上的寄存器要么是 IO 映射的,要么是内存映射的。(对于 x86 来说为 true)Region 显示这些寄存器映射到哪个内核虚拟地址。在这种情况下,它们在给定的内核虚拟地址空间中内存映射。