/* * Queue a buffer list back to incoming or active queues. The buffers * are removed from the buffer list.
*/ void ipu6_isys_buffer_list_queue(struct ipu6_isys_buffer_list *bl, unsignedlong op_flags, enum vb2_buffer_state state)
{ struct ipu6_isys_buffer *ib, *ib_safe; unsignedlong flags; bool first = true;
av = ipu6_isys_queue_to_video(aq);
dev = &av->isys->adev->auxdev.dev;
spin_lock_irqsave(&aq->lock, flags);
list_del(&ib->head); if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_ACTIVE)
list_add(&ib->head, &aq->active); elseif (op_flags & IPU6_ISYS_BUFFER_LIST_FL_INCOMING)
list_add_tail(&ib->head, &aq->incoming);
spin_unlock_irqrestore(&aq->lock, flags);
if (op_flags & IPU6_ISYS_BUFFER_LIST_FL_SET_STATE)
vb2_buffer_done(vb, state);
if (first) {
dev_dbg(dev, "queue buf list %p flags %lx, s %d, %d bufs\n",
bl, op_flags, state, bl->nbufs);
first = false;
}
bl->nbufs--;
}
WARN_ON(bl->nbufs);
}
/* * flush_firmware_streamon_fail() - Flush in cases where requests may * have been queued to firmware and the *firmware streamon fails for a * reason or another.
*/ staticvoid flush_firmware_streamon_fail(struct ipu6_isys_stream *stream)
{ struct device *dev = &stream->isys->adev->auxdev.dev; struct ipu6_isys_queue *aq; unsignedlong flags;
list_del(&ib->head); if (av->streaming) {
dev_dbg(dev, "%s: queue buffer %u back to incoming\n",
av->vdev.name, vb->index); /* Queue already streaming, return to driver. */
list_add(&ib->head, &aq->incoming); continue;
} /* Queue not yet streaming, return to user. */
dev_dbg(dev, "%s: return %u back to videobuf2\n",
av->vdev.name, vb->index);
vb2_buffer_done(ipu6_isys_buffer_to_vb2_buffer(ib),
VB2_BUF_STATE_QUEUED);
}
spin_unlock_irqrestore(&aq->lock, flags);
}
}
/* * Attempt obtaining a buffer list from the incoming queues, a list of buffers * that contains one entry from each video buffer queue. If a buffer can't be * obtained from every queue, the buffers are returned back to the queue.
*/ staticint buffer_list_get(struct ipu6_isys_stream *stream, struct ipu6_isys_buffer_list *bl)
{ struct device *dev = &stream->isys->adev->auxdev.dev; struct ipu6_isys_queue *aq; unsignedlong flags; unsignedlong buf_flag = IPU6_ISYS_BUFFER_LIST_FL_INCOMING;
/* * Convert a buffer list to a isys fw ABI framebuffer set. The * buffer list is not modified.
*/ #define IPU6_ISYS_FRAME_NUM_THRESHOLD (30) void
ipu6_isys_buf_to_fw_frame_buf(struct ipu6_fw_isys_frame_buff_set_abi *set, struct ipu6_isys_stream *stream, struct ipu6_isys_buffer_list *bl)
{ struct ipu6_isys_buffer *ib;
if (!media_pipe || !vb->vb2_queue->start_streaming_called) {
dev_dbg(dev, "media pipeline is not ready for %s\n",
av->vdev.name); return;
}
mutex_lock(&stream->mutex);
if (stream->nr_streaming != stream->nr_queues) {
dev_dbg(dev, "not streaming yet, adding to incoming\n"); goto out;
}
/* * We just put one buffer to the incoming list of this queue * (above). Let's see whether all queues in the pipeline would * have a buffer.
*/
ret = buffer_list_get(stream, &bl); if (ret < 0) {
dev_dbg(dev, "No buffers available\n"); goto out;
}
msg = ipu6_get_fw_msg_buf(stream); if (!msg) {
ret = -ENOMEM; goto out;
}
if (!stream->streaming) {
ret = ipu6_isys_stream_start(av, &bl, true); if (ret)
dev_err(dev, "stream start failed.\n"); goto out;
}
/* * We must queue the buffers in the buffer list to the * appropriate video buffer queues BEFORE passing them to the * firmware since we could get a buffer event back before we * have queued them ourselves to the active queue.
*/
ipu6_isys_buffer_list_queue(&bl, IPU6_ISYS_BUFFER_LIST_FL_ACTIVE, 0);
ret = ipu6_fw_isys_complex_cmd(stream->isys, stream->stream_handle,
buf, msg->dma_addr, sizeof(*buf),
IPU6_FW_ISYS_SEND_TYPE_STREAM_CAPTURE); if (ret < 0)
dev_err(dev, "send stream capture failed\n");
/* * Something went wrong (FW crash / HW hang / not all buffers * returned from isys) if there are still buffers queued in active * queue. We have to clean up places a bit.
*/ while (!list_empty(&aq->active)) { struct vb2_buffer *vb;
ret = ipu6_isys_setup_video(av, &source_entity, &nr_queues); if (ret < 0) {
dev_dbg(dev, "failed to setup video\n"); goto out_return_buffers;
}
ret = ipu6_isys_link_fmt_validate(aq); if (ret) {
dev_dbg(dev, "%s: link format validation failed (%d)\n",
av->vdev.name, ret); goto out_pipeline_stop;
}
ret = ipu6_isys_fw_open(av->isys); if (ret) goto out_pipeline_stop;
stream = av->stream;
mutex_lock(&stream->mutex); if (!stream->nr_streaming) {
ret = ipu6_isys_video_prepare_stream(av, source_entity,
nr_queues); if (ret) goto out_fw_close;
}
stream->nr_streaming++;
dev_dbg(dev, "queue %u of %u\n", stream->nr_streaming,
stream->nr_queues);
/* * The timestamp is invalid as no TSC in some FPGA platform, * so get the sequence from pipeline directly in this case.
*/ if (time == 0) return atomic_read(&stream->sequence) - 1;
for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++) if (time == stream->seq[i].timestamp) {
dev_dbg(dev, "sof: using seq nr %u for ts %llu\n",
stream->seq[i].sequence, time); return stream->seq[i].sequence;
}
for (i = 0; i < IPU6_ISYS_MAX_PARALLEL_SOF; i++)
dev_dbg(dev, "sof: sequence %u, timestamp value %llu\n",
stream->seq[i].sequence, stream->seq[i].timestamp);
if (atomic_read(&ib->str2mmio_flag)) {
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR); /* * Operation on buffer is ended with error and will be reported * to the userspace when it is de-queued
*/
atomic_set(&ib->str2mmio_flag, 0);
} else {
vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
}
}
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.