核间通信--Mailbox原理及内核驱动框架

2023-05-16

https://blog.csdn.net/weixin_34007291/article/details/86026346

核间通信的主要目标是:充分利用硬件提供的机制,实现高效的CORE间通信;给需要CORE间通信的应用程序提供简洁高效的编程接口。

根据所使用的硬件特性,核间通信可能的实现机制有:

  1. Mailbox中断;
  2. 基于共享内存的消息队列;
  3. POW + Group;
  4. FAU;支持原子的读,写,fetch and add操作。

每个core有一个相应的32bit的mailbox寄存器,每一位可被单独地设置或清零。这对于core间的中断非常有用,任意core可直接通过其它core 的mailbox对其它core发出中断。当mailbox被置位时,相应core的中断寄存器也同时被置位,软件可实现其中断处理。

Bootloader支持Octeon_phy_mem_named_block_alloc( ),分配以名字命名的物理内存空间,不管是Service Executive应用程序还是linux kernel都可以通过Octeon_phy_mem_named_block_find( )找到这部分内存,实现core之间的共享数据。

Linux kernel也提供了共享内存的机制。主要有mmap(),系统V,Posix共享内存模型等。系统调用mmap()通过映射一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以向访问普通内存一样对文件进行访问。系统V共享内存指的是把所有共享数据放在共享内存区域(IPC shared memory region),任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。posix共享内存区首先指定一个名字参数调用shm_open,以创建一个新的共享内存区对象或打开一个以存在的共享内存区对象。然后调用mmap把这个共享内存区映射到调用进程的地址空间。传递给shm_open的名字参数随后由希望共享该内存区的任何其他进程使用。

https://blog.csdn.net/weixin_44316996/article/details/124363855

mailbox原理
用于在片上处理器之间通信的一种mailbox队列中断机制,mailbox队列中断机制允许软件通过一组寄存器和关联的中断设置和得到信息在二个处理之间建立通信渠道。

mailbox寄存器解析
MAILBOX_SYSCONFIG寄存器
该寄存器控制通讯接口的各种参数,如下图所示可以控制复位的操作,空闲模式等
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
MAILBOX_MESSAGE_m寄存器
如下图所示MAILBOX_MESSAGE_m寄存器为消息寄存器,用于存储邮箱的下一条要读取的消息,读取完将从FIFO队列中删除该消息。
在这里插入图片描述
如下图所示,使用mailbox2 m= 0 to 11,所以一个mailbox有12个消息寄存器。,对应了也是12个可以存放消息数据的FIFO

在这里插入图片描述
MAILBOX_FIFOSTATUS_m寄存器
如上面所说的每个消息寄存器对应一个FIFO,FIFO是一种先进先出的缓存区,其有空间大小的限制,所以MAILBOX_FIFOSTATUS_m寄存器用于查看是否FIFO的状态已经装满数据了。
在这里插入图片描述
MAILBOX_MSGSTATUS_m寄存器
如下图所示MAILBOX_MSGSTATUS_m寄存器用于读取每个消息缓存区有多少个未读消息。

在这里插入图片描述
注意:每一个消息缓存区最多只能存放4个消息

MAILBOX_IRQSTATUS_CLR_u寄存器
MAILBOX_IRQSTATUS_CLR_u寄存器是中断状态寄存器,其中每个用户user都有一个中断状态寄存器,比如MAILBOX2 就有四个用户(user0 ~ user3)就有对应的四个中断状态寄存器,每一个中断状态寄存器最多可以表示16个消息队列的状态。(0~15 message)。
在这里插入图片描述
每个消息队列的状态分别又下面二位所代表,一个代表邮箱是否装满的状态位,一个代表邮箱是否有新的消息的状态位。当读取到状态位为1时表示中断状态位响应,然后写入1到对应的位置就可以关闭中断状态位。而是否装满的状态位是代表如果这个FIFO缓存区如果不是full就是触发中断。
在这里插入图片描述
MAILBOX_IRQENABLE_SET_u寄存器
MAILBOX_IRQENABLE_SET_u寄存器用于使能消息中断,跟MAILBOX_IRQSTATUS_CLR_u寄存器一样,每个用户都有对应一个寄存器。
在这里插入图片描述
对应上面有二种中断状态位的使能,当读出是1时表示这一位已经使能了,当写入1的时候将是对这个消息的中断进行使能。

在这里插入图片描述
MAILBOX_IRQENABLE_CLR_u寄存器
MAILBOX_IRQENABLE_CLR_u寄存器的作用与MAILBOX_IRQENABLE_SET_u寄存器相反,当写入1时是清除中断位。
在这里插入图片描述
在这里插入图片描述
核间通信方案
如下图所示ARM核和DSP核进行mailbox通信,ARM要发送数据给DSP,1 ARM核先往某个指定的共享内存空间buffer写入数据,然后MAILBOX触发中断和写入关于共享内存空间的地址信息给DSP。2 DSP通过得到mailbox中断的信息读取共享内存空间ARM核发送的buffer数据。3 DSP核读取完数据后将触发mailbox中断给ARM作为回应,告诉ARM核你发送的数据我已经接受完成了。
在这里插入图片描述

https://blog.csdn.net/u010961173/article/details/96422441

1、什么是异构多核SoC处理器

顾名思义,单颗芯片内集成多个不同架构处理单元核心的SoC处理器,我们称之为异构多核SoC处理器,比如:

  1. TI的OMAP-L138(DSP C674x + ARM9)、AM5708(DSP C66x + ARM Cortex-A15)SoC处理器等;
  2. Xilinx的ZYNQ(ARM Cortex-A9 + Artix-7/Kintex-7可编程逻辑架构)SoC处理器等。

