dma_alloc_coherent 和 dma_map_single 的区别
dma_alloc_coherent 和 dma_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 传输,数据使用完即释放。
- 需要映射
kmalloc或vmalloc申请的内存用于 DMA。
总结:
- 短期传输:
kmalloc+dma_map_single+dma_unmap_single - 长期共享:
dma_alloc_coherent+dma_free_coherent


浙公网安备 33010602011771号