V4L/DVB: cx18, cx23885, v4l2 doc, MAINTAINERS: Update Andy Walls' email address
[safe/jmp/linux-2.6] / drivers / media / video / cx18 / cx18-mailbox.c
index 844a62d..956aa19 100644 (file)
@@ -2,6 +2,7 @@
  *  cx18 mailbox functions
  *
  *  Copyright (C) 2007  Hans Verkuil <hverkuil@xs4all.nl>
+ *  Copyright (C) 2008  Andy Walls <awalls@md.metrocast.net>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
@@ -28,6 +29,7 @@
 #include "cx18-mailbox.h"
 #include "cx18-queue.h"
 #include "cx18-streams.h"
+#include "cx18-alsa-pcm.h" /* FIXME make configurable */
 
 static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" };
 
@@ -81,8 +83,11 @@ static const struct cx18_api_info api_info[] = {
        API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS,                    0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK,                 0),
        API_ENTRY(CPU, CX18_CPU_DE_SET_MDL,                     API_FAST),
-       API_ENTRY(CPU, CX18_APU_RESETAI,                        API_FAST),
        API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL,                 API_SLOW),
+       API_ENTRY(APU, CX18_APU_START,                          0),
+       API_ENTRY(APU, CX18_APU_STOP,                           0),
+       API_ENTRY(APU, CX18_APU_RESETAI,                        0),
+       API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32,                   0),
        API_ENTRY(0, 0,                                         0),
 };
 
@@ -96,21 +101,30 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
        return NULL;
 }
 
-static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
+/* Call with buf of n*11+1 bytes */
+static char *u32arr2hex(u32 data[], int n, char *buf)
 {
-       char argstr[MAX_MB_ARGUMENTS*11+1];
        char *p;
        int i;
 
+       for (i = 0, p = buf; i < n; i++, p += 11) {
+               /* kernel snprintf() appends '\0' always */
+               snprintf(p, 12, " %#010x", data[i]);
+       }
+       *p = '\0';
+       return buf;
+}
+
+static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
+{
+       char argstr[MAX_MB_ARGUMENTS*11+1];
+
        if (!(cx18_debug & CX18_DBGFLG_API))
                return;
 
-       for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) {
-               /* kernel snprintf() appends '\0' always */
-               snprintf(p, 12, " %#010x", mb->args[i]);
-       }
        CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
-               "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr);
+                      "\n", name, mb->request, mb->ack, mb->cmd, mb->error,
+                      u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr));
 }
 
 
@@ -118,13 +132,67 @@ static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
  * Functions that run in a work_queue work handling context
  */
 
-static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
+{
+       struct cx18_buffer *buf;
+
+       if (!s->dvb.enabled || mdl->bytesused == 0)
+               return;
+
+       /* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+       /* The likely case */
+       if (list_is_singular(&mdl->buf_list)) {
+               buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+                                      list);
+               if (buf->bytesused)
+                       dvb_dmx_swfilter(&s->dvb.demux,
+                                        buf->buf, buf->bytesused);
+               return;
+       }
+
+       list_for_each_entry(buf, &mdl->buf_list, list) {
+               if (buf->bytesused == 0)
+                       break;
+               dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused);
+       }
+}
+
+
+static void cx18_mdl_send_to_alsa(struct cx18 *cx, struct cx18_stream *s,
+                                 struct cx18_mdl *mdl)
 {
-       u32 handle, mdl_ack_count;
+       struct cx18_buffer *buf;
+
+       if (mdl->bytesused == 0)
+               return;
+
+       /* We ignore mdl and buf readpos accounting here - it doesn't matter */
+
+       /* The likely case */
+       if (list_is_singular(&mdl->buf_list)) {
+               buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
+                                      list);
+               if (buf->bytesused)
+                       cx->pcm_announce_callback(cx->alsa, buf->buf,
+                                                 buf->bytesused);
+               return;
+       }
+
+       list_for_each_entry(buf, &mdl->buf_list, list) {
+               if (buf->bytesused == 0)
+                       break;
+               cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused);
+       }
+}
+
+static void epu_dma_done(struct cx18 *cx, struct cx18_in_work_order *order)
+{
+       u32 handle, mdl_ack_count, id;
        struct cx18_mailbox *mb;
        struct cx18_mdl_ack *mdl_ack;
        struct cx18_stream *s;
-       struct cx18_buffer *buf;
+       struct cx18_mdl *mdl;
        int i;
 
        mb = &order->mb;
@@ -133,48 +201,83 @@ static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
 
        if (s == NULL) {
                CX18_WARN("Got DMA done notification for unknown/inactive"
-                         " handle %d\n", handle);
+                         " 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++) {
-               buf = cx18_queue_get_buf(s, mdl_ack->id, mdl_ack->data_used);
-               CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name,
-                                 mdl_ack->id);
-               if (buf == NULL) {
-                       CX18_WARN("Could not find buf %d for stream %s\n",
-                                 mdl_ack->id, s->name);
-                       continue;
+               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_buf_sync_for_cpu(s, buf);
-               if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
-                       CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
-                                         buf->bytesused);
-
-                       dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
-                                        buf->bytesused);
-
-                       cx18_buf_sync_for_device(s, buf);
+               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;
+               }
 
