DMA与ISA和LPC设备
作者
Pierre Ossman drzeus@drzeus.cx
本文档描述了如何使用旧的ISA DMA控制器进行DMA传输。尽管ISA在今天已经基本淘汰,但LPC总线使用相同的DMA系统,因此它将在相当长的时间内存在。
头文件和依赖项
要进行ISA风格的DMA,您需要包括两个头文件:
#include <linux/dma-mapping.h>
#include <asm/dma.h>
第一个是用于将虚拟地址转换为总线地址的通用DMA API(有关详细信息,请参见使用通用设备进行动态DMA映射)。
第二个包含特定于ISA DMA传输的例程。由于这在所有平台上都不一定存在,请确保您构建的Kconfig依赖于ISA_DMA_API(而不是ISA),以便没有人尝试在不受支持的平台上构建您的驱动程序。
缓冲区分配
ISA DMA控制器对其可以访问的内存有一些非常严格的要求,因此在分配缓冲区时必须格外小心。
(通常,您需要为DMA传输分配一个特殊的缓冲区,而不是直接传输到您的常规数据结构中。)
可进行DMA的地址空间是“物理”内存的最低16 MB。此外,传输块不得跨页边界(这取决于您使用的通道,页边界为64或128 KiB)。
为了分配满足所有这些要求的内存块,您需要将标志GFP_DMA传递给kmalloc。
不幸的是,用于ISA DMA的内存是稀缺的,因此除非您在启动期间分配内存,否则最好也传递__GFP_RETRY_MAYFAIL和__GFP_NOWARN,以使分配器尝试更加努力。
(这种稀缺性也意味着您应尽可能早地分配缓冲区,并在驱动程序卸载之前不要释放它。)
地址转换
要将虚拟地址转换为总线地址,请使用通用DMA API。即使它执行相同的操作,请不要使用isa_virt_to_bus()。原因是函数isa_virt_to_bus()将需要对ISA的Kconfig依赖性,而不仅仅是ISA_DMA_API,这才是您真正需要的。请记住,即使DMA控制器起源于ISA,它也在其他地方使用。
注意:x86_64在涉及ISA时存在破损的DMA API,但已经修复。如果您的架构存在问题,请修复DMA API,而不是恢复到ISA函数。
通道
普通的ISA DMA控制器有8个通道。低四个用于8位传输,而高四个用于16位传输。
(实际上,DMA控制器实际上是两个独立的控制器,其中通道4用于为第二个控制器(0-3)提供DMA访问。这意味着在四个16位通道中,只有三个是可用的。)
您可以以与所有基本资源相似的方式分配这些通道:
extern int request_dma(unsigned int dmanr, const char * device_id);
extern void free_dma(unsigned int dmanr);
使用16位或8位传输的能力不取决于驱动程序作者,而取决于硬件支持。请检查您的规格或测试不同的通道。
传输数据
现在是有趣的部分,实际的DMA传输。
标签:DMA,控制器,驱动程序,dma,传输,ISA,LPC From: https://www.cnblogs.com/pengdonglin137/p/17891165.html