diff --git a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c index 51d75fd8543b..dde711169a70 100644 --- a/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +++ b/drivers/media/platform/msm/vidc/msm_v4l2_vidc.c @@ -335,6 +335,7 @@ static int msm_vidc_initialize_core(struct platform_device *pdev, init_completion(&core->completions[i]); } + INIT_DELAYED_WORK(&core->fw_unload_work, msm_vidc_fw_unload_handler); return rc; } diff --git a/drivers/media/platform/msm/vidc/msm_vidc_common.c b/drivers/media/platform/msm/vidc/msm_vidc_common.c index 95fec1262c4e..590850211812 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_common.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_common.c @@ -15,7 +15,6 @@ #include #include #include -#include #include #include #include "msm_vidc_common.h" @@ -2244,6 +2243,7 @@ static int msm_comm_init_core(struct msm_vidc_inst *inst) goto fail_load_fw; } core->state = VIDC_CORE_LOADED; + dprintk(VIDC_DBG, "Firmware downloaded\n"); } mutex_unlock(&core->lock); @@ -2281,7 +2281,6 @@ fail_vote_bus: static int msm_vidc_deinit_core(struct msm_vidc_inst *inst) { - int rc = 0; struct msm_vidc_core *core; struct hfi_device *hdev; @@ -2305,35 +2304,22 @@ static int msm_vidc_deinit_core(struct msm_vidc_inst *inst) mutex_lock(&core->lock); if (list_empty(&core->instances)) { - if (core->state > VIDC_CORE_INIT) { - if (core->resources.ocmem_size) { - if (inst->state != MSM_VIDC_CORE_INVALID) - msm_comm_unset_ocmem(core); - call_hfi_op(hdev, free_ocmem, - hdev->hfi_device_data); - } - dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n"); - rc = call_hfi_op(hdev, core_release, - hdev->hfi_device_data); - if (rc) { - dprintk(VIDC_ERR, - "Failed to release core, id = %d\n", - core->id); - goto exit; - } - } + cancel_delayed_work(&core->fw_unload_work); - core->state = VIDC_CORE_UNINIT; - - call_hfi_op(hdev, unload_fw, hdev->hfi_device_data); - msm_comm_unvote_buses(core); + /* + * Delay unloading of firmware for 10 sec. This is useful + * in avoiding firmware download delays in cases where we + * will have a burst of back to back video playback sessions + * e.g. thumbnail generation. + */ + schedule_delayed_work(&core->fw_unload_work, + msecs_to_jiffies(10000)); } core_already_uninited: change_inst_state(inst, MSM_VIDC_CORE_UNINIT); -exit: mutex_unlock(&core->lock); - return rc; + return 0; } int msm_comm_force_cleanup(struct msm_vidc_inst *inst) @@ -4541,3 +4527,48 @@ int msm_comm_smem_get_domain_partition(struct msm_vidc_inst *inst, return msm_smem_get_domain_partition(inst->mem_client, flags, buffer_type, domain_num, partition_num); } + +void msm_vidc_fw_unload_handler(struct work_struct *work) +{ + struct msm_vidc_core *core = NULL; + struct hfi_device *hdev = NULL; + int rc = 0; + + core = container_of(work, struct msm_vidc_core, fw_unload_work.work); + if (!core || !core->device) { + dprintk(VIDC_ERR, "%s - invalid work or core handle\n", + __func__); + return; + } + + hdev = core->device; + + mutex_lock(&core->lock); + if (list_empty(&core->instances) && + core->state != VIDC_CORE_UNINIT) { + if (core->state > VIDC_CORE_INIT) { + if (core->resources.ocmem_size) { + if (core->state != VIDC_CORE_INVALID) + msm_comm_unset_ocmem(core); + call_hfi_op(hdev, free_ocmem, + hdev->hfi_device_data); + } + dprintk(VIDC_DBG, "Calling vidc_hal_core_release\n"); + rc = call_hfi_op(hdev, core_release, + hdev->hfi_device_data); + if (rc) { + dprintk(VIDC_ERR, + "Failed to release core, id = %d\n", + core->id); + return; + } + } + + core->state = VIDC_CORE_UNINIT; + + call_hfi_op(hdev, unload_fw, hdev->hfi_device_data); + dprintk(VIDC_DBG, "Firmware unloaded\n"); + msm_comm_unvote_buses(core); + } + mutex_unlock(&core->lock); +} diff --git a/drivers/media/platform/msm/vidc/msm_vidc_internal.h b/drivers/media/platform/msm/vidc/msm_vidc_internal.h index a10d39bf8607..8ac9f0a04304 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_internal.h +++ b/drivers/media/platform/msm/vidc/msm_vidc_internal.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -275,6 +276,7 @@ struct msm_vidc_core { u32 enc_codec_supported; u32 dec_codec_supported; struct msm_vidc_idle_stats idle_stats; + struct delayed_work fw_unload_work; }; struct msm_vidc_inst { @@ -391,4 +393,5 @@ struct msm_smem *msm_smem_user_to_kernel(void *clt, int fd, u32 offset, enum hal_buffer buffer_type); int msm_smem_get_domain_partition(void *clt, u32 flags, enum hal_buffer buffer_type, int *domain_num, int *partition_num); +void msm_vidc_fw_unload_handler(struct work_struct *work); #endif