驱动整体设计介绍

不同的processor

Nvidia DLA的内核驱动KMD(Kernel mode driver)中,并不是把DLA当成一个设备来控制,而是把不同的功能模块当做不同的processor,分别进行任务的管理和控制。在相同processor里分先后,不同队列靠依赖关系控制。当前分了6个processor,代码中如下定义。

#define DLA_OP_BDMA                 0

#define DLA_OP_CONV                  1

#define DLA_OP_SDP                     2

#define DLA_OP_PDP                     3

#define DLA_OP_CDP                     4

#define DLA_OP_RUBIK                  5

对应的芯片架构如下

Headless控制模式

架构上分为高端的headed和低端的headless方案。差别就是是否有MCU来承担IPU的逻辑控制功能。如果有host CPU和MCU两种角色,就是headed方案,否则就是headless。

NVDLA的初始开源版本将仅提供headless模式的软件解决方案。本次运行的场景是在linux下,但是是按照CPU直接操控DLA的寄存器来实现的,也就是headless模式。好处是很容易从无头模式看到核心的IPU控制逻辑。

主要的流程思路

除了初始化,驱动主要处理对上对下两个接口。对上是来和用户态的IOCTL,对下是处理中断。两者最终都是调用或者激活nvdal_task_submit,清理task之间的dependency关系,将合适的task放入processor执行。

图表 1 KMD的主流程

特殊的group寄存器

每个子模块processor有两套寄存器,也就是2个group寄存器。这种乒乓思路类似于队列和shadow寄存器的意图,方便一个任务完成后紧接着处理另外一个group寄存器配置的任务,而不是需要完成产生中断后软件才配置下一个任务,以此保持硬件逻辑的全速运行。

软件里定义如下:

/*** @ingroup Processors* @name Number of groups* @brief Each processor has 2 groups of registers* @{*/#define DLA_NUM_GROUPS       2struct dla_processor_group {uint8_t id;uint8_t rdma_id;uint8_t active;uint8_t events;uint8_t roi_index;uint8_t is_rdma_needed;uint8_t pending;int32_t lut_index;uint8_t programming;uint64_t start_time;struct dla_common_op_desc *op_desc;struct dla_common_op_desc *consumers[DLA_OP_NUM];struct dla_common_op_desc *fused_parent;union dla_operation_container *operation_desc;union dla_surface_container *surface_desc;};

驱动的注册和初始化

NVDLA驱动以Platform device driver的形式注册到内核。依靠name = "NVDLA”来进行match。重要的函数为nvdla_probe。

module_platform_driver(nvdla_driver);static struct platform_driver nvdla_driver = {.probe = nvdla_probe,.remove = __exit_p(nvdla_remove),.driver = {.owner = THIS_MODULE,.name = "NVDLA",.of_match_table = nvdla_of_match,},};

Probe函数nvdla_probe

Step1:

申请nvdla_dev并使用platform_set_drvdata挂载到如参pdev上。

Step2:

用devm_ioremap_resource映射内存,用devm_request_irq注册中断。

Step3:

调用dla_register_driver将全局变量engine关联到nvdla_dev->engine_context,Engine包含了device的各种能力,如DMA, CONV。这个就说明engine的含义是各个DLA中模块独立的处理能力。

把desc_cache和desc_refcount设置全0。最后调用nvdla_drm_probe注册了drm(Direct Rendering Manager)驱动设备。Nvdla使用drm的主要目的是利用了drm的内存分配机制和ioctl。其实和drm的功能没什么关系。Nvdia作为GPU厂商,借用drm更轻车熟路。

中断处理

中断处理nvdla_engine_isr

Step1

dla_isr_handler(nvdla_dev->engine_context);

主要是根据读取S_INTR_STATUS寄存器得到的值,设置对应engine->processors的group->events标记。比如如果是GLB_S_INTR_STATUS_0就设置engine->processors[DLA_OP_CONV].groups[0].events= (1 << DLA_EVENT_OP_COMPLETED)

step2

complete(&nvdla_dev->event_notifier);

这个会唤醒nvdla_task_submit,调用dla_process_events来处理event。因为中断里可能表示有任务完成,那么就可能消除dependency,可能放入新的任务执行。

对用户态的IOCTL接口

对用户态的接口nvdla_submit利用了drm框架的ioctl。

struct drm_driver nvdla_drm_driver里包含了nvdla_drm_ioctls。索引到nvdla_submit。其他几个ioctl是内存相关的。