2、异构多核SoC处理器有什么优势

相对于单核处理器,异构多核SoC处理器能带来性能、成本、功耗、尺寸等更多的组合优势,不同架构间各司其职,各自发挥原本架构独特的优势。比如:

  1. ARM廉价、耗能低,擅长进行控制操作和多媒体显示;
  2. DSP天生为数字信号处理而生,擅长进行专用算法运算;
  3. FPGA擅长高速、多通道数据采集和信号传输。

同时,异构多核SoC处理器核间通过各种通信方式,快速进行数据的传输和共享,可完美实现1+1>2的效果。

3、核间通信方式----Mailbox

3.1 概述

(1)mailbox是一种框架,通过消息队列和中断驱动信号处理多处理器间的通讯;
(2)mailbox的实现分为contoller和client。简单的说就是client 可以通过controller提供的channel发送信息给controller;
(3)在drivers/mailbox下实现的都是controller的源码;
具体到某个厂商的硬件,则描述如下:

Kconfig文件:内核开关,用于配置mbox模块是否编译到内核;

config ARM_MHU     
tristate "ARM MHU Mailbox"     
depends on ARM_AMBA     
help       
    Say Y here if you want to build the ARM MHU controller driver.  The controller has 3 mailbox channels, the last of which can be  used in Secure mode only.

Makefile文件:根据Kconfig编译相应的模块;

我们知道要实现mailbox的源文件其实只有两个

obj-$(CONFIG_MAILBOX) += mailbox.o
obj-$(CONFIG_ARM_MHU) += arm_mhu.o

其中,mailbox.c 是kernel提供的framework,arm_mhu.c 则是具体厂商的实现

(4)client 通过mbox_send_message给controller发送数据的时候必须指定channel;

 int mbox_send_message(struct mbox_chan *chan, void *mssg)

(5)client 在通过mbox_send_message给controller发送数据的时候必须指定channel,channel可以通过以下方式获得。
目前kernel提供了两种方法得到mailbox的channel

struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);

使用完成后调用mbox_free_channel 释放channel,这样别人就可以继续使用这个channel;

void mbox_free_channel(struct mbox_chan *chan); /* may sleep */

其中,mbox_request_channel_byname是mbox_request_channel的一个封装。

3.2 基本框架

在这里插入图片描述
目录:

drivers/mailbox

mailbox.c/mailbox.h/mailbox-test.c/-mailbox.c

3.3 关键数据结构

struct mbox_controller {
    struct device *dev;                                      // 特定mailbox驱动probe时赋值 dev = &pdev->dev
    const struct mbox_chan_ops *ops;                         // mailbox channel需要实现的功能函数
    struct mbox_chan *chans;                                 // mailbox channel指针数组
    int num_chans;                                           // mailbox channel个数
    bool txdone_irq; // 通过中断来判断上次传输是否完成
    bool txdone_poll;   // 通过poll机制来判断上次传输是否完成
    unsigned txpoll_period;                                  // POLL 周期, 以ms计
    struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
                      const struct of_phandle_args *sp);     // 获取特定channel的回调函数
    /* Internal to API */
    struct hrtimer poll_hrt;
    struct list_head node;
};
 
struct mbox_chan {
    struct mbox_controller *mbox;                            // contronller指针
    unsigned txdone_method;                                  
    struct mbox_client *cl;                                  // client指针
    struct completion tx_complete;                           //
    void *active_req;
    unsigned msg_count, msg_free;
    void *msg_data[MBOX_TX_QUEUE_LEN];
    spinlock_t lock; /* Serialise access to the channel */
    void *con_priv;
};
 
struct mbox_chan_ops {
    int (*send_data)(struct mbox_chan *chan, void *data);         // 发送数据(需要last data sent)
    int (*startup)(struct mbox_chan *chan);                       // 特定mailbox 启动
    void (*shutdown)(struct mbox_chan *chan);                     // 特定mailbox 关闭
    bool (*last_tx_done)(struct mbox_chan *chan);                 // 如果TXDONE_BY_POLL 该回调会被使用
    bool (*peek_data)(struct mbox_chan *chan);                    // 检测是否有数据
};
 
struct mbox_client {
    struct device *dev;                                           // client 设备
    bool tx_block;                                                // block until last data is all transmitted
    unsigned long tx_tout;                                        // max block period for timeout
    bool knows_txdone;                                            // txdone 回调,如果controller已经有txdone,则该配置无效
 
    void (*rx_callback)(struct mbox_client *cl, void *mssg);      // 收到数据
    void (*tx_prepare)(struct mbox_client *cl, void *mssg); // 准备数据
    void (*tx_done)(struct mbox_client *cl, void *mssg, int r);   // 检测txdone
};

在这里插入图片描述

3.4 函数接口

3.4.1 mailbox controller api

文件:kernel/include/linux/mailbox_controller.h

(1)注册、注销控制器

int mbox_controller_register(struct mbox_controller *mbox); /* can sleep */--------probe中调用
void mbox_controller_unregister(struct mbox_controller *mbox); /* can sleep */-------probe中调用

(2)(对外接口)将底层收到的数据回调给上层应用

void mbox_chan_received_data(struct mbox_chan *chan, void *data); /* atomic */

(3)通知上层当前数据已经发送完成

void mbox_chan_txdone(struct mbox_chan *chan, int r); /* atomic */

3.4.2 mailbox client api

