linux内存管理 之 DMA

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)





















               

   

你可能感兴趣的:(linux驱动)