首页 > 系统相关 >Linux remoteproc子系统(基于STM32MP157)概览

Linux remoteproc子系统(基于STM32MP157)概览

时间:2024-07-05 21:20:15浏览次数:23  
标签:struct -- STM32MP157 rproc stm32 int remoteproc Linux

remoteproc(Remote Processor Framework)用于管理异构远程处理器设备。这些设备通常在非对称多处理(Asymmetric MultiProcessing,AMP)配置中,可能运行不同的操作系统实例,包括Linux或其他实时操作系统的变体。

remoteproc 框架允许不同平台或架构控制远程处理器(例如,开启电源、加载固件、关闭电源)。此外,该框架还为支持该通信类型的远程处理器添加了rpmsg virtio设备,从而使得特定于平台的远程处理器驱动程序只需提供一些低级处理器,而所有rpmsg驱动程序就可以正常工作。

1 remoteproc配置

 remoteproc配置如下:

Device Drivers
  ->Remoteproc drivers
    ->Support for Remote Processor subsystem
      ->Remoteproc System Resource Manager core--支持SRM。
        ->Remoteproc System Resource Manager device
      ->STM32 remoteproc support 

2 remoteproc文件

remoteproc子系统以及驱动文件如下:

drivers/remoteproc/
├── remoteproc_core.c--remoteproc框架核心。 ├── remoteproc_debugfs.c--创建remoteproc目录,以及为每个remoteproc设备创建调试节点。 ├── remoteproc_elf_loader.c--加载ELF格式固件的接口。 ├── remoteproc_sysfs.c--remoteproc设备属性节点。 ├── remoteproc_virtio.c--创建remoteproc相关的virtio设备。 ├── rproc_srm_core.c--SRM核心。 ├── rproc_srm_dev.c--SystemResourceManager是一个管理remoteproc所需资源的组件,此处用于创建资源设备。 └── stm32_rproc.c--STM32 remoteproc驱动。

3 remoteproc子系统以及API

3.1 remoteproc子系统初始化

remoteproc子系统初始化:

remoteproc_init
  rproc_init_sysfs
    class_register--创建remoteproc类。
  rproc_init_debugfs
    debugfs_initialized--判断debugfs似乎否初始化。
    debugfs_create_dir--创建/sys/kernel/debug/remoteproc/。

每个remoteproc类型设备都会创建如下属性节点:

static struct attribute *rproc_attrs[] = {
    &dev_attr_firmware.attr,
    &dev_attr_state.attr,
    &dev_attr_name.attr,
    NULL
};

实例如下:

