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_videobuf()
161 spin_lock(&s->vb_lock); in cx18_mdl_send_to_videobuf()
162 if (list_empty(&s->vb_capture)) in cx18_mdl_send_to_videobuf()
165 vb_buf = list_first_entry(&s->vb_capture, struct cx18_videobuf_buffer, in cx18_mdl_send_to_videobuf()
168 p = videobuf_to_vmalloc(&vb_buf->vb); in cx18_mdl_send_to_videobuf()
172 offset = vb_buf->bytes_used; in cx18_mdl_send_to_videobuf()
173 list_for_each_entry(buf, &mdl->buf_list, list) { in cx18_mdl_send_to_videobuf()
174 if (buf->bytesused == 0) in cx18_mdl_send_to_videobuf()
177 if ((offset + buf->bytesused) <= vb_buf->vb.bsize) { in cx18_mdl_send_to_videobuf()
178 memcpy(p + offset, buf->buf, buf->bytesused); in cx18_mdl_send_to_videobuf()
179 offset += buf->bytesused; in cx18_mdl_send_to_videobuf()
180 vb_buf->bytes_used += buf->bytesused; in cx18_mdl_send_to_videobuf()
185 if (vb_buf->bytes_used >= s->vb_bytes_per_frame) { in cx18_mdl_send_to_videobuf()
187 vb_buf->bytes_used = 0; in cx18_mdl_send_to_videobuf()
191 vb_buf->vb.ts = ktime_get_ns(); in cx18_mdl_send_to_videobuf()
192 list_del(&vb_buf->vb.queue); in cx18_mdl_send_to_videobuf()
193 vb_buf->vb.state = VIDEOBUF_DONE; in cx18_mdl_send_to_videobuf()
194 wake_up(&vb_buf->vb.done); in cx18_mdl_send_to_videobuf()
197 mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); in cx18_mdl_send_to_videobuf()
200 spin_unlock(&s->vb_lock); in cx18_mdl_send_to_videobuf()
208 if (mdl->bytesused == 0) in cx18_mdl_send_to_alsa()
211 /* We ignore mdl and buf readpos accounting here - it doesn't matter */ in cx18_mdl_send_to_alsa()
214 if (list_is_singular(&mdl->buf_list)) { in cx18_mdl_send_to_alsa()
215 buf = list_first_entry(&mdl->buf_list, struct cx18_buffer, in cx18_mdl_send_to_alsa()
217 if (buf->bytesused) in cx18_mdl_send_to_alsa()
218 cx->pcm_announce_callback(cx->alsa, buf->buf, in cx18_mdl_send_to_alsa()
219 buf->bytesused); in cx18_mdl_send_to_alsa()
223 list_for_each_entry(buf, &mdl->buf_list, list) { in cx18_mdl_send_to_alsa()
224 if (buf->bytesused == 0) in cx18_mdl_send_to_alsa()
226 cx->pcm_announce_callback(cx->alsa, buf->buf, buf->bytesused); in cx18_mdl_send_to_alsa()
239 mb = &order->mb; in epu_dma_done()
240 handle = mb->args[0]; in epu_dma_done()
244 CX18_WARN("Got DMA done notification for unknown/inactive handle %d, %s mailbox seq no %d\n", in epu_dma_done()
246 (order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) ? in epu_dma_done()
247 "stale" : "good", mb->request); in epu_dma_done()
251 mdl_ack_count = mb->args[2]; in epu_dma_done()
252 mdl_ack = order->mdl_ack; in epu_dma_done()
253 for (i = 0; i < mdl_ack_count; i++, mdl_ack++) { in epu_dma_done()
254 id = mdl_ack->id; in epu_dma_done()
256 * Simple integrity check for processing a stale (and possibly in epu_dma_done()
258 * valid range for the stream. in epu_dma_done()
262 * unchanged (and in practice the firmware ping-pongs the in epu_dma_done()
266 * which this check catches for a handle & id mismatch. If the in epu_dma_done()
274 * and send them back to q_free for fw rotation eventually. in epu_dma_done()
276 if ((order->flags & CX18_F_EWO_MB_STALE_UPON_RECEIPT) && in epu_dma_done()
277 !(id >= s->mdl_base_idx && in epu_dma_done()
278 id < (s->mdl_base_idx + s->buffers))) { in epu_dma_done()
279 …CX18_WARN("Fell behind! Ignoring stale mailbox with inconsistent data. Lost MDL for mailbox seq n… in epu_dma_done()
280 mb->request); in epu_dma_done()
283 mdl = cx18_queue_get_mdl(s, id, mdl_ack->data_used); in epu_dma_done()
285 CX18_DEBUG_HI_DMA("DMA DONE for %s (MDL %d)\n", s->name, id); in epu_dma_done()
287 CX18_WARN("Could not find MDL %d for stream %s\n", in epu_dma_done()
288 id, s->name); in epu_dma_done()
293 s->name, mdl->bytesused); in epu_dma_done()
295 if (s->type == CX18_ENC_STREAM_TYPE_TS) { in epu_dma_done()
297 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
298 } else if (s->type == CX18_ENC_STREAM_TYPE_PCM) { in epu_dma_done()
299 /* Pass the data to cx18-alsa */ in epu_dma_done()
300 if (cx->pcm_announce_callback != NULL) { in epu_dma_done()
302 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
304 cx18_enqueue(s, mdl, &s->q_full); in epu_dma_done()
306 } else if (s->type == CX18_ENC_STREAM_TYPE_YUV) { in epu_dma_done()
308 cx18_enqueue(s, mdl, &s->q_free); in epu_dma_done()
310 cx18_enqueue(s, mdl, &s->q_full); in epu_dma_done()
311 if (s->type == CX18_ENC_STREAM_TYPE_IDX) in epu_dma_done()
318 wake_up(&cx->dma_waitq); in epu_dma_done()
319 if (s->id != -1) in epu_dma_done()
320 wake_up(&s->waitq); in epu_dma_done()
326 char *str = order->str; in epu_debug()
328 CX18_DEBUG_INFO("%x %s\n", order->mb.args[0], str); in epu_debug()
330 if (!test_bit(CX18_F_I_LOADED_FW, &cx->i_flags) && p && p > str) in epu_debug()
331 CX18_INFO("FW version: %s\n", p - 1); in epu_debug()
336 switch (order->rpu) { in epu_cmd()
339 switch (order->mb.cmd) { in epu_cmd()
348 order->mb.cmd); in epu_cmd()
355 order->mb.cmd); in epu_cmd()
365 atomic_set(&order->pending, 0); in free_in_work_order()
372 struct cx18 *cx = order->cx; in cx18_in_work_handler()
387 switch (order->rpu) { in mb_ack_irq()
390 ack_mb = &cx->scb->apu2epu_mb; in mb_ack_irq()
394 ack_mb = &cx->scb->cpu2epu_mb; in mb_ack_irq()
397 CX18_WARN("Unhandled RPU (%d) for command %x ack\n", in mb_ack_irq()
398 order->rpu, order->mb.cmd); in mb_ack_irq()
402 req = order->mb.request; in mb_ack_irq()
403 /* Don't ack if the RPU has gotten impatient and timed us out */ in mb_ack_irq()
404 if (req != cx18_readl(cx, &ack_mb->request) || in mb_ack_irq()
405 req == cx18_readl(cx, &ack_mb->ack)) { in mb_ack_irq()
406 …CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence … in mb_ack_irq()
407 rpu_str[order->rpu], rpu_str[order->rpu], req); in mb_ack_irq()
408 order->flags |= CX18_F_EWO_MB_STALE_WHILE_PROC; in mb_ack_irq()
411 cx18_writel(cx, req, &ack_mb->ack); in mb_ack_irq()
422 mb = &order->mb; in epu_dma_done_irq()
423 handle = mb->args[0]; in epu_dma_done_irq()
424 mdl_ack_offset = mb->args[1]; in epu_dma_done_irq()
425 mdl_ack_count = mb->args[2]; in epu_dma_done_irq()
429 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_dma_done_irq()
431 return -1; in epu_dma_done_irq()
434 for (i = 0; i < sizeof(struct cx18_mdl_ack) * mdl_ack_count; i += sizeof(u32)) in epu_dma_done_irq()
435 ((u32 *)order->mdl_ack)[i / sizeof(u32)] = in epu_dma_done_irq()
436 cx18_readl(cx, cx->enc_mem + mdl_ack_offset + i); in epu_dma_done_irq()
438 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_dma_done_irq()
447 char *str = order->str; in epu_debug_irq()
450 str_offset = order->mb.args[1]; in epu_debug_irq()
453 cx18_memcpy_fromio(cx, str, cx->enc_mem + str_offset, 252); in epu_debug_irq()
458 if ((order->flags & CX18_F_EWO_MB_STALE) == 0) in epu_debug_irq()
467 int ret = -1; in epu_cmd_irq()
469 switch (order->rpu) { in epu_cmd_irq()
472 switch (order->mb.cmd) { in epu_cmd_irq()
481 order->mb.cmd); in epu_cmd_irq()
488 order->mb.cmd); in epu_cmd_irq()
502 for (i = 0; i < CX18_MAX_IN_WORK_ORDERS; i++) { in alloc_in_work_order_irq()
511 if (atomic_read(&cx->in_work_order[i].pending) == 0) { in alloc_in_work_order_irq()
512 order = &cx->in_work_order[i]; in alloc_in_work_order_irq()
513 atomic_set(&order->pending, 1); in alloc_in_work_order_irq()
530 mb = &cx->scb->cpu2epu_mb; in cx18_api_epu_cmd_irq()
533 mb = &cx->scb->apu2epu_mb; in cx18_api_epu_cmd_irq()
545 order->flags = 0; in cx18_api_epu_cmd_irq()
546 order->rpu = rpu; in cx18_api_epu_cmd_irq()
547 order_mb = &order->mb; in cx18_api_epu_cmd_irq()
549 /* mb->cmd and mb->args[0] through mb->args[2] */ in cx18_api_epu_cmd_irq()
550 for (i = 0; i < 4; i++) in cx18_api_epu_cmd_irq()
551 (&order_mb->cmd)[i] = cx18_readl(cx, &mb->cmd + i); in cx18_api_epu_cmd_irq()
553 /* mb->request and mb->ack. N.B. we want to read mb->ack last */ in cx18_api_epu_cmd_irq()
554 for (i = 0; i < 2; i++) in cx18_api_epu_cmd_irq()
555 (&order_mb->request)[i] = cx18_readl(cx, &mb->request + i); in cx18_api_epu_cmd_irq()
557 if (order_mb->request == order_mb->ack) { in cx18_api_epu_cmd_irq()
558 …CX18_DEBUG_WARN("Possibly falling behind: %s self-ack'ed our incoming %s to EPU mailbox (sequence … in cx18_api_epu_cmd_irq()
559 rpu_str[rpu], rpu_str[rpu], order_mb->request); in cx18_api_epu_cmd_irq()
562 order->flags = CX18_F_EWO_MB_STALE_UPON_RECEIPT; in cx18_api_epu_cmd_irq()
566 * Individual EPU command processing is responsible for ack-ing in cx18_api_epu_cmd_irq()
567 * a non-stale mailbox as soon as possible in cx18_api_epu_cmd_irq()
571 queue_work(cx->in_work_queue, &order->work); in cx18_api_epu_cmd_irq()
577 * Functions called from a non-interrupt, non work_queue context
583 u32 irq, req, ack, err; in cx18_api_call() local
594 return -EINVAL; in cx18_api_call()
601 info->name, cmd, in cx18_api_call()
605 info->name, cmd, in cx18_api_call()
609 switch (info->rpu) { in cx18_api_call()
611 waitq = &cx->mb_apu_waitq; in cx18_api_call()
612 mb_lock = &cx->epu2apu_mb_lock; in cx18_api_call()
614 mb = &cx->scb->epu2apu_mb; in cx18_api_call()
617 waitq = &cx->mb_cpu_waitq; in cx18_api_call()
618 mb_lock = &cx->epu2cpu_mb_lock; in cx18_api_call()
620 mb = &cx->scb->epu2cpu_mb; in cx18_api_call()
623 CX18_WARN("Unknown RPU (%d) for API call\n", info->rpu); in cx18_api_call()
624 return -EINVAL; in cx18_api_call()
629 * Wait for an in-use mailbox to complete in cx18_api_call()
631 * If the XPU is responding with Ack's, the mailbox shouldn't be in in cx18_api_call()
634 * If the wait for ack after sending a previous command was interrupted in cx18_api_call()
636 * mark it "not busy" from our end, if the XPU hasn't ack'ed it still. in cx18_api_call()
638 req = cx18_readl(cx, &mb->request); in cx18_api_call()
641 (ack = cx18_readl(cx, &mb->ack)) == req, in cx18_api_call()
643 if (req != ack) { in cx18_api_call()
645 cx18_writel(cx, req, &mb->ack); in cx18_api_call()
646 …CX18_ERR("mbox was found stuck busy when setting up for %s; clearing busy and trying to proceed\n", in cx18_api_call()
647 info->name); in cx18_api_call()
649 CX18_DEBUG_API("waited %u msecs for busy mbox to be acked\n", in cx18_api_call()
650 jiffies_to_msecs(timeout-ret)); in cx18_api_call()
655 cx18_writel(cx, cmd, &mb->cmd); in cx18_api_call()
656 for (i = 0; i < args; i++) in cx18_api_call()
657 cx18_writel(cx, data[i], &mb->args[i]); in cx18_api_call()
658 cx18_writel(cx, 0, &mb->error); in cx18_api_call()
659 cx18_writel(cx, req, &mb->request); in cx18_api_call()
660 cx18_writel(cx, req - 1, &mb->ack); /* ensure ack & req are distinct */ in cx18_api_call()
663 * Notify the XPU and wait for it to send an Ack back in cx18_api_call()
665 timeout = msecs_to_jiffies((info->flags & API_FAST) ? 10 : 20); in cx18_api_call()
668 irq, info->name); in cx18_api_call()
670 /* So we don't miss the wakeup, prepare to wait before notifying fw */ in cx18_api_call()
675 ack = cx18_readl(cx, &mb->ack); in cx18_api_call()
676 if (ack != req) { in cx18_api_call()
678 ret = jiffies - t0; in cx18_api_call()
679 ack = cx18_readl(cx, &mb->ack); in cx18_api_call()
681 ret = jiffies - t0; in cx18_api_call()
686 if (req != ack) { in cx18_api_call()
690 CX18_DEBUG_WARN("sending %s timed out waiting %d msecs for RPU acknowledgment\n", in cx18_api_call()
691 info->name, jiffies_to_msecs(ret)); in cx18_api_call()
693 …woken up before mailbox ack was ready after submitting %s to RPU. only waited %d msecs on req %u … in cx18_api_call()
694 info->name, in cx18_api_call()
696 req, ack); in cx18_api_call()
698 return -EINVAL; in cx18_api_call()
703 info->name, jiffies_to_msecs(ret)); in cx18_api_call()
705 CX18_DEBUG_HI_API("waited %u msecs for %s to be acked\n", in cx18_api_call()
706 jiffies_to_msecs(ret), info->name); in cx18_api_call()
709 for (i = 0; i < MAX_MB_ARGUMENTS; i++) in cx18_api_call()
710 data[i] = cx18_readl(cx, &mb->args[i]); in cx18_api_call()
711 err = cx18_readl(cx, &mb->error); in cx18_api_call()
715 * Wait for XPU to perform extra actions for the caller in some cases. in cx18_api_call()
719 if (info->flags & API_SLOW) in cx18_api_call()
723 CX18_DEBUG_API("mailbox error %08x for command %s\n", err, in cx18_api_call()
724 info->name); in cx18_api_call()
725 return err ? -EIO : 0; in cx18_api_call()
735 struct cx18 *cx = s->cx; in cx18_set_filter_param()
739 mode = (cx->filter_mode & 1) ? 2 : (cx->spatial_strength ? 1 : 0); in cx18_set_filter_param()
741 s->handle, 1, mode, cx->spatial_strength); in cx18_set_filter_param()
742 mode = (cx->filter_mode & 2) ? 2 : (cx->temporal_strength ? 1 : 0); in cx18_set_filter_param()
744 s->handle, 0, mode, cx->temporal_strength); in cx18_set_filter_param()
746 s->handle, 2, cx->filter_mode >> 2, 0); in cx18_set_filter_param()
754 struct cx18 *cx = s->cx; in cx18_api_func()
761 s->handle, 0, 0, 0, 0, data[0]); in cx18_api_func()
764 s->handle, data[1], data[0]); in cx18_api_func()
767 s->handle, data[0]); in cx18_api_func()
770 s->handle, data[0]); in cx18_api_func()
774 s->handle, data[0], data[1]); in cx18_api_func()
779 s->handle, data[0]); in cx18_api_func()
782 s->handle, data[0]); in cx18_api_func()
785 s->handle, data[0], data[1], data[2], data[3]); in cx18_api_func()
788 s->handle, data[0]); in cx18_api_func()
791 s->handle, data[0]); in cx18_api_func()
794 s->handle, data[0], data[1], data[2]); in cx18_api_func()
796 cx->filter_mode = (data[0] & 3) | (data[1] << 2); in cx18_api_func()
799 cx->spatial_strength = data[0]; in cx18_api_func()
800 cx->temporal_strength = data[1]; in cx18_api_func()
804 s->handle, data[0], data[1]); in cx18_api_func()
807 s->handle, data[0], data[1], data[2], data[3]); in cx18_api_func()
820 for (i = 0; i < args; i++) in cx18_vapi_result()
841 for (i = 0; i < args; i++) in cx18_vapi()