我已经收集了一些组件(包括软件和硬件)的知识,这些组件涉及基于 ARM 的板中的一般 DMA 事务,但我不明白它是如何完美集成的,我没有找到完整的连贯性对此的描述。
我会写下我已经拥有的高水平知识,我希望有人能在我错的地方纠正我并完成缺失的部分,这样整个画面就会清楚。我的描述从用户空间软件开始,然后深入到硬件组件。被误解的部分采用斜体粗体格式。
- 用户模式应用程序请求从某个设备读取/写入,即进行 I/O 操作。
- 操作系统接收请求并将其交给适当的驱动程序(每个操作系统都有自己的机制来执行此操作,我不需要在这里进一步深入研究,但如果您想在这里分享见解,欢迎您)
- 负责处理 I/O 请求的驱动程序必须知道设备映射到的地址(因为我对基于 ARM 的板感兴趣,afaik 只有内存映射 I/O 而没有端口输入/输出)。在大多数情况下(如果我们考虑类似智能手机的板子),有一个 linux 内核从引导时从引导加载程序给出的设备树中解析设备地址(现代方法),或者 linux 是预编译的对于特定型号系列和电路板,其中包含设备地址(在其源代码中硬编码)(在较旧和过时的方法中)。在某些情况下(在智能手机中经常发生),部分驱动程序是预编译的,只是打包到内核中,即它们的源是封闭的,因此与设备对应的地址是未知的。这是对的吗?
- 鉴于驱动程序知道它要与之通信的设备的相关寄存器的地址,它会分配一个缓冲区(通常在内核空间中),设备将向其写入数据(在 DMA 的帮助下)。驱动程序需要通知设备该缓冲区的位置,但是设备使用(操作内存)的地址与驱动程序(cpu)使用的地址不同,因此,驱动程序需要通知设备关于它刚刚分配的缓冲区的“总线地址”。驱动程序如何通知设备该地址?使用 IOMMU 有多受欢迎?使用 IOMMU 时,是否有一个硬件组件管理寻址或每个设备一个?
- 然后驱动程序命令设备完成其工作(通过操作其寄存器),设备将输出数据直接传输到内存中分配的缓冲区。在这里,我对 device-driver:bus:bus-controller:actual-device 的关系有点困惑。以一些假想的设备为例,它知道以 I2C 协议进行通信;SoC 指定了一个 I2C 总线接口——这实际上是什么?I2C 总线是否有某种总线控制器?cpu是与I2C总线接口通信还是直接与设备通信?(即I2C 总线接口是无缝的)。我想对设备驱动程序有一定经验的人可以很容易地回答这个问题。
- 该设备填充一个 DMA 通道。由于设备没有直接连接到内存,而是通过一些总线连接到 DMA 控制器(控制总线),它与 DMA 交互以将所需的数据传输到内存中分配的缓冲区。当电路板供应商使用 ARM IP 内核和总线规范时,此步骤涉及通过 AMBA 规范(即 AHB/multi-AHB/AXI)的总线上的事务,以及设备和其上的 DMAC 之间的某些协议。我想了解更多关于这一步的信息,实际发生了什么?ARM的DMA控制器有很多规格,哪一种比较流行?哪个过时了?
- 当设备完成时,它发送一个中断,该中断通过中断控制器传送到操作系统,操作系统的中断处理程序将其引导到适当的驱动程序,该驱动程序现在知道 DMA 传输已完成。