文件:kernel/include/linux/mailbox_client.h

(1)发送数据前,申请通道

struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,
                          const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);

(2)数据发送

int mbox_send_message(struct mbox_chan *chan, void *mssg);
void mbox_client_txdone(struct mbox_chan *chan, int r); /* atomic */

(3)数据记录

bool mbox_client_peek_data(struct mbox_chan *chan); /* atomic */

(4)释放通道

void mbox_free_channel(struct mbox_chan *chan); /* may sleep */

3.5 Device Tree中的写法

kernel4.14/Documentation/devicetree/bindings/mailbox/hisilicon,hi6220-mailbox.txt

 
Hisilicon Hi6220 Mailbox Driver
===============================
 
Hisilicon Hi6220 mailbox supports up to 32 channels. Each channel
is unidirectional with a maximum message size of 8 words. I/O is
performed using register access (there is no DMA) and the cell
raises an interrupt when messages are received.
 
Mailbox Device Node(Controller):(设备节点相关的设备树)
====================
 
Required properties:
--------------------
- compatible:        Shall be "hisilicon,hi6220-mbox"
- reg:            Contains the mailbox register address range (base
            address and length); the first item is for IPC
            registers, the second item is shared buffer for
            slots.
- #mbox-cells:        Common mailbox binding property to identify the number
            of cells required for the mailbox specifier. Must be 3.
            <&phandle slot_id dst_irq ack_irq>
              phandle: Label name of mailbox controller
              slot_id: Slot id used either for TX or RX
              dst_irq: IRQ identifier index number which used by MCU
              ack_irq: IRQ identifier index number with generating a
                       TX/RX interrupt to application processor,
                   mailbox driver uses it to acknowledge interrupt
- interrupts:        Contains the interrupt information for the mailbox
            device. The format is dependent on which interrupt
            controller the SoCs use.
 
Optional Properties:
--------------------
- hi6220,mbox-tx-noirq: Property of MCU firmware's feature, so mailbox driver
            use this flag to ask MCU to enable "automatic idle
            flag" mode or IRQ generated mode to acknowledge a TX
            completion.
Example:
--------
    mailbox: mailbox@f7510000 {
        compatible = "hisilicon,hi6220-mbox";
        reg = <0x0 0xf7510000 0x0 0x1000>, /* IPC_S */
              <0x0 0x06dff800 0x0 0x0800>; /* Mailbox */
        interrupt-parent = <&gic>;
        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
        #mbox-cells = <3>;
    };
Mailbox client(client相关的设备树)
===============
Required properties:
--------------------
- compatible:        Many (See the client docs).
- mboxes:        Standard property to specify a Mailbox (See ./mailbox.txt)
            Cells must match 'mbox-cells' (See Mailbox Device Node above).
Optional Properties:
--------------------
- mbox-names:        Name given to channels seen in the 'mboxes' property.
Example:
--------
    stub_clock: stub_clock {
        compatible = "hisilicon,hi6220-stub-clk";
        hisilicon,hi6220-clk-sram = <&sram>;
        #clock-cells = <1>;
        mbox-names = "mbox-tx", "mbox-rx";
        mboxes = <&mailbox 1 0 11>, <&mailbox 0 1 10>;
    };

Example:

kernel4.14/arch/arm64/boot/dts/hisilicon/hi6220.dtsi
 
 
    mailbox: mailbox@f7510000 {
        compatible = "hisilicon,hi6220-mbox";
        reg = <0x0 0xf7510000 0x0 0x1000>, /* IPC_S */
              <0x0 0x06dff800 0x0 0x0800>; /* Mailbox */
        interrupt-parent = <&gic>;
        interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
        #mbox-cells = <3>;
    };
 
Example:
--------
 
    stub_clock: stub_clock {
        compatible = "hisilicon,hi6220-stub-clk";
        hisilicon,hi6220-clk-sram = <&sram>;
        #clock-cells = <1>;
        mbox-names = "mbox-tx", "mbox-rx";
        mboxes = <&mailbox 1 0 11>, <&mailbox 0 1 10>;   <phandle channel_index dst_irq ack_irq>
    };

3.6 原理详解

3.6.1 原理概述
在这里插入图片描述
(1)driver 通过mbox_controller_register 注册controller;
(2)client 通过mbox_request_channel调用driver->startup;
(3)client 通过mbox_send_message调用driver->send_data,并等待txdone;
(4)driver 收到remote的中断读取数据调用mbox_chan_received_data将数据放到 client->rx_buffer中;

3.6.1.1 mailbox driver流程
(1)配置controller属性:
(2)申请chan,配置chan个数
(3)配置of_xlate回调,获取chan
(4)配置chan_ops
(5)配置txdone判断方式
(6)通过mailbox_controller_register 注册controller;

3.6.1.2 mailbox client 流程
(1)通过mbox_request_channel_byname 根据"mbox-names"申请channel;
(2)创建mbox设备;
(3)通过mbox设备的write/read 函数访问controller;
其中,
write 通过调用mbox_send_message,add_to_rbuf拷贝msg到chan->msg_data[MAX = 20],msg_submit读取msg_data[idx],放到tx_prepare中,调用具体驱动的send message写寄存器;

read 通过irq驱动,irq读取寄存器得到消息,调用mailbox.c中的mbox_chan_received_data,再调用client的rx_callback将得到的数据放到client->rx_buffer中;

3.6.2 Mailbox Controller驱动

3.6.2.1 Mailbox Controller驱动初始化

3.6.2.1.1 mbox controller初始化函数

