1. 几种地址类型
虚拟地址
Linux内核使用的地址是虚拟地址,数据类型为void *。例如,kmalloc()和vmalloc()函数返回值就是虚拟地址。
物理地址
处理器真实地址总线上的地址,数据类型为phys_addr_t。
对I/O设备寄存器和内存统一编址的处理器,如ARM/PowerPC,参考手册一般会给出memory map,也就是各种I/O设备的寄存器在物理地址空间的分布。对I/O设备寄存器独立编址的处理器。如X86,访问I/O设备寄存器或内存时,向地址总线发送地址,并通过控制信号来实现对I/O设备寄存器和内存的不同寻址。这些I/O设备寄存器的地址可以在/proc/iomem中查看,必须使用ioremap()映射到虚拟地址空间才可以使用。
总线地址
从I/O设备的角度看,I/O设备使用的地址是总线地址。DMA使用地址也是总线地址,数据类型为dma_addr_t。对一些简单的系统,设备通过DMA可以直接访问物理地址,但大多数系统都有IOMMU将总线地址转换为物理地址。
2. DMA寻址能力
默认情况下Linux认为设备DMA可以进行32位寻址。必须对DMA mask进行设置,将设备的DMA寻址能力通知内核。
int dma_set_mask_and_coherent(struct device *dev, u64 mask)
该函数也可以分为如下两个函数,如果有需要,可以分别对流式映射设置DMA mask,对一致性分配设置DMA mask。
int dma_set_mask(struct device *dev, u64 mask);
int dma_set_coherent_mask(struct dev