寻求Windows PCI驱动中无需DMA的MMIO超64位多字读写API
Windows PCI驱动MMIO大尺寸单次TLP传输(无需DMA)
首先明确:WRITE_REGISTER_BUFFER_ULONG确实会按单个DWORD逐次发起访问,硬件层面可能合并成64位TLP,但没法满足更大尺寸的单次传输需求。以下是无需DMA的可行方案:
1. 写合并(WC)属性映射下的直接内存操作
通过MmMapIoSpace映射MMIO区域时,指定PAGE_WRITECOMBINE属性,这是触发大尺寸TLP的关键——WC属性允许CPU将连续的MMIO写操作合并成单次总线事务。
映射完成后,直接对虚拟地址进行连续赋值或使用内核内存拷贝函数(如RtlCopyMemory),就能触发单次大TLP传输(只要硬件支持对应尺寸):
// 假设已完成MMIO映射,pMmioBase为WC属性的虚拟地址指针 PUCHAR pTargetRegion = (PUCHAR)pMmioBase + YOUR_TARGET_OFFSET; ULONG64 largeData[8]; // 512位数据(8个64位值) // 直接批量赋值 for (int i = 0; i < 8; i++) { ((ULONG64*)pTargetRegion)[i] = largeData[i]; } // 或用内存拷贝(同样能触发合并) RtlCopyMemory(pTargetRegion, largeData, sizeof(largeData));
关键前提:FPGA端的PCIe配置需开启对应尺寸的支持,比如将Max Payload Size设置为至少64字节(512位)。
2. 汇编指令强制批量传输
如果需要更底层的控制,可使用x86/x64的非临时存储指令(如movntdq),直接发起写合并的总线事务,确保单次TLP传输大尺寸数据:
; 内联汇编示例(x64环境) mov rax, pMmioBase ; MMIO目标地址 mov rsi, largeDataBuffer ; 源数据缓冲区 movntdq [rax], xmm0 ; 写入128位 movntdq [rax+16], xmm1 movntdq [rax+32], xmm2 movntdq [rax+48], xmm3 sfence ; 确保所有写操作提交到总线
movntdq指令会绕过CPU缓存,直接生成合并后的总线事务,配合WC属性的MMIO映射,能稳定触发512位的单次TLP传输。
注意事项
- 绝对不要用
PAGE_NOCACHE属性映射MMIO,NC会强制拆分所有访问为最小粒度,无法触发合并。 - 确认FPGA端的PCIe端点配置:Max Payload Size、Max Read Request Size必须支持你需要的传输尺寸。
WRITE_REGISTER_*系列函数仅适合单个寄存器访问,内部实现会限制传输粒度,无法满足大TLP需求。
内容的提问来源于stack exchange,提问作者happychild
相关产品推荐
相关产品推荐