core_initcall(hi6220_mbox_init)
    >>>platform_driver_register(&hi6220_mbox_driver);
module_exit(hi6220_mbox_exit);
    >>>platform_driver_unregister(&hi6220_mbox_driver);
static struct platform_driver hi6220_mbox_driver = {
    .driver = {
        .name = "hi6220-mbox",
        .owner = THIS_MODULE,
        .of_match_table = hi6220_mbox_of_match,
    },
    .probe    = hi6220_mbox_probe,//mbox controller drivers 初始化函数
    .remove    = hi6220_mbox_remove, //mbox controller drivers 逆初始化函数
};
 
static const struct of_device_id hi6220_mbox_of_match[] = {
    { .compatible = "hisilicon,hi6220-mbox", },
    {},
};

3.6.2.1.2 调用probe/remove 函数

probe()函数主要用于初始化mbox controller.

hi6220_mbox_probe(struct platform_device *pdev)
    >>>mbox = devm_kzalloc(dev, sizeof(*mbox), GFP_KERNEL);//分配vendor设备结构体struct hi6220_mbox *mbox
    >>>初始化struct hi6220_mbox *mbox中的相关成员变量
            >>>mbox->mchan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->mchan), GFP_KERNEL);//为chan_num个struct hi6220_mbox_chan申请内存
            >>>mbox->chan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->chan), GFP_KERNEL);//为chan_num个struct mbox_chan申请内存
            >>>mbox->irq = platform_get_irq(pdev, 0);
            >>>res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
                    mbox->ipc = devm_ioremap_resource(dev, res);
            >>>    res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
                    mbox->base = devm_ioremap_resource(dev, res);
            >>>申请中断
                        err = devm_request_irq(dev, mbox->irq, hi6220_mbox_interrupt, 0,    dev_name(dev), mbox);//其中,hi6220_mbox_interrupt为中断mbox->irq对应的服务函数
            >>>初始化controller
                        mbox->controller.dev = dev;
                        mbox->controller.chans = &mbox->chan[0];
                        mbox->controller.num_chans = mbox->chan_num;
                        mbox->controller.ops = &hi6220_mbox_ops;
                        mbox->controller.of_xlate = hi6220_mbox_xlate;
 
                        for (i = 0; i < mbox->chan_num; i++) {
                            mbox->chan[i].con_priv = &mbox->mchan[i];
                            mbox->irq_map_chan[i] = NULL;
 
                            mbox->mchan[i].parent = mbox;
                            mbox->mchan[i].slot   = i;
                        }
            >>>mask and clear all interrupt vectors
                      writel(0x0,  ACK_INT_MSK_REG(mbox->ipc));
                    writel(~0x0, ACK_INT_CLR_REG(mbox->ipc));
              
            >>>判断中断使用poll方式还是中断方式
                    /* use interrupt for tx's ack */
                    if (of_find_property(node, "hi6220,mbox-tx-noirq", NULL))
                        mbox->tx_irq_mode = false;
                    else
                        mbox->tx_irq_mode = true;
                    if (mbox->tx_irq_mode)
                        mbox->controller.txdone_irq = true;
                    else {
                        mbox->controller.txdone_poll = true;
                        mbox->controller.txpoll_period = 5;
                    }
            >>>注册控制器
                err = mbox_controller_register(&mbox->controller);
            >>>保存mbox设备数据到pdev->dev->driver_data
                platform_set_drvdata(pdev, mbox);
hi6220_mbox_remove(struct platform_device *pdev)
        >>>struct hi6220_mbox *mbox = platform_get_drvdata(pdev);
        >>>mbox_controller_unregister(&mbox->controller);

3.6.2.1.3 中断处理流程
probe函数中注册中断,driver 收到remote的中断,读取数据调用mbox_chan_received_data将数据放到 client->rx_buffer中

static irqreturn_t hi6220_mbox_interrupt(int irq, void *p)
        >>>读取中断状态(哪个子中断置位???)
                   state = readl(ACK_INT_STAT_REG(mbox->ipc));
        >>>    查询每个子中断的状态并进行响应        
        while (state) {
        
                    >>>查询中断状态中的最高置1的位
                    intr_bit = __ffs(state);//
                    state &= (state - 1);
 
                    chan = mbox->irq_map_chan[intr_bit];//每个中断位对应一个中断通道
                    if (!chan) {
                        dev_warn(mbox->dev, "%s: unexpected irq vector %d\n",
                             __func__, intr_bit);
                        continue;
                    }
 
                    mchan = chan->con_priv;         //通道私有数据
                    if (mchan->dir == MBOX_TX)      //若该通道(中断)为发送方向
                        mbox_chan_txdone(chan, 0);
                    else {                          //若该通道(中断)为接受方向
                        for (i = 0; i < MBOX_MSG_LEN; i++)
                            msg[i] = readl(mbox->base +MBOX_DATA_REG(mchan->slot) + i * 4);//读取数据
 
                        mbox_chan_received_data(chan, (void *)msg);    //将数据交给数据接受函数进行处理
                    }
 
                    /* clear IRQ source */清中断
                    writel(BIT(mchan->ack_irq), ACK_INT_CLR_REG(mbox->ipc));
                    mbox_set_state(mbox, mchan->slot, MBOX_STATE_IDLE);
                }

3.6.2.2 数据接收流程

数据接收是以中断的方式进行的。

