rpmsg

news/2025/3/19 23:42:25/

struct rproc

通讯的硬件基础是rproc virtio_device,rproc_add时会register_virtio_device,然后virtio_ipc_driver的rpmsg_probe执行,后面的rpmsg_device endpoint都是借助rproc virtio_device完成通讯

static struct rproc_ops rproc_ops = { 

   .kick            ,
    .load        
    .start         ,
    .stop         ,
    .find_loaded_rsc_table 
    .parse_fw   
};

rproc_add
rproc_trigger_auto_boot
rproc_boot
rproc_fw_boot
rproc_handle_resources
rproc_loading_handlers
rproc_handle_vdev
rproc_vdev_do_start
rproc_add_virtio_dev
    register_virtio_device
    

virtio_ipc_driver

virtio_find_vqs
rpmsg_probe
rpmsg_virtio_add_ctrl_dev
virtio_rpmsg_ops
virtio_rpmsg_create_channel
rpmsg_ns_register_device
rpmsg_register_device  

vnet根据rpmsg drivers利用rpmsg device通讯

parse_fw中的内存使用ioremap_wc,无cache.

static inline void virtio_wmb(bool weak_barriers)
{
    if (weak_barriers)
        virt_wmb();
    else
        dma_wmb();
}

比如vnet, remote process创建好后发送消息给host rpmsg_ns_cb, rpmsg_ns_cb创建rpmsg_device,然后与vnet中注册的rpmsg_driver匹配

/* invoked when a name service announcement arrives */
static int rpmsg_ns_cb(struct rpmsg_device *rpdev, void *data, int len,
               void *priv, u32 src)
{
    struct rpmsg_ns_msg *msg = data;
    struct rpmsg_device *newch;
    struct rpmsg_channel_info chinfo;
    struct device *dev = rpdev->dev.parent;
    int ret;

#if defined(CONFIG_DYNAMIC_DEBUG)
    dynamic_hex_dump("NS announcement: ", DUMP_PREFIX_NONE, 16, 1,
             data, len, true);
#endif

    if (len != sizeof(*msg)) {
        dev_err(dev, "malformed ns msg (%d)\n", len);
        return -EINVAL;
    }

    /* don't trust the remote processor for null terminating the name */
    msg->name[RPMSG_NAME_SIZE - 1] = '\0';

    strncpy(chinfo.name, msg->name, sizeof(chinfo.name));
    chinfo.src = RPMSG_ADDR_ANY;
    chinfo.dst = rpmsg32_to_cpu(rpdev, msg->addr);

    dev_info(dev, "%sing channel %s addr 0x%x\n",
         rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY ?
         "destroy" : "creat", msg->name, chinfo.dst);

    if (rpmsg32_to_cpu(rpdev, msg->flags) & RPMSG_NS_DESTROY) {
        ret = rpmsg_release_channel(rpdev, &chinfo);
        if (ret)
            dev_err(dev, "rpmsg_destroy_channel failed: %d\n", ret);
    } else {
        newch = rpmsg_create_channel(rpdev, &chinfo);
        if (!newch)
            dev_err(dev, "rpmsg_create_channel failed\n");
    }

    return 0;
}

static int rpmsg_ns_probe(struct rpmsg_device *rpdev)
{
    struct rpmsg_endpoint *ns_ept;
    struct rpmsg_channel_info ns_chinfo = {
        .src = RPMSG_NS_ADDR,
        .dst = RPMSG_NS_ADDR,
        .name = "name_service",
    };

    /*
     * Create the NS announcement service endpoint associated to the RPMsg
     * device. The endpoint will be automatically destroyed when the RPMsg
     * device will be deleted.
     */

    ns_ept = rpmsg_create_ept(rpdev, rpmsg_ns_cb, NULL, ns_chinfo);
    if (!ns_ept) {
        dev_err(&rpdev->dev, "failed to create the ns ept\n");
        return -ENOMEM;
    }
    rpdev->ept = ns_ept;

    return 0;
}

static struct rpmsg_driver rpmsg_ns_driver = {
    .drv.name = KBUILD_MODNAME,
    .probe = rpmsg_ns_probe,
};

当从端的rpmsg_device与rpmsg_driver匹配时会给主端发送announce信息,然后主端会创建对应的rpmsg_device。

static int virtio_rpmsg_announce_create(struct rpmsg_device *rpdev)
{
    struct virtio_rpmsg_channel *vch = to_virtio_rpmsg_channel(rpdev);
    struct virtproc_info *vrp = vch->vrp;
    struct device *dev = &rpdev->dev;
    int err = 0;

    /* need to tell remote processor's name service about this channel ? */
    if (rpdev->announce && rpdev->ept &&
        virtio_has_feature(vrp->vdev, VIRTIO_RPMSG_F_NS)) {
        struct rpmsg_ns_msg nsm;

        strncpy(nsm.name, rpdev->id.name, RPMSG_NAME_SIZE);
        nsm.addr = cpu_to_rpmsg32(rpdev, rpdev->ept->addr);
        nsm.flags = cpu_to_rpmsg32(rpdev, RPMSG_NS_CREATE);

        err = rpmsg_sendto(rpdev->ept, &nsm, sizeof(nsm), RPMSG_NS_ADDR);
        if (err)
            dev_err(dev, "failed to announce service %d\n", err);
    }

    return err;
}

