原生 PCIe Endpoint IP + AXI-Lite BAR MMIO 完整方案

方案 A:原生 PCIe Endpoint IP + AXI-Lite BAR MMIO 完整方案

一、方案架构说明(无 XDMA、无硬件 DMA)

  1. FPGA 硬件侧
    • 采用 Xilinx 原生 PCIe Gen3 Endpoint IP,不集成 XDMA、不启用 AXI-Stream DMA 通路;
    • IP 仅配置 1 个 BAR 空间(BAR0),挂载 AXI-Lite 从接口;
    • FPGA 内部:AXI-Lite → 自定义寄存器阵列 / FIFO,CPU 通过 MMIO 直接读写;
    • 无 SG 描述符、无 DMA 引擎、无 DMA 中断,纯 CPU PIO 搬运数据。
  2. 软件驱动侧
    • Linux 内核驱动极简,使用标准 PCI 子系统,无需 xdma 内核模块;
    • 流程:PCI 枚举 → iomap 映射 BAR 虚拟地址 → 指针直接读写寄存器 / FIFO;
  3. 适用限制 仅小包控制交互,大数据吞吐量极低,仅用于 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 传输耗时估算

基础参数

  1. PCIe Gen3 单通道速率:8.0 GT/s,每符号 1bit,128b/130b 编码 有效带宽单通道:8G * 128/130 ≈ 7.877 Gbps = 984.6 MB/s
  2. MMIO 写:Posted TLP,无应答;MMIO 读:Non-Posted,必须等待完成包 CplD 往返
  3. 单次 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 读流程:

  1. CPU 发起 MemRd TLP(20B)下发 FPGA
  2. FPGA 返回 CplD 完成包(24B) 单次往返报文总字节:44B 16 次读总 bit:16 * 44 * 8 = 5632 bit 纯线路传输时间 ≈ 715 ns; 叠加 PCIe 链路往返延迟、CPU 阻塞等待、AXI 响应延迟,实测单次 64B 读总耗时 1.8 ~ 3.0 μs

五、关键限制总结

  1. 全程无 XDMA、无硬件 DMA,所有数据由 CPU 循环搬运;
  2. 读性能远差于写,大包场景带宽会急剧下跌;
  3. 仅适合控制指令、寄存器交互,不适合以太网线速数据流;
  4. 若开启 WC(写合并)可小幅降低写延迟,但读延迟无改善。