一.概述

传输过程:sensor->csiphy->dma

平台通过DMA获取从sensor中输出的数据,存放于通过ION分配的内存中。

二.DMA

1. 概念

DMA 传输将数据从一个地址空间复制到另外一个地址空间,不需要cpu介入,这时cup可以处理其他工作。

上面说道DMA把数据放到ION分配的内存中,ION分配的内存,虚拟地址是连续的,可是映射到的物理地址是不连续的,但是DMA操作的物理地址必须是连续的,所以需要使用scatterlist。

ps:这里说的scatterlist,说的是用聚散表管理的内存,就是把一段物理上不连续的内存用链表串起来。CPU看到的内存可以通过MMU做映射,一段连续的虚拟内存可以被映射到不连续的物理内存上, 显然这里是不需要scatterlist这个概念支持的。

2. API函数介绍:

使用DMA需要有exporter 以及 importer ,可以理解为生成者,消费者。在qcom平台新架构中,ION就是生产者,user就是消费者。

1)struct dma_buf * dma_buf_export(void *priv, struct dma_buf_ops *ops,size_t size, int flags)

该函数返回 dma_buf 类型的结构体指针。同时还会创建一个匿名文件绑定在该缓冲区上,因此这个缓冲区可以由其他消费者共享了(实际上此时缓冲区可能并未真正创建,这里只是创建了一个抽象的dma_buf)

在qcom平台此时buffer已经通过ION被创建。

2)int dma_buf_fd(struct dma_buf *dmabuf)

用户程序请求一个文件描述符(fd),该文件描述符指向和缓冲区关联的匿名文件。用户程序可以将文件描述符共享给驱动程序或者用户进程程序。

现在每个消费者可以通过文件描述符fd获取共享缓冲区的引用。

3)struct dma_buf * dma_buf_get(int fd)

该函数返回一个dma_buf的引用,同时增加它的refcount(该值记录着dma_buf被多少消费者引用)。

获取缓冲区应用后,消费者需要将它的设备附着在该缓冲区上,这样可以让生产者知道设备的寻址限制。

4)struct dma_buf_attachment * dma_buf_attach(struct dma_buf *dmabuf, struct device*dev)

该函数返回一个attachment的数据结构,该结构会用于scatterlist的操作。

dma-buf共享框架有一个记录位图,用于管理附着在该共享缓冲区上的消费者。

到这步为止,生产者可以选择不在实际的存储设备上分配该缓冲区,而是等待第一个消费者申请共享内存。

当消费者想要使用共享内存进行DMA操作,那么它就会通过接口dma_buf_map_attachment来访问缓冲区。在调用map_dma_buf前至少有一个消费者与之关联。

5)struct sg_table *  dma_buf_map_attachment(struct dma_buf_attachment *, enumdma_data_direction);

该函数是dma_buf->ops->map_dma_buf的一个封装,它可以对使用该接口的对象隐藏"dma_buf->ops->"

 struct sg_table * 
(*
map_dma_buf)(struct dma_buf_attachment *, enumdma_data_direction);

生产者必须实现该函数。它返回一个映射到调用者地址空间的sg_table,该数据结构包含了缓冲区的scatterlist。

如果第一次调用该函数,生产者现在可以扫描附着在共享缓冲区上的消费者,核实附着设备的请求,为缓冲区选择一个合适的物理存储空间。

基于枚举类型dma_data_direction,多个消费者可能同时访问共享内存(比如读操作)。

如果被一个信号中断,map_dma_buf()可能返回-EINTR。

API部分摘自 https://blog.csdn.net/prike/article/details/72874879

三.ION

为什么要使用ION?

为了节省开销,以及不必要的拷贝。通过ION分配的内存,调用ion_share_dma_buf_fd函数得到关联到全局可见的文件描述符fd,在不同的进程中mmap此fd,可以得到此进程中指向此物理的的虚拟地址。

四.代码分析

1. alloc buf

1)int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd) 函数分析

