Memory management 数据采集设备的Linux驱动程序和API体系结构

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事务,并成功完成。然而,在这个实现中,我们只捕获内核驱动程序

我们正试图为一个定制的数据采集设备编写一个驱动程序/API,它可以捕获多个“通道”的数据。为了便于讨论,我们假设这是一个多通道视频捕获设备。该设备通过8xPCIe Gen-1链路连接到系统,理论吞吐量为16Gbps。我们的实际数据速率约为2.8Gbps(~350MB/秒)

由于数据速率的要求,我们认为必须小心驱动程序/API体系结构。我们已经实现了一个基于描述符的DMA机制和相关的驱动程序。例如,我们可以从设备启动一个256KB的DMA事务,并成功完成。然而,在这个实现中,我们只捕获内核驱动程序中的数据,然后删除它,而根本不将数据流传输到用户空间。本质上,这只是一个小型DMA测试实现

我们认为我们必须把这个问题分成三个部分:1。内核驱动程序2。用户空间API 3。用户代码

采集设备在PCIe地址空间中有一个寄存器,用于指示是否有任何通道的数据要从该设备读取。因此,我们的内核驱动程序必须轮询这个位向量。当内核驱动程序看到这个位集时,它启动一个DMA事务。然而,用户应用程序不需要知道所有这些DMA事务和数据,直到整个数据块准备就绪(例如,假设设备为我们提供每个事务16行视频数据,但我们只需要在整个视频帧准备就绪时通知用户)。我们只需要将整个帧传输到用户应用程序

这是我们的第一次尝试:

  • 我们的用户端API允许用户应用程序为“通道”注册函数回调
  • 用户端API有一个“start”函数,用户应用程序可以调用该函数,它使用ioctl向内核驱动程序发送启动消息
  • 在内核驱动程序中,在收到启动消息后,我们启动了一个内核线程,该线程持续监视“数据就绪”位向量,当它看到新数据时,将其复制到驱动程序分配的(kmalloc)缓冲区。它一直这样做,直到收集的数据的大小达到“帧大小”
  • 此时,一个定制的linux信号(类似于SIGINT、SIGHUP等)被发送到运行驱动程序的进程。我们的API捕捉到这个信号,然后调用相应的用户回调函数
  • 用户回调函数调用API(transfer_data)中的函数,该函数使用ioctl调用向内核发送用户空间缓冲区地址,内核通过将通道帧数据复制到用户空间来完成数据传输
  • 除了性能糟糕之外,以上所有功能都正常工作。我们只能实现大约2MB/秒的传输速率。我们需要完全重写这篇文章,我们愿意接受任何建议或示例指针

    其他说明:

    • 不幸的是,我们无法更改硬件设备中的任何内容。因此,我们必须轮询“数据就绪”位,并基于该位启动DMA

    • 有些人建议将Infiniband驱动程序作为参考,但我们完全迷失在这段代码中


      • 你现在可能已经过了这一关,但如果不是的话,这是我的2p

      • 很难相信你的卡在使用时不会产生中断 它已经传输了数据。它有一个DMA引擎,可以处理 “描述符”,可能是分散-聚集的元素 列表我假设它可以生成PCIe“中断”;YMMV
      • 不要费心在内核中搜寻现有的类似驱动程序。你 也许会走运,但我怀疑不会
      • 您需要编写一个块读,为其提供一个大的内存缓冲区。驱动程序read op(a)获取用户缓冲区的用户页面列表,并将其锁定在内存中(
        get_user_pages
        );(b) 使用
        pci_map_sg
        创建散点列表;(c) 在列表中迭代(
        用于每个\u sg
        );(d) 对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,我认为这就是所谓的“描述符”

        该卡现在有一个描述符列表,对应于大用户缓冲区的物理总线地址。当数据到达卡时,它会将数据直接写入用户空间,写入用户缓冲区,而用户级读取仍然被阻止。当它完成描述符列表时,卡必须能够中断,否则它就没用了。驱动程序响应中断并取消阻止用户级读取


        就这样。当然,细节是令人讨厌的,文档记录也很差,但这应该是基本的架构。如果你真的没有中断,你可以在内核中设置一个计时器来轮询转账的完成情况,但是如果它真的是一张定制卡,你应该拿回你的钱。

        你现在可能已经过了这一关,但如果不是的话,这是我的2p

      • 很难相信你的卡在使用时不会产生中断 它已经传输了数据。它有一个DMA引擎,可以处理 “描述符”,可能是分散-聚集的元素 列表我假设它可以生成PCIe“中断”;YMMV
      • 不要费心在内核中搜寻现有的类似驱动程序。你 也许会走运,但我怀疑不会
      • 您需要编写一个块读,为其提供一个大的内存缓冲区。驱动程序read op(a)获取用户缓冲区的用户页面列表,并将其锁定在内存中(
        get_user_pages
        );(b) 使用
        pci_map_sg
        创建散点列表;(c) 在列表中迭代(
        用于每个\u sg
        );(d) 对于每个条目,将相应的物理总线地址和数据长度写入DMA控制器,我认为这就是所谓的“描述符”

        这张卡片现在有一个描述符列表