-                       if (s->handle != CX18_INVALID_TASK_HANDLE &&
-                           test_bit(CX18_F_S_STREAMING, &s->s_flags))
-                               cx18_vapi(cx,
-                                      CX18_CPU_DE_SET_MDL, 5, s->handle,
-                                      (void __iomem *)
-                                      &cx->scb->cpu_mdl[buf->id] - cx->enc_mem,
-                                      1, buf->id, s->buf_size);
-               } else
-                       set_bit(CX18_F_B_NEED_BUF_SWAP, &buf->b_flags);
+               CX18_DEBUG_HI_DMA("%s recv bytesused = %d\n",
+                                 s->name, mdl->bytesused);
+
+               if (s->type == CX18_ENC_STREAM_TYPE_TS) {
+                       cx18_mdl_send_to_dvb(s, mdl);
+                       cx18_enqueue(s, mdl, &s->q_free);
+               } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) {
+                       /* Pass the data to cx18-alsa */
+                       if (cx->pcm_announce_callback != NULL) {
+                               cx18_mdl_send_to_alsa(cx, s, mdl);
+                               cx18_enqueue(s, mdl, &s->q_free);
+                       } else {
+                               cx18_enqueue(s, mdl, &s->q_full);
+                       }
+               } else {
+                       cx18_enqueue(s, mdl, &s->q_full);
+                       if (s->type == CX18_ENC_STREAM_TYPE_IDX)
+                               cx18_stream_rotate_idx_mdls(cx);
+               }
        }
+       /* Put as many MDLs as possible back into fw use */
+       cx18_stream_load_fw_queue(s);
+
        wake_up(&cx->dma_waitq);
        if (s->id != -1)
                wake_up(&s->waitq);
 }
 
-static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_debug(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        char *p;
        char *str = order->str;
@@ -185,7 +288,7 @@ static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
                CX18_INFO("FW version: %s\n", p - 1);
 }
 
-static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void epu_cmd(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        switch (order->rpu) {
        case CPU:
@@ -214,18 +317,18 @@ static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order)
+void free_in_work_order(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        atomic_set(&order->pending, 0);
 }
 
-void cx18_epu_work_handler(struct work_struct *work)
+void cx18_in_work_handler(struct work_struct *work)
 {
-       struct cx18_epu_work_order *order =
-                       container_of(work, struct cx18_epu_work_order, work);
+       struct cx18_in_work_order *order =
+                       container_of(work, struct cx18_in_work_order, work);
        struct cx18 *cx = order->cx;
        epu_cmd(cx, order);
-       free_epu_work_order(cx, order);
+       free_in_work_order(cx, order);
 }
 
 
@@ -233,7 +336,7 @@ void cx18_epu_work_handler(struct work_struct *work)
  * Functions that run in an interrupt handling context
  */
 
-static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static void mb_ack_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        struct cx18_mailbox __iomem *ack_mb;
        u32 ack_irq, req;
@@ -257,10 +360,10 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
        /* Don't ack if the RPU has gotten impatient and timed us out */
        if (req != cx18_readl(cx, &ack_mb->request) ||
            req == cx18_readl(cx, &ack_mb->ack)) {
-               CX18_WARN("Possibly falling behind: %s self-ack'ed our incoming"
-                         " %s to EPU mailbox (sequence no. %u) while "
-                         "processing\n",
-                         rpu_str[order->rpu], rpu_str[order->rpu], req);
+               CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+                               "incoming %s to EPU mailbox (sequence no. %u) "
+                               "while processing\n",
+                               rpu_str[order->rpu], rpu_str[order->rpu], req);
                order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC;
                return;
        }
