aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/cx18/cx18-mailbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/cx18/cx18-mailbox.c')
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c527
1 files changed, 427 insertions, 100 deletions
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index acff7dfb60df..de5e723fdf44 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -2,6 +2,7 @@
2 * cx18 mailbox functions 2 * cx18 mailbox functions
3 * 3 *
4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl> 4 * Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
5 * Copyright (C) 2008 Andy Walls <awalls@radix.net>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by 8 * it under the terms of the GNU General Public License as published by
@@ -26,15 +27,14 @@
26#include "cx18-scb.h" 27#include "cx18-scb.h"
27#include "cx18-irq.h" 28#include "cx18-irq.h"
28#include "cx18-mailbox.h" 29#include "cx18-mailbox.h"
30#include "cx18-queue.h"
31#include "cx18-streams.h"
32
33static const char *rpu_str[] = { "APU", "CPU", "EPU", "HPU" };
29 34
30#define API_FAST (1 << 2) /* Short timeout */ 35#define API_FAST (1 << 2) /* Short timeout */
31#define API_SLOW (1 << 3) /* Additional 300ms timeout */ 36#define API_SLOW (1 << 3) /* Additional 300ms timeout */
32 37
33#define APU 0
34#define CPU 1
35#define EPU 2
36#define HPU 3
37
38struct cx18_api_info { 38struct cx18_api_info {
39 u32 cmd; 39 u32 cmd;
40 u8 flags; /* Flags, see above */ 40 u8 flags; /* Flags, see above */
@@ -82,8 +82,9 @@ static const struct cx18_api_info api_info[] = {
82 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0), 82 API_ENTRY(CPU, CX18_CPU_GET_ENC_PTS, 0),
83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0), 83 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL_ACK, 0),
84 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST), 84 API_ENTRY(CPU, CX18_CPU_DE_SET_MDL, API_FAST),
85 API_ENTRY(CPU, CX18_APU_RESETAI, API_FAST),
86 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW), 85 API_ENTRY(CPU, CX18_CPU_DE_RELEASE_MDL, API_SLOW),
86 API_ENTRY(APU, CX18_APU_RESETAI, 0),
87 API_ENTRY(CPU, CX18_CPU_DEBUG_PEEK32, 0),
87 API_ENTRY(0, 0, 0), 88 API_ENTRY(0, 0, 0),
88}; 89};
89 90
@@ -97,70 +98,175 @@ static const struct cx18_api_info *find_api_info(u32 cmd)
97 return NULL; 98 return NULL;
98} 99}
99 100
100static struct cx18_mailbox __iomem *cx18_mb_is_complete(struct cx18 *cx, int rpu, 101static void dump_mb(struct cx18 *cx, struct cx18_mailbox *mb, char *name)
101 u32 *state, u32 *irq, u32 *req)
102{ 102{
103 struct cx18_mailbox __iomem *mb = NULL; 103 char argstr[MAX_MB_ARGUMENTS*11+1];
104 int wait_count = 0; 104 char *p;
105 u32 ack; 105 int i;
106
107 switch (rpu) {
108 case APU:
109 mb = &cx->scb->epu2apu_mb;
110 *state = cx18_readl(cx, &cx->scb->apu_state);
111 *irq = cx18_readl(cx, &cx->scb->epu2apu_irq);
112 break;
113 106
114 case CPU: 107 if (!(cx18_debug & CX18_DBGFLG_API))
115 mb = &cx->scb->epu2cpu_mb; 108 return;
116 *state = cx18_readl(cx, &cx->scb->cpu_state);
117 *irq = cx18_readl(cx, &cx->scb->epu2cpu_irq);
118 break;
119 109
120 case HPU: 110 for (i = 0, p = argstr; i < MAX_MB_ARGUMENTS; i++, p += 11) {
121 mb = &cx->scb->epu2hpu_mb; 111 /* kernel snprintf() appends '\0' always */
122 *state = cx18_readl(cx, &cx->scb->hpu_state); 112 snprintf(p, 12, " %#010x", mb->args[i]);
123 *irq = cx18_readl(cx, &cx->scb->epu2hpu_irq);
124 break;
125 } 113 }
114 CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s"
115 "\n", name, mb->request, mb->ack, mb->cmd, mb->error, argstr);
116}
126 117
127 if (mb == NULL)
128 return mb;
129 118
130 do { 119/*
131 *req = cx18_readl(cx, &mb->request); 120 * Functions that run in a work_queue work handling context
132 ack = cx18_readl(cx, &mb->ack); 121 */
133 wait_count++;
134 } while (*req != ack && wait_count < 600);
135 122
136 if (*req == ack) { 123static void epu_dma_done(struct cx18 *cx, struct cx18_epu_work_order *order)
137 (*req)++; 124{
138 if (*req == 0 || *req == 0xffffffff) 125 u32 handle, mdl_ack_count, id;
139 *req = 1; 126 struct cx18_mailbox *mb;
140 return mb; 127 struct cx18_mdl_ack *mdl_ack;
128 struct cx18_stream *s;
129 struct cx18_buffer *buf;
130 int i;
131
132 mb = &order->mb;
133 handle = mb->args[0];
134 s = cx18_handle_to_stream(cx, handle);
135
136 if (s == NULL) {
137 CX18_WARN("Got DMA done notification for unknown/inactive"
138 " handle %d, %s mailbox seq no %d\n", handle,
139 (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ?
140 "stale" : "good", mb->request);
141 return;
141 } 142 }
142 return NULL; 143
144 mdl_ack_count = mb->args[2];
145 mdl_ack = order->mdl_ack;
146 for (i = 0; i < mdl_ack_count; i++, mdl_ack++) {
147 id = mdl_ack->id;
148 /*
149 * Simple integrity check for processing a stale (and possibly
150 * inconsistent mailbox): make sure the buffer id is in the
151 * valid range for the stream.
152 *
153 * We go through the trouble of dealing with stale mailboxes
154 * because most of the time, the mailbox data is still valid and
155 * unchanged (and in practice the firmware ping-pongs the
156 * two mdl_ack buffers so mdl_acks are not stale).
157 *
158 * There are occasions when we get a half changed mailbox,
159 * which this check catches for a handle & id mismatch. If the
160 * handle and id do correspond, the worst case is that we
161 * completely lost the old buffer, but pick up the new buffer
162 * early (but the new mdl_ack is guaranteed to be good in this
163 * case as the firmware wouldn't point us to a new mdl_ack until
164 * it's filled in).
165 *
166 * cx18_queue_get buf() will detect the lost buffers
167 * and send them back to q_free for fw rotation eventually.
168 */
169 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) &&
170 !(id >= s->mdl_offset &&
171 id < (s->mdl_offset + s->buffers))) {
172 CX18_WARN("Fell behind! Ignoring stale mailbox with "
173 " inconsistent data. Lost buffer for mailbox "
174 "seq no %d\n", mb->request);
175 break;
176 }
177 buf = cx18_queue_get_buf(s, id, mdl_ack->data_used);
178
179 CX18_DEBUG_HI_DMA("DMA DONE for %s (buffer %d)\n", s->name, id);
180 if (buf == NULL) {
181 CX18_WARN("Could not find buf %d for stream %s\n",
182 id, s->name);
183 /* Put as many buffers as possible back into fw use */
184 cx18_stream_load_fw_queue(s);
185 continue;
186 }
187
188 if (s->type == CX18_ENC_STREAM_TYPE_TS && s->dvb.enabled) {
189 CX18_DEBUG_HI_DMA("TS recv bytesused = %d\n",
190 buf->bytesused);
191 dvb_dmx_swfilter(&s->dvb.demux, buf->buf,
192 buf->bytesused);
193 }
194 /* Put as many buffers as possible back into fw use */
195 cx18_stream_load_fw_queue(s);
196 /* Put back TS buffer, since it was removed from all queues */
197 if (s->type == CX18_ENC_STREAM_TYPE_TS)
198 cx18_stream_put_buf_fw(s, buf);
199 }
200 wake_up(&cx->dma_waitq);
201 if (s->id != -1)
202 wake_up(&s->waitq);
143} 203}
144 204
145long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb) 205static void epu_debug(struct cx18 *cx, struct cx18_epu_work_order *order)
146{ 206{
147 const struct cx18_api_info *info = find_api_info(mb->cmd); 207 char *p;
148 struct cx18_mailbox __iomem *ack_mb; 208 char *str = order->str;
149 u32 ack_irq;
150 u8 rpu = CPU;
151 209
152 if (info == NULL && mb->cmd) { 210 CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str);
153 CX18_WARN("Cannot ack unknown command %x\n", mb->cmd); 211 p = strchr(str, '.');
154 return -EINVAL; 212 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str)
155 } 213 CX18_INFO("FW version: %s\n", p - 1);
156 if (info) 214}
157 rpu = info->rpu;
158 215
159 switch (rpu) { 216static void epu_cmd(struct cx18 *cx, struct cx18_epu_work_order *order)
160 case HPU: 217{
161 ack_irq = IRQ_EPU_TO_HPU_ACK; 218 switch (order->rpu) {
162 ack_mb = &cx->scb->hpu2epu_mb; 219 case CPU:
220 {
221 switch (order->mb.cmd) {
222 case CX18_EPU_DMA_DONE:
223 epu_dma_done(cx, order);
224 break;
225 case CX18_EPU_DEBUG:
226 epu_debug(cx, order);
227 break;
228 default:
229 CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
230 order->mb.cmd);
231 break;
232 }
163 break; 233 break;
234 }
235 case APU:
236 CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
237 order->mb.cmd);
238 break;
239 default:
240 break;
241 }
242}
243
244static
245void free_epu_work_order(struct cx18 *cx, struct cx18_epu_work_order *order)
246{
247 atomic_set(&order->pending, 0);
248}
249
250void cx18_epu_work_handler(struct work_struct *work)
251{
252 struct cx18_epu_work_order *order =
253 container_of(work, struct cx18_epu_work_order, work);
254 struct cx18 *cx = order->cx;
255 epu_cmd(cx, order);
256 free_epu_work_order(cx, order);
257}
258
259
260/*
261 * Functions that run in an interrupt handling context
262 */
263
264static void mb_ack_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
265{
266 struct cx18_mailbox __iomem *ack_mb;
267 u32 ack_irq, req;
268
269 switch (order->rpu) {
164 case APU: 270 case APU:
165 ack_irq = IRQ_EPU_TO_APU_ACK; 271 ack_irq = IRQ_EPU_TO_APU_ACK;
166 ack_mb = &cx->scb->apu2epu_mb; 272 ack_mb = &cx->scb->apu2epu_mb;
@@ -170,26 +276,197 @@ long cx18_mb_ack(struct cx18 *cx, const struct cx18_mailbox *mb)
170 ack_mb = &cx->scb->cpu2epu_mb; 276 ack_mb = &cx->scb->cpu2epu_mb;
171 break; 277 break;
172 default: 278 default:
173 CX18_WARN("Unknown RPU for command %x\n", mb->cmd); 279 CX18_WARN("Unhandled RPU (%d) for command %x ack\n",
174 return -EINVAL; 280 order->rpu, order->mb.cmd);
281 return;
175 } 282 }
176 283
177 cx18_setup_page(cx, SCB_OFFSET); 284 req = order->mb.request;
178 cx18_write_sync(cx, mb->request, &ack_mb->ack); 285 /* Don't ack if the RPU has gotten impatient and timed us out */
286 if (req != cx18_readl(cx, &ack_mb->request) ||
287 req == cx18_readl(cx, &ack_mb->ack)) {
288 CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
289 "incoming %s to EPU mailbox (sequence no. %u) "
290 "while processing\n",
291 rpu_str[order->rpu], rpu_str[order->rpu], req);
292 order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC;
293 return;
294 }
295 cx18_writel(cx, req, &ack_mb->ack);
179 cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq); 296 cx18_write_reg_expect(cx, ack_irq, SW2_INT_SET, ack_irq, ack_irq);
180 return 0; 297 return;
298}
299
300static int epu_dma_done_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
301{
302 u32 handle, mdl_ack_offset, mdl_ack_count;
303 struct cx18_mailbox *mb;
304
305 mb = &order->mb;
306 handle = mb->args[0];
307 mdl_ack_offset = mb->args[1];
308 mdl_ack_count = mb->args[2];
309
310 if (handle == CX18_INVALID_TASK_HANDLE ||
311 mdl_ack_count == 0 || mdl_ack_count > CX18_MAX_MDL_ACKS) {
312 if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
313 mb_ack_irq(cx, order);
314 return -1;
315 }
316
317 cx18_memcpy_fromio(cx, order->mdl_ack, cx->enc_mem + mdl_ack_offset,
318 sizeof(struct cx18_mdl_ack) * mdl_ack_count);
319
320 if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
321 mb_ack_irq(cx, order);
322 return 1;
323}
324
325static
326int epu_debug_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
327{
328 u32 str_offset;
329 char *str = order->str;
330
331 str[0] = '\0';
332 str_offset = order->mb.args[1];
333 if (str_offset) {
334 cx18_setup_page(cx, str_offset);
335 cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252);
336 str[252] = '\0';
337 cx18_setup_page(cx, SCB_OFFSET);
338 }
339
340 if ((order->flags & CX18_F_EWO_MB_STALE) == 0)
341 mb_ack_irq(cx, order);
342
343 return str_offset ? 1 : 0;
181} 344}
182 345
346static inline
347int epu_cmd_irq(struct cx18 *cx, struct cx18_epu_work_order *order)
348{
349 int ret = -1;
350
351 switch (order->rpu) {
352 case CPU:
353 {
354 switch (order->mb.cmd) {
355 case CX18_EPU_DMA_DONE:
356 ret = epu_dma_done_irq(cx, order);
357 break;
358 case CX18_EPU_DEBUG:
359 ret = epu_debug_irq(cx, order);
360 break;
361 default:
362 CX18_WARN("Unknown CPU to EPU mailbox command %#0x\n",
363 order->mb.cmd);
364 break;
365 }
366 break;
367 }
368 case APU:
369 CX18_WARN("Unknown APU to EPU mailbox command %#0x\n",
370 order->mb.cmd);
371 break;
372 default:
373 break;
374 }
375 return ret;
376}
377
378static inline
379struct cx18_epu_work_order *alloc_epu_work_order_irq(struct cx18 *cx)
380{
381 int i;
382 struct cx18_epu_work_order *order = NULL;
383
384 for (i = 0; i < CX18_MAX_EPU_WORK_ORDERS; i++) {
385 /*
386 * We only need "pending" atomic to inspect its contents,
387 * and need not do a check and set because:
388 * 1. Any work handler thread only clears "pending" and only
389 * on one, particular work order at a time, per handler thread.
390 * 2. "pending" is only set here, and we're serialized because
391 * we're called in an IRQ handler context.
392 */
393 if (atomic_read(&cx->epu_work_order[i].pending) == 0) {
394 order = &cx->epu_work_order[i];
395 atomic_set(&order->pending, 1);
396 break;
397 }
398 }
399 return order;
400}
401
402void cx18_api_epu_cmd_irq(struct cx18 *cx, int rpu)
403{
404 struct cx18_mailbox __iomem *mb;
405 struct cx18_mailbox *order_mb;
406 struct cx18_epu_work_order *order;
407 int submit;
408
409 switch (rpu) {
410 case CPU:
411 mb = &cx->scb->cpu2epu_mb;
412 break;
413 case APU:
414 mb = &cx->scb->apu2epu_mb;
415 break;
416 default:
417 return;
418 }
419
420 order = alloc_epu_work_order_irq(cx);
421 if (order == NULL) {
422 CX18_WARN("Unable to find blank work order form to schedule "
423 "incoming mailbox command processing\n");
424 return;
425 }
426
427 order->flags = 0;
428 order->rpu = rpu;
429 order_mb = &order->mb;
430
431 /* mb->cmd and mb->args[0] through mb->args[2] */
432 cx18_memcpy_fromio(cx, &order_mb->cmd, &mb->cmd, 4 * sizeof(u32));
433 /* mb->request and mb->ack. N.B. we want to read mb->ack last */
434 cx18_memcpy_fromio(cx, &order_mb->request, &mb->request,
435 2 * sizeof(u32));
436
437 if (order_mb->request == order_mb->ack) {
438 CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our "
439 "incoming %s to EPU mailbox (sequence no. %u)"
440 "\n",
441 rpu_str[rpu], rpu_str[rpu], order_mb->request);
442 dump_mb(cx, order_mb, "incoming");
443 order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT;
444 }
445
446 /*
447 * Individual EPU command processing is responsible for ack-ing
448 * a non-stale mailbox as soon as possible
449 */
450 submit = epu_cmd_irq(cx, order);
451 if (submit > 0) {
452 queue_work(cx->work_queue, &order->work);
453 }
454}
455
456
457/*
458 * Functions called from a non-interrupt, non work_queue context
459 */
183 460
184static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[]) 461static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
185{ 462{
186 const struct cx18_api_info *info = find_api_info(cmd); 463 const struct cx18_api_info *info = find_api_info(cmd);
187 u32 state = 0, irq = 0, req, oldreq, err; 464 u32 state, irq, req, ack, err;
188 struct cx18_mailbox __iomem *mb; 465 struct cx18_mailbox __iomem *mb;
466 u32 __iomem *xpu_state;
189 wait_queue_head_t *waitq; 467 wait_queue_head_t *waitq;
190 int timeout = 100; 468 struct mutex *mb_lock;
191 int cnt = 0; 469 long int timeout, ret;
192 int sig = 0;
193 int i; 470 int i;
194 471
195 if (info == NULL) { 472 if (info == NULL) {
@@ -201,50 +478,104 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
201 CX18_DEBUG_HI_API("%s\n", info->name); 478 CX18_DEBUG_HI_API("%s\n", info->name);
202 else 479 else
203 CX18_DEBUG_API("%s\n", info->name); 480 CX18_DEBUG_API("%s\n", info->name);
204 cx18_setup_page(cx, SCB_OFFSET);
205 mb = cx18_mb_is_complete(cx, info->rpu, &state, &irq, &req);
206 481
207 if (mb == NULL) { 482 switch (info->rpu) {
208 CX18_ERR("mb %s busy\n", info->name); 483 case APU:
209 return -EBUSY; 484 waitq = &cx->mb_apu_waitq;
485 mb_lock = &cx->epu2apu_mb_lock;
486 irq = IRQ_EPU_TO_APU;
487 mb = &cx->scb->epu2apu_mb;
488 xpu_state = &cx->scb->apu_state;
489 break;
490 case CPU:
491 waitq = &cx->mb_cpu_waitq;
492 mb_lock = &cx->epu2cpu_mb_lock;
493 irq = IRQ_EPU_TO_CPU;
494 mb = &cx->scb->epu2cpu_mb;
495 xpu_state = &cx->scb->cpu_state;
496 break;
497 default:
498 CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu);
499 return -EINVAL;
210 } 500 }
211 501
212 oldreq = req - 1; 502 mutex_lock(mb_lock);
503 /*
504 * Wait for an in-use mailbox to complete
505 *
506 * If the XPU is responding with Ack's, the mailbox shouldn't be in
507 * a busy state, since we serialize access to it on our end.
508 *
509 * If the wait for ack after sending a previous command was interrupted
510 * by a signal, we may get here and find a busy mailbox. After waiting,
511 * mark it "not busy" from our end, if the XPU hasn't ack'ed it still.
512 */
513 state = cx18_readl(cx, xpu_state);
514 req = cx18_readl(cx, &mb->request);
515 timeout = msecs_to_jiffies(10);
516 ret = wait_event_timeout(*waitq,
517 (ack = cx18_readl(cx, &mb->ack)) == req,
518 timeout);
519 if (req != ack) {
520 /* waited long enough, make the mbox "not busy" from our end */
521 cx18_writel(cx, req, &mb->ack);
522 CX18_ERR("mbox was found stuck busy when setting up for %s; "
523 "clearing busy and trying to proceed\n", info->name);
524 } else if (ret != timeout)
525 CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n",
526 jiffies_to_msecs(timeout-ret));
527
528 /* Build the outgoing mailbox */
529 req = ((req & 0xfffffffe) == 0xfffffffe) ? 1 : req + 1;
530
213 cx18_writel(cx, cmd, &mb->cmd); 531 cx18_writel(cx, cmd, &mb->cmd);
214 for (i = 0; i < args; i++) 532 for (i = 0; i < args; i++)
215 cx18_writel(cx, data[i], &mb->args[i]); 533 cx18_writel(cx, data[i], &mb->args[i]);
216 cx18_writel(cx, 0, &mb->error); 534 cx18_writel(cx, 0, &mb->error);
217 cx18_writel(cx, req, &mb->request); 535 cx18_writel(cx, req, &mb->request);
536 cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */
218 537
219 switch (info->rpu) { 538 /*
220 case APU: waitq = &cx->mb_apu_waitq; break; 539 * Notify the XPU and wait for it to send an Ack back
221 case CPU: waitq = &cx->mb_cpu_waitq; break; 540 */
222 case EPU: waitq = &cx->mb_epu_waitq; break; 541 timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20);
223 case HPU: waitq = &cx->mb_hpu_waitq; break; 542
224 default: return -EINVAL; 543 CX18_DEBUG_HI_IRQ("sending interrupt SW1: %x to send %s\n",
225 } 544 irq, info->name);
226 if (info->flags & API_FAST)
227 timeout /= 2;
228 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq); 545 cx18_write_reg_expect(cx, irq, SW1_INT_SET, irq, irq);
229 546
230 while (!sig && cx18_readl(cx, &mb->ack) != cx18_readl(cx, &mb->request) 547 ret = wait_event_timeout(
231 && cnt < 660) { 548 *waitq,
232 if (cnt > 200 && !in_atomic()) 549 cx18_readl(cx, &mb->ack) == cx18_readl(cx, &mb->request),
233 sig = cx18_msleep_timeout(10, 1); 550 timeout);
234 cnt++; 551
235 } 552 if (ret == 0) {
236 if (sig) 553 /* Timed out */
237 return -EINTR; 554 mutex_unlock(mb_lock);
238 if (cnt == 660) { 555 CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU "
239 cx18_writel(cx, oldreq, &mb->request); 556 "acknowledgement\n",
240 CX18_ERR("mb %s failed\n", info->name); 557 info->name, jiffies_to_msecs(timeout));
241 return -EINVAL; 558 return -EINVAL;
242 } 559 }
560
561 if (ret != timeout)
562 CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n",
563 jiffies_to_msecs(timeout-ret), info->name);
564
565 /* Collect data returned by the XPU */
243 for (i = 0; i < MAX_MB_ARGUMENTS; i++) 566 for (i = 0; i < MAX_MB_ARGUMENTS; i++)
244 data[i] = cx18_readl(cx, &mb->args[i]); 567 data[i] = cx18_readl(cx, &mb->args[i]);
245 err = cx18_readl(cx, &mb->error); 568 err = cx18_readl(cx, &mb->error);
246 if (!in_atomic() && (info->flags & API_SLOW)) 569 mutex_unlock(mb_lock);
570
571 /*
572 * Wait for XPU to perform extra actions for the caller in some cases.
573 * e.g. CX18_CPU_DE_RELEASE_MDL will cause the CPU to send all buffers
574 * back in a burst shortly thereafter
575 */
576 if (info->flags & API_SLOW)
247 cx18_msleep_timeout(300, 0); 577 cx18_msleep_timeout(300, 0);
578
248 if (err) 579 if (err)
249 CX18_DEBUG_API("mailbox error %08x for command %s\n", err, 580 CX18_DEBUG_API("mailbox error %08x for command %s\n", err,
250 info->name); 581 info->name);
@@ -253,12 +584,7 @@ static int cx18_api_call(struct cx18 *cx, u32 cmd, int args, u32 data[])
253 584
254int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]) 585int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[])
255{ 586{
256 int res = cx18_api_call(cx, cmd, args, data); 587 return cx18_api_call(cx, cmd, args, data);
257
258 /* Allow a single retry, probably already too late though.
259 If there is no free mailbox then that is usually an indication
260 of a more serious problem. */
261 return (res == -EBUSY) ? cx18_api_call(cx, cmd, args, data) : res;
262} 588}
263 589
264static int cx18_set_filter_param(struct cx18_stream *s) 590static int cx18_set_filter_param(struct cx18_stream *s)
@@ -281,8 +607,9 @@ static int cx18_set_filter_param(struct cx18_stream *s)
281int cx18_api_func(void *priv, u32 cmd, int in, int out, 607int cx18_api_func(void *priv, u32 cmd, int in, int out,
282 u32 data[CX2341X_MBOX_MAX_DATA]) 608 u32 data[CX2341X_MBOX_MAX_DATA])
283{ 609{
284 struct cx18 *cx = priv; 610 struct cx18_api_func_private *api_priv = priv;
285 struct cx18_stream *s = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; 611 struct cx18 *cx = api_priv->cx;
612 struct cx18_stream *s = api_priv->s;
286 613
287 switch (cmd) { 614 switch (cmd) {
288 case CX2341X_ENC_SET_OUTPUT_PORT: 615 case CX2341X_ENC_SET_OUTPUT_PORT: