Memory management 数据采集设备的Linux驱动程序和API体系结构
我们正试图为一个定制的数据采集设备编写一个驱动程序/API,它可以捕获多个“通道”的数据。为了便于讨论,我们假设这是一个多通道视频捕获设备。该设备通过8xPCIe Gen-1链路连接到系统,理论吞吐量为16Gbps。我们的实际数据速率约为2.8Gbps(~350MB/秒) 由于数据速率的要求,我们认为必须小心驱动程序/API体系结构。我们已经实现了一个基于描述符的DMA机制和相关的驱动程序。例如,我们可以从设备启动一个256KB的DMA事务,并成功完成。然而,在这个实现中,我们只捕获内核驱动程序中的数据,然后删除它,而根本不将数据流传输到用户空间。本质上,这只是一个小型DMA测试实现 我们认为我们必须把这个问题分成三个部分:1。内核驱动程序2。用户空间API 3。用户代码 采集设备在PCIe地址空间中有一个寄存器,用于指示是否有任何通道的数据要从该设备读取。因此,我们的内核驱动程序必须轮询这个位向量。当内核驱动程序看到这个位集时,它启动一个DMA事务。然而,用户应用程序不需要知道所有这些DMA事务和数据,直到整个数据块准备就绪(例如,假设设备为我们提供每个事务16行视频数据,但我们只需要在整个视频帧准备就绪时通知用户)。我们只需要将整个帧传输到用户应用程序 这是我们的第一次尝试:Memory management 数据采集设备的Linux驱动程序和API体系结构,memory-management,linux-kernel,driver,linux-device-driver,dma,Memory Management,Linux Kernel,Driver,Linux Device Driver,Dma,我们正试图为一个定制的数据采集设备编写一个驱动程序/API,它可以捕获多个“通道”的数据。为了便于讨论,我们假设这是一个多通道视频捕获设备。该设备通过8xPCIe Gen-1链路连接到系统,理论吞吐量为16Gbps。我们的实际数据速率约为2.8Gbps(~350MB/秒) 由于数据速率的要求,我们认为必须小心驱动程序/API体系结构。我们已经实现了一个基于描述符的DMA机制和相关的驱动程序。例如,我们可以从设备启动一个256KB的DMA事务,并成功完成。然而,在这个实现中,我们只捕获内核驱动程序
- 不幸的是,我们无法更改硬件设备中的任何内容。因此,我们必须轮询“数据就绪”位,并基于该位启动DMA
- 有些人建议将Infiniband驱动程序作为参考,但我们完全迷失在这段代码中
- 很难相信你的卡在使用时不会产生中断 它已经传输了数据。它有一个DMA引擎,可以处理 “描述符”,可能是分散-聚集的元素 列表我假设它可以生成PCIe“中断”;YMMV
- 不要费心在内核中搜寻现有的类似驱动程序。你 也许会走运,但我怀疑不会 您需要编写一个块读,为其提供一个大的内存缓冲区。驱动程序read op(a)获取用户缓冲区的用户页面列表,并将其锁定在内存中(
- 你现在可能已经过了这一关,但如果不是的话,这是我的2p
get_user_pages
);(b) 使用pci_map_sg
创建散点列表;(c) 在列表中迭代(用于每个\u sg
);(d) 对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,我认为这就是所谓的“描述符”
该卡现在有一个描述符列表,对应于大用户缓冲区的物理总线地址。当数据到达卡时,它会将数据直接写入用户空间,写入用户缓冲区,而用户级读取仍然被阻止。当它完成描述符列表时,卡必须能够中断,否则它就没用了。驱动程序响应中断并取消阻止用户级读取
就这样。当然,细节是令人讨厌的,文档记录也很差,但这应该是基本的架构。如果你真的没有中断,你可以在内核中设置一个计时器来轮询转账的完成情况,但是如果它真的是一张定制卡,你应该拿回你的钱。你现在可能已经过了这一关,但如果不是的话,这是我的2p
get_user_pages
);(b) 使用pci_map_sg
创建散点列表;(c) 在列表中迭代(用于每个\u sg
);(d) 对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,我认为这就是所谓的“描述符”
这张卡片现在有一个描述符列表