可以不使用 BAR 空间,但影响很大。
简单说:
没有 BAR 空间,Linux 仍然可能枚举到 PCIe 设备;
但是 Linux 驱动很难控制 FPGA 里的 DMA、寄存器、中断状态和业务逻辑。
也就是说:
配置空间:设备还能被发现
BAR 空间:驱动能不能真正控制设备
1. 不使用 BAR 空间,设备还能被 Linux 识别吗?
可以。
即使没有 BAR,PCIe Endpoint 仍然有 配置空间,Linux 仍然可以读取:
Vendor ID
Device ID
Class Code
Command / Status
PCIe Capability
MSI Capability
所以 Linux 可能仍然能看到设备:
lspci
也可能还能根据:
Vendor ID / Device ID
匹配驱动。
但是问题在于:
能识别设备 ≠ 能控制设备
没有 BAR 后,驱动缺少访问 FPGA 自定义寄存器的入口。
2. 没有 BAR,最大影响是什么?
最大影响是:
Linux 驱动不能通过 readl()/writel() 访问 FPGA 自定义寄存器
也就是说,下面这些都没有地方写:
DMA_ADDR_LOW
DMA_ADDR_HIGH
DMA_LEN
DMA_DIR
DMA_CTRL.START
IRQ_ENABLE
IRQ_CLEAR
RESET
原来有 BAR 时:
writel(dma_addr_low, bar0 + REG_DMA_ADDR_LOW);
writel(dma_addr_high, bar0 + REG_DMA_ADDR_HIGH);
writel(len, bar0 + REG_DMA_LEN);
writel(DMA_DIR_C2H, bar0 + REG_DMA_DIR);
writel(DMA_CTRL_START, bar0 + REG_DMA_CTRL);
没有 BAR 后:
bar0 不存在
pci_iomap() 没有可映射对象
驱动没有地方写这些寄存器
3. 对 DMA 的影响最大
对于你现在讨论的 Block DMA,BAR 几乎是必需的。
因为 Block DMA 启动前,驱动必须告诉 FPGA:
Host DMA buffer 地址是多少?
传输长度是多少?
方向是 H2C 还是 C2H?
使用哪个通道?
什么时候开始?
是否使能中断?
正常流程是:
驱动写 BAR 寄存器
→ FPGA 读取 DMA 参数
→ FPGA 发 PCIe Memory Read / Memory Write
→ DMA 完成后 FPGA 中断通知 Host
如果没有 BAR,驱动没法告诉 FPGA 这些参数。
结果就是:
DMA 地址无法下发
DMA 长度无法下发
DMA 方向无法配置
DMA 无法 START
DMA 状态无法读取
DMA 错误无法查询
所以对 Block DMA 来说:
没有 BAR,基本无法正常做软件可控 DMA。
4. 对中断的影响
MSI/MSI-X 是 FPGA 向 Host 发中断。
但是驱动通常需要通过 BAR 控制:
IRQ_ENABLE
IRQ_STATUS
IRQ_CLEAR
没有 BAR 会导致:
4.1 不能灵活使能/关闭中断
正常有 BAR:
writel(IRQ_EN_DMA_DONE | IRQ_EN_DMA_ERROR, bar0 + REG_IRQ_ENABLE);
没有 BAR:
驱动无法控制 FPGA 哪些事件可以触发中断
4.2 不能清中断
正常中断处理:
irq_status = readl(bar0 + REG_IRQ_STATUS);
writel(irq_status, bar0 + REG_IRQ_CLEAR);
readl(bar0 + REG_IRQ_STATUS);
没有 BAR:
驱动不知道 FPGA 为何中断
驱动也无法清 FPGA 的 pending IRQ
这很危险,可能导致:
中断一直重复触发
驱动无法判断 DONE / ERROR
无法恢复 DMA 状态
5. 对 probe() 的影响
有 BAR 时,probe() 一般做:
pci_enable_device()
pci_request_regions()
pci_iomap()
readl(VERSION)
关闭 IRQ
清 IRQ
复位 DMA
分配 DMA buffer
申请中断
创建设备节点
没有 BAR 后,这几步会受影响:
| pci_request_regions() | 没有 BAR region 可申请,或者只申请不到 MMIO |
| pci_iomap() | 没有 BAR 可映射 |
| 读取 VERSION | 无法读取 FPGA 版本 |
| 关闭 IRQ_ENABLE | 无法关闭 FPGA 中断 |
| 清 IRQ_STATUS | 无法清旧中断 |
| 复位 DMA Engine | 无法通过寄存器复位 |
| 初始化 DMA Engine | 无法配置控制寄存器 |
结果是:
probe 只能识别设备,但无法真正初始化 FPGA 用户逻辑。
6. 对用户态接口的影响
如果没有 BAR,你的用户态流程会断掉。
原流程:
open()
mmap DMA buffer
ioctl START_DMA
poll 等待完成
读取 mmap buffer
其中 ioctl START_DMA 依赖驱动写 FPGA 寄存器。
没有 BAR 后:
open 可能还能成功
mmap Host DMA buffer 也可能还能做
但是 ioctl START_DMA 没法真正启动 FPGA DMA
poll 也等不到可靠完成事件
所以字符设备会变成:
有 /dev/my_pcie0
但是功能不可控
7. 没有 BAR,还有什么替代办法?
理论上有,但都不推荐作为常规 PCIe DMA 设备方案。
方案一:用配置空间 Vendor Specific Capability
可以在 PCIe 配置空间里放一些 Vendor Specific Capability,然后驱动通过:
pci_read_config_dword()
pci_write_config_dword()
读写少量控制信息。
但是缺点很大:
1. 配置空间很小
2. 访问慢
3. 不适合频繁控制
4. 不适合大量寄存器
5. 不适合 DMA doorbell
6. 不适合复杂状态机
配置空间主要用于枚举和能力声明,不适合当正常控制寄存器空间用。
方案二:FPGA 固定 DMA 地址,自主 DMA
比如 FPGA 上电后就往某个固定 Host 地址 DMA。
这个基本不现实,因为:
1. Host 物理地址不是固定的
2. Linux 内存分配是动态的
3. IOMMU 可能会转换 DMA 地址
4. FPGA 不知道 Host buffer 在哪里
5. 安全性很差
驱动必须通过某种方式把 dma_handle 告诉 FPGA。最常见方式就是 BAR 寄存器。
方案三:Host 内存里放 Descriptor,FPGA 自己取
这是 Scatter-Gather DMA 的思路。
但是问题是:
FPGA 第一次怎么知道 Descriptor Ring 的地址?
仍然需要一个启动/配置通道告诉 FPGA:
descriptor base address
ring size
doorbell
start
这些通常还是通过 BAR 寄存器下发。
所以即使用 SGDMA,BAR 仍然很常见。
方案四:FPGA 只作为纯数据采集设备,固定逻辑自动运行
比如 FPGA 上电后自动采集,自动 DMA,Host 只接收中断。
但仍然有几个问题:
1. Host buffer 地址如何告诉 FPGA?
2. 数据长度如何配置?
3. 出错如何复位?
4. 中断如何清除?
5. 状态如何读取?
最终通常还是需要 BAR。
8. 不使用 BAR,会不会影响 PCIe Memory Read / Write?
不会直接影响 FPGA 发 DMA TLP 的能力。
也就是说:
FPGA 理论上仍然可以发 PCIe Memory Read / Memory Write
但问题是:
它不知道应该读写哪个 Host 地址
它不知道传输长度
它不知道什么时候开始
它不知道 Host 当前分配的 DMA buffer 在哪里
所以不是硬件能力完全消失,而是:
缺少软件控制通道
9. 不使用 BAR,对 MSI/MSI-X 有什么影响?
MSI
MSI 不一定强制依赖 BAR。
MSI Capability 在配置空间中,PCI Core 可以配置 MSI Message Address / Data。
但是你的 FPGA 用户逻辑仍然需要知道:
什么时候发 MSI?
发完后 Host 如何清状态?
中断状态在哪里?
如果没有 BAR,驱动很难读写:
IRQ_STATUS
IRQ_ENABLE
IRQ_CLEAR
所以 MSI 本身可能可用,但系统不完整。
MSI-X
MSI-X 更麻烦。
MSI-X Table 和 PBA 通常位于某个 BAR 空间中,MSI-X Capability 里会描述:
Table BIR
Table Offset
PBA BIR
PBA Offset
如果完全没有 BAR,MSI-X 通常不好实现,甚至无法放置 MSI-X Table / PBA。
所以:
不用 BAR,MSI 还有可能;
不用 BAR,MSI-X 基本不适合。
10. 哪些设备可以没有 BAR?
有些非常简单的 PCIe 设备理论上可以没有 BAR,比如:
1. 只需要被枚举,不需要 Host 控制
2. 只用配置空间完成极少量控制
3. 固定功能设备
4. 测试用 Endpoint
5. 非常特殊的协议设备
但是对 FPGA PCIe DMA 设备来说,通常不建议。
11. 对你的 FPGA PCIe DMA 项目来说
如果你的目标是:
Linux 驱动控制 FPGA DMA
用户态 ioctl 启动 DMA
mmap buffer 收发数据
MSI/MSI-X 通知完成
poll 等待结果
那么建议:
必须使用 BAR0 作为控制寄存器空间
推荐结构仍然是:
配置空间:设备身份、BAR 描述、MSI/MSI-X Capability
BAR0:DMA 控制寄存器、状态寄存器、中断寄存器
Host DMA buffer:真正搬运的数据
关系是:
驱动通过 BAR0 控制 FPGA
FPGA 通过 DMA 访问 Host buffer
FPGA 通过 MSI/MSI-X 通知驱动
12. 最终结论
如果不使用 BAR 空间:
1. Linux 仍然可能枚举到 PCIe 设备
2. 驱动仍然可能根据 Vendor ID / Device ID 绑定设备
3. 但驱动无法方便访问 FPGA 自定义寄存器
4. DMA 地址、长度、方向、START 很难下发
5. DMA 状态、错误、中断状态很难读取
6. FPGA 中断很难清除
7. remove 时也很难可靠停止 DMA
8. 对 Block DMA 来说基本不可行
一句话:
没有 BAR,PCIe 设备还能“被看见”;
但 FPGA DMA 设备基本无法“被控制”。
所以对你这个 FPGA PCIe Block DMA 驱动 来说,BAR0 控制寄存器空间几乎是必须的。


