Lines Matching +full:always +full:- +full:wait +full:- +full:for +full:- +full:ack

1 // SPDX-License-Identifier: GPL-2.0-or-later
11 #include "cx18-driver.h"
12 #include "cx18-io.h"
13 #include "cx18-scb.h"
14 #include "cx18-irq.h"
15 #include "cx18-mailbox.h"
16 #include "cx18-queue.h"
17 #include "cx18-streams.h"
18 #include "cx18-alsa-pcm.h" /* FIXME make configurable */
85 for (i = 0; api_info[i].cmd; i++) in find_api_info()
97 for (i = 0, p = buf; i < n; i++, p += 11) { in u32arr2hex()
98 /* kernel snprintf() appends '\0' always */ in u32arr2hex()
112 CX18_DEBUG_API("%s: req %#010x ack %#010x cmd %#010x err %#010x args%s\n", in dump_mb()
113 name, mb->request, mb->ack, mb->cmd, mb->error, in dump_mb()
114 u32arr2hex(mb->args, MAX_MB_ARGUMENTS, argstr)); in dump_mb()
126 if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0) in cx18_mdl_send_to_dvb()
129 /* We ignore mdl and buf readpos accounting here - it doesn't matter */ in cx18_mdl_send_to_dvb()
132 if (list_is_singular(&mdl->buf_list)) { in cx18_mdl_send_to_dvb()
133 buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, in cx18_mdl_send_to_dvb()
135 if (buf->bytesused) in cx18_mdl_send_to_dvb()
136 dvb_dmx_swfilter(&s->dvb->demux, in cx18_mdl_send_to_dvb()
137 buf->buf, buf->bytesused); in cx18_mdl_send_to_dvb()
141 list_for_each_entry(buf, &mdl->buf_list, list) { in cx18_mdl_send_to_dvb()
142 if (buf->bytesused == 0) in cx18_mdl_send_to_dvb()
144 dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused); in cx18_mdl_send_to_dvb()
157 if (mdl->bytesused == 0) in cx18_mdl_send_to_vb2()
161 spin_lock(&s->vb_lock); in cx18_mdl_send_to_vb2()
162 if (list_empty(&s->vb_capture)) in cx18_mdl_send_to_vb2()
165 vb_buf = list_first_entry(&s->vb_capture, struct cx18_vb2_buffer, in cx18_mdl_send_to_vb2()
168 p = vb2_plane_vaddr(&vb_buf->vb.vb2_buf, 0); in cx18_mdl_send_to_vb2()
172 bsize = vb2_get_plane_payload(&vb_buf->vb.vb2_buf, 0); in cx18_mdl_send_to_vb2()
173 offset = vb_buf->bytes_used; in cx18_mdl_send_to_vb2()
174 list_for_each_entry(buf, &mdl->buf_list, list) { in cx18_mdl_send_to_vb2()
175 if (buf->bytesused == 0) in cx18_mdl_send_to_vb2()
178 if ((offset + buf->bytesused) <= bsize) { in cx18_mdl_send_to_vb2()
179 memcpy(p + offset, buf->buf, buf->bytesused); in cx18_mdl_send_to_vb2()
180 offset += buf->bytesused; in cx18_mdl_send_to_vb2()
181 vb_buf->bytes_used += buf->bytesused; in cx18_mdl_send_to_vb2()
186 if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { in cx18_mdl_send_to_vb2()
188 vb_buf->bytes_used = 0; in cx18_mdl_send_to_vb2()
192 vb_buf->vb.vb2_buf.timestamp = ktime_get_ns(); in cx18_mdl_send_to_vb2()
193 vb_buf->vb.sequence = s->sequence++; in cx18_mdl_send_to_vb2()
194 list_del(&vb_buf->list); in cx18_mdl_send_to_vb2()
195 vb2_buffer_done(&vb_buf->vb.vb2_buf, VB2_BUF_STATE_DONE); in cx18_mdl_send_to_vb2()
198 mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); in cx18_mdl_send_to_vb2()
201 spin_unlock(&s->vb_lock); in cx18_mdl_send_to_vb2()
209 if (mdl->bytesused == 0) in cx18_mdl_send_to_alsa()
212 /* We ignore mdl and buf readpos accounting here - it doesn't matter */ in cx18_mdl_send_to_alsa()
215 if (list_is_singular(&mdl->buf_list)) { in cx18_mdl_send_to_alsa()
216 buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, in cx18_mdl_send_to_alsa()
218 if (buf->bytesused) in cx18_mdl_send_to_alsa()
219 cx->pcm_announce_callback(cx->alsa, buf->buf, in cx18_mdl_send_to_alsa()
220 buf->bytesused); in cx18_mdl_send_to_alsa()
224 list_for_each_entry(buf, &mdl->buf_list, list) { in cx18_mdl_send_to_alsa()
225 if (buf->bytesused == 0) in cx18_mdl_send_to_alsa()
227 cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); in cx18_mdl_send_to_alsa()
240 mb = &order->mb; in epu_dma_done()
241 handle = mb->args[0]; in epu_dma_done()
245 CX18_WARN("Got DMA done notification for unknown/inactive handle %d, %s mailbox seq no %d\n", in epu_dma_done()
247 (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? in epu_dma_done()
248 "stale" : "good", mb->request); in epu_dma_done()
252 mdl_ack_count = mb->args[2]; in epu_dma_done()
253 mdl_ack = order->mdl_ack; in epu_dma_done()
254 for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { in epu_dma_done()
255 id = mdl_ack->id; in epu_dma_done()
257 * Simple integrity check for processing a stale (and possibly in epu_dma_done()
259 * valid range for the stream. in epu_dma_done()
263 * unchanged (and in practice the firmware ping-pongs the in epu_dma_done()
267 * which this check catches for a handle & id mismatch. If the in epu_dma_done()
275 * and send them back to q_free for fw rotation eventually. in epu_dma_done()
277 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && in epu_dma_done()
278 !(id >= s->mdl_base_idx && in epu_dma_done()
279 id < (s->mdl_base_idx + s->buffers))) { in epu_dma_done()
280 …CX18_WARN("Fell behind! Ignoring stale mailbox with inconsistent data. Lost MDL for mailbox seq n… in epu_dma_done()
281 mb->request); in epu_dma_done()
284 mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); in epu_dma_done()
286 CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); in epu_dma_done()
288 CX18_WARN("Could not find MDL %d for stream %s\n", in epu_dma_done()
289 id, s->name); in epu_dma_done()
294 s->name, mdl->bytesused); in epu_dma_done()
296 if (s->type == CX18_ENC_STREAM_TYPE_TS) { in epu_dma_done()
298 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
299 } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { in epu_dma_done()
300 /* Pass the data to cx18-alsa */ in epu_dma_done()
301 if (cx->pcm_announce_callback != NULL) { in epu_dma_done()
303 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
305 cx18_enqueue(s, mdl, &s->q_full); in epu_dma_done()
307 } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { in epu_dma_done()
309 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
311 cx18_enqueue(s, mdl, &s->q_full); in epu_dma_done()
312 if (s->type == CX18_ENC_STREAM_TYPE_IDX) in epu_dma_done()
319 wake_up(&cx->dma_waitq); in epu_dma_done()
320 if (s->id != -1) in epu_dma_done()
321 wake_up(&s->waitq); in epu_dma_done()
327 char *str = order->str; in epu_debug()
329 CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); in epu_debug()
331 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) in epu_debug()
332 CX18_INFO("FW version: %s\n", p - 1); in epu_debug()
337 switch (order->rpu) { in epu_cmd()
340 switch (order->mb.cmd) { in epu_cmd()
349 order->mb.cmd); in epu_cmd()
356 order->mb.cmd); in epu_cmd()
366 atomic_set(&order->pending, 0); in free_in_work_order()
373 struct cx18 *cx = order->cx; in cx18_in_work_handler()
388 switch (order->rpu) { in mb_ack_irq()
391 ack_mb = &cx->scb->apu2epu_mb; in mb_ack_irq()
395 ack_mb = &cx->scb->cpu2epu_mb; in mb_ack_irq()
398 CX18_WARN("Unhandled RPU (%d) for command %x ack\n", in mb_ack_irq()
399 order->rpu, order->mb.cmd); in mb_ack_irq()
403 req = order->mb.request; in mb_ack_irq()
404 /* Don't ack if the RPU has gotten impatient and timed us out */ in mb_ack_irq()
405 if (req != cx18_readl(cx, &ack_mb->request) || in mb_ack_irq()
406 req == cx18_readl(cx, &ack_mb->ack)) { in mb_ack_irq()
407 …CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence … in mb_ack_irq()
408 rpu_str[order->rpu], rpu_str[order->rpu], req); in mb_ack_irq()
409 order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; in mb_ack_irq()
412 cx18_writel(cx, req, &ack_mb->ack); in mb_ack_irq()
423 mb = &order->mb; in epu_dma_done_irq()
424 handle = mb->args[0]; in epu_dma_done_irq()
425 mdl_ack_offset = mb->args[1]; in epu_dma_done_irq()
426 mdl_ack_count = mb->args[2]; in epu_dma_done_irq()
430 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_dma_done_irq()
432 return -1; in epu_dma_done_irq()
435 for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32)) in epu_dma_done_irq()
436 ((u32 *)order->mdl_ack)[i / sizeof(u32)] = in epu_dma_done_irq()
437 cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i); in epu_dma_done_irq()
439 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_dma_done_irq()
448 char *str = order->str; in epu_debug_irq()
451 str_offset = order->mb.args[1]; in epu_debug_irq()
454 cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); in epu_debug_irq()
459 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_debug_irq()
468 int ret = -1; in epu_cmd_irq()
470 switch (order->rpu) { in epu_cmd_irq()
473 switch (order->mb.cmd) { in epu_cmd_irq()
482 order->mb.cmd); in epu_cmd_irq()
489 order->mb.cmd); in epu_cmd_irq()
503 for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { in alloc_in_work_order_irq()
512 if (atomic_read(&cx->in_work_order[i].pending) == 0) { in alloc_in_work_order_irq()
513 order = &cx->in_work_order[i]; in alloc_in_work_order_irq()
514 atomic_set(&order->pending, 1); in alloc_in_work_order_irq()
531 mb = &cx->scb->cpu2epu_mb; in cx18_api_epu_cmd_irq()
534 mb = &cx->scb->apu2epu_mb; in cx18_api_epu_cmd_irq()
546 order->flags = 0; in cx18_api_epu_cmd_irq()
547 order->rpu = rpu; in cx18_api_epu_cmd_irq()
548 order_mb = &order->mb; in cx18_api_epu_cmd_irq()
550 /* mb->cmd and mb->args[0] through mb->args[2] */ in cx18_api_epu_cmd_irq()
551 for (i = 0; i < 4; i++) in cx18_api_epu_cmd_irq()
552 (&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i); in cx18_api_epu_cmd_irq()
554 /* mb->request and mb->ack. N.B. we want to read mb->ack last */ in cx18_api_epu_cmd_irq()
555 for (i = 0; i < 2; i++) in cx18_api_epu_cmd_irq()
556 (&order_mb->request)[i] = cx18_readl(cx, &mb->request + i); in cx18_api_epu_cmd_irq()
558 if (order_mb->request == order_mb->ack) { in cx18_api_epu_cmd_irq()
559 …CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence … in cx18_api_epu_cmd_irq()
560 rpu_str[rpu], rpu_str[rpu], order_mb->request); in cx18_api_epu_cmd_irq()
563 order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; in cx18_api_epu_cmd_irq()
567 * Individual EPU command processing is responsible for ack-ing in cx18_api_epu_cmd_irq()
568 * a non-stale mailbox as soon as possible in cx18_api_epu_cmd_irq()
572 queue_work(cx->in_work_queue, &order->work); in cx18_api_epu_cmd_irq()
578 * Functions called from a non-interrupt, non work_queue context
584 u32 irq, req, ack, err; in cx18_api_call() local
595 return -EINVAL; in cx18_api_call()
602 info->name, cmd, in cx18_api_call()
606 info->name, cmd, in cx18_api_call()
610 switch (info->rpu) { in cx18_api_call()
612 waitq = &cx->mb_apu_waitq; in cx18_api_call()
613 mb_lock = &cx->epu2apu_mb_lock; in cx18_api_call()
615 mb = &cx->scb->epu2apu_mb; in cx18_api_call()
618 waitq = &cx->mb_cpu_waitq; in cx18_api_call()
619 mb_lock = &cx->epu2cpu_mb_lock; in cx18_api_call()
621 mb = &cx->scb->epu2cpu_mb; in cx18_api_call()
624 CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); in cx18_api_call()
625 return -EINVAL; in cx18_api_call()
630 * Wait for an in-use mailbox to complete in cx18_api_call()
632 * If the XPU is responding with Ack's, the mailbox shouldn't be in in cx18_api_call()
635 * If the wait for ack after sending a previous command was interrupted in cx18_api_call()
637 * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. in cx18_api_call()
639 req = cx18_readl(cx, &mb->request); in cx18_api_call()
642 (ack = cx18_readl(cx, &mb->ack)) == req, in cx18_api_call()
644 if (req != ack) { in cx18_api_call()
646 cx18_writel(cx, req, &mb->ack); in cx18_api_call()
647 …CX18_ERR("mbox was found stuck busy when setting up for %s; clearing busy and trying to proceed\n", in cx18_api_call()
648 info->name); in cx18_api_call()
650 CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", in cx18_api_call()
651 jiffies_to_msecs(timeout-ret)); in cx18_api_call()
656 cx18_writel(cx, cmd, &mb->cmd); in cx18_api_call()
657 for (i = 0; i < args; i++) in cx18_api_call()
658 cx18_writel(cx, data[i], &mb->args[i]); in cx18_api_call()
659 cx18_writel(cx, 0, &mb->error); in cx18_api_call()
660 cx18_writel(cx, req, &mb->request); in cx18_api_call()
661 cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ in cx18_api_call()
664 * Notify the XPU and wait for it to send an Ack back in cx18_api_call()
666 timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); in cx18_api_call()
669 irq, info->name); in cx18_api_call()
671 /* So we don't miss the wakeup, prepare to wait before notifying fw */ in cx18_api_call()
676 ack = cx18_readl(cx, &mb->ack); in cx18_api_call()
677 if (ack != req) { in cx18_api_call()
679 ret = jiffies - t0; in cx18_api_call()
680 ack = cx18_readl(cx, &mb->ack); in cx18_api_call()
682 ret = jiffies - t0; in cx18_api_call()
687 if (req != ack) { in cx18_api_call()
691 CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU acknowledgment\n", in cx18_api_call()
692 info->name, jiffies_to_msecs(ret)); in cx18_api_call()
694 …woken up before mailbox ack was ready after submitting %s to RPU. only waited %d msecs on req %u … in cx18_api_call()
695 info->name, in cx18_api_call()
697 req, ack); in cx18_api_call()
699 return -EINVAL; in cx18_api_call()
704 info->name, jiffies_to_msecs(ret)); in cx18_api_call()
706 CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", in cx18_api_call()
707 jiffies_to_msecs(ret), info->name); in cx18_api_call()
710 for (i = 0; i < MAX_MB_ARGUMENTS; i++) in cx18_api_call()
711 data[i] = cx18_readl(cx, &mb->args[i]); in cx18_api_call()
712 err = cx18_readl(cx, &mb->error); in cx18_api_call()
716 * Wait for XPU to perform extra actions for the caller in some cases. in cx18_api_call()
720 if (info->flags & API_SLOW) in cx18_api_call()
724 CX18_DEBUG_API("mailbox error %08x for command %s\n", err, in cx18_api_call()
725 info->name); in cx18_api_call()
726 return err ? -EIO : 0; in cx18_api_call()
736 struct cx18 *cx = s->cx; in cx18_set_filter_param()
740 mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); in cx18_set_filter_param()
742 s->handle, 1, mode, cx->spatial_strength); in cx18_set_filter_param()
743 mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); in cx18_set_filter_param()
745 s->handle, 0, mode, cx->temporal_strength); in cx18_set_filter_param()
747 s->handle, 2, cx->filter_mode >> 2, 0); in cx18_set_filter_param()
755 struct cx18 *cx = s->cx; in cx18_api_func()
762 s->handle, 0, 0, 0, 0, data[0]); in cx18_api_func()
765 s->handle, data[1], data[0]); in cx18_api_func()
768 s->handle, data[0]); in cx18_api_func()
771 s->handle, data[0]); in cx18_api_func()
775 s->handle, data[0], data[1]); in cx18_api_func()
780 s->handle, data[0]); in cx18_api_func()
783 s->handle, data[0]); in cx18_api_func()
786 s->handle, data[0], data[1], data[2], data[3]); in cx18_api_func()
789 s->handle, data[0]); in cx18_api_func()
792 s->handle, data[0]); in cx18_api_func()
795 s->handle, data[0], data[1], data[2]); in cx18_api_func()
797 cx->filter_mode = (data[0] & 3) | (data[1] << 2); in cx18_api_func()
800 cx->spatial_strength = data[0]; in cx18_api_func()
801 cx->temporal_strength = data[1]; in cx18_api_func()
805 s->handle, data[0], data[1]); in cx18_api_func()
808 s->handle, data[0], data[1], data[2], data[3]); in cx18_api_func()
821 for (i = 0; i < args; i++) in cx18_vapi_result()
842 for (i = 0; i < args; i++) in cx18_vapi()