in mtk-cmdq-mailbox.c [341:404]
static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)
{
struct cmdq_pkt *pkt = (struct cmdq_pkt *)data;
struct cmdq_thread *thread = (struct cmdq_thread *)chan->con_priv;
struct cmdq *cmdq = dev_get_drvdata(chan->mbox->dev);
struct cmdq_task *task;
unsigned long curr_pa, end_pa;
/* Client should not flush new tasks if suspended. */
WARN_ON(cmdq->suspended);
task = kzalloc(sizeof(*task), GFP_ATOMIC);
if (!task)
return -ENOMEM;
task->cmdq = cmdq;
INIT_LIST_HEAD(&task->list_entry);
task->pa_base = pkt->pa_base;
task->thread = thread;
task->pkt = pkt;
if (list_empty(&thread->task_busy_list)) {
WARN_ON(clk_bulk_enable(cmdq->gce_num, cmdq->clocks));
/*
* 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,
thread->base + CMDQ_THR_CURR_ADDR);
writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->shift_pa,
thread->base + CMDQ_THR_END_ADDR);
writel(thread->priority, thread->base + CMDQ_THR_PRIORITY);
writel(CMDQ_THR_IRQ_EN, thread->base + CMDQ_THR_IRQ_ENABLE);
writel(CMDQ_THR_ENABLED, thread->base + CMDQ_THR_ENABLE_TASK);
} else {
WARN_ON(cmdq_thread_suspend(cmdq, thread) < 0);
curr_pa = readl(thread->base + CMDQ_THR_CURR_ADDR) <<
cmdq->shift_pa;
end_pa = readl(thread->base + CMDQ_THR_END_ADDR) <<
cmdq->shift_pa;
/* check boundary */
if (curr_pa == end_pa - CMDQ_INST_SIZE ||
curr_pa == end_pa) {
/* set to this task directly */
writel(task->pa_base >> cmdq->shift_pa,
thread->base + CMDQ_THR_CURR_ADDR);
} else {
cmdq_task_insert_into_thread(task);
smp_mb(); /* modify jump before enable thread */
}
writel((task->pa_base + pkt->cmd_buf_size) >> cmdq->shift_pa,
thread->base + CMDQ_THR_END_ADDR);
cmdq_thread_resume(thread);
}
list_move_tail(&task->list_entry, &thread->task_busy_list);
return 0;
}