DRM_IOCTL_DEF_DRV(NVDLA_SUBMIT, nvdla_submit, DRM_RENDER_ALLOW),

1.       用copy_from_user从ioctl接口复制一些用户态的task数据到内核。

2.       调用nvdla_fill_task_desc填充task结构体

3.       调用nvdla_task_submit。

主流程函数讲解

主流程入口函数nvdla_task_submit

Step1

调用dla_execute_task

Step2

等待wait_for_completion(&nvdla_dev->event_notifier),然后调用dla_process_events。

dla_process_events和dla_handle_events

dla_process_events遍历DLA_OP_NUM个processor调用dla_handle_events(processor)。

dla_handle_events遍历自己的processor->groups读取信息,先处理dma相关的event,调用dla_update_consumers来解除dependency_count。如果发现有operation的dependency_count降为0,就dla_enable_operation。这就等于是收到中断后,遍历所有类型的processor,遍历所有的group来解除dependency,找到能执行的下一个任务。

dla_handle_events最后调用了dla_op_completion来处理complete event。

dla_op_completion

1.       先调用dla_update_consumers清理dependency。

2.       如果(engine->network->num_operations == engine->num_proc_hwl)说明网络都算完了。如果还有任务接着调用dla_program_operation和dla_enable_operation来执行下一个任务,和dla_submit_operation的思路差不多。

dla_execute_task

/*** Execute task selected by task scheduler** 1. Read network configuration for the task* 2. Initiate processors with head of list for same op* 3. Start processing events received*/

Step1

dla_read_network_config:

1.       将网络的信息读取到network全局变量。注意这里通过DMA直接读取network descriptor的结构体,不是逐个成员复制。

2.       用DMA将operation descriptor,dependency读取过来。

3.       用DMA读取surface descriptor,LUT,ROI的信息。

Step2

dla_initiate_processors

1.       遍历DLA_OP_NUM调用dla_get_op_desc找到类型中第一个任务,调用dla_submit_operation提交。

2.       调用dla_put_op_desc。将提交后的dla_common_op_desc consumer在desc_refcount对应的count--,如果为0就删除。

3.       调用dla_dequeue_operation将同类型的下一个操作从取出来,使用的是dla_get_op_desc来取。Dequeue的含义就是取下一个,似乎用fetch更合适。如果有下个op需要执行就调用dla_submit_operation继续执行,否则返回。但是dla_dequeue_operation调用dla_submit_operation并不查看返回结果,所以相当于有空闲资源有任务就继续提交,没有就算了。

dla_get_op_desc

1.       在desc_cache中找到当前task,以(desc->index == index && desc->roi_index == roi_index)判定相同。desc_refcount++

2.       如果没找到,在desc_cache取一个新entry,设置好,读取该task的对应的dependency_graph_addr的内容,设置desc_refcount为1。

dla_submit_operation

1.       调用dla_prepare_operation。看看有没有空闲的processor group,将任务描述放入空闲processor的group。没有空闲就返回错误。

2.       如果processor->is_ready,如果没有ready,就退出。

3.       如果ready,调用dla_program_operation。这里就开始设置对应操作类型的processor的寄存器了。也就是提交任务给硬件了。

4.       如果(op_desc->dependency_count == 0),就enable任务。这个问说明在上一步只是把所有运行的配置做好。任务是否能运行,dependency的关系是在AP的driver里完成的,而不是让DLA硬件来完成。另外,在任务的配置过程中,AP并不是通过某种命令发给DLA,而是DLA的各个子模块处理的processor的控制细节寄存器完全暴露出来,由AP直接配置各寄存器。

来源:华为云社区  作者:lurayvis

