You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多CPU服务器上FPGA PCIe设备DMA请求致Linux挂死问题排查

FPGA PCIe DMA 双CPU服务器挂死问题排查

问题描述

我正在开发基于FPGA的PCI Express(PCIe)设备,同时编写适配Linux系统的内核驱动。设备支持通过DMA模式向Linux主机内存写入数据,流程如下:

  • 驱动分配128KB连续内存区域并获取对应的DMA(总线)地址;
  • 驱动将该DMA地址写入FPGA PCIe设备;
  • FPGA PCIe设备生成以该DMA地址为起始的Memory Write PCIe事务(驱动已设置Bus Master位)。

该方案在单CPU Ubuntu桌面PC上运行正常,但在搭载两颗物理Intel CPU的超微服务器上,设备触发Memory Write事务时系统直接挂死。

驱动相关代码

// 采用64位DMA寻址
if (!dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) 
    printk(KERN_WARNING "%s: using 64bit DMA addressing\n", DRIVER_NAME);

...

// 内存分配与映射
struct page *dma_pages;
dma_pages = alloc_pages_node(NUMA_NO_NODE, GFP_ATOMIC | __GFP_NOWARN | __GFP_COMP | __GFP_MEMALLOC, mem_order); 
    
virt_addr = (unsigned long)page_address(dma_pages);

// 此DMA地址将传入FPGA
dma_addr = dma_map_single(&fpga_dev->pdev->dev, virt_addr, size, DMA_BIDIRECTIONAL);

已尝试的排查操作

  • 确认PCIe链路正常,CPU可读写FPGA寄存器并向FPGA传输数据;
  • 内核启动时禁用IOMMU(添加启动参数iommu=off intel_iommu=off amd_iommu=off);
  • BIOS中禁用Intel VT-d;
  • 尝试NUMA相关配置(禁用、启用,在不同节点分配内存);
  • 更换PCIe插槽及对应CPU,当前插槽曾正常运行另一PCIe网卡。

后续排查思路

1. DMA地址有效性校验

  • 打印dma_addr的具体值,确认是64位有效地址,且未超出服务器PCIe设备的寻址范围;
  • 用dma_mapping_error()检查dma_map_single()的返回值,确认映射是否成功,避免无效地址传入FPGA;
  • 尝试使用dma_alloc_coherent()替代alloc_pages_node()+dma_map_single()的组合,该函数会直接分配并映射适合DMA的内存,减少手动操作的错误。

2. PCIe事务属性检查

  • 确认FPGA生成的Memory Write事务的地址宽度是否为64位,部分双CPU服务器可能不支持32位DMA跨节点访问;
  • 检查事务的**请求者ID(Requestor ID)**是否正确,双CPU系统中PCIe设备可能挂接在特定CPU的PCIe根桥下,错误的Requestor ID会导致地址路由失败;
  • 验证事务的字节使能(Byte Enable)、**突发长度(Burst Length)**是否符合PCIe规范,部分服务器对非规范的突发事务兼容性较差。

3. 内存属性与缓存一致性

  • 确认分配的内存是否为**非缓存(Uncached)或写合并(Write-Combining)**类型,双CPU系统中缓存一致性协议对DMA内存的要求更严格;
  • 使用set_memory_wc()将分配的内存设置为写合并属性,避免缓存导致的数据不一致或系统挂死;
  • 检查dma_map_single()的方向参数,若仅需FPGA写入主机内存,使用DMA_FROM_DEVICE替代DMA_BIDIRECTIONAL,减少不必要的缓存同步操作。

4. 系统日志与硬件调试

  • 启用内核调试日志(如debug、pci=verbose启动参数),查看挂死前是否有内核报错或警告;
  • 使用FPGA的调试工具(如逻辑分析仪、JTAG)捕获PCIe事务,确认事务是否正确发出,以及主机是否响应;
  • 尝试降低FPGA的DMA传输速率(如减小突发长度、降低时钟频率),排查是否因事务速率过高导致系统总线过载。

单CPU桌面与双CPU服务器的核心差异

1. NUMA架构差异

双CPU服务器通常采用NUMA(非统一内存访问)架构,每个CPU拥有独立的本地内存和PCIe控制器,内存访问存在本地/远程节点的差异;单CPU桌面为UMA(统一内存访问)架构,所有内存和PCIe设备共享同一总线。若DMA内存分配在非PCIe设备所在CPU的远程节点,可能导致地址路由失败或触发系统挂死。

2. PCIe拓扑与路由差异

双CPU服务器的PCIe插槽可能分别挂接在不同CPU的根桥下,设备的Requestor ID需要正确关联到对应CPU的内存控制器;单CPU桌面的所有PCIe设备共享同一根桥,路由逻辑更简单。部分双CPU服务器的PCIe链路支持更严格的事务规范,对非标准事务的容错性更低。

3. IOMMU与内存保护差异

双CPU服务器的IOMMU/VT-d功能通常更复杂,即使禁用后仍可能存在残留的内存保护机制;单CPU桌面的IOMMU功能相对简单,禁用后基本不会影响DMA操作。

4. 缓存一致性协议差异

双CPU系统采用更复杂的缓存一致性协议(如Intel QPI/UPI),DMA内存的缓存属性设置错误可能导致缓存同步失败,进而触发系统挂死;单CPU系统的缓存一致性逻辑更简单,对DMA内存的限制较少。

内容的提问来源于stack exchange,提问作者ya_urock

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 15:58:14