内存分配之DMA操作

编程知识 行业动态 更新时间:2024-06-13 00:19:09

DMA操作

DMA内存分配有两种方式,一致性DMA和流式DMA,在早期的内存区域中有一个DMA ZONE,占用内存地址0至16M的空间,供ISA设备的DMA内存,现在有的设备DMA操作时没有地址的限制,可以在全内存范围内分配内存来用于DMA操作,所以也就不需要DMA ZONE了。

\linux-4.12.4\include\linux

static inline void *dma_alloc_coherent(struct device *dev, size_t size,dma_addr_t *dma_handle, gfp_t flag)

#define dma_unmap_single(d, a, s, r) dma_unmap_single_attrs(d, a, s, r, 0)

#define dma_map_sg(d, s, n, r) dma_map_sg_attrs(d, s, n, r, 0)

#define dma_unmap_sg(d, s, n, r) dma_unmap_sg_attrs(d, s, n, r, 0)

#define dma_map_page(d, p, o, s, r) dma_map_page_attrs(d, p, o, s, r, 0)

#define dma_unmap_page(d, a, s, r) dma_unmap_page_attrs(d, a, s, r, 0)

以上接口函数对应DMA操作函数结构体:

const struct dma_map_ops arm_dma_ops = {

//一致性DMA

.alloc = arm_dma_alloc,//在该结构中此处分配出来的内存是 uncache的。

.free = arm_dma_free,

.mmap = arm_dma_mmap,  //与.alloc配合使用,将地址映射到用户空间

//流式DMA,分配内存区域在目前ARM平台上可以是任何区域

.get_sgtable = arm_dma_get_sgtable,

.map_page = arm_dma_map_page,  //将kmalloc分配的地址映射出DMA地址,即物理地址

.unmap_page = arm_dma_unmap_page,

.map_sg = arm_dma_map_sg, //该函数其实是内部封装了map_page

.unmap_sg = arm_dma_unmap_sg,//对流式DMA映射的页PG_dcache_clean,表示没有进行cache同步,如果使用cache要重新进行同步

.sync_single_for_cpu = arm_dma_sync_single_for_cpu,

.sync_single_for_device = arm_dma_sync_single_for_device,

.sync_sg_for_cpu = arm_dma_sync_sg_for_cpu,

.sync_sg_for_device = arm_dma_sync_sg_for_device,

};

//以下是硬件实现了内存和cache的一致性,coherent,是由硬件支持的,具体解释如下文:

const struct dma_map_ops arm_coherent_dma_ops = {

.alloc = arm_coherent_dma_alloc,

.free = arm_coherent_dma_free,

.mmap = arm_coherent_dma_mmap,

.get_sgtable = arm_dma_get_sgtable,

.map_page = arm_coherent_dma_map_page,

.map_sg = arm_dma_map_sg,

};

/

static void *arm_coherent_dma_alloc(struct device *dev, size_t size,

dma_addr_t *handle, gfp_t gfp, unsigned long attrs)

{

return __dma_alloc(dev, size, handle, gfp, PAGE_KERNEL, true,

   attrs, __builtin_return_address(0));

}

 

void *arm_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,

    gfp_t gfp, unsigned long attrs)

{

pgprot_t prot = __get_dma_pgprot(attrs, PAGE_KERNEL);

 

return __dma_alloc(dev, size, handle, gfp, prot, false,

   attrs, __builtin_return_address(0));

}

比较两个函数调用__dma_alloc的区别只有一个参数的区别:

static void *__dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,

 gfp_t gfp, pgprot_t prot, bool is_coherent,

 unsigned long attrs, const void *caller)

 

struct arm_dma_alloc_args args = {

.dev = dev,

.size = PAGE_ALIGN(size),

.gfp = gfp,

.prot = prot,

.caller = caller,

.want_vaddr = ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) == 0),

.coherent_flag = is_coherent ? COHERENT : NORMAL,

};

 

static void *cma_allocator_alloc(struct arm_dma_alloc_args *args,

 struct page **ret_page)

{

return __alloc_from_contiguous(args->dev, args->size, args->prot,

       ret_page, args->caller,

       args->want_vaddr, args->coherent_flag,

       args->gfp);

}

/

static void *__alloc_from_contiguous(struct device *dev, size_t size,

     pgprot_t prot, struct page **ret_page,

     const void *caller, bool want_vaddr,

     int coherent_flag, gfp_t gfp)

{

unsigned long order = get_order(size);

size_t count = size >> PAGE_SHIFT;

struct page *page;

void *ptr = NULL;

 

page = dma_alloc_from_contiguous(dev, count, order, gfp);

if (!page)

return NULL;

 

__dma_clear_buffer(page, size, coherent_flag);

 

}

更多推荐

内存分配之DMA操作

本文发布于:2023-03-27 22:19:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/489bfde4a28e50a4fcfd151d36af1e88.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:分配   内存   操作   DMA

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!