int cam_mem_mgr_alloc_and_map(struct cam_mem_mgr_alloc_cmd *cmd)
{........rc = cam_mem_util_ion_alloc(cmd, // 进入此函数,alloc  buf 以及 share fd,请看下面分析&ion_hdl,&ion_fd);if (rc) {CAM_ERR(CAM_CRM, "Ion allocation failed");return rc;}idx = cam_mem_get_slot();if (idx < 0) {rc = -ENOMEM;goto slot_fail;}if ((cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE) ||(cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS) ||(cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)) {enum cam_smmu_region_id region;if (cmd->flags & CAM_MEM_FLAG_HW_READ_WRITE)region = CAM_SMMU_REGION_IO;if (cmd->flags & CAM_MEM_FLAG_HW_SHARED_ACCESS)region = CAM_SMMU_REGION_SHARED;rc = cam_mem_util_map_hw_va(cmd->flags, // 请看 cam_mem_util_map_hw_va 分析cmd->mmu_hdls,cmd->num_hdl,ion_fd,&hw_vaddr,&len,region);if (rc)goto map_hw_fail;}mutex_lock(&tbl.bufq[idx].q_lock);tbl.bufq[idx].fd = ion_fd; // cam_mem_util_ion_alloc 返回的 share fd tbl.bufq[idx].dma_buf = NULL;tbl.bufq[idx].flags = cmd->flags;tbl.bufq[idx].buf_handle = GET_MEM_HANDLE(idx, ion_fd);// 通过一些计算得到buf handle,qcom自己搞的玩意if (cmd->flags & CAM_MEM_FLAG_PROTECTED_MODE)CAM_MEM_MGR_SET_SECURE_HDL(tbl.bufq[idx].buf_handle, true);tbl.bufq[idx].kmdvaddr = 0;if (cmd->num_hdl > 0)tbl.bufq[idx].vaddr = hw_vaddr;elsetbl.bufq[idx].vaddr = 0;tbl.bufq[idx].i_hdl = ion_hdl; // ion alloc 返回的ion handletbl.bufq[idx].len = cmd->len;tbl.bufq[idx].num_hdl = cmd->num_hdl;memcpy(tbl.bufq[idx].hdls, cmd->mmu_hdls,sizeof(int32_t) * cmd->num_hdl);tbl.bufq[idx].is_imported = false;mutex_unlock(&tbl.bufq[idx].q_lock);cmd->out.buf_handle = tbl.bufq[idx].buf_handle; // Qcom buf handlecmd->out.fd = tbl.bufq[idx].fd; // cam_mem_util_ion_alloc 返回的 share fd ,cmd 后面会被传回hal层,之后的map buf 操作就是传递此fd到kernelcmd->out.vaddr = 0;CAM_DBG(CAM_CRM, "buf handle: %x, fd: %d, len: %zu",cmd->out.buf_handle, cmd->out.fd,tbl.bufq[idx].len);return rc;map_hw_fail:cam_mem_put_slot(idx);
slot_fail:ion_free(tbl.client, ion_hdl);return rc;
}

2) cam_mem_util_ion_alloc 分析

