一致性DMA映射演示

使用 dma_alloc_coherent 分配DMA缓冲区并导出到用户空间

概述

在本章节中,我们将学习如何在Linux内核驱动中使用一致性DMA映射。通过dma_alloc_coherent函数,我们可以分配一段DMA缓冲区,并将其内容导出到用户空间供查看。一致性DMA映射确保CPU和DMA设备可以看到一致的内存视图,无需软件缓存同步。

用户空间 内核空间 DMA设备 系统调用 DMA传输 DMA缓冲区 dma_alloc_coherent

关键概念

函数和数据结构

函数/结构 描述
dma_alloc_coherent 分配一致性DMA内存,返回虚拟和物理地址。
dma_free_coherent 释放由dma_alloc_coherent分配的内存。
mmap 将内核内存映射到用户空间。
struct file_operations 定义设备文件操作的结构体。

代码示例

以下是一个简单的内核驱动示例,演示如何使用dma_alloc_coherent分配DMA缓冲区,并通过mmap将其导出到用户空间。

驱动代码片段

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/dma-mapping.h>

#define DEVICE_NAME "dma_demo"
#define DMA_BUF_SIZE 4096

static void *dma_vaddr;
static dma_addr_t dma_paddr;
static struct device *dev;

static int dma_mmap(struct file *filp, struct vm_area_struct *vma)
{
    return dma_mmap_coherent(dev, vma, dma_vaddr, dma_paddr, DMA_BUF_SIZE);
}

static struct file_operations fops = {
    .mmap = dma_mmap,
};

static int __init dma_init(void)
{
    dev = &pdev->dev; // 假设pdev是平台设备
    dma_vaddr = dma_alloc_coherent(dev, DMA_BUF_SIZE, &dma_paddr, GFP_KERNEL);
    if (!dma_vaddr) {
        return -ENOMEM;
    }
    // 初始化DMA缓冲区内容
    memset(dma_vaddr, 0xAB, DMA_BUF_SIZE);
    // 注册设备等操作...
    return 0;
}

static void __exit dma_exit(void)
{
    dma_free_coherent(dev, DMA_BUF_SIZE, dma_vaddr, dma_paddr);
}

module_init(dma_init);
module_exit(dma_exit);
MODULE_LICENSE("GPL");
注意: 实际代码中需要处理错误检查、设备注册等细节。以上代码仅为演示核心概念。

用户空间访问

在用户空间,可以通过mmap系统调用将DMA缓冲区映射到进程的地址空间,然后直接访问其内容。

用户空间测试程序

#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <unistd.h>

#define DMA_DEV "/dev/dma_demo"
#define BUF_SIZE 4096

int main()
{
    int fd = open(DMA_DEV, O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    void *addr = mmap(NULL, BUF_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (addr == MAP_FAILED) {
        perror("mmap");
        close(fd);
        return -1;
    }

    // 读取并打印DMA缓冲区的前16字节
    printf("DMA Buffer content: ");
    for (int i = 0; i < 16; i++) {
        printf("%02X ", ((unsigned char *)addr)[i]);
    }
    printf("\n");

    munmap(addr, BUF_SIZE);
    close(fd);
    return 0;
}

总结

通过本章的学习,我们掌握了如何使用dma_alloc_coherent分配一致性DMA缓冲区,并通过mmap将其导出到用户空间。这种方法在需要高效DMA传输的应用中非常有用,如网络包处理、音频视频流处理等。

  1. 一致性DMA映射简化了内存管理,无需显式缓存同步。
  2. dma_alloc_coherent返回的物理地址可直接用于DMA设备。
  3. 通过mmap将DMA缓冲区导出到用户空间,允许用户程序直接访问。