我希望对 PCIe 设备的所有读写请求都由 CPU 缓存进行缓存。然而,它并没有像我预期的那样工作。
这些是我对回写 MMIO 区域的假设。
- 对 PCIe 设备的写入仅在缓存回写时发生。
- TLP 有效负载的大小是缓存块大小 (64B)。
然而,捕获的 TLP 并不符合我的假设。
- 每次写入 MMIO 区域时都会写入 PCIe 设备。
- TLP 有效负载的大小为 1B。
我写了8个字节0xff
使用以下用户空间程序和设备驱动程序连接到 MMIO 区域。
用户程序的一部分
struct pcie_ioctl ioctl_control;
ioctl_control.bar_select = BAR_ID;
ioctl_control.num_bytes_to_write = atoi(argv[1]);
if (ioctl(fd, IOCTL_WRITE_0xFF, &ioctl_control) < 0) {
printf("ioctl failed\n");
}
设备驱动程序的一部分
case IOCTL_WRITE_0xFF:
{
int i;
char *buff;
struct pci_cdev_struct *pci_cdev = pci_get_drvdata(fpga_pcie_dev.pci_device);
copy_from_user(&ioctl_control, (void __user *)arg, sizeof(ioctl_control));
buff = kmalloc(sizeof(char) * ioctl_control.num_bytes_to_write, GFP_KERNEL);
for (i = 0; i < ioctl_control.num_bytes_to_write; i++) {
buff[i] = 0xff;
}
memcpy(pci_cdev->bar[ioctl_control.bar_select], buff, ioctl_control.num_bytes_to_write);
kfree(buff);
break;
}
我修改了 MTRR 以进行相应的 MMIO 区域回写。 MMIO区域从0x0c7300000开始,长度为0x100000(1MB)。以下是cat /proc/mtrr
不同政策的结果。请注意,我将每个区域设为独有。
不可缓存
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: uncachable
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
写组合
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-combining
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
回写
reg00: base=0x080000000 ( 2048MB), size= 1024MB, count=1: uncachable
reg01: base=0x380000000000 (58720256MB), size=524288MB, count=1: uncachable
reg02: base=0x0c0000000 ( 3072MB), size= 64MB, count=1: uncachable
reg03: base=0x0c4000000 ( 3136MB), size= 32MB, count=1: uncachable
reg04: base=0x0c6000000 ( 3168MB), size= 16MB, count=1: uncachable
reg05: base=0x0c7000000 ( 3184MB), size= 1MB, count=1: uncachable
reg06: base=0x0c7100000 ( 3185MB), size= 1MB, count=1: uncachable
reg07: base=0x0c7200000 ( 3186MB), size= 1MB, count=1: uncachable
reg08: base=0x0c7300000 ( 3187MB), size= 1MB, count=1: write-back
reg09: base=0x0c7400000 ( 3188MB), size= 1MB, count=1: uncachable
以下是使用不同策略的 8B 写入的波形捕获。我使用集成逻辑分析仪(ILA)来捕获这些波形。请观看pcie_endpoint_litepcietlpdepacketizer_tlp_req_payload_dat
when pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
已设置。可以通过计数来统计数据包的数量pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid
在这些波形示例中。
-
不可缓存: link https://i.stack.imgur.com/ubxfn.png-> 正确,1B x 8 数据包
-
写组合: link https://i.stack.imgur.com/wheZf.png-> 正确,8B x 1 包
-
回写: link https://i.stack.imgur.com/qCeIc.png-> 意外,1B x 8 数据包
系统配置如下。
-
CPU:英特尔(R) 至强(R) CPU E5-2630 v4 @ 2.20GHz
-
OS:Linux内核4.15.0-38
-
PCIe设备:Xilinx FPGA KC705 编程litepcie https://github.com/enjoy-digital/litepcie
相关链接
- 从 x86 CPU 生成 64 字节读取 PCIe TLP https://stackoverflow.com/questions/51918804/generating-a-64-byte-read-pcie-tlp-from-an-x86-cpu
- 如何在英特尔® 架构上实施 64B PCIe* 突发传输 https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/pcie-burst-transfer-paper.pdf
- 写入组合缓冲区乱序写入和 PCIe https://software.intel.com/en-us/forums/software-tuning-performance-optimization-platform-monitoring/topic/711304
- Ryzen 是否支持内存映射 IO 的回写式缓存(通过 PCIe 接口)? https://community.amd.com/thread/229989
- MTRR(内存类型范围寄存器)控制 https://www.kernel.org/doc/Documentation/x86/mtrr.txt
- 对Linux进行PAT https://www.kernel.org/doc/ols/2008/ols2008v2-pages-135-144.pdf
- 深入了解 TLP:PCI Express 设备如何通信(第一部分) http://xillybus.com/tutorials/pci-express-tlp-pcie-primer-tutorial-guide-1