From 38b1e119c82d52d498896a74f474483880d86d59 Mon Sep 17 00:00:00 2001 From: Govindaraj Rajagopal Date: Wed, 22 May 2019 11:47:36 -0700 Subject: [PATCH] msm: vidc: queue batched buffers upon timeout Client expects all the buffers to be returned in certain scenarios but driver does not return due to decode batching feature. Add delayed_work functionality to queue batched buffers to video hardware upon timeout, so that all the buffers will be returned to client. Change-Id: I926de1da93d941ff2a64bfec1bbd351de2f3a601 Signed-off-by: Govindaraj Rajagopal --- msm/vidc/msm_v4l2_vidc.c | 11 +++ msm/vidc/msm_vidc.c | 3 + msm/vidc/msm_vidc_common.c | 140 ++++++++++++++++++++++++++-------- msm/vidc/msm_vidc_common.h | 5 ++ msm/vidc/msm_vidc_internal.h | 2 + msm/vidc/msm_vidc_platform.c | 16 ++++ msm/vidc/msm_vidc_res_parse.c | 2 + msm/vidc/msm_vidc_resources.h | 1 + 8 files changed, 150 insertions(+), 30 deletions(-) diff --git a/msm/vidc/msm_v4l2_vidc.c b/msm/vidc/msm_v4l2_vidc.c index fd64cee4d061..804c9b124f96 100644 --- a/msm/vidc/msm_v4l2_vidc.c +++ b/msm/vidc/msm_v4l2_vidc.c @@ -555,6 +555,12 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) goto err_cores_exceeded; } + core->vidc_core_workq = create_singlethread_workqueue( + "vidc_core_workq"); + if (!core->vidc_core_workq) { + dprintk(VIDC_ERR, "%s: create core workq failed\n", __func__); + goto err_core_workq; + } mutex_lock(&vidc_driver->lock); list_add_tail(&core->list, &vidc_driver->cores); mutex_unlock(&vidc_driver->lock); @@ -581,6 +587,9 @@ static int msm_vidc_probe_vidc_device(struct platform_device *pdev) return rc; err_fail_sub_device_probe: + if (core->vidc_core_workq) + destroy_workqueue(core->vidc_core_workq); +err_core_workq: vidc_hfi_deinitialize(core->hfi_type, core->device); err_cores_exceeded: if (core->resources.cvp_internal) { @@ -662,6 +671,8 @@ static int msm_vidc_remove(struct platform_device *pdev) return -EINVAL; } + if (core->vidc_core_workq) + destroy_workqueue(core->vidc_core_workq); vidc_hfi_deinitialize(core->hfi_type, core->device); if (core->resources.cvp_internal) { device_remove_file(&core->vdev[MSM_VIDC_CVP].vdev.dev, diff --git a/msm/vidc/msm_vidc.c b/msm/vidc/msm_vidc.c index 10d84555ad21..39935643c43a 100644 --- a/msm/vidc/msm_vidc.c +++ b/msm/vidc/msm_vidc.c @@ -1536,6 +1536,7 @@ void *msm_vidc_open(int core_id, int session_type) INIT_MSM_VIDC_LIST(&inst->etb_data); INIT_MSM_VIDC_LIST(&inst->fbd_data); + INIT_DELAYED_WORK(&inst->batch_work, msm_vidc_batch_handler); kref_init(&inst->kref); inst->session_type = session_type; @@ -1696,6 +1697,8 @@ static void msm_vidc_cleanup_instance(struct msm_vidc_inst *inst) } mutex_unlock(&inst->registeredbufs.lock); + cancel_batch_work(inst); + msm_comm_free_freq_table(inst); msm_comm_free_input_cr_table(inst); diff --git a/msm/vidc/msm_vidc_common.c b/msm/vidc/msm_vidc_common.c index daf52123aad7..0ced7f4cfb48 100644 --- a/msm/vidc/msm_vidc_common.c +++ b/msm/vidc/msm_vidc_common.c @@ -4351,6 +4351,35 @@ err_bad_input: return rc; } +void msm_vidc_batch_handler(struct work_struct *work) +{ + int rc = 0; + struct msm_vidc_inst *inst; + + inst = container_of(work, struct msm_vidc_inst, batch_work.work); + + inst = get_inst(get_vidc_core(MSM_VIDC_CORE_VENUS), inst); + if (!inst) { + dprintk(VIDC_ERR, "%s: invalid params\n", __func__); + return; + } + + if (inst->state == MSM_VIDC_CORE_INVALID) { + dprintk(VIDC_ERR, "%s: invalid state\n", __func__); + goto exit; + } + + dprintk(VIDC_HIGH, "%s: %x: queue pending batch buffers\n", + __func__, hash32_ptr(inst->session)); + + rc = msm_comm_qbufs_batch(inst, NULL); + if (rc) + dprintk(VIDC_ERR, "%s: batch qbufs failed\n", __func__); + +exit: + put_inst(inst); +} + static int msm_comm_qbuf_superframe_to_hfi(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf) { @@ -4562,6 +4591,45 @@ int msm_comm_qbufs(struct msm_vidc_inst *inst) return rc; } +int msm_comm_qbufs_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf) +{ + int rc = 0; + struct msm_vidc_buffer *buf; + + rc = msm_comm_scale_clocks_and_bus(inst); + if (rc) + dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); + + mutex_lock(&inst->registeredbufs.lock); + list_for_each_entry(buf, &inst->registeredbufs.list, list) { + /* Don't queue if buffer is not OUTPUT_MPLANE */ + if (buf->vvb.vb2_buf.type != OUTPUT_MPLANE) + goto loop_end; + /* Don't queue if buffer is not a deferred buffer */ + if (!(buf->flags & MSM_VIDC_FLAG_DEFERRED)) + goto loop_end; + /* Don't queue if RBR event is pending on this buffer */ + if (buf->flags & MSM_VIDC_FLAG_RBR_PENDING) + goto loop_end; + + print_vidc_buffer(VIDC_HIGH, "batch-qbuf", inst, buf); + rc = msm_comm_qbuf_to_hfi(inst, buf); + if (rc) { + dprintk(VIDC_ERR, "%s: Failed batch qbuf to hfi: %d\n", + __func__, rc); + break; + } +loop_end: + /* Queue pending buffers till the current buffer only */ + if (buf == mbuf) + break; + } + mutex_unlock(&inst->registeredbufs.lock); + + return rc; +} + /* * msm_comm_qbuf_decode_batch - count the buffers which are not queued to * firmware yet (count includes rbr pending buffers too) and @@ -4574,9 +4642,8 @@ int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, { int rc = 0; u32 count = 0; - struct msm_vidc_buffer *buf; - if (!inst || !mbuf) { + if (!inst || !inst->core || !mbuf) { dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); return -EINVAL; } @@ -4601,43 +4668,55 @@ int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, if (count < inst->batch.size) { print_vidc_buffer(VIDC_HIGH, "batch-qbuf deferred", inst, mbuf); + schedule_batch_work(inst); return 0; } + + /* + * Batch completed - queing bufs to firmware. + * so cancel pending work if any. + */ + cancel_batch_work(inst); } - rc = msm_comm_scale_clocks_and_bus(inst); + rc = msm_comm_qbufs_batch(inst, mbuf); if (rc) - dprintk(VIDC_ERR, "%s: scale clocks failed\n", __func__); - - mutex_lock(&inst->registeredbufs.lock); - list_for_each_entry(buf, &inst->registeredbufs.list, list) { - /* Don't queue if buffer is not CAPTURE_MPLANE */ - if (buf->vvb.vb2_buf.type != OUTPUT_MPLANE) - goto loop_end; - /* Don't queue if buffer is not a deferred buffer */ - if (!(buf->flags & MSM_VIDC_FLAG_DEFERRED)) - goto loop_end; - /* Don't queue if RBR event is pending on this buffer */ - if (buf->flags & MSM_VIDC_FLAG_RBR_PENDING) - goto loop_end; - - print_vidc_buffer(VIDC_HIGH, "batch-qbuf", inst, buf); - rc = msm_comm_qbuf_to_hfi(inst, buf); - if (rc) { - dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", - __func__, rc); - break; - } -loop_end: - /* Queue pending buffers till the current buffer only */ - if (buf == mbuf) - break; - } - mutex_unlock(&inst->registeredbufs.lock); + dprintk(VIDC_ERR, "%s: Failed qbuf to hfi: %d\n", + __func__, rc); return rc; } +int schedule_batch_work(struct msm_vidc_inst *inst) +{ + struct msm_vidc_core *core; + struct msm_vidc_platform_resources *res; + + if (!inst || !inst->core) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + core = inst->core; + res = &core->resources; + + cancel_delayed_work(&inst->batch_work); + queue_delayed_work(core->vidc_core_workq, &inst->batch_work, + msecs_to_jiffies(res->batch_timeout)); + + return 0; +} + +int cancel_batch_work(struct msm_vidc_inst *inst) +{ + if (!inst) { + dprintk(VIDC_ERR, "%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_delayed_work(&inst->batch_work); + + return 0; +} + int msm_comm_try_get_bufreqs(struct msm_vidc_inst *inst) { int rc = -EINVAL, i = 0; @@ -5331,6 +5410,7 @@ int msm_comm_flush(struct msm_vidc_inst *inst, u32 flags) msm_clock_data_reset(inst); + cancel_batch_work(inst); if (inst->state == MSM_VIDC_CORE_INVALID) { dprintk(VIDC_ERR, "Core %pK and inst %pK are in bad state\n", diff --git a/msm/vidc/msm_vidc_common.h b/msm/vidc/msm_vidc_common.h index 7d20fd15ae91..a91208c1ed42 100644 --- a/msm/vidc/msm_vidc_common.h +++ b/msm/vidc/msm_vidc_common.h @@ -286,12 +286,17 @@ void msm_comm_store_mark_data(struct msm_vidc_list *data_list, void msm_comm_fetch_mark_data(struct msm_vidc_list *data_list, u32 index, u32 *mark_data, u32 *mark_target); int msm_comm_release_mark_data(struct msm_vidc_inst *inst); +int msm_comm_qbufs_batch(struct msm_vidc_inst *inst, + struct msm_vidc_buffer *mbuf); int msm_comm_qbuf_decode_batch(struct msm_vidc_inst *inst, struct msm_vidc_buffer *mbuf); +int schedule_batch_work(struct msm_vidc_inst *inst); +int cancel_batch_work(struct msm_vidc_inst *inst); int msm_comm_num_queued_bufs(struct msm_vidc_inst *inst, u32 type); int msm_comm_set_index_extradata(struct msm_vidc_inst *inst, uint32_t extradata_id, uint32_t value); int msm_comm_set_extradata(struct msm_vidc_inst *inst, uint32_t extradata_id, uint32_t value); bool msm_comm_check_for_inst_overload(struct msm_vidc_core *core); +void msm_vidc_batch_handler(struct work_struct *work); #endif diff --git a/msm/vidc/msm_vidc_internal.h b/msm/vidc/msm_vidc_internal.h index 5d8d165b82eb..2162909fe33e 100644 --- a/msm/vidc/msm_vidc_internal.h +++ b/msm/vidc/msm_vidc_internal.h @@ -442,6 +442,7 @@ struct msm_vidc_core { struct msm_vidc_capability *capabilities; struct delayed_work fw_unload_work; struct work_struct ssr_work; + struct workqueue_struct *vidc_core_workq; enum hal_ssr_trigger_type ssr_type; bool smmu_fault_handled; bool trigger_ssr; @@ -518,6 +519,7 @@ struct msm_vidc_inst { struct msm_vidc_codec_data *codec_data; struct hal_hdr10_pq_sei hdr10_sei_params; struct batch_mode batch; + struct delayed_work batch_work; struct msm_vidc_inst_smem_ops *smem_ops; int (*buffer_size_calculators)(struct msm_vidc_inst *inst); }; diff --git a/msm/vidc/msm_vidc_platform.c b/msm/vidc/msm_vidc_platform.c index eaf20bb9fe4a..d9c4804f8faf 100644 --- a/msm/vidc/msm_vidc_platform.c +++ b/msm/vidc/msm_vidc_platform.c @@ -444,6 +444,10 @@ static struct msm_vidc_common_data lito_common_data_v0[] = { .key = "qcom,decode-batching", .value = 1, }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, { .key = "qcom,dcvs", .value = 1, @@ -515,6 +519,10 @@ static struct msm_vidc_common_data lito_common_data_v1[] = { .key = "qcom,decode-batching", .value = 1, }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, { .key = "qcom,dcvs", .value = 1, @@ -594,6 +602,10 @@ static struct msm_vidc_common_data kona_common_data[] = { .key = "qcom,decode-batching", .value = 1, }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, { .key = "qcom,dcvs", .value = 1, @@ -736,6 +748,10 @@ static struct msm_vidc_common_data sm8150_common_data[] = { .key = "qcom,decode-batching", .value = 1, }, + { + .key = "qcom,batch-timeout", + .value = 200, + }, { .key = "qcom,dcvs", .value = 1, diff --git a/msm/vidc/msm_vidc_res_parse.c b/msm/vidc/msm_vidc_res_parse.c index b0a95ce4724d..d2d66bb60291 100644 --- a/msm/vidc/msm_vidc_res_parse.c +++ b/msm/vidc/msm_vidc_res_parse.c @@ -827,6 +827,8 @@ int read_platform_resources_from_drv_data( "qcom,domain-attr-cache-pagetables"); res->decode_batching = find_key_value(platform_data, "qcom,decode-batching"); + res->batch_timeout = find_key_value(platform_data, + "qcom,batch-timeout"); res->dcvs = find_key_value(platform_data, "qcom,dcvs"); res->fw_cycles = find_key_value(platform_data, diff --git a/msm/vidc/msm_vidc_resources.h b/msm/vidc/msm_vidc_resources.h index 90d4d03d7df2..76b5b8d206bd 100644 --- a/msm/vidc/msm_vidc_resources.h +++ b/msm/vidc/msm_vidc_resources.h @@ -195,6 +195,7 @@ struct msm_vidc_platform_resources { bool non_fatal_pagefaults; bool cache_pagetables; bool decode_batching; + uint32_t batch_timeout; bool dcvs; struct msm_vidc_codec_data *codec_data; int codec_data_count;