/sys/class/remoteproc/remoteproc0/
|-- firmware--配置/lib/firmware目录下的固件名称。
|-- name--远端处理器名称。
|-- state--仅支持start(rproc_boot)/stop(rproc_shutdown)两个写状态。读状态包括offline/suspended/running/crashed/deleted/invalid。
`-- uevent

3.2 remoteproc API

struct rproc是remoteproc框架中对一个Remote Processor的抽象:

struct rproc {
    struct list_head node;
    struct iommu_domain *domain;
    const char *name;
    char *firmware;--对应固件名称。
    void *priv;
    struct rproc_ops *ops;
    struct device dev;
    atomic_t power;
    unsigned int state;
    struct mutex lock;
    struct dentry *dbg_dir;
    struct list_head traces;
    int num_traces;
    struct list_head carveouts;
    struct list_head mappings;
    u32 bootaddr;--rproc执行的第一条指令地址。
    struct list_head rvdevs;
    struct list_head subdevs;
    struct idr notifyids;
    int index;
    struct work_struct crash_handler;
    unsigned int crash_cnt;
    bool recovery_disabled;
    int max_notifyid;
    struct resource_table *table_ptr;
    struct resource_table *cached_table;
    size_t table_sz;
    bool has_iommu;
    bool auto_boot;
    struct list_head dump_segments;
    int nb_vdev;
    bool early_boot;
};

struct rproc_ops是特定remoteproc设备的操作函数:

struct rproc_ops {
    int (*start)(struct rproc *rproc);--给remoteproc上电并且启动。
    int (*stop)(struct rproc *rproc);--给remoteproc下电。
    void (*kick)(struct rproc *rproc, int vqid);
    void * (*da_to_va)(struct rproc *rproc, u64 da, int len);
    int (*parse_fw)(struct rproc *rproc, const struct firmware *fw);
    int (*handle_rsc)(struct rproc *rproc, u32 rsc_type, void *rsc,
              int offset, int avail);
    struct resource_table *(*find_loaded_rsc_table)(
                struct rproc *rproc, const struct firmware *fw);
    int (*load)(struct rproc *rproc, const struct firmware *fw);--加载固件到内存,给remoteproc使用。
    int (*sanity_check)(struct rproc *rproc, const struct firmware *fw);--对固件进行合理性检查。
    u32 (*get_boot_addr)(struct rproc *rproc, const struct firmware *fw);--获取启动地址。
};

remoteproc创建者相关API:

struct rproc *rproc_alloc(struct device *dev, const char *name,
              const struct rproc_ops *ops,
              const char *firmware, int len);--分配一个struct rproc,并对其进行初始化。
void rproc_put(struct rproc *rproc);--减小remoteproc引用计数。
int rproc_add(struct rproc *rproc);--将struct rproc注册到remoteproc框架中,创建remoteproc相关设备。
int rproc_del(struct rproc *rproc);--移除remoteproc设备。
void rproc_free(struct rproc *rproc);--释放struct rproc。

rproc_alloc:

rproc_alloc
  device_initialize--初始化设备。
  dev_set_name--设置设备名称。
  rproc_crash_handler_work

rproc_add:

rproc_add
  device_add--创建rproc设备。
  rproc_create_debug_dir--创建特定remoteproc的调试节点。
  devm_of_platform_populate
  rproc_boot--在early_boot为true时调用。
  rproc_trigger_auto_boot--支持autoboot的情况下调用。

rproc_boot启动远程处理器:

  • 为固件申请资源。
  • 对固件进行合法性检查。
  • 将固件内容加载到内存中。
  • 给处理器上电。
  • 释放固件资源。
rproc_boot
  request_firmware--根据rproc->firmware名称,到fw_path目录下查找固件并加载。参考《Linux下固件加载器Firmware Loader》。
  rproc_fw_boot
    rproc_fw_sanity_check--调用rproc_ops的sanity_check对固件进行基本检查。对于ELF文件则是调用rproc_elf_sanity_check()进行检查。
    rproc_enable_iommu--如果存在IOMMU的话,使能IOMMU。
    rproc_get_boot_addr--调用rproc_ops的get_boot_addr函数获取启动地址。对于ELF文件则是调用rproc_elf_get_boot_addr()。
    rproc_parse_fw--调用rproc_ops的parse_fw函数。
    rproc_handle_resources--处理rproc的resource_table。
    rproc_alloc_registered_carveouts--分配rproc所有注册的carveouts。
    rproc_start
      rproc_load_segments--调用rproc_ops的load函数。对于ELF文件则是调用rproc_elf_load_segments(),加载ELF的Segment到内存中。
      rproc_find_loaded_rsc_table--调用rproc_ops的find_loaded_src_table,从固件中加载resource table。
      rproc_prepare_subdevices--遍历rproc的subdevs并调用prepare函数。
      rproc->ops->start--给远程处理器上电。
      rproc_start_subdevices--调用subdevs的start函数。
  release_firmware--释放固件相关资源。

remoteproc使用者相关API:

int rproc_boot(struct rproc *rproc);--启动remote processor,加载固件并上电启动。
void rproc_shutdown(struct rproc *rproc);--对remote processor下电。
void rproc_report_crash(struct rproc *rproc, enum rproc_crash_type type);
int rproc_coredump_add_segment(struct rproc *rproc, dma_addr_t da, size_t size);
int rproc_coredump_add_custom_segment(struct rproc *rproc,
                      dma_addr_t da, size_t size,
                      void (*dumpfn)(struct rproc *rproc,
                             struct rproc_dump_segment *segment,
                             void *dest),
                      void *priv);

4 STM32 remoteproc驱动

4.1 STM32 remoteproc dts

    mlahb {
        compatible = "simple-bus";
        #address-cells = <1>;
        #size-cells = <1>;
        dma-ranges = <0x00000000 0x38000000 0x10000>,--分别对应DeviceAddress、BusAddress、Size。
                 <0x10000000 0x10000000 0x60000>,
                 <0x30000000 0x30000000 0x60000>;

        m4_rproc: m4@10000000 {
            compatible = "st,stm32mp1-m4";
            reg = <0x10000000 0x40000>,
                  <0x30000000 0x40000>,
                  <0x38000000 0x10000>;
            resets = <&scmi0_reset RST_SCMI0_MCU>;
            st,syscfg-holdboot = <&rcc 0x10C 0x1>;
            st,syscfg-tz = <&rcc 0x000 0x1>;
            st,syscfg-rsc-tbl = <&tamp 0x144 0xFFFFFFFF>;
            st,syscfg-copro-state = <&tamp 0x148 0xFFFFFFFF>;
            st,syscfg-pdds = <&pwr_mcu 0x0 0x1>;
            status = "disabled";

            m4_system_resources {
                compatible = "rproc-srm-core";
                status = "disabled";
            };
        };
    };

&m4_rproc {
    memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>,
            <&vdev0vring1>, <&vdev0buffer>;--M4所使用到的内存空间。
    mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>;--remoteproc使用到的Mailbox硬件。
    mbox-names = "vq0", "vq1", "shutdown";
    interrupt-parent = <&exti>;
    interrupts = <68 1>;
    wakeup-source;--具备唤醒功能。
    status = "okay";
};

&m4_rproc {
    m4_system_resources {
        #address-cells = <1>;
        #size-cells = <0>;

        m4_timers2: timer@40000000 {
            compatible = "rproc-srm-dev";
            reg = <0x40000000 0x400>;
            clocks = <&rcc TIM2_K>;
            clock-names = "int";
            status = "disabled";
        };
        m4_timers3: timer@40001000 {
            compatible = "rproc-srm-dev";
            reg = <0x40001000 0x400>;
            clocks = <&rcc TIM3_K>;
            clock-names = "int";
            status = "disabled";
        };
...
}; };

结合M4的LinkerScript:

MEMORY
{
  m_interrupts (RX)  : ORIGIN = 0x00000000, LENGTH = 0x00000298
  m_text       (RX)  : ORIGIN = 0x10000000, LENGTH = 0x00020000
  m_data       (RW)  : ORIGIN = 0x10020000, LENGTH = 0x00020000
  m_ipc_shm    (RW)  : ORIGIN = 0x10040000, LENGTH = 0x00008000
}

Linux下对应的reserved-memory如下:

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;

        mcuram2: mcuram2@10000000 {
            compatible = "shared-dma-pool";
            reg = <0x10000000 0x40000>;--存放M4的m_text和m_data两块内存。
            no-map;
        };

        vdev0vring0: vdev0vring0@10040000 {
            compatible = "shared-dma-pool";
            reg = <0x10040000 0x1000>;--和M4的共享内存。
            no-map;
        };

        vdev0vring1: vdev0vring1@10041000 {
            compatible = "shared-dma-pool";
            reg = <0x10041000 0x1000>;--和M4的共享内存。
            no-map;
        };

        vdev0buffer: vdev0buffer@10042000 {
            compatible = "shared-dma-pool";
            reg = <0x10042000 0x4000>;--和M4的共享内存。
            no-map;
        };

        mcuram: mcuram@30000000 {
            compatible = "shared-dma-pool";
            reg = <0x30000000 0x40000>;
            no-map;
        };

        retram: retram@38000000 {
            compatible = "shared-dma-pool";
            reg = <0x38000000 0x10000>;
            no-map;
        };
    };

4.2 remoteproc驱动(ST32MP157)

 STM32MP157的remoteproc驱动:

  • 分配一个struct rproc。
  • 解析dts并初始化。
  • 申请Mailbox。
  • 将remoteproc加入到remoteproc框架中。
stm32_rproc_driver
  stm32_rproc_probe
    rproc_alloc--分配一个struct rproc,对应的struct rproc_ops为st_rproc_ops。
    create_workqueue
    stm32_rproc_parse_dt
      devm_request_irq
        stm32_rproc_wdg
      device_init_wakeup--支持wakeup-source时,使能中断唤醒设备功能。
      dev_pm_set_wake_irq--配置唤醒中断。
      devm_reset_control_get_by_index
      stm32_rproc_of_memory_translations--解析dma-ranges节点。
    stm32_rproc_stop
    stm32_rproc_request_mbox
      mbox_request_channel_byname
      stm32_rproc_mb_vq_work
    rproc_add--将M4的remoteproc注册到remoteproc框架中,创建了设备以及debugfs调试节点。
  stm32_rproc_remove
    rproc_shutdown
    rproc_del
    stm32_rproc_free_mbox
    destroy_workqueue
    dev_pm_clear_wake_irq
    device_init_wakeup
    rproc_free

 st_rproc_ops提供了平台特有的remoteproc操作函数集:

static struct rproc_ops st_rproc_ops = {
    .start        = stm32_rproc_start,
    .stop        = stm32_rproc_stop,
    .kick        = stm32_rproc_kick,
    .load        = stm32_rproc_elf_load_segments,
    .parse_fw    = stm32_rproc_parse_fw,
    .find_loaded_rsc_table = stm32_rproc_elf_find_loaded_rsc_table,
    .sanity_check    = stm32_rproc_elf_sanity_check,
    .get_boot_addr    = stm32_rproc_elf_get_boot_addr,
};

 stm32_rproc_start通过SMCCC配置启动M4的寄存器:

stm32_rproc_start
  stm32_rproc_add_coredump_trace
  stm32_rproc_set_hold_boot--根据安全需求通过SMCCC(安全)或者regmap(非安全)配置寄存器释放复位,启动M4。

 stm32_rproc_elf_load_segments根据ELF头将内容加载到内存中:

stm32_rproc_elf_load_segments
  rproc_elf_load_segments
    --遍历PT_LOAD段,将其加载到内存中。

4.3 通过remoteproc启动M4

查看M4状态:

cat /sys/class/remoteproc/remoteproc0/state
offline

将LED_CM4.elf固件放入/lib/firmware中,配置M4固件名称:

echo LED_CM4.elf > /sys/class/remoteproc/remoteproc0/firmware

启动M4:

echo start > /sys/class/remoteproc/remoteproc0/state

停止M4:

echo stop > /sys/class/remoteproc/remoteproc0/state

标签:struct,--,STM32MP157,rproc,stm32,int,remoteproc,Linux
From: https://www.cnblogs.com/arnoldlu/p/18280216

相关文章

  • Linux 交叉编译(toolchain) ARM aarch64版 libc++.so 库
    前言全局说明libc++源码libc++是LLVM项目提供的一个C++标准库的实现,它是KonaKart等项目的基础。由于libc++是开源>的,因此您可以在其官方仓库中找到源代码。一、说明如果您想要阅读libc++的源代码,可以按照以下步骤进行:访问libc++的官方GitHub仓库:https://github.com/llv......
  • 信号量——Linux并发之魂
    欢迎来到 破晓的历程的博客引言今天,我们继续学习Linux线程本分,在Linux条件变量中,我们对条件变量的做了详细的说明,今天我们要利用条件变量来引出我们的另一个话题——信号量内容的学习。1.复习条件变量在上一期博客中,我们没有对条件变量做具体的使用,所以,这里我们通......
  • 【LinuxC语言】手撕Http协议之accept_request函数实现(一)
    文章目录前言accept_request函数作用accept_request实现解析方法根据不同方法进行不同操作http服务器响应格式unimplemented函数实现总结前言在计算机网络中,HTTP协议是一种常见的应用层协议,它定义了客户端和服务器之间如何进行数据交换。在这篇文......
  • Linux 提权-SUID/SGID_1
    本文通过Google翻译SUID|SGIDPart-1–LinuxPrivilegeEscalation这篇文章所产生,本人仅是对机器翻译中部分表达别扭的字词进行了校正及个别注释补充。导航0前言1了解特殊权限2寻找SUID/SGID二进制文件–手动方法2.1枚举SUID二进制文件2.2枚举SGID......
  • linux打印命令的执行时间
    首先你需要找到.bashrc这个文件使用find/-name.bashrc vim/etc/skel/.bashrc新增配置exportHISTTIMEFORMAT="%F%T"刷新配置source/etc/skel/.bashrc 如果不想要时间打印,需要删除,注释还是会起作用的 我这里是没有......
  • Linux软件安装
    一、软件为什么需要安装1、安装检查2、释放文件3、复制可执行文件4、DLL动态链接库/安装服务5、注册表6、开始菜单和快捷方式二、脚本和程序的区别不需要编译的:Javascript、Python、Ruby……需要编译的:C、C++、Swift、Kotlin、Go……......
  • 在Linux中,使用rsync同步数据时,假如采用的是ssh方式,并且目标机器的sshd端端并不是默认
    在使用rsync通过SSH进行数据同步时,如果目标机器的SSH服务没有运行在默认的22端口上,你需要指定SSH连接应该使用的端口。这可以通过-e选项来实现,后面跟上ssh命令和-p参数来指定端口号。以下是使用非默认端口的SSH进行rsync同步的基本命令格式:rsync-avz-e"ssh-p<port>"<sourc......
  • 在Linux中,使用rsync服务模式时,如果指定了⼀个密码文件,那么这个密码文件的权限应该设置
    在使用rsync的服务模式时,如果使用了密码认证机制,密码文件是一个非常重要的安全组件。密码文件通常包含用户名称和加密后的密码,用于验证客户端的访问权限。为了确保密码文件的安全性,应该将其权限设置为尽可能严格。理想情况下,密码文件的权限应该设置为仅允许rsync服务进程访问......
  • 在Linux中,假如公司网站访问速度变的很慢很慢,该如何处理?
    在Linux服务器上解决公司网站访问速度慢的问题,可以从多个角度进行分析和处理。以下是一些步骤和方法:网络性能分析:检查服务器的带宽使用情况,确认是否有大量数据传输导致网络拥堵。使用工具如ping命令检测服务器与外部网络的连通性。利用traceroute命令追踪数据包路由路径,查......
  • 在Linux中,rsync同步时,如何删除目标数据多出来的数据,即源上不存在,但目标却存在的文件或
    在Linux中,rsync命令是一个非常强大且灵活的工具,用于文件和目录的同步。当使用rsync进行同步时,如果希望删除目标目录中那些不再存在于源目录中的文件或目录,你可以使用--delete选项。下面是一些关于如何使用--delete选项的详细说明:1.使用--delete选项当你在rsync命令中加入--del......