Fork me on GitHub
侧边栏

dma_alloc_coherent 和 dma_map_single 的区别

dma_alloc_coherentdma_map_single 的主要区别在于 内存分配方式、地址一致性适用场景


1. dma_alloc_coherent

特点:

  • 分配并映射 一个 DMA 兼容的缓冲区。
  • 返回的 CPU 地址和 DMA 地址 一致性(coherent),即 CPU 和设备对该区域的访问始终保持同步,不需要额外的缓存同步操作。
  • 分配的内存通常来自 DMA 兼容区(如 dma_direct_alloc),不会是高地址的不可访问区域。
  • 适用于 设备会持续访问的缓冲区,例如环形缓冲区(ring buffer)、共享内存(shared buffer)。

使用方式:

void *cpu_addr;
dma_addr_t dma_handle;

cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, GFP_KERNEL);
if (!cpu_addr) {
    dev_err(dev, "Failed to allocate DMA buffer\n");
    return -ENOMEM;
}

// 设备和 CPU 可以直接访问 cpu_addr,数据总是同步的

// 使用完成后释放
dma_free_coherent(dev, size, cpu_addr, dma_handle);

2. dma_map_single

特点:

  • 仅映射 现有的 CPU 地址(如 kmalloc 分配的地址)。
  • 可能需要调用 dma_sync_single_for_{cpu|device} 进行缓存同步,因为 CPU 和设备的视图可能不同步(非一致性)。
  • 适用于 临时传输 的数据缓冲区,而不是长时间共享的内存。
  • 需要 手动释放映射dma_unmap_single)。

使用方式:

void *cpu_addr = kmalloc(size, GFP_KERNEL);
dma_addr_t dma_handle;

if (!cpu_addr)
    return -ENOMEM;

// DMA 映射
dma_handle = dma_map_single(dev, cpu_addr, size, DMA_TO_DEVICE);
if (dma_mapping_error(dev, dma_handle)) {
    dev_err(dev, "DMA mapping failed\n");
    kfree(cpu_addr);
    return -EIO;
}

// 设备可以访问 dma_handle 指向的地址

// 传输完成后,解除映射
dma_unmap_single(dev, dma_handle, size, DMA_TO_DEVICE);

// 释放 CPU 端的缓冲区
kfree(cpu_addr);

3. 主要区别对比

dma_alloc_coherent dma_map_single
作用 分配并映射 DMA 兼容的内存 仅映射已有的 CPU 内存
缓存一致性 一致性内存(不需要 dma_sync 可能是非一致性内存,需要 dma_sync
适用场景 长时间存在的共享缓冲区 临时传输数据的缓冲区
释放方式 dma_free_coherent dma_unmap_single + kfree

何时用 dma_alloc_coherent

  • 设备和 CPU 长期共享 该缓冲区,如 DMA ring buffer。
  • 需要避免 CPU 和设备缓存不一致问题(无需 dma_sync)。

何时用 dma_map_single

  • 只进行 短时间的 DMA 传输,数据使用完即释放。
  • 需要映射 kmallocvmalloc 申请的内存用于 DMA。

总结:

  • 短期传输kmalloc + dma_map_single + dma_unmap_single
  • 长期共享dma_alloc_coherent + dma_free_coherent
posted @ 2025-03-16 20:20  yooooooo  阅读(960)  评论(0)    收藏  举报