/* If we've filled the buffer as per the callers res then dispatch it */ if (vb_buf->bytes_used >= s->vb_bytes_per_frame) {
dispatch = 1;
vb_buf->bytes_used = 0;
}
mb = &order->mb;
handle = mb->args[0];
s = cx18_handle_to_stream(cx, handle);
if (s == NULL) {
CX18_WARN("Got DMA done notification for unknown/inactive handle %d, %s mailbox seq no %d\n",
handle,
(order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? "stale" : "good", mb->request); return;
}
mdl_ack_count = mb->args[2];
mdl_ack = order->mdl_ack; for (i = 0; i < mdl_ack_count; i++, mdl_ack++) {
id = mdl_ack->id; /* * Simple integrity check for processing a stale (and possibly * inconsistent mailbox): make sure the MDL id is in the * valid range for the stream. * * We go through the trouble of dealing with stale mailboxes * because most of the time, the mailbox data is still valid and * unchanged (and in practice the firmware ping-pongs the * two mdl_ack buffers so mdl_acks are not stale). * * There are occasions when we get a half changed mailbox, * which this check catches for a handle & id mismatch. If the * handle and id do correspond, the worst case is that we * completely lost the old MDL, but pick up the new MDL * early (but the new mdl_ack is guaranteed to be good in this * case as the firmware wouldn't point us to a new mdl_ack until * it's filled in). * * cx18_queue_get_mdl() will detect the lost MDLs * and send them back to q_free for fw rotation eventually.
*/ if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
!(id >= s->mdl_base_idx &&
id < (s->mdl_base_idx + s->buffers))) {
CX18_WARN("Fell behind! Ignoring stale mailbox with inconsistent data. Lost MDL for mailbox seq no %d\n",
mb->request); break;
}
mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used);
CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); if (mdl == NULL) {
CX18_WARN("Could not find MDL %d for stream %s\n",
id, s->name); continue;
}
CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str);
p = strchr(str, '.'); if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
CX18_INFO("FW version: %s\n", p - 1);
}
staticvoid epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order)
{ switch (order->rpu) { case CPU:
{ switch (order->mb.cmd) { case CX18_EPU_DMA_DONE:
epu_dma_done(cx, order); break; case CX18_EPU_DEBUG:
epu_debug(cx, order); break; default:
CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
order->mb.cmd); break;
} break;
} case APU:
CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
order->mb.cmd); break; default: break;
}
}
for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { /* * We only need "pending" atomic to inspect its contents, * and need not do a check and set because: * 1. Any work handler thread only clears "pending" and only * on one, particular work order at a time, per handler thread. * 2. "pending" is only set here, and we're serialized because * we're called in an IRQ handler context.
*/ if (atomic_read(&cx->in_work_order[i].pending) == 0) {
order = &cx->in_work_order[i];
atomic_set(&order->pending, 1); break;
}
} return order;
}
void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
{ struct cx18_mailbox __iomem *mb; struct cx18_mailbox *order_mb; struct cx18_in_work_order *order; int submit; int i;
switch (rpu) { case CPU:
mb = &cx->scb->cpu2epu_mb; break; case APU:
mb = &cx->scb->apu2epu_mb; break; default: return;
}
order = alloc_in_work_order_irq(cx); if (order == NULL) {
CX18_WARN("Unable to find blank work order form to schedule incoming mailbox command processing\n"); return;
}
/* * Individual EPU command processing is responsible for ack-ing * a non-stale mailbox as soon as possible
*/
submit = epu_cmd_irq(cx, order); if (submit > 0) {
queue_work(cx->in_work_queue, &order->work);
}
}
/* * Functions called from a non-interrupt, non work_queue context
*/
mutex_lock(mb_lock); /* * Wait for an in-use mailbox to complete * * If the XPU is responding with Ack's, the mailbox shouldn't be in * a busy state, since we serialize access to it on our end. * * If the wait for ack after sending a previous command was interrupted * by a signal, we may get here and find a busy mailbox. After waiting, * mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
*/
req = cx18_readl(cx, &mb->request);
timeout = msecs_to_jiffies(10);
ret = wait_event_timeout(*waitq,
(ack = cx18_readl(cx, &mb->ack)) == req,
timeout); if (req != ack) { /* waited long enough, make the mbox "not busy" from our end */
cx18_writel(cx, req, &mb->ack);
CX18_ERR("mbox was found stuck busy when setting up for %s; clearing busy and trying to proceed\n",
info->name);
} elseif (ret != timeout)
CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n",
jiffies_to_msecs(timeout-ret));
cx18_writel(cx, cmd, &mb->cmd); for (i = 0; i < args; i++)
cx18_writel(cx, data[i], &mb->args[i]);
cx18_writel(cx, 0, &mb->error);
cx18_writel(cx, req, &mb->request);
cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */
/* * Notify the XPU and wait for it to send an Ack back
*/
timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20);
CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
irq, info->name);
/* So we don't miss the wakeup, prepare to wait before notifying fw */
prepare_to_wait(waitq, &w, TASK_UNINTERRUPTIBLE);
cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
if (req != ack) {
mutex_unlock(mb_lock); if (ret >= timeout) { /* Timed out */
CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU acknowledgment\n",
info->name, jiffies_to_msecs(ret));
} else {
CX18_DEBUG_WARN("woken up before mailbox ack was ready after submitting %s to RPU. only waited %d msecs on req %u but awakened with unmatched ack %u\n",
info->name,
jiffies_to_msecs(ret),
req, ack);
} return -EINVAL;
}
if (ret >= timeout)
CX18_DEBUG_WARN("failed to be awakened upon RPU acknowledgment sending %s; timed out waiting %d msecs\n",
info->name, jiffies_to_msecs(ret)); else
CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
jiffies_to_msecs(ret), info->name);
/* Collect data returned by the XPU */ for (i = 0; i < MAX_MB_ARGUMENTS; i++)
data[i] = cx18_readl(cx, &mb->args[i]);
err = cx18_readl(cx, &mb->error);
mutex_unlock(mb_lock);
/* * Wait for XPU to perform extra actions for the caller in some cases. * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all MDLs * back in a burst shortly thereafter
*/ if (info->flags & API_SLOW)
cx18_msleep_timeout(300, 0);
if (err)
CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
info->name); return err ? -EIO : 0;
}
int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
{ return cx18_api_call(cx, cmd, args, data);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.