SandyBridge平台PCIe驱动64字节写入无数据包发送问题
PCIe内核驱动64字节写入失效问题(Intel SandyBridge平台)
我正在使用gcc 11.3为x86架构Intel SandyBridge平台开发PCIe内核驱动,目标实现单次64字节数据写入。目前32字节写入功能正常,但复制32字节写入代码逻辑实现64字节写入时,处理器未发送任何PCIe数据包。
正常工作的32字节写入代码
已完成内核空间到用户空间的映射,以下代码可成功向PCIe内存写入32字节数据(PCIe内存由配置为64字节负载的Intel FPGA托管):
// data指向长度为8的uint32数组(共32字节) // addr指向PCIe内存中内核映射的write-combine地址 void write_32(uint8_t *data, uint8_t *addr) { asm volatile ( "vmovdqa %[data_lo], %%ymm1 \n\t" "vmovdqa %%ymm1, %[addr_lo] \n\t" // 输出 : [addr_lo] "=m"(* addr) // 输入 : [data_lo] "m"(* data) // 破坏列表 : "memory" ); }
失效的64字节写入代码
由于SandyBridge平台限制,需通过两次32字节移动实现64字节写入(理想是发送单个64字节负载,退而求其次两个32字节负载也可接受),但调用以下函数时处理器未发送任何PCIe数据包:
// data指向长度为16的uint32数组(共64字节) // addr指向PCIe内存中内核映射的write-combine地址 static int write_64(uint8_t *data, void __iomem *addr) { // 将数据移动到256位ymm寄存器 uint8_t *data_upper = data + 32; void __iomem *addr_upper = addr + 32; asm volatile ( "vmovdqa %[data_lo], %%ymm3 \n\t" "vmovdqa %[data_hi], %%ymm4 \n\t" "vmovntdq %%ymm3, %[addr_lo] \n\t" "vmovntdq %%ymm4, %[addr_hi] \n\t" // 输出 : [addr_lo] "=m"(*(volatile uint8_t * __force) addr), [addr_hi] "=m"(*(volatile uint8_t * __force) addr_upper) // 输入 : [data_lo] "m"(*(volatile const char (*__force)[32]) data), [data_hi] "m"(*(volatile const char (*__force)[32]) data_upper) // 破坏列表 : "ymm3", "ymm4", "memory" ); return 0; }
内存初始化代码
static int chr_mmap(struct file *filp, struct vm_area_struct *vma) { struct chr_dev_bookkeep *chr_dev_bk; struct dev_bookkeep *dev_bk; unsigned long len, pfn; int ret; pgoff_t pgoff; len = vma->vm_end - vma->vm_start; pgoff = vma->vm_pgoff; printk(KERN_DEBUG "Mapping %ld bytes\n", len); printk(KERN_DEBUG "Start: %ld End: %ld\n", vma->vm_start, vma->vm_end); chr_dev_bk = filp->private_data; dev_bk = chr_dev_bk->dev_bk; if ((len == 0) || (len+pgoff) > dev_bk->kmem_info.size) { return -EINVAL; } vma->vm_ops = &intel_fpga_vm_ops; vma->vm_flags |= VM_PFNMAP | VM_DONTCOPY | VM_DONTEXPAND; //vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); vma->vm_private_data = dev_bk; //PFN: 页帧号 pfn = __pa(dev_bk->kmem_info.virt_addr + (pgoff<<PAGE_SHIFT))>>PAGE_SHIFT; ret = remap_pfn_range(vma, vma->vm_start, pfn, len, vma->vm_page_prot); if (ret < 0) { printk(KERN_DEBUG "could not remap kernel buffer to user-space."); return -ENXIO; } return 0; }
已确认信息
- 待写入的64字节数据十六进制转储与预期一致
- 地址为32字节对齐,符合要求
- 注释掉单个
vmovntdq语句时,可向PCIe内存64字节字线的高半区或低半区写入一半数据 - 通过
lspci和cat pat_memtype_list确认,PCIe BAR分配的内存区域为write-combine类型,符合要求
单独调用两次移动操作可正常工作(即分别写入低半区和高半区),完整代码的汇编输出符合预期:两次数据移入寄存器,再两次写入内存。开启-O3优化后,处理器仍仅发送包含data_lo的单个32字节写入。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

