1、DMA:直接内存访问
用于在主存贮器和设备内存之间的大量数据的交换,无须CPU参与,可以提高系统效率。
2、内核中的DMA层
struct dma_map_ops {
____void* (*alloc_coherent)(struct device *dev, size_t size,
________________dma_addr_t *dma_handle, gfp_t gfp);
____void (*free_coherent)(struct device *dev, size_t size,
____________ void *vaddr, dma_addr_t dma_handle);
____dma_addr_t (*map_page)(struct device *dev, struct page *page,
____________ unsigned long offset, size_t size,
____________ enum dma_data_direction dir,
____________ struct dma_attrs *attrs);
____void (*unmap_page)(struct device *dev, dma_addr_t dma_handle,
____________ size_t size, enum dma_data_direction dir,
____________ struct dma_attrs *attrs);
____int (*map_sg)(struct device *dev, struct scatterlist *sg,
________ int nents, enum dma_data_direction dir,
________ struct dma_attrs *attrs);
____void (*unmap_sg)(struct device *dev,
____________ struct scatterlist *sg, int nents,
____________ enum dma_data_direction dir,
____________ struct dma_attrs *attrs);
____void (*sync_single_for_cpu)(struct device *dev,
________________ dma_addr_t dma_handle, size_t size,
________________ enum dma_data_direction dir);
____void (*sync_single_for_device)(struct device *dev,
________________ dma_addr_t dma_handle, size_t size,
________________ enum dma_data_direction dir);
____void (*sync_sg_for_cpu)(struct device *dev,
________________struct scatterlist *sg, int nents,
________________enum dma_data_direction dir);
____void (*sync_sg_for_device)(struct device *dev,
________________ struct scatterlist *sg, int nents,
________________ enum dma_data_direction dir);
____int (*mapping_error)(struct device *dev, dma_addr_t dma_addr);
____int (*dma_supported)(struct device *dev, u64 mask);
____int (*set_dma_mask)(struct device *dev, u64 mask);
____int is_phys;
};
3、DMA的地址
dma_addr_t
4、dma_set_mask
查询DMA寻址范围
5、DMA映射
a、一致性DMA映射
static inline void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t gfp)
void dma_free_coherent(struct evice *dev, size_t size, void *vaddr, dma_addr_t bus)
分配一组连续的物理页面,适合于驱动程序自己分配,自己释放的DMA操作。
b、流式DMA映射
dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir);
使用于不是由驱动程序自己分配的DMA区域。
建立DMA映射的关键点有两个:一是确保CPU侧的虚拟地址所对应的物理地址能够被设备DMA正确访问,二是确保cache一致性问题。
如果第一点不满足,可用回弹缓冲区解决。
第二点可用struct dma_map_ops函数来处理:sync_single_for_cpu
sync_single_for_device
sync_sg_for_cpu
sync_sg_for_device
c、分散/聚集映射
struct scatterlist {
unsigned long page_link;
unsigned intoffset;
unsigned intlength;
dma_addr_t dma_address;
unsigned intdma_length;
}
int dma_map_sg(strut device *dev, struct scatterlist *sg, int nents, enum dma_data_direction dir)
d、回弹缓冲区
CPU侧俄虚拟地址对应的物理地址不适合设备的DMA操作,需要建立回弹缓冲区。
e、DMA池
一致性DMA映射只能映射页面的整数倍的DMA缓冲区,如果需要更小的DMA缓冲区,则要在DMA一致性映射的基础上的DMA池机制。
在DMA一致性映射基础上,将页面分成块大小的DMA缓冲区。
struct dma_pool {
struct list_head page_list;
spinlock_t lock;
size_t size;
struct device *dev;
size_t allocation;
size_t boundary;
char name[32];
wait_queue_head_t waitq;
struct list_head pools;
}
DMA池的建立:struct dma_pool *dma_pool_create(const char *name, struct device *dev, size_t size, size_t align,size_t boundary)
DMA池的销毁:void dma_pool_destroy(struct dma_pool *pool)
DMA缓冲块的分配:void *dma_pool_alloc(struct dma_pool *pool, gfp_t mem_flags, dma_addr_t *handle)
DMA缓冲块的释放:void dma_pool_free(struct dma_pool *pool, void *vaddr_t addr)