映射MMIO区域回写不起作用

时间:2018-11-15 01:21:54

标签: linux caching x86 fpga pci-e

我希望对所有PCIe设备的读写请求都由CPU缓存来缓存。但是,它不符合我的预期。

这些是我对回写MMIO区域的假设。

  1. 对PCIe设备的写入仅在高速缓存写回时发生。
  2. TLP有效负载的大小是缓存块大小(64B)。

但是,捕获的TLP不符合我的假设。

  1. 每次写入MMIO区域时都会写入PCIe设备。
  2. 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时,请注意pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid。在这些波形示例中,您可以通过计数pcie_endpoint_litepcietlpdepacketizer_tlp_req_valid来计算数据包的数量。

  1. 不可缓存link->正确,1B x 8包
  2. 写合并link->正确,8B x 1包
  3. 回写link->意外的1B x 8包

系统配置如下。

  • CPU :英特尔(R)至强(R)CPU E5-2630 v4 @ 2.20GHz
  • 操作系统:Linux内核4.15.0-38
  • PCIe设备:使用litepcie编程的Xilinx FPGA KC705

相关链接

  1. Generating a 64-byte read PCIe TLP from an x86 CPU
  2. How to Implement a 64B PCIe* Burst Transfer on Intel® Architecture
  3. Write Combining Buffer Out of Order Writes and PCIe
  4. Do Ryzen support write-back caching for Memory Mapped IO (through PCIe interface)?
  5. MTRR (Memory Type Range Register) control
  6. PATting Linux
  7. Down to the TLP: How PCI express devices talk (Part I)

1 个答案:

答案 0 :(得分:2)

简而言之,似乎在设计上无法映射MMIO区域回写。

如果有人发现有可能,请上传答案。

我来找John McCalpin的文章和答案。首先,无法映射MMIO区域回写。其次,可以在某些处理器上解决该问题。

  1. 无法映射MMIO区域回写

    Quote from this link

      

    仅供参考:WB类型不适用于内存映射的IO。您可以   对位进行编程以将映射设置为WB,但是系统将   收到不知道如何处理的交易时便崩溃   处理。从理论上讲,可以使用WP或WT进行缓存   从MMIO读取数据,但必须通过软件处理一致性。

    Quote from this link

      

    只有当我同时将PAT和MTRR都设置为WB时,内核才会崩溃

  2. 某些处理器上可能有解决方法

    Notes on Cached Access to Memory-Mapped IO Regions, John McCalpin

      

    至少可以对一组映射进行处理   x86-64处理器,它基于MMIO空间两次的映射。   用一组允许写合并的属性映射MMIO范围   存储(但仅未缓存的读取)。再次映射MMIO范围   具有一组允许高速缓存行读取的属性(但仅   未缓存的非写合并存储)。