以高通camera 申请ion内存看dma-buf

本文深入解析DMA-BUF与IONBUFFER的工作原理,详细介绍了如何通过IONBUFFER和DMA-BUF实现内存缓冲区的管理和跨进程共享。文章涵盖IONBUFFER的分配、与DMA-BUF的绑定过程,以及FD与FILE的关联机制。

1 fd 与ion buffer, file绑定

    简单总结就是申请一个buffer,再创建一个dmabuf 结构体然后将,然后将dmabuf中得指针指向buffer,dmabuf 再传递给一个匿名的inode,获取到一个file,这样file和dmabuf绑定起来,也就和buffer关联上。然后再从进程中分配一个空闲的fd,将fd 和file囊绑定。这样就能通过fd 快速查找到buffer。file 是个全系统的,他和进程无关,但是fd 是每个进程都是自己独立的,所以再跨进程传输时只需要保证fd 和同一个file绑定就可以实现buffer的共享。

高通camera 申请ion buffer 并且smmu 映射是在cam_mem_mgr_alloc_and_map 函数种。

cam_mem_mgr_alloc_and_map->cam_mem_util_ion_alloc

 

cam_mem_util_ion_alloc 函数会返回dma-buf 和fd。确定分配得buffer 大小, 从哪个heap种分配,ion有很多heap。会调用

cam_mem_util_get_dma_buf_fd。

cam_mem_mgr_alloc_and_map->cam_mem_util_ion_alloc->cam_mem_util_get_dma_buf_fd

 

static int cam_mem_util_get_dma_buf_fd(size_t len,
	size_t align,
	unsigned int heap_id_mask,
	unsigned int flags,
	struct dma_buf **buf,
	int *fd)
{
	struct dma_buf *dmabuf = NULL;
	int rc = 0;

	if (!buf || !fd) {
		CAM_ERR(CAM_MEM, "Invalid params, buf=%pK, fd=%pK", buf, fd);
		return -EINVAL;
	}
        // 分配一个buffer  并且将buffer 与dma-buf 结构体绑定
	*buf = ion_alloc(len, heap_id_mask, flags);
	if (IS_ERR_OR_NULL(*buf))
		return -ENOMEM;
       /* 从当前进程种分配一个空闲得fd,注意这里是从进程得到fd,fd 关联得file file却不是
       *属于进程的,所以不能close 就万事大吉。close 是将fd重新放入进程得空闲数组种,file 
       *得索引值只是减1.file 如果索引值原本不是1,那么file 不会释放,分配得buffer就不会释放*/
	*fd = dma_buf_fd(*buf, O_CLOEXEC);
	if (*fd < 0) {
		CAM_ERR(CAM_MEM, "get fd fail, *fd=%d", *fd);
		rc = -EINVAL;
		goto get_fd_fail;
	}

	//dma_buf_get 是对前面分配得匿名file 索引值加1.因为分配得时候已经加1,
       //这里再加1 实际上所以值已经变为2
	dmabuf = dma_buf_get(*fd);
	if (IS_ERR_OR_NULL(dmabuf)) {
		CAM_ERR(CAM_MEM, "dma_buf_get failed, *fd=%d", *fd);
		rc = -EINVAL;
	}

	return rc;

get_fd_fail:
	dma_buf_put(*buf);// dma_buf_put 是与dma_buf_get相对得,就是将所以值再减去1
	return rc;
}

1.1获得一个ion buffer 和file

ion_

