【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。

相关推荐
Tipriest_2 小时前
Linux 环境变量的添加与查看详解
linux·环境变量
牢七3 小时前
新linux
linux
HIT_Weston6 小时前
27、【Ubuntu】【远程开发】内网穿透:CA 签名
linux·运维·ubuntu
阿巴~阿巴~6 小时前
基于UDP协议的英汉翻译服务系统:从网络通信到字典查询的完整机制
linux·服务器·网络·网络协议·udp协议·套接字绑定·英汉翻译服务系统
阿巴~阿巴~6 小时前
简易回声服务器实现与网络测试指南
linux·服务器·网络·udp协议·网络测试·udp套接字编程
Aldrich_328 小时前
蓝桥杯嵌入式赛道—-软件篇(GPIO输出模式配置)
c语言·vscode·stm32·单片机·嵌入式硬件·蓝桥杯
Kisorge8 小时前
【电机控制】基于STM32F103C8T6的二轮平衡车设计——LQR线性二次线控制器(算法篇)
stm32·嵌入式硬件·算法
凡间客9 小时前
Ansible安装与入门
linux·运维·ansible
君以思为故9 小时前
认识Linux -- 进程概念
linux·服务器