在用户空间中启用写入组合IO访问

Chi*_*ggs 10 c linux linux-device-driver linux-kernel pci-e

我有一个带有用户空间驱动程序的PCIe设备.我正在通过BAR向设备写命令,命令对延迟敏感,数据量很小(~64字节),所以我不想使用DMA.

如果我在使用内核重新映射BAR的物理地址ioremap_wc,然后写64字节到BAR 的内核中,我可以看到,64字节PCIe上写成一个TLP.如果我允许我的用户空间程序到mmap带有MAP_SHARED标志的区域然后写入64字节,我会在PCIe总线上看到多个TPL,而不是单个事务.

根据内核PAT文档,我应该能够将写入组合页面导出到用户空间:

希望将某些页面导出到用户空间的驱动程序通过使用mmap接口和组合来完成

1) pgprot_noncached()

2)io_remap_pfn_range()remap_pfn_range()vm_insert_pfn()

通过PAT支持,pgprot_writecombine添加了一个新的API .因此,驱动程序可以继续使用上述顺序,使用 步骤1 pgprot_noncached()pgprot_writecombine()步骤1,然后执行步骤2.

根据此文档,我的mmap处理程序中的相关内核代码如下所示:

 vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);

 return io_remap_pfn_range(vma,
                           vma->vm_start,
                           info->mem[vma->vm_pgoff].addr >> PAGE_SHIFT,
                           vma->vm_end - vma->vm_start,
                           vma->vm_page_prot);
Run Code Online (Sandbox Code Playgroud)

我的PCIe设备显示在lspci中,BAR标记为预期的预取:

    Latency: 0, Cache Line Size: 64 bytes
    Interrupt: pin A routed to IRQ 11
    Region 0: Memory at d8000000 (64-bit, prefetchable) [size=32M]
    Region 2: Memory at d4000000 (64-bit, prefetchable) [size=64M]
Run Code Online (Sandbox Code Playgroud)

当我mmap从用户空间调用时,我看到一条日志消息(设置了debugpat kernel boot参数):

reserve_memtype添加[mem 0xd4000000-0xd7ffffff],跟踪写入组合,req写入组合,ret写入组合

我还可以看到/sys/kernel/debug/x86/pat_memtype_listPAT条目看起来正确并且没有重叠区域:

write-combining @ 0xd4000000-0xd8000000
uncached-minus  @ 0xd8000000-0xda000000
Run Code Online (Sandbox Code Playgroud)

我还检查过没有与PAT配置冲突的MTRR条目.据我所知,所有内容都设置正确,以便在用户空间中进行写入组合,但是使用PCIe分析器观察PCIe总线上的事务,那里的用户空间访问模式与从内核执行的相同写入完全不同打完ioremap_wc电话后.

为什么写入组合不能像用户空间那样工作?

我还能做些什么来进一步调试?

我目前正在使用单插槽6核i7-3930K.

小智 1

我不知道这是否有帮助,但这就是我在 PCIe 上进行写组合的方式。当然,它在内核空间中,但这符合英特尔文档。如果您遇到困难,值得一试。

全局定义:

unsigned int __attribute__ ((aligned(0x20))) srcArr[ARR_SIZE];
Run Code Online (Sandbox Code Playgroud)

在你的函数中:

int *pDestAddr

for (i = 0; i < ARR_SIZE; i++) {
    _mm_stream_si32(pDestAddr + i, pSrcAddr[i]);
}
Run Code Online (Sandbox Code Playgroud)