<think>我们正在处理一个关于将ION堆转换为DMA-BUF堆的问题。首先,我们需要理解IONDMA-BUF在Linux内核中的作用。ION是Android系统中用于内存管理的堆分配器,主要用于多媒体和图形处理。而DMA-BUF是Linux内核中用于跨设备共享内存缓冲区的机制,它提供了一个通用的框架,允许不同的设备驱动程序共享相同的物理内存区域。从Linux内核4.12版本开始,ION已被标记为弃用,并建议使用DMA-BUF堆作为替代。因此,将ION堆转换为DMA-BUF堆是为了遵循内核的发展方向,并利用DMA-BUF堆的标准化接口。实现转换的步骤大致如下:1.**理解DMA-BUF堆框架**:首先需要熟悉DMA-BUF堆的API和数据结构。DMA-BUF堆框架提供了一组标准的操作(如分配、释放、映射等),我们需要实现这些操作来管理堆内存。2.**识别ION堆的功能**:分析现有ION堆的功能,例如它分配的内存类型(如连续、非连续、带缓存等),以及它如何与设备驱动交互。3.**实现DMA-BUF堆分配器**:-创建一个新的DMA-BUF堆分配器,实现`structdma_heap_ops`中定义的回调函数,包括`allocate`函数。-在`allocate`函数中,需要分配物理内存,并创建一个`dma_buf`对象来管理这个内存区域。这通常涉及:-使用内核的内存分配函数(如`alloc_pages`、`dma_alloc_coherent`等)分配内存-创建一个`dma_buf`对象,并设置其操作函数(`structdma_buf_ops`),包括映射、取消映射、释放等。-根据ION堆的特性,可能需要实现特定的内存属性,例如连续内存(CMA)或非连续内存(使用scatter-gather列表)。4.**注册DMA-BUF堆**:使用`dma_heap_add`函数将新实现的堆注册到系统中。这样,用户空间就可以通过`/dev/dma_heap`目录访问这个堆。5.**用户空间接口**:用户空间通过打开`/dev/dma_heap/<heap_name>`,然后使用`DMA_HEAP_IOC_ALLOC`ioctl来分配缓冲区,得到一个DMA-BUF文件描述符。6.**迁移现有ION用户**:将原来使用ION的驱动或应用程序改为使用DMA-BUF堆。这可能涉及修改用户空间的库(如gralloc)和内核驱动程序。引用中提到的关键点:-引用[1]提到DMA映射API和IOMMU/CMA的使用,在实现DMA-BUF堆时,分配内存应使用DMA映射API(如`dma_alloc_coherent`),这样可以利用IOMMU或CMA来提供连续的物理内存视图。-引用[2]提到缓存一致性问题,在DMA-BUF实现中,需要提供同步机制(如`DMA_BUF_IOCTL_SYNC`)来管理CPU和设备之间的缓存一致性。-引用[3]提到DRM驱动中DMA-BUF的使用,可以作为参考实现。具体实现步骤示例(简化版):在内核模块中,首先定义一个堆操作结构:```cstaticconststructdma_heap_opsmy_heap_ops={.allocate=my_heap_allocate,};```然后实现`my_heap_allocate`函数:```cstaticintmy_heap_allocate(structdma_heap*heap,unsignedlonglen,unsignedlongfd_flags,unsignedlongheap_flags){//1.分配内存(例如使用CMA)structpage*page=dma_alloc_from_contiguous(dev,size,order,GFP_KERNEL);//或者使用其他方式分配内存//2.创建sg_table来描述内存sg_table=kmalloc(sizeof(*sg_table),GFP_KERNEL);sg_alloc_table(sg_table,1,GFP_KERNEL);sg_set_page(sg_table->sgl,page,size,0);//3.创建dma_bufexp_info=kzalloc(sizeof(*exp_info),GFP_KERNEL);exp_info->ops=&my_dma_buf_ops;exp_info->size=size;exp_info->sg_table=sg_table;dmabuf=dma_buf_export(exp_info);//4.为dma_buf创建文件描述符fd=dma_buf_fd(dmabuf,fd_flags);returnfd;}```同时,需要实现`structdma_buf_ops`中的函数,如`map_dma_buf`、`unmap_dma_buf`、`release`等。最后,注册堆:```cstructdma_heap_export_infoexp_info={.name="my_heap",.ops=&my_heap_ops,.priv=NULL,};dma_heap_add(&exp_info);```这样,用户空间就可以通过`/dev/dma_heap/my_heap`来分配缓冲区。注意:实际实现中需要处理错误情况、内存释放、缓存同步等问题。相关问题:1.DMA-BUF堆与ION堆的主要区别是什么?2.如何在内核中实现一个支持连续内存分配的DMA-BUF堆?3.用户空间如何使用DMA-BUF堆分配内存?4.在DMA-BUF堆中如何处理缓存一致性问题?</think>### 将 ION 堆转换为 DMA-BUF 堆的实现方法和步骤 #### **背景说明** ION 是 Android 特有的内存分配器,用于管理多媒体硬件(如 GPU、摄像头)的共享内存。而 DMA-BUF 是 Linux 内核标准的跨驱动内存共享框架。随着内核发展(4.12+),ION 已被标记为**弃用**,迁移到 DMA-BUF 堆成为官方推荐方案[^1][^3]。 --- ### **核心实现步骤** #### **1. 理解架构差异** - **ION 堆**:通过 `/dev/ion` 设备节点提供自定义堆(如 `system`、`carveout`)。 - **DMA-BUF 堆**:通过 `/dev/dma_heap/` 目录提供标准化堆(如 `cma`、`system`),基于 `dma_heap` 内核框架[^1][^3]。 #### **2. 实现 DMA-BUF 堆分配器** 需在内核中实现 `struct dma_heap_ops` 接口: ```c // 示例:连续内存分配器(CMA)实现 static const struct dma_heap_ops cma_heap_ops = { .allocate = cma_heap_allocate, // 核心分配函数 }; static int cma_heap_allocate(struct dma_heap *heap, unsigned long len, unsigned long fd_flags, unsigned long heap_flags) { // 1. 通过CMA分配物理连续内存 struct page *page = dma_alloc_from_contiguous(dev, size, order, GFP_KERNEL); // 2. 创建sg_table描述内存区域 sg_table = kmalloc(sizeof(*sg_table), GFP_KERNEL); sg_alloc_table(sg_table, 1, GFP_KERNEL); sg_set_page(sg_table->sgl, page, size, 0); // 3. 导出为DMA-BUF对象 exp_info = kzalloc(sizeof(*exp_info), GFP_KERNEL); exp_info->ops = &cma_heap_buf_ops; exp_info->size = size; exp_info->sg_table = sg_table; dmabuf = dma_buf_export(exp_info); // 4. 返回文件描述符 fd = dma_buf_fd(dmabuf, fd_flags); return fd; } ``` #### **3. 注册堆到内核** ```c struct dma_heap_export_info exp_info = { .name = "custom_cma", // 堆名称(用户空间可见) .ops = &cma_heap_ops, // 操作函数集 .priv = NULL // 私有数据 }; dma_heap_add(&exp_info); // 注册到/sys/class/dma_heap/ ``` #### **4. 用户空间访问** 用户程序通过标准接口分配内存: ```bash # 打开堆设备 fd = open("/dev/dma_heap/custom_cma", O_RDWR); # 分配DMA-BUF ioctl(fd, DMA_HEAP_IOC_ALLOC, &alloc_param); ``` 返回的 `fd` 即 DMA-BUF 文件描述符,可跨进程/驱动共享[^1][^3]。 --- ### **关键迁移注意事项** 1. **内存类型转换**: - ION 的 `ION_HEAP_TYPE_SYSTEM` → DMA-BUF 的 `system_heap` - ION 的 `ION_HEAP_TYPE_CARVEOUT` → 通过 `dma_alloc_coherent` 实现[^1] - ION 的 `ION_HEAP_TYPE_DMA` → 使用 `cma_heap` 或自定义 IOMMU 映射[^1] 2. **缓存一致性处理**: - 使用 `DMA_BUF_IOCTL_SYNC` ioctl 同步 CPU/设备缓存[^2] - 遵循序列:`SYNC_START → 读写内存 → SYNC_END`[^2] 3. **驱动适配**: -ION 客户端(如 GPU 驱动)需改用 `dma_buf_attach()`/`dma_buf_map_attachment()` - 替换 `ion_share_dma_buf_fd()` 为 `dma_buf_fd()`[^3] --- ### **性能优化建议** - **大页分配**:对 GPU/摄像头等大内存设备,使用 `order > 0` 的复合页降低TLB压力 - **CPU 绑定**:对延迟敏感任务,将进程绑定到大核(参考引用[4]的 CPU 调优)[^4] - **零拷贝**:利用 `mmap()` 直接访问 DMA-BUF,避免用户空间复制[^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值