方案 A:原生 PCIe Endpoint IP + AXI-Lite BAR MMIO 完整方案
一、方案架构说明(无 XDMA、无硬件 DMA)
- FPGA 硬件侧
- 采用 Xilinx 原生
PCIe Gen3 EndpointIP,不集成 XDMA、不启用 AXI-Stream DMA 通路; - IP 仅配置 1 个 BAR 空间(BAR0),挂载 AXI-Lite 从接口;
- FPGA 内部:AXI-Lite → 自定义寄存器阵列 / FIFO,CPU 通过 MMIO 直接读写;
- 无 SG 描述符、无 DMA 引擎、无 DMA 中断,纯 CPU PIO 搬运数据。
- 采用 Xilinx 原生
- 软件驱动侧
- Linux 内核驱动极简,使用标准 PCI 子系统,无需 xdma 内核模块;
- 流程:PCI 枚举 → iomap 映射 BAR 虚拟地址 → 指针直接读写寄存器 / FIFO;
- 适用限制 仅小包控制交互,大数据吞吐量极低,仅用于 64B 以内短报文、寄存器配置。
二、FPGA 硬件顶层极简结构(伪代码)
verilog
// 原生PCIe Gen3 EP IP,仅AXI-Lite,无DMA
pcie_3_ep_native inst_pcie (
.sys_clk_100mhz(sys_clk),
.rst_n(sys_rst_n),
// PCIe高速收发
.pcie_rx(pcie_rx),
.pcie_tx(pcie_tx),
// AXI-Lite 控制BAR(唯一用户通路)
.s_axi_lite_awaddr(axi_lite_awaddr),
.s_axi_lite_awvalid(axi_lite_awvalid),
.s_axi_lite_awready(axi_lite_awready),
.s_axi_lite_wdata(axi_lite_wdata),
.s_axi_lite_wstrb(axi_lite_wstrb),
.s_axi_lite_wvalid(axi_lite_wvalid),
.s_axi_lite_wready(axi_lite_wready),
.s_axi_lite_bresp(axi_lite_bresp),
.s_axi_lite_bvalid(axi_lite_bvalid),
.s_axi_lite_bready(axi_lite_bready),
.s_axi_lite_araddr(axi_lite_araddr),
.s_axi_lite_arvalid(axi_lite_arvalid),
.s_axi_lite_arready(axi_lite_arready),
.s_axi_lite_rdata(axi_lite_rdata),
.s_axi_lite_rresp(axi_lite_rresp),
.s_axi_lite_rvalid(axi_lite_rvalid),
.s_axi_lite_rready(axi_lite_rready)
);
// 用户寄存器/FIFO,CPU通过AXI-Lite MMIO访问
user_reg_fifo inst_user_fifo (
.clk(user_clk),
.rst_n(user_rst_n),
// 对接PCIe AXI-Lite
.s_axil_awaddr(axi_lite_awaddr),
.s_axil_awvalid(axi_lite_awvalid),
.s_axil_awready(axi_lite_awready),
.s_axil_wdata(axi_lite_wdata),
.s_axil_wstrb(axi_lite_wstrb),
.s_axil_wvalid(axi_lite_wvalid),
.s_axil_wready(axi_lite_wready),
.s_axil_bresp(axi_lite_bresp),
.s_axil_bvalid(axi_lite_bvalid),
.s_axil_bready(axi_lite_bready),
.s_axil_araddr(axi_lite_araddr),
.s_axil_arvalid(axi_lite_arvalid),
.s_axil_arready(axi_lite_arready),
.s_axil_rdata(axi_lite_rdata),
.s_axil_rresp(axi_lite_rresp),
.s_axil_rvalid(axi_lite_rvalid),
.s_axil_rready(axi_lite_rready)
);
三、Linux 内核驱动极简例程(无 XDMA 依赖)
c
运行
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/io.h>
// 设备VID/DID,自行替换IP配置值
#define PCI_VENDOR_XILINX 0x10ee
#define PCI_DEV_NATIVE_PCIE 0x0001
struct pcie_dev {
void __iomem *bar0_base; // BAR0虚拟映射基地址
resource_size_t bar0_len;
struct pci_dev *pdev;
};
static struct pcie_dev g_dev;
// 64B数据写入FPGA FIFO(CPU循环MMIO写,纯PIO)
static void mmio_write_64b(struct pcie_dev *dev, u8 *buf)
{
u32 *mmio_ptr = dev->bar0_base;
int i;
// 64字节 = 16个32bit寄存器
for(i = 0; i < 16; i++){
iowrite32(((u32*)buf)[i], mmio_ptr + i);
}
}
// 从FPGA读取64B数据(MMIO读,存在PCIe往返延迟)
static void mmio_read_64b(struct pcie_dev *dev, u8 *buf)
{
u32 *mmio_ptr = dev->bar0_base;
int i;
for(i = 0; i < 16; i++){
((u32*)buf)[i] = ioread32(mmio_ptr + i);
}
}
static int pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int ret;
struct pcie_dev *priv = &g_dev;
priv->pdev = pdev;
// 1. 使能PCIe设备内存空间
ret = pci_enable_device(pdev);
if(ret) return ret;
pci_set_master(pdev);
// 2. 映射BAR0(AXI-Lite寄存器区)
priv->bar0_len = pci_resource_len(pdev, 0);
priv->bar0_base = pci_iomap(pdev, 0, priv->bar0_len);
if(!priv->bar0_base){
pci_disable_device(pdev);
return -ENOMEM;
}
printk("Native PCIe EP BAR0 mapped ok, no XDMA\n");
return 0;
}
static void pcie_remove(struct pci_dev *pdev)
{
struct pcie_dev *priv = &g_dev;
pci_iounmap(pdev, priv->bar0_base);
pci_disable_device(pdev);
}
static const struct pci_device_id pcie_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_XILINX, PCI_DEV_NATIVE_PCIE) },
{0,}
};
MODULE_DEVICE_TABLE(pci, pcie_id_table);
static struct pci_driver native_pcie_drv = {
.name = "native-pcie-axil",
.id_table = pcie_id_table,
.probe = pcie_probe,
.remove = pcie_remove,
};
module_pci_driver(native_pcie_drv);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Native PCIe Gen3 AXI-Lite MMIO, NO XDMA");
四、PCIe Gen3 x1 64 字节 MMIO 传输耗时估算
基础参数
- PCIe Gen3 单通道速率:8.0 GT/s,每符号 1bit,128b/130b 编码 有效带宽单通道:
8G * 128/130 ≈ 7.877 Gbps = 984.6 MB/s - MMIO 写:Posted TLP,无应答;MMIO 读:Non-Posted,必须等待完成包 CplD 往返
- 单次 32bit 寄存器访问 = 1 个最小 PCIe TLP 包头开销(~20 字节包头)
1)64B 写操作(CPU→FPGA,H2C,Posted)
64B 拆分为 16 次 32bit MMIO 写: 每次写 TLP 载荷 4B,包头 20B,单包总 24B; 16 次独立小包,无写合并优化场景(默认 nocache)。 总传输 bit:16 * 24B * 8 = 3072 bit 理论传输时间:
\(T_{wire} = \frac{3072}{7.877\times10^9} \approx 390\ \text{ns}\)
叠加 CPU 流水线、AXI-Lite 握手、PCIe IP 内部延迟,实测总耗时:700 ~ 1200 ns
2)64B 读操作(FPGA→CPU,C2H,Non-Posted,往返)
每一次 32bit 读流程:
- CPU 发起 MemRd TLP(20B)下发 FPGA
- FPGA 返回 CplD 完成包(24B) 单次往返报文总字节:44B 16 次读总 bit:
16 * 44 * 8 = 5632 bit纯线路传输时间 ≈ 715 ns; 叠加 PCIe 链路往返延迟、CPU 阻塞等待、AXI 响应延迟,实测单次 64B 读总耗时 1.8 ~ 3.0 μs
五、关键限制总结
- 全程无 XDMA、无硬件 DMA,所有数据由 CPU 循环搬运;
- 读性能远差于写,大包场景带宽会急剧下跌;
- 仅适合控制指令、寄存器交互,不适合以太网线速数据流;
- 若开启 WC(写合并)可小幅降低写延迟,但读延迟无改善。