mailbox數據發送和接收的過程【轉】


轉自: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM