diff options
Diffstat (limited to 'drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c')
| -rw-r--r-- | drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c | 95 |
1 files changed, 82 insertions, 13 deletions
diff --git a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c index dc2004790a47..f3073d1e7f42 100644 --- a/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c +++ b/drivers/media/platform/mediatek/vcodec/vdec_msg_queue.c @@ -52,9 +52,26 @@ static struct list_head *vdec_get_buf_list(int hardware_index, struct vdec_lat_b } } +static void vdec_msg_queue_inc(struct vdec_msg_queue *msg_queue, int hardware_index) +{ + if (hardware_index == MTK_VDEC_CORE) + atomic_inc(&msg_queue->core_list_cnt); + else + atomic_inc(&msg_queue->lat_list_cnt); +} + +static void vdec_msg_queue_dec(struct vdec_msg_queue *msg_queue, int hardware_index) +{ + if (hardware_index == MTK_VDEC_CORE) + atomic_dec(&msg_queue->core_list_cnt); + else + atomic_dec(&msg_queue->lat_list_cnt); +} + int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf *buf) { struct list_head *head; + int status; head = vdec_get_buf_list(msg_ctx->hardware_index, buf); if (!head) { @@ -66,11 +83,18 @@ int vdec_msg_queue_qbuf(struct vdec_msg_queue_ctx *msg_ctx, struct vdec_lat_buf list_add_tail(head, &msg_ctx->ready_queue); msg_ctx->ready_num++; - if (msg_ctx->hardware_index != MTK_VDEC_CORE) + vdec_msg_queue_inc(&buf->ctx->msg_queue, msg_ctx->hardware_index); + if (msg_ctx->hardware_index != MTK_VDEC_CORE) { wake_up_all(&msg_ctx->ready_to_use); - else - queue_work(buf->ctx->dev->core_workqueue, - &buf->ctx->msg_queue.core_work); + } else { + if (buf->ctx->msg_queue.core_work_cnt < + atomic_read(&buf->ctx->msg_queue.core_list_cnt)) { + status = queue_work(buf->ctx->dev->core_workqueue, + &buf->ctx->msg_queue.core_work); + if (status) + buf->ctx->msg_queue.core_work_cnt++; + } + } mtk_v4l2_debug(3, "enqueue buf type: %d addr: 0x%p num: %d", msg_ctx->hardware_index, buf, msg_ctx->ready_num); @@ -127,6 +151,7 @@ struct vdec_lat_buf *vdec_msg_queue_dqbuf(struct vdec_msg_queue_ctx *msg_ctx) return NULL; } list_del(head); + vdec_msg_queue_dec(&buf->ctx->msg_queue, msg_ctx->hardware_index); msg_ctx->ready_num--; mtk_v4l2_debug(3, "dqueue buf type:%d addr: 0x%p num: %d", @@ -156,11 +181,29 @@ void vdec_msg_queue_update_ube_wptr(struct vdec_msg_queue *msg_queue, uint64_t u bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue) { + struct vdec_lat_buf *buf, *tmp; + struct list_head *list_core[3]; + struct vdec_msg_queue_ctx *core_ctx; + int ret, i, in_core_count = 0, count = 0; long timeout_jiff; - int ret; + + core_ctx = &msg_queue->ctx->dev->msg_queue_core_ctx; + spin_lock(&core_ctx->ready_lock); + list_for_each_entry_safe(buf, tmp, &core_ctx->ready_queue, core_list) { + if (buf && buf->ctx == msg_queue->ctx) { + list_core[in_core_count++] = &buf->core_list; + list_del(&buf->core_list); + } + } + + for (i = 0; i < in_core_count; i++) { + list_add(list_core[in_core_count - (1 + i)], &core_ctx->ready_queue); + queue_work(msg_queue->ctx->dev->core_workqueue, &msg_queue->core_work); + } + spin_unlock(&core_ctx->ready_lock); timeout_jiff = msecs_to_jiffies(1000 * (NUM_BUFFER_COUNT + 2)); - ret = wait_event_timeout(msg_queue->lat_ctx.ready_to_use, + ret = wait_event_timeout(msg_queue->ctx->msg_queue.core_dec_done, msg_queue->lat_ctx.ready_num == NUM_BUFFER_COUNT, timeout_jiff); if (ret) { @@ -168,8 +211,20 @@ bool vdec_msg_queue_wait_lat_buf_full(struct vdec_msg_queue *msg_queue) msg_queue->lat_ctx.ready_num); return true; } - mtk_v4l2_err("failed with lat buf isn't full: %d", - msg_queue->lat_ctx.ready_num); + + spin_lock(&core_ctx->ready_lock); + list_for_each_entry_safe(buf, tmp, &core_ctx->ready_queue, core_list) { + if (buf && buf->ctx == msg_queue->ctx) { + count++; + list_del(&buf->core_list); + } + } + spin_unlock(&core_ctx->ready_lock); + + mtk_v4l2_err("failed with lat buf isn't full: list(%d %d) count:%d", + atomic_read(&msg_queue->lat_list_cnt), + atomic_read(&msg_queue->core_list_cnt), count); + return false; } @@ -206,6 +261,7 @@ static void vdec_msg_queue_core_work(struct work_struct *work) container_of(msg_queue, struct mtk_vcodec_ctx, msg_queue); struct mtk_vcodec_dev *dev = ctx->dev; struct vdec_lat_buf *lat_buf; + int status; lat_buf = vdec_msg_queue_dqbuf(&dev->msg_queue_core_ctx); if (!lat_buf) @@ -221,11 +277,18 @@ static void vdec_msg_queue_core_work(struct work_struct *work) mtk_vcodec_dec_disable_hardware(ctx, MTK_VDEC_CORE); vdec_msg_queue_qbuf(&ctx->msg_queue.lat_ctx, lat_buf); - if (!list_empty(&dev->msg_queue_core_ctx.ready_queue)) { - mtk_v4l2_debug(3, "re-schedule to decode for core: %d", - dev->msg_queue_core_ctx.ready_num); - queue_work(dev->core_workqueue, &msg_queue->core_work); + wake_up_all(&ctx->msg_queue.core_dec_done); + spin_lock(&dev->msg_queue_core_ctx.ready_lock); + lat_buf->ctx->msg_queue.core_work_cnt--; + + if (lat_buf->ctx->msg_queue.core_work_cnt < + atomic_read(&lat_buf->ctx->msg_queue.core_list_cnt)) { + status = queue_work(lat_buf->ctx->dev->core_workqueue, + &lat_buf->ctx->msg_queue.core_work); + if (status) + lat_buf->ctx->msg_queue.core_work_cnt++; } + spin_unlock(&dev->msg_queue_core_ctx.ready_lock); } int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue, @@ -239,12 +302,18 @@ int vdec_msg_queue_init(struct vdec_msg_queue *msg_queue, if (msg_queue->wdma_addr.size) return 0; + msg_queue->ctx = ctx; + msg_queue->core_work_cnt = 0; vdec_msg_queue_init_ctx(&msg_queue->lat_ctx, MTK_VDEC_LAT0); INIT_WORK(&msg_queue->core_work, vdec_msg_queue_core_work); + + atomic_set(&msg_queue->lat_list_cnt, 0); + atomic_set(&msg_queue->core_list_cnt, 0); + init_waitqueue_head(&msg_queue->core_dec_done); + msg_queue->wdma_addr.size = vde_msg_queue_get_trans_size(ctx->picinfo.buf_w, ctx->picinfo.buf_h); - err = mtk_vcodec_mem_alloc(ctx, &msg_queue->wdma_addr); if (err) { mtk_v4l2_err("failed to allocate wdma_addr buf"); |