我们正在尝试为自定义数据采集设备编写驱动程序/ API,该设备可以捕获多个"频道"数据的。为了便于讨论,我们假设这是一个多通道视频捕获设备。该设备通过8xPCIe Gen-1链路连接到系统,该链路的理论吞吐量为16Gbps。我们的实际数据速率约为2.8Gbps(约350MB /秒)。
由于数据速率要求,我们认为我们必须小心驱动程序/ API架构。我们已经实现了基于描述符的DMA机制和相关的驱动程序。例如,我们可以从设备启动256KB的DMA事务并成功完成。但是,在此实现中,我们只捕获内核驱动程序中的数据,然后丢弃它,我们根本不会将数据流式传输到用户空间。从本质上讲,这只是一个小型DMA测试实现。
我们认为我们必须将问题分为三个部分:1。内核驱动程序2.用户空间API 3.用户代码
采集设备在PCIe地址空间中有一个寄存器,用于指示是否有来自设备的任何通道的数据读取。因此,我们的内核驱动程序必须轮询该位向量。当内核驱动程序看到此位置位时,它会启动DMA事务。然而,用户应用程序不需要知道所有这些DMA事务和数据,直到整个数据块准备就绪(例如,假设设备为每个事务提供16行视频数据,但我们需要通知用户仅在整个视频帧准备就绪时)。我们只需要将整个帧传输到用户应用程序。
这是我们的第一次尝试:
以上所有方法都运行正常,但性能非常糟糕。我们只能达到约2MB /秒的传输速率。我们需要完全重写这一点,并且我们对任何建议或指针示例都持开放态度。
其他说明:
不幸的是,我们无法更改硬件设备中的任何内容。所以我们必须轮询数据就绪"数据就绪"位并根据该位启动DMA。
有些人建议将Infiniband驱动程序作为参考,但我们在该代码中完全丢失了。
答案 0 :(得分:0)
你现在可能已经过了这个,但如果不是,那就是我的2p。
您需要编写一个阻塞读取,为其提供大容量内存缓冲区。驱动程序读取操作(a)获取用户缓冲区的用户页面列表并将其锁定在内存中(get_user_pages
); (b)使用pci_map_sg
创建分散列表; (c)遍历清单(for_each_sg
); (d)对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,就像我假设您正在调用“描述符”一样。
卡现在有一个描述符列表,这些描述符对应于大用户缓冲区的物理总线地址。当数据到达卡时,它会将其直接写入用户空间,写入用户缓冲区,同时仍然阻止用户级读取。当它完成描述符列表时,卡必须能够中断,否则它是无用的。驱动程序响应中断并取消阻止用户级读取。
就是这样。当然,细节是令人讨厌的,并且记录不完整,但这应该是基本架构。如果你真的没有中断,你可以在内核中设置一个计时器来轮询完成传输,但如果它真的是一张自定义卡,你应该收回你的钱。