轉自:https://blog.csdn.net/tiantao2012/article/details/78030580
我們知道在client 在通過mbox_send_message給controller發送數據的時候必須指定channel。例如下面的code
dc_sync->mbox =
(&dc_sync->cl, 0);
/* Populate data packet */
/* sp.abc = 123; etc */
/* Send message to remote in blocking mode */
mbox_send_message(dc_sync->mbox, &sp);
/* At this point 'sp' has been sent */
目前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的一個包裝。所以這里直接看看mbox_request_channel
struct mbox_chan *mbox_request_channel(struct mbox_client *cl, int index)
{
struct device *dev = cl->dev;
struct mbox_controller *mbox;
struct of_phandle_args spec;
struct mbox_chan *chan;
unsigned long flags;
int ret;
spin_lock_irqsave(&chan->lock, flags);
chan->msg_free = 0;
chan->msg_count = 0;
chan->active_req = NULL;
chan->cl = cl;
init_completion(&chan->tx_complete);
//初始化chan,並最終startup
ret = chan->mbox->ops->startup(chan);
if (ret) {
dev_err(dev, "Unable to startup the chan (%d)\n", ret);
mbox_free_channel(chan);
chan = ERR_PTR(ret);
}
}
以之前的arm_mhu.c 中定義的mbox_chan_ops為例
static const struct mbox_chan_ops mhu_ops = {
.send_data = mhu_send_data,
.startup = mhu_startup,
.shutdown = mhu_shutdown,
.last_tx_done = mhu_last_tx_done,
};
static int mhu_startup(struct mbox_chan *chan)
{
struct mhu_link *mlink = chan->con_priv;
u32 val;
int ret;
val = readl_relaxed(mlink->tx_reg + INTR_STAT_OFS);
writel_relaxed(val, mlink->tx_reg + INTR_CLR_OFS);
原來就是注冊了一個中斷,其回調函數是mhu_rx_interrupt
ret = request_irq(mlink->irq, mhu_rx_interrupt,
IRQF_SHARED, "mhu_link", chan);
if (ret) {
dev_err(chan->mbox->dev,
"Unable to acquire IRQ %d\n", mlink->irq);
return ret;
}
return 0;
}
這個中斷函數如下:
當client 給controller 通過mbox_send_message發送數據后,arm_mhu 會產生一個中斷給cotroller。
static irqreturn_t mhu_rx_interrupt(int irq, void *p)
{
struct mbox_chan *chan = p;
struct mhu_link *mlink = chan->con_priv;
u32 val;
val = readl_relaxed(mlink->rx_reg + INTR_STAT_OFS);
if (!val)
return IRQ_NONE;
controller調用mbox_chan_received_data 就可以得到client發送來的數據
mbox_chan_received_data(chan, (void *)&val);
writel_relaxed(val, mlink->rx_reg + INTR_CLR_OFS);
return IRQ_HANDLED;
}
void mbox_chan_received_data(struct mbox_chan *chan, void *mssg)
{
讀去數據后,調用client的rx_callback 通知client
/* No buffering the received data */
if (chan->cl->rx_callback)
chan->cl->rx_callback(chan->cl, mssg);
}
controller接收數據的flow 清楚了,再看看client是如何調用mbox_send_message 發送數據的
mbox_send_message->msg_submit
if (chan->cl->tx_prepare)
chan->cl->tx_prepare(chan->cl, data);
/* Try to submit a message to the MBOX controller */
err = chan->mbox->ops->send_data(chan, data);
if (!err) {
chan->active_req = data;
chan->msg_count--;
}
最終還是調用controll而的send_data 發送數據,本例controller的send_data函數為mhu_send_data
static int mhu_send_data(struct mbox_chan *chan, void *data)
{
struct mhu_link *mlink = chan->con_priv;
u32 *arg = data;
就是寫controller的一個寄存器就行了,client寫了之后后觸發中斷,controller會在中斷中讀到數據,並通過mbox_chan_received_data 通知client已經讀取數據了
writel_relaxed(*arg, mlink->tx_reg + INTR_SET_OFS);
return 0;
}
————————————————
版權聲明:本文為CSDN博主「tiantao2012」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/tiantao2012/article/details/78030580