[英]Linux Driver and API architecture for a data acquisition device
我们正在尝试为自定义数据获取设备编写驱动程序/ API,该设备可捕获多个数据“通道”。 为了便于讨论,我们假设这是一个多通道视频捕获设备。 该设备通过8xPCIe Gen-1链路连接到系统,其理论吞吐量为16Gbps。 我们的实际数据速率约为2.8Gbps(〜350MB /秒)。
由于数据速率要求,我们认为我们必须对驱动程序/ API体系结构保持谨慎。 我们已经实现了基于描述符的DMA机制和相关的驱动程序。 例如,我们可以从设备启动一个256KB的DMA事务,该事务成功完成。 但是,在此实现中,我们仅在内核驱动程序中捕获数据,然后将其删除,并且根本不将数据流传输到用户空间。 本质上,这只是一个小的DMA测试实现。
我们认为我们必须将问题分为三个部分:1.内核驱动程序2.用户空间API 3.用户代码
采集设备在PCIe地址空间中有一个寄存器,该寄存器指示是否有数据要从该设备的任何通道读取。 因此,我们的内核驱动程序必须轮询此位向量。 当内核驱动程序看到该位置1时,它将启动DMA事务。 但是,在准备好整个数据块之前,用户应用程序不需要了解所有这些DMA事务和数据(例如,假定该设备每个事务为我们提供16行视频数据,但是我们需要通知仅当整个视频帧就绪时才可以使用)。 我们只需要将整个帧传输到用户应用程序。
这是我们的首次尝试:
上面的所有方法都可以正常工作,只是性能很差。 我们只能达到大约2MB /秒的传输速率。 我们需要完全重写它,我们对任何建议或示例指针都持开放态度。
其他说明:
不幸的是,我们无法更改硬件设备中的任何内容。 因此,我们必须轮询“数据就绪”位并基于该位启动DMA。
有人建议参考Infiniband驱动程序作为参考,但是我们完全不了解该代码。
您现在可能已经过去了,但如果没有,这是我的2分。
您需要写一个阻塞读取,您将为其提供大的内存缓冲区。 读取操作op(a)的驱动程序获取用户缓冲区的用户页面列表,并将其锁定在内存中( get_user_pages
); (b)使用pci_map_sg
创建一个分散列表; (c)遍历列表( for_each_sg
); (d)对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,就像我假设您所说的“描述符”一样。
该卡现在具有一个描述符列表,这些描述符与大型用户缓冲区的物理总线地址相对应。 当数据到达卡时,它将数据直接写到用户空间,用户缓冲区中,而用户级别的读取仍被阻止。 完成描述符列表后,该卡必须能够中断,否则就没用了。 驱动程序响应该中断并取消阻止您的用户级读取。
就是这样。 当然,这些细节是令人讨厌的,并且文档记录很少,但这应该是基本的体系结构。 如果您确实没有中断,则可以在内核中设置一个计时器以轮询传输是否完成,但是如果它确实是定制卡,则应该退还您的钱。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.