@@ -269,7 +372,7 @@ static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
        return;
 }
 
-static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+static int epu_dma_done_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 handle, mdl_ack_offset, mdl_ack_count;
        struct cx18_mailbox *mb;
@@ -295,7 +398,7 @@ static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static
-int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_debug_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        u32 str_offset;
        char *str = order->str;
@@ -316,7 +419,7 @@ int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
+int epu_cmd_irq(struct cx18 *cx, struct cx18_in_work_order *order)
 {
        int ret = -1;
 
@@ -348,12 +451,12 @@ int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
 }
 
 static inline
-struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
+struct cx18_in_work_order *alloc_in_work_order_irq(struct cx18 *cx)
 {
        int i;
-       struct cx18_epu_work_order *order = NULL;
+       struct cx18_in_work_order *order = NULL;
 
-       for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
+       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:
@@ -362,8 +465,8 @@ struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
                 * 2. "pending" is only set here, and we're serialized because
                 * we're called in an IRQ handler context.
                 */
-               if (atomic_read(&cx->epu_work_order[i].pending) == 0) {
-                       order = &cx->epu_work_order[i];
+               if (atomic_read(&cx->in_work_order[i].pending) == 0) {
+                       order = &cx->in_work_order[i];
                        atomic_set(&order->pending, 1);
                        break;
                }
@@ -375,7 +478,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
 {
        struct cx18_mailbox __iomem *mb;
        struct cx18_mailbox *order_mb;
-       struct cx18_epu_work_order *order;
+       struct cx18_in_work_order *order;
        int submit;
 
        switch (rpu) {
@@ -389,7 +492,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
                return;
        }
 
-       order = alloc_epu_work_order_irq(cx);
+       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");
@@ -399,13 +502,20 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
        order->flags = 0;
        order->rpu = rpu;
        order_mb = &order->mb;
-       cx18_memcpy_fromio(cx, order_mb, mb, sizeof(struct cx18_mailbox));
+
+       /* mb->cmd and mb->args[0] through mb->args[2] */
+       cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32));
+       /* mb->request and mb->ack.  N.B. we want to read mb->ack last */
+       cx18_memcpy_fromio(cx, &order_mb->request, &mb->request,
+                          2 * sizeof(u32));
 
        if (order_mb->request == order_mb->ack) {
-               CX18_WARN("Possibly falling behind: %s self-ack'ed our incoming"
-                         " %s to EPU mailbox (sequence no. %u)\n",
-                         rpu_str[rpu], rpu_str[rpu], order_mb->request);
-               dump_mb(cx, order_mb, "incoming");
+               CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
+                               "incoming %s to EPU mailbox (sequence no. %u)"
+                               "\n",
+                               rpu_str[rpu], rpu_str[rpu], order_mb->request);
+               if (cx18_debug & CX18_DBGFLG_WARN)
+                       dump_mb(cx, order_mb, "incoming");
                order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
        }
 
@@ -415,7 +525,7 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
         */
        submit = epu_cmd_irq(cx, order);
        if (submit > 0) {
-               queue_work(cx18_work_queue, &order->work);
+               queue_work(cx->in_work_queue, &order->work);
        }
 }
 
@@ -424,13 +534,6 @@ void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
  * Functions called from a non-interrupt, non work_queue context
  */
 
