PCIe 端点到端点通信

PCIe 端点到端点通信

这只是一个关于与 PCIe 设备通信的高级问题。据我所知,只要根端口(Linux 内核)设置了一些初始信息(例如 BAR 值),就应该能够进行直接的端点到端点通信,而无需根端口中间人的工作。所以让我解释一下我尝试过的方法,也许有人能发现我遗漏了什么。

首先,我启动插入了 2 个设备的机器。我记录分配给目标设备(完成器)的 BAR。据我所知,这些 BAR 是总线地址,是 PCIe 线路上的一种物理地址,PCIe 交换机使用它来路由流量。第二个设备是 FPGA(请求器),因此我从内核中删除了该设备

echo 1 > /sys/devices/pci0000\:00/0000\:00\:03.0/0000\:04\:00.0/remove

移除设备后,我会刷新 FPGA。然后,我会在 PCI 配置空间中分配某些参数。具体来说,我设置了字节 4 位 0、1 和 2。这应该是 I/O 空间、内存空间和总线主控。具体来说,我知道如果我希望设备能够请求 PCIe 总线上的信息,则最后一个是必需的。https://wiki.osdev.org/PCI

此时我重新扫描我的 PCIe 总线,以便内核可以看到我的设备是什么样子。

echo 1 > /sys/bus/pci/rescan

此时,我使用 lspci 检查我的更改是否在配置空间中起作用,一切似乎都很好。内核已设置 BAR,但我的设备被列为总线主控。

sudo lspci -nn -k -x -d 0700:8038
04:00.0 Memory controller [0580]: Device [0700:8038]
    Subsystem: Xilinx Corporation Device [10ee:0007]
00: 00 07 38 80 07 01 10 40 00 00 80 05 08 00 00 00
10: 00 00 20 fb 00 00 00 00 00 00 00 00 00 00 00 00

从这里我发出对 BAR0(从 NVMe 驱动器读取)+0x08 的读取请求,根据内核代码,这应该是 NVMe 版本。https://elixir.bootlin.com/linux/latest/source/include/linux/nvme.h#L105

此时,我期望 NVMe 驱动器能够为我的非发布请求生成一个完成数据包,但我的 PCIe 控制器却在 FPGA 上超时,这意味着即使交换机也没有确认我的请求(我认为)。可能我的 FPGA 无法正确生成这些请求,但遗憾的是我没有办法确定 PCIe 总线的范围。

因此,我正在检查以确保我没有错过一些过于复杂的标志或位,也许对 BAR 的工作方式或端点等存在误解。如果有人发现我尝试做的事情存在问题,请告诉我。基于此http://xillybus.com/tutorials/pci-express-tlp-pcie-primer-tutorial-guide-1有可能我的主板根本就不是设计来允许在两个设备之间切换的,但我不知道如何检查这一点。

这允许外围设备直接访问 CPU 的内存(DMA)或与对等外围设备交换 TLP(在交换实体支持的范围内)。

感谢您的任何帮助。

答案1

对于遇到类似问题的人,有一条关于 PCIe 的规则我不知道(而且由于我不拥有该标准,因此仍然无法找到有关该规则的具体信息)。从 BAR 中指定的寄存器读取时。您必须读取数据的大小,不能读取寄存器的一部分。

在我的情况下,我试图读取一个 64 位(2 个双字)寄存器,但我指定了一个仅针对 1 个双字的读取请求。显然,这让我的 NVMe 驱动器拒绝响应。将双字计数增加到 2,然后我突然就得到了数据。我猜这是设备相关的,但也许与我如何寻址数据有关?我寻址为 64 位和 32 位,没有变化,所以我不认为是那样。

有人知道标准中是否有关于此问题的说明,或者这是否严格针对特定设备?我会标记任何可以提供具体原因的人。

相关内容