/*
 * when an rpmsg driver is probed with a channel, we seamlessly create
 * it an endpoint, binding its rx callback to a unique local rpmsg
 * address.
 *
 * if we need to, we also announce about this channel to the remote
 * processor (needed in case the driver is exposing an rpmsg service).
 */

static int rpmsg_dev_probe(struct device *dev)
{
    struct rpmsg_device *rpdev = to_rpmsg_device(dev);
    struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver);
    struct rpmsg_channel_info chinfo = {};
    struct rpmsg_endpoint *ept = NULL;
    int err;

    err = dev_pm_domain_attach(dev, true);
    if (err)
        goto out;

    if (rpdrv->callback) {
        strncpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE);
        chinfo.src = rpdev->src;
        chinfo.dst = RPMSG_ADDR_ANY;

        ept = rpmsg_create_ept(rpdev, rpdrv->callback, NULL, chinfo);
        if (!ept) {
            dev_err(dev, "failed to create endpoint\n");
            err = -ENOMEM;
            goto out;
        }

        rpdev->ept = ept;
        rpdev->src = ept->addr;
    }

    err = rpdrv->probe(rpdev);
    if (err) {
        dev_err(dev, "%s: failed: %d\n", __func__, err);
        goto destroy_ept;
    }

    if (ept && rpdev->ops->announce_create) {
        err = rpdev->ops->announce_create(rpdev);
        if (err) {
            dev_err(dev, "failed to announce creation\n");
            goto remove_rpdev;
        }
    }

    return 0;

remove_rpdev:
    if (rpdrv->remove)
        rpdrv->remove(rpdev);
destroy_ept:
    if (ept)
        rpmsg_destroy_ept(ept);
out:
    return err;
}

static struct bus_type rpmsg_bus = {
    .name        = "rpmsg",
    .match        = rpmsg_dev_match,
    .dev_groups    = rpmsg_dev_groups,
    .uevent        = rpmsg_uevent,
    .probe        = rpmsg_dev_probe,
    .remove        = rpmsg_dev_remove,
};


http://www.ppmy.cn/news/903985.html

相关文章

GPGGA \ GPRMC 格式解析

一、GPGGA格式解析 示例: $GPGGA,044744.00,3122.4658,N,12025.2791,E,1,10,3.00,12.575,M,7.100,M,00,0000*5F 解析说明: 字段0:$GPGGA,语句ID,表明该语句为Global Positioning System Fix Data(GGA&…

GMRP

gmrp(garp multicast registration protocol,garp组播注册协议)是基于garp的一个组播注册协议,用于维护交换机中的组播注册信息。所有支持gmrp的交换机都能够接收来自其他交换机的组播注册信息,并动态更新本地的组播注…

【论文阅读】GaitSet: Regarding Gait as a Set for Cross-View Gait Recognition

GaitSet: Regarding Gait as a Set for Cross-View Gait Recognition 摘要IntroGaitSet问题公式描述Set PoolingHorizontal Pyramid MappingMultilayer Global Pipeline 训练和测试实验 论文信息: 作者:Hanqing Chao, Yiwei He, Junping Zhang, Jianfen…

R语言基础绘图包--控制axis label位置--par(mgp)与mtext

代码 png("mtext.pdf") plot(1:10, type"n", xaxt"n", yaxt"n", ylab"original ylab site", xlab"original xlab site")for(j in 1:4) for(i in 0:10) mtext(as.character(i),sidej,linei) dev.of…

【软考软件评测师】2018年下案例分析历年真题

【软考软件评测师】2018年下案例分析历年真题 2018下案例分析历年真题 【软考软件评测师】2018年下案例分析历年真题2018下案例分析历年真题第一题(15分)2018下案例分析历年真题第二题(20分)2018下案例分析历年真题第三题&#xf…

GARP和GVRP的简介

文章目录 1.简介及其应用2.封包结构、类型和差异3.属性注册和注销的过程4.三个定时器及其作用5.收到event的行为6.两个状态机(Applicant和Register)7.三种注册模式Normal文章说明 1.简介及其应用 GARP(General Attribute Register Protocol)&#xff0c…

R语言作图:坐标轴设置

要绘制一张赏心悦目的统计图表,坐标轴的设置至关重要。在R语言底层作图中,对坐标轴的调整主要通过调整plot函数、axis函数和title函数的一系列参数完成。 plot(x,y, ...) axis(side,at NULL, labels TRUE, tick TRUE, line NA, pos NA, outer FAL…

pnpm:简介

一、概念 performant npm ,意味“高性能的 npm”。pnpm由npm/yarn衍生而来,解决了npm/yarn内部潜在的bug,极大的优化了性能,扩展了使用场景。被誉为“最先进的包管理工具” 二、特点: 速度快、节约磁盘空间、支持mo…