https://blog.csdn.net/weixin_34007291/article/details/86026346
核间通信的主要目标是:充分利用硬件提供的机制,实现高效的CORE间通信;给需要CORE间通信的应用程序提供简洁高效的编程接口。
根据所使用的硬件特性,核间通信可能的实现机制有:
- Mailbox中断;
- 基于共享内存的消息队列;
- POW + Group;
- 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处理器,比如:
- TI的OMAP-L138(DSP C674x + ARM9)、AM5708(DSP C66x + ARM Cortex-A15)SoC处理器等;
- Xilinx的ZYNQ(ARM Cortex-A9 + Artix-7/Kintex-7可编程逻辑架构)SoC处理器等。
2、异构多核SoC处理器有什么优势
相对于单核处理器,异构多核SoC处理器能带来性能、成本、功耗、尺寸等更多的组合优势,不同架构间各司其职,各自发挥原本架构独特的优势。比如:
- ARM廉价、耗能低,擅长进行控制操作和多媒体显示;
- DSP天生为数字信号处理而生,擅长进行专用算法运算;
- 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);
其中,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;
const struct mbox_chan_ops *ops;
struct mbox_chan *chans;
int num_chans;
bool txdone_irq;
bool txdone_poll;
unsigned txpoll_period;
struct mbox_chan *(*of_xlate)(struct mbox_controller *mbox,
const struct of_phandle_args *sp);
struct hrtimer poll_hrt;
struct list_head node;
};
struct mbox_chan {
struct mbox_controller *mbox;
unsigned txdone_method;
struct mbox_client *cl;
struct completion tx_complete;
void *active_req;
unsigned msg_count, msg_free;
void *msg_data[MBOX_TX_QUEUE_LEN];
spinlock_t lock;
void *con_priv;
};
struct mbox_chan_ops {
int (*send_data)(struct mbox_chan *chan, void *data);
int (*startup)(struct mbox_chan *chan);
void (*shutdown)(struct mbox_chan *chan);
bool (*last_tx_done)(struct mbox_chan *chan);
bool (*peek_data)(struct mbox_chan *chan);
};
struct mbox_client {
struct device *dev;
bool tx_block;
unsigned long tx_tout;
bool knows_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);
};
3.4 函数接口
3.4.1 mailbox controller api
文件:kernel/include/linux/mailbox_controller.h
(1)注册、注销控制器
int mbox_controller_register(struct mbox_controller *mbox); --------probe中调用
void mbox_controller_unregister(struct mbox_controller *mbox); -------probe中调用
(2)(对外接口)将底层收到的数据回调给上层应用
void mbox_chan_received_data(struct mbox_chan *chan, void *data);
(3)通知上层当前数据已经发送完成
void mbox_chan_txdone(struct mbox_chan *chan, int r);
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);
(3)数据记录
bool mbox_client_peek_data(struct mbox_chan *chan);
(4)释放通道
void mbox_free_channel(struct mbox_chan *chan);
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>,
<0x0 0x06dff800 0x0 0x0800>;
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>,
<0x0 0x06dff800 0x0 0x0800>;
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,
.remove = hi6220_mbox_remove,
};
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);
>>>初始化struct hi6220_mbox *mbox中的相关成员变量
>>>mbox->mchan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->mchan), GFP_KERNEL);
>>>mbox->chan = devm_kzalloc(dev,mbox->chan_num * sizeof(*mbox->chan), GFP_KERNEL);
>>>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);
>>>初始化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方式还是中断方式
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);
}
清中断
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);
3.6.2.3 数据发送流程
3.6.2.3.1 数据发送分为三种方式
中断方式,polling方式,ACK方式
#define TXDONE_BY_IRQ BIT(0)
#define TXDONE_BY_POLL BIT(1)
#define TXDONE_BY_ACK BIT(2)
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);
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_submit(chan);
>>>data = chan->msg_data[idx];
>>>chan->cl->tx_prepare(chan->cl, data);
>>>err = chan->mbox->ops->send_data(chan, 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);
>>>
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);
>>>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(使用前将#替换为@)