hi6220_mbox_interrupt()
        >>>for (i = 0; i < MBOX_MSG_LEN; i++)
            msg[i] = readl(mbox->base +MBOX_DATA_REG(mchan->slot) + i * 4);//读取数据
        >>>mbox_chan_received_data(chan, (void *)msg);    //讲数据交给数据接受函数进行处理
                >>>chan->cl->rx_callback(chan->cl, mssg); //上层client回调

3.6.2.3 数据发送流程
3.6.2.3.1 数据发送分为三种方式

中断方式,polling方式,ACK方式

#define TXDONE_BY_IRQ    BIT(0) /* controller has remote RTR irq */
#define TXDONE_BY_POLL    BIT(1) /* controller can read status of last TX */
#define TXDONE_BY_ACK    BIT(2) /* S/W ACK recevied by Client ticks the TX */    

3.6.2.3.2 数据发送的基本流程

1 获取mailbox的channel

1)申请通道时,client对象指定了自己的需求和能力;
2)在原子上下文中不能调用;
3)通道在一个client占用之后,没有释放之前,不能被其它client使用;
4)分配完成之后,任何此通道上接受的数据包将通过rx_callback传递到客户端
5)使用完成后调用mbox_free_channel 释放channel,这样别人就可以继续使用这个channel

void mbox_free_channel(struct mbox_chan *chan); /* may sleep */
struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index);
 
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
函数功能:通过dts中配置的channel index申请通道
        >>>of_parse_phandle_with_args(dev->of_node, "mboxes", "#mbox-cells", index, &spec)
        >>>根据dts中配置的channel index获得mbox_chan
                list_for_each_entry(mbox, &mbox_cons, node)
                    chan = mbox->of_xlate(mbox, &spec);
        >>>初始化mbox
                chan->msg_free = 0;
                chan->msg_count = 0;
                chan->active_req = NULL;
                chan->cl = cl;
                init_completion(&chan->tx_complete);
        >>>启动通道
                ret = chan->mbox->ops->startup(chan);
 
struct mbox_chan *mbox_request_channel_byname(struct mbox_client *cl,const char *name);
函数功能:通过channel name 申请通道,调用mbox_request_channel()函数来实现

2 使用mbox_send_message给controller发送数据

函数功能:在client提交数据到controller进而发送到目标处理器的过程中。
若client设置为tx_block,此函数调用只有在远程已经完成数据接受或tx_out(超时)才能返回;
若client设置为非block模式下,client的每个请求将被此API进行缓存,并返回一个非负数;
若client请求没有进入queue,将返回一个负数。
无论失败,还是成功,API将调用tx_done;

int mbox_send_message(struct mbox_chan *chan, void *mssg)
        >>>    t = add_to_rbuf(chan, mssg);    //将要发送的msg发暂存到对应通道的rbuf中
        >>>msg_submit(chan);
                >>>data = chan->msg_data[idx];
                >>>chan->cl->tx_prepare(chan->cl, data);   //发到缓存
                >>>err = chan->mbox->ops->send_data(chan, data);  //发送数据  hi6220_mbox_send_data,
                        >>>mbox_set_state(mbox, slot, MBOX_STATE_TX);
                        >>>if (mbox->tx_irq_mode)
                                    mbox_set_mode(mbox, slot, MBOX_ACK_IRQ);
                        >>>发送数据
                                for (i = 0; i < MBOX_MSG_LEN; i++)
                                    writel(buf[i], mbox->base + MBOX_DATA_REG(slot) + i * 4);
                        >>>/* trigger remote request */
                                writel(BIT(mchan->dst_irq), DST_INT_RAW_REG(mbox->ipc));
                        等待中断。。。。。。。。。。
                        ------------------------------------------------------
                        在中断服务函数中
                        发送完成中断到来----------->
                        >>>hi6220_mbox_interrupt
                                >>>mbox_chan_txdone(chan, 0);
                                        >>>tx_tick(chan, r);
                                                >>>msg_submit(chan);
                                                >>>chan->cl->tx_done(chan->cl, mssg, r);
                        ------------------------------------------------------
                >>>若为polling方式下,启定时器
                        hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
                
        >>>若为block形式的发送
                >>>设置超时时间
                        wait = msecs_to_jiffies(3600000);//永不超时
                        wait = msecs_to_jiffies(chan->cl->tx_tout);
                        
                >>>阻塞等待超时或完成
                        ret = wait_for_completion_timeout(&chan->tx_complete, wait);
                >>>若超时时间到
                        tx_tick(chan, t);
                                >>>chan->cl->tx_done(chan->cl, mssg, r);
                                >>>complete(&chan->tx_complete);

3.6.3 Mailbox Client驱动

以mailbox-test为例说明。

struct mbox_test_device {
    struct device        *dev;
    void __iomem        *tx_mmio;
    void __iomem        *rx_mmio;
    struct mbox_chan    *tx_channel;
    struct mbox_chan    *rx_channel;
    char            *rx_buffer;
    char            *signal;
    char            *message;
    spinlock_t        lock;
    wait_queue_head_t    waitq;
    struct fasync_struct    *async_queue;
};

3.6.3.1 Client 设备树相关的配置

Controller
----------
 
Required properties:
- compatible            : Should be "st,stih407-mailbox"
- reg                   : Offset and length of the device's register set
- mbox-name             : Name of the mailbox
- #mbox-cells:          : Must be 2
                          <&phandle instance channel direction>
                            phandle   : Label name of controller
                            instance  : Instance number
                            channel   : Channel number
Optional properties
- interrupts            : Contains the IRQ line for a Rx mailbox
Example:
 