-static void cx18_api_log_ack_delay(struct cx18 *cx, int msecs)
-{
-       if (msecs > CX18_MAX_MB_ACK_DELAY)
-               msecs = CX18_MAX_MB_ACK_DELAY;
-       atomic_inc(&cx->mbox_stats.mb_ack_delay[msecs]);
-}
-
 static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 {
        const struct cx18_api_info *info = find_api_info(cmd);
@@ -439,18 +542,27 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
        u32 __iomem *xpu_state;
        wait_queue_head_t *waitq;
        struct mutex *mb_lock;
-       long int timeout, ret;
+       unsigned long int t0, timeout, ret;
        int i;
+       char argstr[MAX_MB_ARGUMENTS*11+1];
+       DEFINE_WAIT(w);
 
        if (info == NULL) {
                CX18_WARN("unknown cmd %x\n", cmd);
                return -EINVAL;
        }
 
-       if (cmd == CX18_CPU_DE_SET_MDL)
-               CX18_DEBUG_HI_API("%s\n", info->name);
-       else
-               CX18_DEBUG_API("%s\n", info->name);
+       if (cx18_debug & CX18_DBGFLG_API) { /* only call u32arr2hex if needed */
+               if (cmd == CX18_CPU_DE_SET_MDL) {
+                       if (cx18_debug & CX18_DBGFLG_HIGHVOL)
+                               CX18_DEBUG_HI_API("%s\tcmd %#010x args%s\n",
+                                               info->name, cmd,
+                                               u32arr2hex(data, args, argstr));
+               } else
+                       CX18_DEBUG_API("%s\tcmd %#010x args%s\n",
+                                      info->name, cmd,
+                                      u32arr2hex(data, args, argstr));
+       }
 
        switch (info->rpu) {
        case APU:
@@ -485,7 +597,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
         */
        state = cx18_readl(cx, xpu_state);
        req = cx18_readl(cx, &mb->request);
-       timeout = msecs_to_jiffies(20); /* 1 field at 50 Hz vertical refresh */
+       timeout = msecs_to_jiffies(10);
        ret = wait_event_timeout(*waitq,
                                 (ack = cx18_readl(cx, &mb->ack)) == req,
                                 timeout);
@@ -495,8 +607,8 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
                CX18_ERR("mbox was found stuck busy when setting up for %s; "
                         "clearing busy and trying to proceed\n", info->name);
        } else if (ret != timeout)
-               CX18_DEBUG_API("waited %u usecs for busy mbox to be acked\n",
-                              jiffies_to_usecs(timeout-ret));
+               CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n",
+                              jiffies_to_msecs(timeout-ret));
 
        /* Build the outgoing mailbox */
        req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1;
@@ -510,40 +622,54 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
        /*
         * Notify the XPU and wait for it to send an Ack back
-        * 21 ms = ~ 0.5 frames at a frame rate of 24 fps
-        * 42 ms = ~ 1 frame at a frame rate of 24 fps
         */
-       timeout = msecs_to_jiffies((info->flags & API_FAST) ? 21 : 42);
+       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);
 
-       ret = wait_event_timeout(
-                      *waitq,
-                      cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
-                      timeout);
-       if (ret == 0) {
-               /* Timed out */
+       t0 = jiffies;
+       ack = cx18_readl(cx, &mb->ack);
+       if (ack != req) {
+               schedule_timeout(timeout);
+               ret = jiffies - t0;
+               ack = cx18_readl(cx, &mb->ack);
+       } else {
+               ret = jiffies - t0;
+       }
+
+       finish_wait(waitq, &w);
+
+       if (req != ack) {
                mutex_unlock(mb_lock);
-               i = jiffies_to_msecs(timeout);
-               cx18_api_log_ack_delay(cx, i);
-               CX18_WARN("sending %s timed out waiting %d msecs for RPU "
-                         "acknowledgement\n", info->name, i);
+               if (ret >= timeout) {
+                       /* Timed out */
+                       CX18_DEBUG_WARN("sending %s timed out waiting %d msecs "
+                                       "for RPU acknowledgement\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;
-       } else if (ret < 0) {
-               /* Interrupted */
-               mutex_unlock(mb_lock);
-               CX18_WARN("sending %s was interrupted waiting for RPU"
-                         "acknowledgement\n", info->name);
-               return -EINTR;
        }
 
-       i = jiffies_to_msecs(timeout-ret);
-       cx18_api_log_ack_delay(cx, i);
-       if (ret != timeout)
+       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",
-                                 i, info->name);
+                                 jiffies_to_msecs(ret), info->name);
 
        /* Collect data returned by the XPU */
        for (i = 0; i < MAX_MB_ARGUMENTS; i++)
@@ -553,7 +679,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
 
        /*
         * 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 buffers
+        * 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)
@@ -590,8 +716,9 @@ static int cx18_set_filter_param(struct cx18_stream *s)
 int cx18_api_func(void *priv, u32 cmd, int in, int out,
                u32 data[CX2341X_MBOX_MAX_DATA])
 {
-       struct cx18 *cx = priv;
-       struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG];
+       struct cx18_api_func_private *api_priv = priv;
+       struct cx18 *cx = api_priv->cx;
+       struct cx18_stream *s = api_priv->s;
 
        switch (cmd) {
        case CX2341X_ENC_SET_OUTPUT_PORT: