首页
chatGPT
关于
友链
其它
统计
更多
壁纸
留言
Search
1
cgroup--(4)cgroup v1和cgroup v2的详细介绍
6,408 阅读
2
修改Linux Kernel defconfig的标准方法
6,381 阅读
3
Android系统之VINTF(1)manifests&compatibility matrices
5,974 阅读
4
使用git生成patch和应用patch
3,453 阅读
5
c语言的__attribute__
3,168 阅读
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
登录
Search
标签搜索
shell
Linux
c
uboot
Vim
vintf
Linux驱动
Android
device_tree
git
DEBUG
arm64
链表
数据结构
IDR
内核
ELF
gcc
ARM
网址
adtxl
累计撰写
367
篇文章
累计收到
14
条评论
首页
栏目
默认分类
文章收集
学习总结
算法
环境配置
知识点
入门系列
vim
shell
Git
Make
Android
Linux
Linux命令
内存管理
Linux驱动
Language
C++
C
工具
软件工具
Bug
COMPANY
页面
chatGPT
关于
友链
其它
统计
壁纸
留言
搜索到
133
篇与
的结果
2022-05-27
Linux内存管理:什么是CMA(contiguous memory allocation)连续内存分配器?可与DMA结合使用
转载自https://blog.csdn.net/Rong_Toa/article/details/109558234https://blog.csdn.net/Adrian503/article/details/115519542?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-115519542-blog-109558234.pc_relevant_paycolumn_v3&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1-115519542-blog-109558234.pc_relevant_paycolumn_v3&utm_relevant_index=2
2022年05月27日
632 阅读
0 评论
0 点赞
2022-05-25
Uboot--bootcmd和bootargs参数
转载自https://blog.csdn.net/qq_28877125/article/details/120785133
2022年05月25日
2,602 阅读
0 评论
0 点赞
2022-05-24
FPGA学习
暂无简介
2022年05月24日
528 阅读
0 评论
0 点赞
2022-05-23
IC设计流程简述
转载自https://ee.ofweek.com/2021-03/ART-11000-2801-30488728.html
2022年05月23日
781 阅读
0 评论
0 点赞
2022-05-23
[转载]一文看懂FPGA原型验证的技术进阶之路
转载自https://www.synopsys.com/blogs/smart-everything/zh-cn/2020/08/fpag-prototying/
2022年05月23日
525 阅读
0 评论
0 点赞
2022-05-18
initrd_start地址是如何确定的?
暂无简介
2022年05月18日
749 阅读
0 评论
0 点赞
2022-04-13
docker的基本使用
暂无简介
2022年04月13日
575 阅读
0 评论
0 点赞
2022-04-13
Android中ftrace的使用
暂无简介
2022年04月13日
789 阅读
0 评论
0 点赞
2022-04-07
Linux内存管理(22)DMA engine framework--3_dma controller驱动
转载自http://www.wowotech.net/linux_kenrel/dma_controller_driver.html1. 前言本文将从provider的角度,介绍怎样在linux kernel dmaengine的框架下,编写dma controller驱动。2. dma controller驱动的软件框架设备驱动的本质是描述并抽象硬件,然后为consumer提供操作硬件的友好接口。dma controller驱动也不例外,它要做的事情无外乎是:1)抽象并控制DMA控制器。2)管理DMA channel(可以是物理channel,也可以是虚拟channel),并向client driver提供友好、易用的接口。3)以DMA channel为操作对象,响应client driver(consumer)的传输请求,并控制DMA controller,执行传输。当然,按照惯例,为了统一提供给consumer的API,并减少DMA controller driver的开发难度(从论述题变为填空题),dmaengine framework提供了一套controller driver的开发框架,主要思路是:1)使用struct dma_device抽象DMA controller,controller driver只要填充该结构中必要的字段,就可以完成dma controller的驱动开发。2)使用struct dma_chan(图片1中的DCn)抽象物理的DMA channel(图片1中的CHn),物理channel和controller所能提供的通道数一一对应。3)基于物理的DMA channel,使用struct virt_dma_cha抽象出虚拟的dma channel(图片1中的VCx)。多个虚拟channel可以共享一个物理channel,并在这个物理channel上进行分时传输。4)基于这些数据结构,提供一些便于controller driver开发的API,供driver使用。上面三个数据结构的描述,可参考第3章的介绍。然后,我们会在第4章介绍相关的API、controller driver的开发思路和步骤以及dmaengine中和controller driver有关的重要流程。3. 主要数据结构描述3.1 struct dma_device用于抽象dma controller的struct dma_device是一个庞杂的数据结构(具体可参考include/linux/dmaengine.h中的代码),不过真正需要dma controller driver关心的内容却不是很多,主要包括:注1:为了加快对dmaengine framework的理解和掌握,这里只描述一些简单的应用场景,更复杂的场景,只有等到有需求的时候,再更深入的理解。channels,一个链表头,用于保存该controller支持的所有dma channel(struct dma_chan,具体可参考3.2小节)。在初始化的时候,dma controller driver首先要调用INIT_LIST_HEAD初始化它,然后调用list_add_tail将所有的channel添加到该链表头中。cap_mask,一个bitmap,用于指示该dma controller所具备的能力(可以进行什么样的DMA传输),例如(具体可参考enum dma_transaction_type的定义): DMA_MEMCPY,可进行memory copy; DMA_MEMSET,可进行memory set; DMA_SG,可进行scatter list传输; DMA_CYCLIC,可进行cyclic类的传输; DMA_INTERLEAVE,可进行交叉传输; 等等,等等(各种奇奇怪怪的传输类型,不看不知道,一看吓一跳!!)。另外,该bitmap的定义,需要和后面device_prep_dma_xxx形式的回调函数对应(bitmap中支持某个传输类型,就必须提供该类型对应的回调函数)。src_addr_widths,一个bitmap,表示该controller支持哪些宽度的src类型,包括1、2、3、4、8、16、32、64(bytes)等(具体可参考enum dma_slave_buswidth 的定义)。dst_addr_widths,一个bitmap,表示该controller支持哪些宽度的dst类型,包括1、2、3、4、8、16、32、64(bytes)等(具体可参考enum dma_slave_buswidth 的定义)。directions,一个bitmap,表示该controller支持哪些传输方向,包括DMA_MEM_TO_MEM、DMA_MEM_TO_DEV、DMA_DEV_TO_MEM、DMA_DEV_TO_DEV,具体可参考enum dma_transfer_direction的定义和注释。max_burst,支持的最大的burst传输的size。descriptor_reuse,指示该controller的传输描述可否可重复使用(client driver可只获取一次传输描述,然后进行多次传输)。device_alloc_chan_resources/device_free_chan_resources,client driver申请/释放 dma channel的时候,dmaengine会调用dma controller driver相应的alloc/free回调函数,以准备相应的资源。具体要准备哪些资源,则需要dma controller driver根据硬件的实际情况,自行决定(这就是dmaengine framework的流氓之处,呵呵~)。device_prep_dma_xxx,同理,client driver通过dmaengine_prep_xxx API获取传输描述符的时候,damengine则会直接回调dma controller driver相应的device_prep_dma_xxx接口。至于要在这些回调函数中做什么事情,dma controller driver自己决定就是了(真懒啊!)。device_config,client driver调用dmaengine_slave_config[2]配置dma channel的时候,dmaengine会调用该回调函数,交给dma controller driver处理。device_pause/device_resume/device_terminate_all,同理,client driver调用dmaengine_pause、dmaengine_resume、dmaengine_terminate_xxx等API的时候,dmaengine会调用相应的回调函数。device_issue_pending,client driver调用dma_async_issue_pending启动传输的时候,会调用调用该回调函数。总结:dmaengine对dma controller的抽象和封装,只是薄薄的一层:仅封装出来一些回调函数,由dma controller driver实现,被client driver调用,dmaengine本身没有太多的操作逻辑。3.2 struct dma_chanstruct dma_chan用于抽象dma channel,其内容为:struct dma_chan { struct dma_device *device; dma_cookie_t cookie; dma_cookie_t completed_cookie; /* sysfs */ int chan_id; struct dma_chan_dev *dev; struct list_head device_node; struct dma_chan_percpu __percpu *local; int client_count; int table_count; /* DMA router */ struct dma_router *router; void *route_data; void *private; };需要dma controller driver关心的字段包括:device,指向该channel所在的dma controller。cookie,client driver以该channel为操作对象获取传输描述符时,dma controller driver返回给client的最后一个cookie。completed_cookie,在这个channel上最后一次完成的传输的cookie。dma controller driver可以在传输完成时调用辅助函数dma_cookie_complete设置它的value。device_node,链表node,用于将该channel添加到dma_device的channel列表中。router、route_data,TODO。3.3 struct virt_dma_chastruct virt_dma_chan用于抽象一个虚拟的dma channel,多个虚拟channel可以共用一个物理channel,并由软件调度多个传输请求,将多个虚拟channel的传输串行地在物理channel上完成。该数据结构的定义如下:/* drivers/dma/virt-dma.h */ struct virt_dma_desc { struct dma_async_tx_descriptor tx; /* protected by vc.lock */ struct list_head node; }; struct virt_dma_chan { struct dma_chan chan; struct tasklet_struct task; void (*desc_free)(struct virt_dma_desc *); spinlock_t lock; /* protected by vc.lock */ struct list_head desc_allocated; struct list_head desc_submitted; struct list_head desc_issued; struct list_head desc_completed; struct virt_dma_desc *cyclic; };chan,一个struct dma_chan类型的变量,用于和client driver打交道(屏蔽物理channel和虚拟channel的差异)。task,一个tasklet,用于等待该虚拟channel上传输的完成(由于是虚拟channel,传输完成与否只能由软件判断)。desc_allocated、desc_submitted、desc_issued、desc_completed,四个链表头,用于保存不同状态的虚拟channel描述符(struct virt_dma_desc,仅仅对struct dma_async_tx_descriptor做了一个简单的封装)。4. dmaengine向dma controller driver提供的API汇整damengine直接向dma controller driver提供的API并不多(大部分的逻辑交互都位于struct dma_device结构的回调函数中),主要包括:1)struct dma_device变量的注册和注销接口/* include/linux/dmaengine.h */ int dma_async_device_register(struct dma_device *device); void dma_async_device_unregister(struct dma_device *device);dma controller driver准备好struct dma_device变量后,可以调用dma_async_device_register将它(controller)注册到kernel中。该接口会对device指针进行一系列的检查,然后对其做进一步的初始化,最后会放在一个名称为dma_device_list的全局链表上,以便后面使用。dma_async_device_unregister,注销接口。2)cookie有关的辅助接口,位于drivers/dma/dmaengine.h中,包括static inline void dma_cookie_init(struct dma_chan *chan) static inline dma_cookie_t dma_cookie_assign(struct dma_async_tx_descriptor *tx) static inline void dma_cookie_complete(struct dma_async_tx_descriptor *tx) static inline enum dma_status dma_cookie_status(struct dma_chan *chan, dma_cookie_t cookie, struct dma_tx_state *state)由于cookie有关的操作,有很多共性,dmaengine就提供了一些通用实现:void dma_cookie_init,初始化dma channel中的cookie、completed_cookie字段。dma_cookie_assign,为指针的传输描述(tx)分配一个cookie。dma_cookie_complete,当某一个传输(tx)完成的时候,可以调用该接口,更新该传输所对应channel的completed_cookie字段。dma_cookie_status,获取指定channel(chan)上指定cookie的传输状态。3)依赖处理接口void dma_run_dependencies(struct dma_async_tx_descriptor *tx);由前面的描述可知,client可以同时提交多个具有依赖关系的dma传输。因此当某个传输结束的时候,dma controller driver需要检查是否有依赖该传输的传输,如果有,则传输之。这个检查并传输的过程,可以借助该接口进行(dma controller driver只需调用即可,省很多事)。4)device tree有关的辅助接口extern struct dma_chan *of_dma_simple_xlate(struct of_phandle_args *dma_spec, struct of_dma *ofdma); extern struct dma_chan *of_dma_xlate_by_chan_id(struct of_phandle_args *dma_spec, struct of_dma *ofdma);上面两个接口可用于将client device node中有关dma的字段解析出来,并获取对应的dma channel。后面实际开发的时候会举例说明。5)虚拟dma channel有关的API后面会有专门的文章介绍虚拟dma,这里不再介绍。5. 编写一个dma controller driver的方法和步骤上面啰嗦了这么多,相信大家还是似懂非懂(很正常,我也是,dmaengine framework特点就是框架简单,细节复杂)。到底怎么在dmaengine的框架下编写dma controller驱动呢?现在看来,只靠这篇文章,可能达不到目的了,这里先罗列一下基本步骤,后续我们会结合实际的开发过程,进一步的理解和掌握。编写一个dma controller driver的基本步骤包括(不考虑虚拟channel的情况):1)定义一个struct dma_device变量,并根据实际的硬件情况,填充其中的关键字段。2)根据controller支持的channel个数,为每个channel定义一个struct dma_chan变量,进行必要的初始化后,将每个channel都添加到struct dma_device变量的channels链表中。3)根据硬件特性,实现struct dma_device变量中必要的回调函数(device_alloc_chan_resources/device_free_chan_resources、device_prep_dma_xxx、device_config、device_issue_pending等等)。4)调用dma_async_device_register将struct dma_device变量注册到kernel中。5)当client driver申请dma channel时(例如通过device tree中的dma节点获取),dmaengine core会调用dma controller driver的device_alloc_chan_resources函数,controller driver需要在这个接口中奖该channel的资源准备好。6)当client driver配置某个dma channel时,dmaengine core会调用dma controller driver的device_config函数,controller driver需要在这个函数中将client想配置的内容准备好,以便进行后续的传输。7)client driver开始一个传输之前,会把传输的信息通过dmaengine_prep_slave_xxx接口交给controller driver,controller driver需要在对应的device_prep_dma_xxx回调中,将这些要传输的内容准备好,并返回给client driver一个传输描述符。8)然后,client driver会调用dmaengine_submit将该传输提交给controller driver,此时dmaengine会调用controller driver为每个传输描述符所提供的tx_submit回调函数,controller driver需要在这个函数中将描述符挂到该channel对应的传输队列中。9)client driver开始传输时,会调用dma_async_issue_pending,controller driver需要在对应的回调函数(device_issue_pending)中,依次将队列上所有的传输请求提交给硬件。10)等等。
2022年04月07日
901 阅读
0 评论
0 点赞
2022-03-16
uboot常见的命令
暂无简介
2022年03月16日
797 阅读
0 评论
0 点赞
1
...
5
6
7
...
14