diff --git a/drivers/media/platform/msm/vidc/msm_vidc.c b/drivers/media/platform/msm/vidc/msm_vidc.c index 02bfc459614f..20d5ba661a6b 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_vidc.c @@ -1238,7 +1238,7 @@ static inline int vb2_bufq_init(struct msm_vidc_inst *inst, q->ops = msm_venc_get_vb2q_ops(); q->mem_ops = &msm_vidc_vb2_mem_ops; q->drv_priv = inst; - q->allow_zero_bytesused = 1; + q->allow_zero_bytesused = !V4L2_TYPE_IS_OUTPUT(type); return vb2_queue_init(q); } @@ -1356,6 +1356,7 @@ void *msm_vidc_open(int core_id, int session_type) INIT_MSM_VIDC_LIST(&inst->pending_getpropq); INIT_MSM_VIDC_LIST(&inst->outputbufs); INIT_MSM_VIDC_LIST(&inst->registeredbufs); + INIT_MSM_VIDC_LIST(&inst->eosbufs); kref_init(&inst->kref); @@ -1448,6 +1449,7 @@ fail_mem_client: DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq); DEINIT_MSM_VIDC_LIST(&inst->outputbufs); DEINIT_MSM_VIDC_LIST(&inst->registeredbufs); + DEINIT_MSM_VIDC_LIST(&inst->eosbufs); kfree(inst); inst = NULL; @@ -1473,6 +1475,7 @@ static void cleanup_instance(struct msm_vidc_inst *inst) dprintk(VIDC_ERR, "Failed to release scratch buffers\n"); } + msm_comm_release_eos_buffers(inst); if (msm_comm_release_persist_buffers(inst)) { dprintk(VIDC_ERR, @@ -1516,6 +1519,7 @@ int msm_vidc_destroy(struct msm_vidc_inst *inst) DEINIT_MSM_VIDC_LIST(&inst->pending_getpropq); DEINIT_MSM_VIDC_LIST(&inst->outputbufs); DEINIT_MSM_VIDC_LIST(&inst->registeredbufs); + DEINIT_MSM_VIDC_LIST(&inst->eosbufs); v4l2_fh_del(&inst->event_handler); v4l2_fh_exit(&inst->event_handler); diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 7ae3a1ea5eba..ca72d0fa31a1 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -1829,6 +1829,26 @@ static struct vb2_buffer *get_vb_from_device_addr(struct buf_queue *bufq, return vb; } +static bool is_eos_buffer(struct msm_vidc_inst *inst, u32 device_addr) +{ + struct eos_buf *temp, *next; + bool found = false; + + mutex_lock(&inst->eosbufs.lock); + list_for_each_entry_safe(temp, next, &inst->eosbufs.list, list) { + if (temp->smem->device_addr == device_addr) { + found = true; + list_del(&temp->list); + msm_comm_smem_free(inst, temp->smem); + kfree(temp); + break; + } + } + mutex_unlock(&inst->eosbufs.lock); + + return found; +} + static void handle_ebd(enum hal_command_response cmd, void *data) { struct msm_vidc_cb_data_done *response = data; @@ -1849,6 +1869,14 @@ static void handle_ebd(enum hal_command_response cmd, void *data) return; } + empty_buf_done = (struct vidc_hal_ebd *)&response->input_done; + /* If this is internal EOS buffer, handle it in driver */ + if (is_eos_buffer(inst, empty_buf_done->packet_buffer)) { + dprintk(VIDC_DBG, "Received EOS buffer %pK\n", + (void *)empty_buf_done->packet_buffer); + goto exit; + } + vb = get_vb_from_device_addr(&inst->bufq[OUTPUT_PORT], response->input_done.packet_buffer); if (vb) { @@ -1900,6 +1928,7 @@ static void handle_ebd(enum hal_command_response cmd, void *data) msm_vidc_debugfs_update(inst, MSM_VIDC_DEBUGFS_EVENT_EBD); } +exit: put_inst(inst); } @@ -3587,6 +3616,66 @@ int msm_vidc_comm_cmd(void *instance, union msm_v4l2_cmd *cmd) "Failed to flush buffers: %d\n", rc); } break; + + case V4L2_DEC_CMD_STOP: + { + struct vidc_frame_data data = {0}; + struct hfi_device *hdev; + struct eos_buf *binfo; + u32 smem_flags = 0; + + get_inst(inst->core, inst); + if (inst->session_type != MSM_VIDC_DECODER) { + dprintk(VIDC_DBG, + "Non-Decoder session. DEC_STOP is not valid\n"); + rc = -EINVAL; + goto exit; + } + + binfo = kzalloc(sizeof(*binfo), GFP_KERNEL); + if (!binfo) { + dprintk(VIDC_ERR, "%s: Out of memory\n", __func__); + rc = -ENOMEM; + goto exit; + } + + if (inst->flags & VIDC_SECURE) + smem_flags |= SMEM_SECURE; + + binfo->smem = msm_comm_smem_alloc(inst, + SZ_4K, 1, smem_flags, + HAL_BUFFER_INPUT, 0); + if (!binfo->smem) { + dprintk(VIDC_ERR, + "Failed to allocate eos memory\n"); + goto exit; + } + + mutex_lock(&inst->eosbufs.lock); + list_add_tail(&binfo->list, &inst->eosbufs.list); + mutex_unlock(&inst->eosbufs.lock); + + data.alloc_len = binfo->smem->size; + data.device_addr = binfo->smem->device_addr; + data.clnt_data = data.device_addr; + data.buffer_type = HAL_BUFFER_INPUT; + data.filled_len = 0; + data.offset = 0; + data.flags = HAL_BUFFERFLAG_EOS; + data.timestamp = LLONG_MAX; + data.extradata_addr = data.device_addr; + data.extradata_size = 0; + dprintk(VIDC_DBG, "Queueing EOS buffer %pK\n", + (void *)data.device_addr); + hdev = inst->core->device; + + rc = call_hfi_op(hdev, session_etb, inst->session, + &data); +exit: + put_inst(inst); + break; + } + default: dprintk(VIDC_ERR, "Unknown Command %d\n", which_cmd); rc = -ENOTSUPP; @@ -4307,6 +4396,26 @@ exit: return rc; } +void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst) +{ + struct eos_buf *buf, *next; + + if (!inst) { + dprintk(VIDC_ERR, + "Invalid instance pointer = %pK\n", inst); + return; + } + + mutex_lock(&inst->eosbufs.lock); + list_for_each_entry_safe(buf, next, &inst->eosbufs.list, list) { + list_del(&buf->list); + msm_comm_smem_free(inst, buf->smem); + kfree(buf); + } + INIT_LIST_HEAD(&inst->eosbufs.list); + mutex_unlock(&inst->eosbufs.lock); +} + int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst) { struct msm_smem *handle; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.h b/drivers/media/platform/msm/vidc/msm_vidc_common.h index 5658df95db26..d6e8a84fb5bb 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.h @@ -60,6 +60,7 @@ int msm_comm_release_scratch_buffers(struct msm_vidc_inst *inst, bool check_for_reuse); int msm_comm_release_persist_buffers(struct msm_vidc_inst *inst); int msm_comm_release_output_buffers(struct msm_vidc_inst *inst); +void msm_comm_release_eos_buffers(struct msm_vidc_inst *inst); int msm_comm_force_cleanup(struct msm_vidc_inst *inst); int msm_comm_suspend(int core_id); enum hal_extradata_id msm_comm_get_hal_extradata_index( diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index 4cb900bbca10..08ba0bfb566e 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -132,6 +132,11 @@ enum buffer_owner { MAX_OWNER }; +struct eos_buf { + struct list_head list; + struct msm_smem *smem; +}; + struct internal_buf { struct list_head list; enum hal_buffer buffer_type; @@ -270,6 +275,7 @@ struct msm_vidc_inst { struct msm_vidc_list persistbufs; struct msm_vidc_list pending_getpropq; struct msm_vidc_list outputbufs; + struct msm_vidc_list eosbufs; struct msm_vidc_list registeredbufs; struct buffer_requirements buff_req; void *mem_client;