diff options
author | Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com> | 2020-07-05 14:37:16 +0800 |
---|---|---|
committer | Jassi Brar <jaswinder.singh@linaro.org> | 2020-08-03 23:56:38 -0500 |
commit | 884996986347dbe3b735cfa9bc041dd98a533796 (patch) | |
tree | 79277de1ab4665a190cf0d97ddf31a844c5b9736 /drivers | |
parent | bb2b06e08157c1f542506ce3ed59cc3309eacb78 (diff) | |
download | linux-884996986347dbe3b735cfa9bc041dd98a533796.tar.gz linux-884996986347dbe3b735cfa9bc041dd98a533796.tar.bz2 linux-884996986347dbe3b735cfa9bc041dd98a533796.zip |
mailbox: mediatek: cmdq: clear task in channel before shutdown
Do success callback in channel when shutdown. For those task not finish,
callback with error code thus client has chance to cleanup or reset.
Signed-off-by: Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com>
Reviewed-by: CK Hu <ck.hu@mediatek.com>
Reviewed-by: Bibby Hsieh <bibby.hsieh@mediatek.com>
Signed-off-by: Jassi Brar <jaswinder.singh@linaro.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/mailbox/mtk-cmdq-mailbox.c | 38 |
1 files changed, 38 insertions, 0 deletions
diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c index 08bd4f1eb469..484d4438cd83 100644 --- a/drivers/mailbox/mtk-cmdq-mailbox.c +++ b/drivers/mailbox/mtk-cmdq-mailbox.c @@ -349,6 +349,12 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data) if (list_empty(&thread->task_busy_list)) { WARN_ON(clk_enable(cmdq->clock) < 0); + /* + * The thread reset will clear thread related register to 0, + * including pc, end, priority, irq, suspend and enable. Thus + * set CMDQ_THR_ENABLED to CMDQ_THR_ENABLE_TASK will enable + * thread and make it running. + */ WARN_ON(cmdq_thread_reset(cmdq, thread) < 0); writel(task->pa_base >> cmdq->shift_pa, @@ -391,6 +397,38 @@ static int cmdq_mbox_startup(struct mbox_chan *chan) static void cmdq_mbox_shutdown(struct mbox_chan *chan) { + struct cmdq_thread *thread = (struct cmdq_thread *)chan->con_priv; + struct cmdq *cmdq = dev_get_drvdata(chan->mbox->dev); + struct cmdq_task *task, *tmp; + unsigned long flags; + + spin_lock_irqsave(&thread->chan->lock, flags); + if (list_empty(&thread->task_busy_list)) + goto done; + + WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0); + + /* make sure executed tasks have success callback */ + cmdq_thread_irq_handler(cmdq, thread); + if (list_empty(&thread->task_busy_list)) + goto done; + + list_for_each_entry_safe(task, tmp, &thread->task_busy_list, + list_entry) { + cmdq_task_exec_done(task, CMDQ_CB_ERROR); + kfree(task); + } + + cmdq_thread_disable(cmdq, thread); + clk_disable(cmdq->clock); +done: + /* + * The thread->task_busy_list empty means thread already disable. The + * cmdq_mbox_send_data() always reset thread which clear disable and + * suspend statue when first pkt send to channel, so there is no need + * to do any operation here, only unlock and leave. + */ + spin_unlock_irqrestore(&thread->chan->lock, flags); } static int cmdq_mbox_flush(struct mbox_chan *chan, unsigned long timeout) |