// cam_mem_util_ion_alloc 分析
static int cam_mem_util_ion_alloc(struct cam_mem_mgr_alloc_cmd *cmd,struct ion_handle **hdl,int *fd)
{.....rc = cam_mem_util_get_dma_buf_fd(cmd->len, // 进入此函数cmd->align,heap_id,ion_flag,hdl,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 ion_handle **hdl,int *fd)
{
......*hdl = ion_alloc(tbl.client, len, align, heap_id_mask, flags); //分配buf,返回ION handle,hdl->buffer alloc 的首地址,后面会被放到dmabuf->priv变量中,// user在mmap的时候返回if (IS_ERR_OR_NULL(*hdl))return -ENOMEM;*fd = ion_share_dma_buf_fd(tbl.client, *hdl);// share ion handle,返回可以被 mmap 的fd,重点讲解if (*fd < 0) {CAM_ERR(CAM_CRM, "get fd fail");rc = -EINVAL;goto get_fd_fail;}return rc;
.......
}int ion_share_dma_buf_fd(struct ion_client *client, struct ion_handle *handle)
{struct dma_buf *dmabuf;int fd;dmabuf = ion_share_dma_buf(client, handle);// 此函数,主要调用 dma_buf_export 返回 struct dma_buf *dmabuf;下面有具体分析if (IS_ERR(dmabuf))return PTR_ERR(dmabuf);fd = dma_buf_fd(dmabuf, O_CLOEXEC); // dma_buf_fd()将步骤ion_share_dma_buf中创建的dam_buf对象关联到全局可见的文件描述符fd,同时通过ioctl方法将fd传递给应用层。if (fd < 0)dma_buf_put(dmabuf);return fd; // 返回fd
}struct dma_buf *ion_share_dma_buf(struct ion_client *client,struct ion_handle *handle)
{......buffer = handle->buffer; // ion alloc buf, 下面会放到 exp_info.privion_buffer_get(buffer);mutex_unlock(&client->lock);exp_info.ops = &dma_buf_ops; // ion ops,后面 dma_buf_map_attachment 中会调用其中的 ion_map_dma_buf 方法,mmap时调用 ion_mmapexp_info.size = buffer->size;exp_info.flags = O_RDWR;exp_info.priv = buffer; //赋值给priv变量,后面import会用到,此buffer就是存放stream数据的dmabuf = dma_buf_export(&exp_info); // dma_buf_export(dma架构中的exporter) 创建dma_buf对象if (IS_ERR(dmabuf)) {ion_buffer_put(buffer);return dmabuf;}return dmabuf;
}

3)alloc 之后的 map

//  cam_mem_util_map_hw_va 分析

cam_mem_util_map_hw_va
    cam_smmu_map_user_iova
        cam_smmu_check_fd_in_list
 // 检查fd是否以及存在
        cam_smmu_map_buffer_and_add_to_list // add fd to list
            dma_buf_get  // dma_buf_get(fd)获取dma_buf对象,importer使用,每个消费者可以通过文件描述符fd获取共享缓冲区的引用,该函数返回一个dma_buf的引用,同时增加它的refcount(该值记录着dma_buf被多少消费者引/用)。获取缓冲区引用后,消费者需要将它的设备附着在该缓冲区上,这样可以让生产者知道设备的寻址限制。
            cam_smmu_map_buffer_validate // 验证buffer有效性
                dma_buf_attach          // 该函数返回一个attachment的数据结构,该结构会用于scatter list的操作。
                             // dma-buf共享框架有一个记录位图,用于管理附着在该共享缓冲区上的消费者。
                             // 到这步为止,生产者可以选择不在实际的存储设备上分配该缓冲区,而是等待第一个消费者申请共享内存。
                dma_buf_map_attachment // 当消费者想要使用共享内存进行DMA操作,那么它就会通过接口                                                                                                  // dma_buf_map_attachment来访问缓冲区。在调用map_dma_buf前至少有一个消费者                                                                   // 与之关联。

dma_buf_map_attachment 中调用 ion_map_dma_buf 分析

// dma_buf_map_attachment 中调用 ion_map_dma_buf 分析
static struct sg_table *ion_map_dma_buf(struct dma_buf_attachment *attachment,enum dma_data_direction direction)
{struct dma_buf *dmabuf = attachment->dmabuf;struct ion_buffer *buffer = dmabuf->priv;struct sg_table *table;table = ion_dupe_sg_table(buffer->sg_table); // 重新alloc一个sg_table,并把buffer->sg_table->sgl拷贝到新的sg_table中if (!table)return NULL;ion_buffer_sync_for_device(buffer, attachment->dev, direction); // 同步ion buffer 到 DMAreturn table;
}static struct sg_table *ion_dupe_sg_table(struct sg_table *orig_table)
{int ret, i;struct scatterlist *sg, *sg_orig;struct sg_table *table;table = kzalloc(sizeof(*table), GFP_KERNEL);if (!table)return NULL;ret = sg_alloc_table(table, orig_table->nents, GFP_KERNEL); // 分配一个有 orig_table->nents 个 scatterlist的sg_tableif (ret) {kfree(table);return NULL;}sg_orig = orig_table->sgl;for_each_sg(table->sgl, sg, table->nents, i) { // 拷贝 sg_orig 到 table->sglmemcpy(sg, sg_orig, sizeof(*sg));sg_orig = sg_next(sg_orig);}return table;
}static void ion_buffer_sync_for_device(struct ion_buffer *buffer,struct device *dev,enum dma_data_direction dir)
{struct ion_vma_list *vma_list;int pages = PAGE_ALIGN(buffer->size) / PAGE_SIZE; // 计算 pagesint i;pr_debug("%s: syncing for device %s\n", __func__,dev ? dev_name(dev) : "null");if (!ion_buffer_fault_user_mappings(buffer))return;mutex_lock(&buffer->lock);for (i = 0; i < pages; i++) {struct page *page = buffer->pages[i]; // 将 ION buffer 拆分为 pagesif (ion_buffer_page_is_dirty(page))ion_pages_sync_for_device(dev, ion_buffer_page(page), // scatter ion buffer 到 DMAPAGE_SIZE, dir);ion_buffer_page_clean(buffer->pages + i);}list_for_each_entry(vma_list, &buffer->vmas, list) {struct vm_area_struct *vma = vma_list->vma;zap_page_range(vma, vma->vm_start, vma->vm_end - vma->vm_start,NULL);}mutex_unlock(&buffer->lock);}void ion_pages_sync_for_device(struct device *dev, struct page *page,size_t size, enum dma_data_direction dir)
{struct scatterlist sg;WARN_ONCE(!dev, "A device is required for dma_sync\n");sg_init_table(&sg, 1);sg_set_page(&sg, page, size, 0);/** This is not correct - sg_dma_address needs a dma_addr_t that is valid* for the targeted device, but this works on the currently targeted* hardware.*/sg_dma_address(&sg) = page_to_phys(page); // 转换 page 为物理地址 ,赋值给 sg->dma_address 为 dma_addr_t 类型dma_sync_sg_for_device(dev, &sg, 1, dir); // DMA debug?
}

总之:此函数作用就是把ion分配的buffer的虚拟地址对应的物理地址,

2. map buffer

分析log,发现只有IPE调用了,CSLMAP操作。在HAL层调用CSLALLOC时,已经把buffer给到DMA,并且CSLALLOC成功后,HAL会调用mmap,拿到user空间的虚拟地址,然后插入到链表中。

五.更正一些错误

上面是刚刚接触qc camera新架构时写的,由于以前比较稚嫩,所以写文章还是有些错误的,我这里更正一下,以前错误的解释就不删除了,可以提醒自己。

1.CSLAlloc call ioctl 时会传递 cam_mem_mgr_alloc_cmd allocCmd,code如下:

/* CAM_REQ_MGR_ALLOC_BUF */
struct cam_mem_mgr_alloc_cmd {uint64_t len;uint64_t align;int32_t mmu_hdls[CAM_MEM_MMU_MAX_HANDLE];uint32_t num_hdl;uint32_t flags;struct cam_mem_alloc_out_params out;
};

1)mmu_hdls是每个camera hw device唯一的,可以理解为alloc传递的mmu_hdls是哪个device的就是在分配内存给哪个device用,当然后续还可以通过CSLMAP来让其他device也使用。实际上这个mmu_hdls是devices在UMD ioctl CAM_QUERY_CAP到 KMD通过call cam_smmu_get_handle获得的

2)cam smmu维护着iommu_cb_set.cb_info[idx].smmu_buf_list链表,用来记录每个device所map的buffer,idx = GET_SMMU_TABLE_IDX(handle);其实这里可以直接把idx理解为device,毕竟mmu_hdls是唯一的

3)其他的参数就不解释了

2.某些时候CSLALLOC时已经MAP了,为什么还要调用CSLMAP?

1)Device 在 UMD call CSLAlloc 时,不知道这个buffer以后还会给哪些device用,所以当其他Device使用时需要call CSLMAP

2)Device 在 UMD call CSLAlloc 时,传递的 num_hdl = 0 时,KMD是不会进行map操作,只是分配一个buffer,需要CSLMAP后device才能使用

3.device为什么需要CSLMAP buffer?

CSLMAP有一个主要的作用是call  dma_buf_attach 以及 dma_buf_map_attachment,这样我们才能通过DMA传输DRAM上的数据到Device,具体dma相关可以参考https://blog.csdn.net/hexiaolong2009/category_9542494.html写的很好。

QCOM 新架构 camera 数据获取相关推荐

  1. 细鹏系列裸金属服务器多核算力,鲲鹏凌云,开启多元计算新架构_外发版(40页)-原创力文档...

    鲲鹏凌云,开启多元计算新架构 华为云鲲鹏云服务整体介绍及实践 华为云鲲鹏凌云生态总监 白雁 这是最好的时代,这是最坏的时代 应用移动化和数据多样性,呼唤新的算力 移动智能终端逐渐取代传统PC 世界正在 ...

  2. Arm 发布移动端 v9 体系新架构,CPU、GPU、IP全囊括了

    作者 | 夕颜 头图 | 下载于ICphoto 出品 | AI 科技大本营(ID:rgznai100) 2021年5月25日晚,Arm发布了针对移动端的Armv9体系新架构,除了公布首款全面计算(To ...

  3. 百度云「升级战」:王海峰站台,新架构全面AI化,AI和知识中台登场

    5月18日,"ABC SUMMIT 2020百度夏季云智峰会"在线上召开.刚刚经历了人事变动的百度云迎来重磅升级,大会以"百度智能云加速产业智能化"为主题,百度 ...

  4. 超越最新无监督域自适应方法,研究人员提轻量CNN新架构OSNet

    作者 | Kaiyang Zhou, Xiatian Zhu, Yongxin Yang, Andrea Cavallaro, and Tao Xiang 译者 | TroyChang 编辑 | Ja ...

  5. 张亚勤:新范式、新架构和新模态突破传统算力,推动物理世界走向数字化

    本文转自联想创投 近日,在联想创投2020 CEO年会上,清华大学讲席教授.智能产业研究院院长.美国艺术与科学院院士.百度前总裁张亚勤先生带来了<未来科技趋势展望>. 张亚勤表示,数字化的 ...

  6. 深信服副总裁张开翼:随需应变的IT新架构

    19日,由中国电子学会主办,ZD至顶网协办的第八届中国云计算大会进入了大会第二天.深信服副总裁张开翼在第二天的主会上以"随需应变的IT新架构"为主题,介绍了深信服从专注于网络安全到 ...

  7. 区块链新一代监管框架 ---《STRISA 一种实施旅行规则的新架构》

    1. 系统定义 兼容TRISA((Travel Rule Informa-tion Sharing Architecture)监管系统 TRISA 旅行规则信息共享架构提供数字金融单位注册和监管服务, ...

  8. 搜索引擎新架构:与SQL不得不说的故事

    简介:本话题将围绕阿里巴巴搜索引擎HA3架构,和大家详细阐述搜索引擎在面对架构深度学习和数据规模的挑战时,如何以数据库SQL的执行方式来应对解决. 特邀嘉宾:罗涛--阿里巴巴集团资深技术专家 视频地址 ...

  9. 深入剖析阿里云推荐引擎——新架构,新体验

    摘要:本文的整理自2017云栖大会-上海峰会上阿里云算法专家郑重(卢梭)的分享讲义,从2016年2月V2.0公开使用到现在,阿里云推荐引擎有了更大的进步.有着获取排序的在线计算,修正匹配的近线计算及匹 ...

最新文章

  1. 在Ubuntu 14.04 64bit上编译安装Crtmpserver trunk svn 811版本!
  2. 解决ubuntu上opengl的问题
  3. 高德渲染网关Go语言重构实践
  4. 【java的socket编程】结合多线程Thread实现通信(使用线程池和非线程池对比)、java开发UDP/IP网络程序
  5. 【三万字!】Dubbo、Zookeeper学习笔记!秒杀面试官!——双非上岸阿里巴巴系列
  6. 重学前端学习笔记(八)--JavaScript中的原型和类
  7. facebook 开源_Facebook开源主管开放
  8. php而且,PHP – David's Blog
  9. iss版本服务器读取_Netty每次读取客户端数量
  10. 脉歌蓝牙耳机线评测_漂亮的高音质蓝牙耳机 脉歌MACAW TX-90评测
  11. Atitit java 原生 客户端 native desktop桌面 javafx 浏览器环境 导入jar jfxrt.jar 17M package com.attilax.ui;
  12. 网页游戏怎么修改数据_2014一周网页游戏数据报告(8.18—8.24)
  13. 【Linux运维】01-Linux运维概述与CentOS系统安装
  14. 联想电脑安装黑苹果全教程
  15. 集成学习—多算法融合
  16. 纯前端滑块拼图验证组件(多端兼容)
  17. WPF随笔(四)--窗口多屏显示及全屏
  18. 安装黑苹果提示未能安装_安装黑苹果最后一分钟提示失败求助
  19. 工作组和域的概念及辨析
  20. 人工智能-----自然语言处理(NLP)基础理解

热门文章

  1. SPOJ 7258 (后缀自动机)
  2. 珍爱网产品经理:为年轻人创造私密、高效的社交空间
  3. 使用scrapy 爬取酷狗音乐歌手及歌曲名并存入mongodb中
  4. stc8a_步进电机控制,加减速
  5. oracle中如何执行存储过程,Oracle如何执行存储过程
  6. Mac——技巧:用“提醒事项”将任务分配给其他人
  7. CF1408F Two Different
  8. 一个与霍炬直接对话的机会:ChainNode AMA: 星河滚烫,开源成就区块链人间理想?
  9. 『津津乐道播客』#097. 我跟差评打官司(主播:霍炬)
  10. Windows上GAWK的使用(一)