mailbox0: mailbox@0  {
        compatible      = "st,stih407-mailbox";
        reg             = <0x08f00000 0x1000>;
        interrupts      = <GIC_SPI 1 IRQ_TYPE_NONE>;
        #mbox-cells     = <2>;
        mbox-name       = "a9";
};
Client
------
 
Required properties:
- compatible            : Many (See the client docs)
- reg                   : Shared (between Application and Remote) memory address
- mboxes                : Standard property to specify a Mailbox (See ./mailbox.txt)
                          Cells must match 'mbox-cells' (See Controller docs above)
Optional properties
- mbox-names            : Name given to channels seen in the 'mboxes' property.
 
Example:
 
mailbox_test {
        compatible      = "mailbox-test";
        reg             = <0x[shared_memory_address], [shared_memory_size]>;
        mboxes          = <&mailbox2 0 1>, <&mailbox0 2 1>;
        mbox-names      = "tx", "rx";
};

3.6.3.2 Client初始化

static struct platform_driver mbox_test_driver = {
	.driver = {
		.name = "mailbox_test",
		.of_match_table = mbox_test_match,
	},
	.probe  = mbox_test_probe,
	.remove = mbox_test_remove,
};
module_platform_driver(mbox_test_driver);
 
static int mbox_test_probe(struct platform_device *pdev)
	>>>tdev = devm_kzalloc(&pdev->dev, sizeof(*tdev), GFP_KERNEL);
	>>>res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	>>>size = resource_size(res);
	>>>tdev->tx_mmio = devm_ioremap_resource(&pdev->dev, res);
	>>>申请通道
		tdev->tx_channel = mbox_test_request_channel(pdev, "tx");
		tdev->rx_channel = mbox_test_request_channel(pdev, "rx");
				>>> client = devm_kzalloc(&pdev->dev, sizeof(*client), GFP_KERNEL);
				>>> client->dev		= &pdev->dev;
				>>> client->rx_callback	= mbox_test_receive_message;
				>>> client->tx_prepare	= mbox_test_prepare_message;
				>>> client->tx_done		= mbox_test_message_sent;
				>>> client->tx_block	= true;
				>>> client->knows_txdone	= false;
				>>> client->tx_tout		= 500;
				>>> channel = mbox_request_channel_byname(client, name);  //调用API申请通道
	>>>platform_set_drvdata(pdev, tdev);
	
	>>>spin_lock_init(&tdev->lock);
	>>>tdev->rx_buffer = devm_kzalloc(&pdev->dev,
					   MBOX_MAX_MSG_LEN, GFP_KERNEL);
	>>>ret = mbox_test_add_debugfs(pdev, tdev);
	>>>init_waitqueue_head(&tdev->waitq);
static int mbox_test_remove(struct platform_device *pdev)
	>>> debugfs_remove_recursive(root_debugfs_dir);
	>>> mbox_free_channel(tdev->tx_channel);
	>>> mbox_free_channel(tdev->rx_channel);

3.6.3.3 Client数据收发

数据接收(回调函数)
static void mbox_test_receive_message(struct mbox_client *client, void *message)
	spin_lock_irqsave(&tdev->lock, flags);
	if (tdev->rx_mmio) {
		memcpy_fromio(tdev->rx_buffer, tdev->rx_mmio, MBOX_MAX_MSG_LEN);
	} else if (message) {
		memcpy(tdev->rx_buffer, message, MBOX_MAX_MSG_LEN);
	}
	mbox_data_ready = true;
	spin_unlock_irqrestore(&tdev->lock, flags);
 
	wake_up_interruptible(&tdev->waitq);
 
	kill_fasync(&tdev->async_queue, SIGIO, POLL_IN);
 
 
数据发送
static void mbox_test_prepare_message(struct mbox_client *client, void *message)
{
	struct mbox_test_device *tdev = dev_get_drvdata(client->dev);
 
	if (tdev->tx_mmio) {
		if (tdev->signal)
			memcpy_toio(tdev->tx_mmio, tdev->message, MBOX_MAX_MSG_LEN);
		else
			memcpy_toio(tdev->tx_mmio, message, MBOX_MAX_MSG_LEN);
	}
}
 
