【STM32MP157 异核通信框架学习篇】(10)Linux下Remoteproc相关API (下)

文章目录

  • [1 概要](#1 概要)
  • [2 Linux下Remoteproc相关API](#2 Linux下Remoteproc相关API)
    • [2.8 rproc 设备树节点](#2.8 rproc 设备树节点)
  • [3 总结](#3 总结)

1 概要

使用正点原子的stm32mp157mini进行RPMSG多核通信试验。

硬件:STM32MP157

软件:STM32CubeIDE / STM32CubeMX

远程处理器(Remoteproc)框架负责根据固件资源表中可用的信息激活 Linux 端的进程间通信(IPC),本节我们来分析 Linux 下的 Remoteproc 相关驱动,了解 Remoteproc 是怎样控制远程处理器的。本小节的内容会涉及到分析代码,会比较枯燥乏味,如果只想了解 Remotepro使用方法,可以直接看本章的最后一小节。

本章分为如下几部分(文章末尾会附上链接):

  1. 资源表
  2. 存储和系统资源分配
  3. Linux 下 Remoteproc 相关 API
  4. 链接脚本
  5. Remoteproc 的使用

2 Linux下Remoteproc相关API

2.8 rproc 设备树节点

打开stm32mp151.dtsi 设备树文件,找到设备树中和M4相关的Remoteproc配置,如下:

在上面的代码段里,有三个节点:mlahb节点、m4_rproc节点和m4_system_resources节点。m4_rproc节点下就是加载和管理M4固件的配置信息。m4_system_resources节点(也就是M4的资源管理器)下就是M4的资源分配配置信息。第10行,compatible属性值为"st,stm32mp1m4",在Linux内核源码中搜索此属性值找到对应的驱动文件为drivers/remoteproc/stm32_rproc.c,打开此文件找到如下内容:

c 复制代码
1   static const struct of_device_id stm32_rproc_match[] = { 
2           { .compatible = "st,stm32mp1-m4" }, 
3           {}, 
4   }; 
5   MODULE_DEVICE_TABLE(of, stm32_rproc_match); 
6   /* 此处省略部分代码 */ 
7   static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, 
8                            stm32_rproc_suspend, stm32_rproc_resume); 
9  
10  static struct platform_driver stm32_rproc_driver = { 
11          .probe = stm32_rproc_probe, 
12          .remove = stm32_rproc_remove, 
13          .shutdown = stm32_rproc_shutdown, 
14          .driver = { 
15                  .name = "stm32-rproc", 
16                  .pm = &stm32_rproc_pm_ops, 
17                  .of_match_table = of_match_ptr(stm32_rproc_match), 
18          }, 
19  }; 
20  /* 向Linux内核注册stm32_rproc_driver驱动 */ 
21  module_platform_driver(stm32_rproc_driver); 
22  MODULE_DESCRIPTION("STM32 Remote Processor Control Driver"); 
23  MODULE_AUTHOR("Ludovic Barre <ludovic.barre@st.com>"); 
24  MODULE_AUTHOR("Fabien Dessenne <fabien.dessenne@st.com>"); 
25  MODULE_LICENSE("GPL v2"); 

上面的驱动代码是一个标准的platform驱动,第2行就是设备树下匹配到驱动程序的地方,在stm32_rproc_match中。第15行,成员name属性是stm32-rproc,即定义了驱动的名字是stm32-rproc,它是用于驱动与设备匹配的。

第17行,用于匹配对应的device,即匹配设备树中的节点。第21行module_platform_driver()函数向Linux内核注册stm32_rproc_driver这个platform驱动。当设备和驱动匹配成功以后,stm32_rproc_driver->probe函数(即stm32_rproc_probe()函数)就会被执行。下面,我们直接去

看stm32_rproc_probe()函数做了哪些操作。stm32_rproc_probe()函数在Linux内核源码的drivers/remoteproc/stm32_rproc.c文件下,其函数定义如下所示:

c 复制代码
1   static int stm32_rproc_probe(struct platform_device *pdev) 
2   { 
3     struct device *dev = &pdev->dev; 
4     struct stm32_rproc *ddata; 
5     struct device_node *np = dev->of_node; 
6     struct rproc *rproc; 
7     int ret; 
8  
9     ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(32)); 
10    if (ret) 
11            return ret; 
12 
13    rproc=rproc_alloc(dev,np->name,&st_rproc_ops,NULL,sizeof(*ddata)); 
14    if (!rproc) 
15            return -ENOMEM; 
16 
17    rproc->has_iommu = false; 
18    ddata = rproc->priv; 
19    ddata->workqueue = create_workqueue(dev_name(dev)); 
20    if (!ddata->workqueue) { 
21            dev_err(dev, "cannot create workqueue\n"); 
22            ret = -ENOMEM; 
23            goto free_rproc; 
24    } 
25 
26    platform_set_drvdata(pdev, rproc); 
27 
28    ret = stm32_rproc_parse_dt(pdev);
29    if (ret) 
30            goto free_wkq; 
31  if (!rproc->early_boot) { 
32            ret = stm32_rproc_stop(rproc); 
33            if (ret) 
34                    goto free_wkq; 
35    } 
36 
37    ret = stm32_rproc_request_mbox(rproc); 
38    if (ret) 
39            goto free_wkq; 
40 
41    ret = rproc_add(rproc); 
42    if (ret) 
43            goto free_mb; 
44 
45    return 0; 
46 
47  free_mb: 
48    stm32_rproc_free_mbox(rproc); 
49  free_wkq: 
50    destroy_workqueue(ddata->workqueue); 
51  free_rproc: 
52    if (device_may_wakeup(dev)) { 
53            dev_pm_clear_wake_irq(dev); 
54            device_init_wakeup(dev, false); 
55    } 
56    rproc_free(rproc); 
57    return ret; 
58  } 

第4行,ddata指针是ST官方的私有数据stm32_rproc结构体。

第6行,声明了一个rproc类型的结构体。

第9行,DMA相关配置。

第13行,rproc_alloc函数主要作用是分配一个新的rproc结构体空间,同时st_rproc_ops地址赋值给rproc->ops参数,目的是调用回调函数完成对应的功能(类似XXX_ops的结构体中的成员变量就是一些回调函数),这行的目的就是分配一个新的远程处理器(rproc)结构体,使用此函数创建 rproc 结构体后,应调用 rproc_add() 以完成远程处理器的注册,在后面我们会看到调用此函数。

第18行,保存ST官方的私有数据到rproc结构体里。

第19行,创建工作队列,workqueue的名称是设备的名字,每个workqueue就是一个内核进程,为系统创建一个内核线程。

第28行,调用stm32_rproc_parse_dt()函数来获取设备树中的属性,目的就是完成M4设备的配置。

第31~35 行,如果没有加载固件则调用stm32_rproc_stop 函数,该函数会做一些操作,如请求关闭远程处理器,此时传输阻塞,会打印"warning: remote FW shutdown without ack",并将远程处理器状态设置为离线状态等。

第37行,stm32_rproc_request_mbox()函数为远程处理器申请邮箱,A7 和 M4 可通过邮箱发布数据。

第41行,rproc_add()函数在前面的介绍中我们已经了解了,就是注册一个远程处理器。

第56行,rproc_free()函数释放由 rproc_alloc ()分配的 rproc 。 下面我们来看看st_rproc_ops结构体,在stm32_rproc.c找到如下代码:

st_rproc_ops 结构体中有几个处理程序,每个处理程序对应一个回调函数,如 start 处理程序接受一个 rproc 结构体,然后打开设备电源并启动它。stop处理程序采用 rproc 并关闭远程处理器。kick处理程序接受一个 rproc 和一个放置新消息的虚拟队列的索引,调用此函数时会中断远程处理器并让它知道它有待处理的消息。find_loaded_rsc_table就是查找已经加载的固件资源表,执行的是stm32_rproc_elf_find_loaded_rsc_table()函数。 每个 Remoteproc 的实现至少应该提供 start 和 stop 处理程序,关于这些函数我们不必深入分析,只要我们知道这是ST官方实现操作M4相关的接口函数就行了。

3 总结

本章节讲述了Linux下Remoteproc相关API。

相关推荐
前端小趴菜~时倾37 分钟前
自我提升-python爬虫学习:day04
爬虫·python·学习
淮北4948 小时前
vim学习进阶
学习·编辑器·vim
maosheng11468 小时前
RHCSA的第一次作业
linux·运维·服务器
busideyang9 小时前
为什么推挽输出不能接收串口数据,而准双向口可以?
c语言·stm32·单片机·嵌入式硬件·嵌入式
wifi chicken9 小时前
Linux 端口扫描及拓展
linux·端口扫描·网络攻击
旺仔.2919 小时前
Linux 信号详解
linux·运维·网络
放飞梦想C9 小时前
CPU Cache
linux·cache
济6179 小时前
STM32定时器进阶:从模式控制器完全指南,一文学会TRGI/TRGO---STM32 HAL库专栏
stm32·单片机·嵌入式·stm32hal库编程
sayang_shao9 小时前
ARM架构运行模式学习笔记
arm开发·学习·架构
Hoshino.4110 小时前
基于Linux中的数据库操作——下载与安装(1)
linux·运维·数据库