NVDLA软件架构和源码解析 第一章—内核驱动相关推荐

  1. Google Test(GTest)使用方法和源码解析——模板类测试技术分析和应用

    写C++难免会遇到模板问题,如果要针对一个模板类进行测试,似乎之前博文中介绍的方式只能傻乎乎的一个一个特化类型后再进行测试.其实GTest提供了两种测试模板类的方法,本文我们将介绍方法的使用,并分析其 ...

  2. Google Test(GTest)使用方法和源码解析——参数自动填充技术分析和应用

    在我们设计测试用例时,我们需要考虑很多场景.每个场景都可能要细致地考虑到到各个参数的选择.比如我们希望使用函数IsPrime检测10000以内字的数字,难道我们要写一万行代码么?(转载请指明出于bre ...

  3. Google Test(GTest)使用方法和源码解析——预处理技术分析和应用

    预处理 在<Google Test(GTest)使用方法和源码解析--概况>最后一部分,我们介绍了GTest的预处理特性.现在我们就详细介绍该特性的使用和相关源码.(转载请指明出于brea ...

  4. Zxing生成二维码思路和源码解析

    Zxing生成二维码思路和源码解析 本博文是一篇介绍google zxing包生成二维码的思路和它的源码的文章. 一.引入 如何调用zxing的代码生成一个二维码呢?主要的函数只有一个,如下所示: B ...

  5. 状态模式的介绍及状态机模型的函数库javascript-state-machine的用法和源码解析

    文章大体就两部分: 状态模式 状态机模型的函数库javascript-state-machine的用法和源码解析 场景及问题背景: 我们平时开发时本质上就是对应用程序的各种状态进行切换并作出相应处理. ...

  6. Dubbo原理和源码解析之服务引用

    github新增仓库 "dubbo-read"(点此查看),集合所有<Dubbo原理和源码解析>系列文章,后续将继续补充该系列,同时将针对Dubbo所做的功能扩展也进行 ...

  7. Google Test(GTest)使用方法和源码解析——私有属性代码测试技术分析

    有些时候,我们不仅要测试类暴露出来的公有方法,还要测试其受保护的或者私有方法.GTest测试框架提供了一种方法,让我们可以测试类的私有方法.但是这是一种侵入式的,会破坏原来代码的结构,所以我觉得还是谨 ...

  8. Google Test(GTest)使用方法和源码解析——断言的使用方法和解析

    在之前博文的基础上,我们将介绍部分断言的使用,同时穿插一些源码.(转载请指明出于breaksoftware的csdn博客) 断言(Assertions) 断言是GTest局部测试中最简单的使用方法,我 ...

  9. Google Test(GTest)使用方法和源码解析——Listener技术分析和应用

    在<Google Test(GTest)使用方法和源码解析--结果统计机制分析>文中,我么分析了GTest如何对测试结果进行统计的.本文我们将解析其结果输出所使用到的Listener机制. ...

最新文章

  1. [云炬创业基础笔记]第七章创业资源测试7
  2. python文件打包成exe是 upx不可用、找不到py文件_使用PyInstaller将Python程序打包成一个单独的exe文件...
  3. 内存位置访问无效_万字长文——java内存模型之volatile深入解读
  4. AQS理解之六,AQS的其他实现类
  5. JavaScript实现heapsort堆排序算法(附完整源码)
  6. 7年专科生程序员同时去腾讯和微软面试,问HR结果以为听错了,结局反转!!
  7. 数组删除一行_一行Python代码能做出哪些神器的事情
  8. Java 10 var关键字详解和示例教程
  9. 互联网公司端午节礼盒歧视指南
  10. Redis 中文入库成功,读取数据写入文件乱码问题
  11. C语言课程设计题目介绍(10个标准题目)
  12. 在Linux和qt下安装EasyPr遇到的问题
  13. 5安卓输入法键盘显示 搜索_手机输入法谁更黑科技?讯飞搜狗百度大PK
  14. SMILES的基本规则
  15. kodi文件管理smb服务器,KODI+NAS的常见技巧
  16. 有关SoftICE的详细操作指导教程
  17. html日历页面节假日_JavaScript实现有农历和节气节假日的日历
  18. 娑罗双树,半枯半荣,娑罗花开,盛者必衰
  19. java offset函数的使用方法_js的offset是什么意思及使用详解
  20. 哪吒之魔童降世视听语言影评_《哪吒之魔童降世》观后感——不用吹爆,但值得点赞...

热门文章

  1. Linux删除证书文件命令,Linux基础面面观之文件复制、移动、删除的命令
  2. vba调用linux shell,调用命令提示符并通过VBA中的Shell Exec执行命令
  3. spring boot 相关注解
  4. Oracle PLSQL 客户端 连接Oracle12.2 出现权限问题的解决办法以及绿色版Oracle客户端的使用....
  5. 服务器上出现应用程序错误。此应用程序的当前自定义错误设置禁止远程查看应用程序错误的详细信息(出于安全原因)。...
  6. jquery 使用textarea
  7. openlayers 中的一些方法
  8. mysql语句解析_mysql 语句的查询过程解析
  9. 动态规划基础——爬楼梯(Leetcode 70)
  10. C/C++排序算法(2)希尔排序