static void mbox_test_message_sent(struct mbox_client *client,
				   void *message, int r)
{
	if (r)
		dev_warn(client->dev,
			 "Client: Message could not be sent: %d\n", r);
	else
		dev_info(client->dev,
			 "Client: Message sent\n");
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

核间通信--Mailbox原理及内核驱动框架 的相关文章

  • 阿里云服务器的搭建和部署(小白教程)

    阿里云服务器的搭建和部署 xff08 小白教程 xff09 一 购买服务器二 管理云服务器三 环境配置1 JDK的配置与下载2 tomcat的配置与下载3 MySQL的安装与配置 四 外网访问服务器 个人推荐阿里云 因为里面有一个大学生的云
  • 一篇带你搞懂Python3 中的 def __init__

    在学习python 100 days时 xff0c 在面向对象编程基础的那一块 xff0c 封装一个class时 xff0c 突然出现def init 的方法 xff0c 刚开始时 xff0c 对他的理解很模糊 xff0c 为什么定义一个类
  • 时间序列异常检测综述

    1 Introduction 时序异常检测几个可以运用的点 xff1a 1 欺诈检测 2 工业数据检测 简介一下 xff1a 异常检测很久之前就有了 最早可以追溯到 J Fox 1972 Outliers in Time Series Jo
  • Linux基础----Makefile(1)

    前言 刚开始学习Linux xff0c 这些那真的是新知识 xff0c 由于感觉将来FPGA的学习会越来越靠近软件的方向发展 xff0c 所以觉得有必要好好地学习一下嵌入式的东西 xff0c 因此有必要把学习的过程记录下来 xff0c 方便
  • 【OpenCV】ChArUco标定板角点的检测Detection of ChArUco Corners

    opencv3 4 15源文档链接 link ChArUco标定板角点的检测 GoalSource codeCharuco板创建ChArUco板检测ChArUco姿势估计 ArUco标记和板的快速检测和多功能性是非常有用的 然而 xff0c
  • 错误 MSB3721

    错误 MSB3721 命令 C Program Files NVIDIA GPU Computing Toolkit CUDA v10 2 bin nvcc exe gencode 61 arch 61 compute 30 code 61
  • 倒立摆状态反馈控制——分析、建模与仿真(matlab)

    倒立摆状态反馈控制 引言 倒立摆是机器人学中一个非常重要的模型 xff0c 火箭 导弹 独轮车 双足机器人 四足机器人 xff0c 基本都是倒立摆的变形 问题描述 关于倒立摆的问题描述如下 xff1a 如图所示的倒立摆系统 摆的关节连接在一
  • docker pull rabbitmq:management 怎样指定版本

    docker pull rabbitmq 3 8 1 management
  • git 命令学习

    git 命令学习 git clone https github com zhaji01 notes git 克隆远程仓库 git status 本地仓库状态 git add lt file gt 把修改 xff08 包括创建 修改 删除 解
  • 【实例记录】在ubuntu上运行python实现与单片机多线程串口通信

    文章目录 工具步骤 工具 工具 xff1a 自己电脑双系统的ubuntu18 04 单片机esp8266 一个usb转ttl模块 xff0c ubuntu上已经下载了python的3 6和pip xff0c 还需要pip install s
  • 【过程记录 】windows和ubuntu两台电脑局域网进行socket通信收发数据和传输文件

    实验图片和前期准备 xff1a ubuntu作为服务端 xff0c windows客户端传输数据和文件 xff1a windows作为服务端 xff0c ubuntu作为客户端 xff1a 实验图片和前期准备 xff1a 服务端发送和接受i
  • 过程记录 yolov3目标检测输出目标坐标和原图物体像素坐标比较

    设备 xff1a jetsonnano B01 一个usb广角摄像头 语言为python 库为opencv 框架pytorch 大家都知道yolov3的坐标变换过程比较复杂 xff0c 大概要经过图片缩放 xff0c 对数空间变换等等 xf
  • Rt-Thread学习笔记-----信号量(五)

    线程间同步 1 什么是线程间同步 xff1f 同步是指按预定的先后次序进行运行 xff0c 线程同步是指多个线程通过特定的机制来控制线程之间的执行顺序 xff0c 也可以说是在线程之间通过同步建立起执行顺序的关系 xff0c 如果没有同步
  • C++类和对象——空指针访问成员函数

    C 43 43 中空指针也是可以访问成员函数的 xff0c 但是也要注意有没有用到this指针 xff1b 如果用到this指针 xff0c 需要加以判断保证代码的健壮性 span class token macro property sp
  • nodejs实现简单的自动化部署

    如题 xff0c nodejs通过码云提供的web hooks实现简单的服务器自动部署 大致流程 xff1a 1 通过码云提供的web hooks xff0c 创建一个request通过后的回调接口 xff08 说白了就是配置一个码云审批通
  • 2022届春招实习面经(CV岗)——offer经

    已拿offer公司 xff1a 腾讯 ponyai vivo研究院 华为 字节 面了一面就没继续面了 xff1a 海康威视 虎牙 京东 本科211 xff0c 硕士985 二区在投论文 43 顶会下的top5比赛 43 小厂三个月实习经历
  • LeetCode刷题笔记 --- python

    目录 一 python交换两个变量的值1 1 使用tuple1 2 使用临时变量temp 二 python中 和 区别三 python列表的使用3 1 列表的基本操作3 2 列表实现栈操作3 3 列表实现排序3 4 列表的算法效率 四 py
  • 无人机高度控制

    这个第一次看就完全没看懂 xff0c 现在再看还是没看懂orz xff0c 而且定高还是重要的功能和考点 xff0c 详细分析一下程序吧 首先是表示高度信息的结构体 xff1a 数据结构声明 typedef struct float Z S
  • ssh_exchange_identification: Connection closed by remote host

    ssh exchange identification Connection closed by remote host 导致这个问题的原因有很多 xff0c 笔者是因为在ssh中设置了代理 xff0c 这个可以作为阅读者排查问题的一个点
  • 匿名无人机飞控代码整理5

    先跳过高度部分 xff0c 这里看location部分 可以看出来这部分也是直接与我们的循迹 追踪任务相关的 所以这部分的掌握应该很重要把 前面有很多暂时不需要看 xff0c flyctrl那个巨长 所以就先看速度环控制部分了 if swi

随机推荐

  • 匿名无人机飞控代码整理

    看了半天 xff0c 各部分都看得都很零散 xff0c 写的也很简略 xff0c 但目前为止还是无法对系统各部分做具体一点的整合 xff0c 今天试试看 1 先从主函数起 xff0c 进入主轮询函数 Main Task 这个主函数的调用就在
  • 一直没看的无人机定高

    除了定高的部分 xff0c 其他没看的还有一些控制函数 定高的原理的话 xff0c 也是利用了两级pid xff0c 按照原本的理解 xff0c 从外环开始看的话 xff0c 反馈高度比较容易获得 xff0c 就是激光测距得到的高度 期望高
  • 匿名无人机代码FlightCtrl简单分析

    这个flightCtrl文件 xff0c 是真的很长又很难 各种标志位啊 xff0c 判断啊 xff0c 开关啊 xff0c 逻辑判断啊什么的 xff0c 趁通宵把代码梳理一遍 这个文件里的函数虽不算最多 xff0c 但引用的头文件相当多
  • 简历—项目经验范例

    xff08 看着比较专业的一份项目经验样板 xff09 原文链接https mp weixin qq com s rxGTTVKryvYoyst jsayLw 项目一 米乐淘网上商城 项目名称 xff1a 米乐淘网上商城 开发环境 xff1
  • 家庭网络和路由器

    1 什么是家庭网络 xff1f 一个典型的家庭网络由多个设备组成 xff0c 且几乎所有的家庭网络都有一个路由器作为它们的中心设备 路由器连接到 Internet 连接 xff0c 然后与本地网络上的一台或多台计算机共享该连接 家庭网络通常
  • ROS动态调整PID

    64 动态调整PID ROS提供了一个专门用于动态调整参数的功能包dynamic reconfigure 它实现了动态配置参数的机制 我们先来创建一个功能包 添加相应的一些依赖 cd catkin ws src catkin create
  • CubeMX配置串口的程序烧入板子不跑的解决方法

    对于cubeMX配置串口 xff0c keil5编译通过的 xff0c 自己确定无问题的程序 xff0c 以ISP烧入 xff0c 烧入板子后无法运行的情况 xff0c 我暂时的解决策略是按住reset键点击 开始编程 xff0c 点击后松
  • realsense D455+ROS+OpenCV4.5完成目标距离检测

    ROS OpenCV 1 环境配置 1 1 realsense SDK2 0安装 通过官网找到最新的SDK包并下载 Intel RealSense SDK 2 0 解压安装包 xff08 librealsense 2 47 0 tar gz
  • 什么是 PID 控制器:工作原理及其应用

    什么是 PID 控制器 xff1a 工作原理及其应用 什么是PID控制器 xff1f 历史PID控制器框图PID控制器的工作P 控制器I 控制器D 控制器 PID控制器的类型开 关控制比例控制标准型PID控制器实时 PID 控制器 调优方法
  • 什么是缓冲区

    1 什么是缓冲区 缓冲区又称为缓存 xff0c 它是内存空间的一部分 也就是说 xff0c 在内存空间中预留了一定的存储空间 xff0c 这些存储空间用来缓冲输入或输出的数据 xff0c 这部分预留的空间就叫做缓冲区 缓冲区根据其对应的是输
  • FreeRTOS系统解析-1、FreeRTOS系统简介

    1 系统简介 不同的的多任务系统有不同的侧重点 以工作站和桌面电脑为例 xff1a 早期的处理器非常昂贵 xff0c 多以那时的多任务用于实现在单处理器上支持多用户 这类系统中的调度算法侧重于让每个用户 公平共享 处理器时间 随着处理器的功
  • 目标检测 YOLOv5 常见的边框(bounding box )坐标矩形框表示方法

    将txt格式的真值框 xff08 Ground Truth xff09 在原图上显示 具体过程坎坷 xff0c 以下博主提供了思路 xff0c 学习了yolo格式label的归一化和坐标求解 xff01 1 https blog csdn
  • momenta实习面经

    走的火箭计划内推 xff0c 链接https mp weixin qq com s zllOky0biV9zn1Qfbg4XZg 线上先做了一套题 xff0c 写的2小时但是打开界面发现倒计时有10小时 xff0c 于是悠哉悠哉慢慢做结果2
  • 树莓派4B + Ubuntu18.04 + RealSense SDK

    有段时间没写博客了 xff0c 今天心血来潮 xff0c 记录一下 我自己的配置在标题写的很清楚 xff0c 用的是ros1 安装步骤我是建议 xff1a ubuntu gt realsense SDK gt ros gt ros wrap
  • ubuntu18.04安装ROS Melodic(最详细配置)

    前期准备 61 61 设置软件源 xff1a 国外的 xff1a sudo sh c 39 echo 34 deb http packages ros org ros ubuntu lsb release sc main 34 gt etc
  • 3步搞定CSDN中代码背景颜色的修改

    1 进入内容管理 xff0c 点击最下方的博客设置 2 修改
  • 2019电赛--无人机题目OpenMV总结

    此文章在我的博客链接 xff1a https sublimerui top archives d508d500 html NOTES xff1a 上一篇相关博文 xff0c 准备阶段OpenMV学习笔记链接 xff1a https blog
  • 大疆精灵4RTK自定义三维航线规划(开源)

    大疆精灵4rtk是无人机摄影测量行业的一款里程碑式的产品 xff0c 极大地拓展了无人机摄影测量的应用领域 然而 xff0c 大疆官方只提供了有限的航线规划功能 xff0c 如带状航线 井字航线 xff0c 5向飞行 xff0c 仿地飞行等
  • docker拉取RabbitMq镜像并安装

    RabbitMQ安装入门篇 文章目录 前言一 Docker拉取RabbitMq镜像二 docker下启动RabbitMq容器三 查看RabbitMq是否启动总结 前言 这篇文章为了方便初学者入门 xff0c 在linux环境下用docker
  • 核间通信--Mailbox原理及内核驱动框架

    https blog csdn net weixin 34007291 article details 86026346 核间通信的主要目标是 xff1a 充分利用硬件提供的机制 xff0c 实现高效的CORE间通信 xff1b 给需要CO