diff --git a/driver/platform/waipio/src/msm_vidc_waipio.c b/driver/platform/waipio/src/msm_vidc_waipio.c index 2d6093ec21..2499a7357b 100644 --- a/driver/platform/waipio/src/msm_vidc_waipio.c +++ b/driver/platform/waipio/src/msm_vidc_waipio.c @@ -934,11 +934,13 @@ static struct msm_platform_inst_capability instance_data_waipio[] = { MSM_VIDC_POWER_SAVE_MODE, 1, MSM_VIDC_MAX_QUALITY_MODE}, - {CODED_FRAMES, DEC, CODECS_ALL, 0, 1, 1, 0, + {CODED_FRAMES, DEC, CODECS_ALL, + CODED_FRAMES_MBS_ONLY, CODED_FRAMES_ADAPTIVE_FIELDS, + 1, CODED_FRAMES_MBS_ONLY, 0, HFI_PROP_CODED_FRAMES}, - {BIT_DEPTH, DEC, CODECS_ALL, 8 << 16 | 8, 10 << 16 | 10, 1, 8 << 16 | 8, + {BIT_DEPTH, DEC, CODECS_ALL, BIT_DEPTH_8, BIT_DEPTH_10, 1, BIT_DEPTH_8, 0, HFI_PROP_LUMA_CHROMA_BIT_DEPTH}, diff --git a/driver/variant/iris2/src/msm_vidc_iris2.c b/driver/variant/iris2/src/msm_vidc_iris2.c index 6eca81b88d..7bb1c07d4d 100644 --- a/driver/variant/iris2/src/msm_vidc_iris2.c +++ b/driver/variant/iris2/src/msm_vidc_iris2.c @@ -367,8 +367,10 @@ static int __watchdog_iris2(struct msm_vidc_core *vidc_core, u32 intr_status) return -EINVAL; } - if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2) + if (intr_status & WRAPPER_INTR_STATUS_A2HWD_BMSK_IRIS2) { + d_vpr_e("%s: received watchdog interrupt\n", __func__); rc = 1; + } return rc; } diff --git a/driver/vidc/inc/msm_vidc_core.h b/driver/vidc/inc/msm_vidc_core.h index 140b57985b..8ad1e64388 100644 --- a/driver/vidc/inc/msm_vidc_core.h +++ b/driver/vidc/inc/msm_vidc_core.h @@ -57,7 +57,6 @@ struct msm_vidc_core_power { enum msm_vidc_core_state { MSM_VIDC_CORE_DEINIT = 0, MSM_VIDC_CORE_INIT = 1, - MSM_VIDC_CORE_ERROR = 2, }; struct msm_vidc_core { diff --git a/driver/vidc/inc/msm_vidc_debug.h b/driver/vidc/inc/msm_vidc_debug.h index 2a179c6ab8..a929a773cd 100644 --- a/driver/vidc/inc/msm_vidc_debug.h +++ b/driver/vidc/inc/msm_vidc_debug.h @@ -56,11 +56,13 @@ enum vidc_msg_prio { #define dprintk(__level, sid, __fmt, ...) \ do { \ - pr_err(VIDC_DBG_TAG __fmt, \ - "level", \ - sid, \ - "codec", \ - ##__VA_ARGS__); \ + if (msm_vidc_debug & __level) { \ + pr_err(VIDC_DBG_TAG __fmt, \ + level_str(__level), \ + sid, \ + "codec", \ + ##__VA_ARGS__); \ + } \ } while (0) #define s_vpr_e(sid, __fmt, ...) dprintk(VIDC_ERR, sid, __fmt, ##__VA_ARGS__) @@ -99,4 +101,7 @@ enum vidc_msg_prio { do { if (value) \ d_vpr_e("BugOn"); \ } while (0) + +const char *level_str(u32 level); + #endif diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 38798323e3..4c40413648 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -114,7 +114,15 @@ static inline bool is_linear_colorformat(enum msm_vidc_colorformat_type colorfor { return colorformat == MSM_VIDC_FMT_NV12 || colorformat == MSM_VIDC_FMT_NV21 || - colorformat == MSM_VIDC_FMT_P010; + colorformat == MSM_VIDC_FMT_P010 || + colorformat == MSM_VIDC_FMT_RGBA8888; +} + +static inline bool is_ubwc_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_NV12C || + colorformat == MSM_VIDC_FMT_TP10C || + colorformat == MSM_VIDC_FMT_RGBA8888C; } static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorformat) @@ -123,6 +131,15 @@ static inline bool is_10bit_colorformat(enum msm_vidc_colorformat_type colorform colorformat == MSM_VIDC_FMT_TP10C; } +static inline bool is_8bit_colorformat(enum msm_vidc_colorformat_type colorformat) +{ + return colorformat == MSM_VIDC_FMT_NV12 || + colorformat == MSM_VIDC_FMT_NV12C || + colorformat == MSM_VIDC_FMT_NV21 || + colorformat == MSM_VIDC_FMT_RGBA8888 || + colorformat == MSM_VIDC_FMT_RGBA8888C; +} + static inline bool is_secondary_output_mode(struct msm_vidc_inst *inst) { return false; // TODO: inst->stream_output_mode == HAL_VIDEO_DECODER_SECONDARY; @@ -161,6 +178,11 @@ static inline bool is_active_session(u64 prev, u64 curr) MSM_VIDC_SESSION_INACTIVE_THRESHOLD_MS); } +static inline bool is_session_error(struct msm_vidc_inst* inst) +{ + return inst->state == MSM_VIDC_ERROR; +} + void print_vidc_buffer(u32 tag, const char *str, struct msm_vidc_inst *inst, struct msm_vidc_buffer *vbuf); void print_vb2_buffer(const char *str, struct msm_vidc_inst *inst, @@ -179,7 +201,7 @@ int v4l2_type_to_driver_port(struct msm_vidc_inst *inst, u32 type, const char *func); const char *state_name(enum msm_vidc_inst_state state); int msm_vidc_change_inst_state(struct msm_vidc_inst *inst, - enum msm_vidc_inst_state state, const char *func); + enum msm_vidc_inst_state request_state, const char *func); int msm_vidc_get_input_internal_buffers(struct msm_vidc_inst *inst, enum msm_vidc_buffer_type buffer_type); int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst, @@ -199,9 +221,13 @@ int msm_vidc_session_streamon(struct msm_vidc_inst *inst, int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, enum msm_vidc_port_type port); int msm_vidc_session_close(struct msm_vidc_inst *inst); +int msm_vidc_kill_session(struct msm_vidc_inst* inst); int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst); +int msm_vidc_change_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, const char *func); int msm_vidc_core_init(struct msm_vidc_core *core); int msm_vidc_core_deinit(struct msm_vidc_core *core); +int msm_vidc_core_timeout(struct msm_vidc_core *core); int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *data); int msm_vidc_trigger_ssr(struct msm_vidc_core *core, @@ -236,6 +262,8 @@ int msm_vidc_queue_buffer(struct msm_vidc_inst *inst, struct vb2_buffer *vb2); int msm_vidc_destroy_internal_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *buffer); void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst); +int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, + enum msm_vidc_buffer_type type); struct msm_vidc_buffer *get_meta_buffer(struct msm_vidc_inst *inst, struct msm_vidc_buffer *vbuf); struct msm_vidc_inst *get_inst_ref(struct msm_vidc_core *core, @@ -261,10 +289,13 @@ int msm_vidc_state_change_input_psc(struct msm_vidc_inst *inst); int msm_vidc_state_change_last_flag(struct msm_vidc_inst *inst); int msm_vidc_get_mbs_per_frame(struct msm_vidc_inst *inst); int msm_vidc_get_fps(struct msm_vidc_inst *inst); -int msm_vidc_num_queued_bufs(struct msm_vidc_inst *inst, u32 type); +int msm_vidc_num_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type, enum msm_vidc_buffer_attributes attr); void core_lock(struct msm_vidc_core *core, const char *function); void core_unlock(struct msm_vidc_core *core, const char *function); +bool core_lock_check(struct msm_vidc_core *core, const char *function); void inst_lock(struct msm_vidc_inst *inst, const char *function); void inst_unlock(struct msm_vidc_inst *inst, const char *function); +bool inst_lock_check(struct msm_vidc_inst *inst, const char *function); #endif // _MSM_VIDC_DRIVER_H_ diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index e14038e643..12b56181e2 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -43,6 +43,10 @@ #define DEFAULT_BITSTREM_ALIGNMENT 16 #define H265_BITSTREM_ALIGNMENT 32 #define DEFAULT_MAX_HOST_BUF_COUNT 32 +#define BIT_DEPTH_8 (8 << 16 | 8) +#define BIT_DEPTH_10 (10 << 16 | 10) +#define CODED_FRAMES_MBS_ONLY HFI_BITMASK_FRAME_MBS_ONLY_FLAG +#define CODED_FRAMES_ADAPTIVE_FIELDS HFI_BITMASK_MB_ADAPTIVE_FRAME_FIELD_FLAG /* TODO * #define MAX_SUPERFRAME_COUNT 32 diff --git a/driver/vidc/src/msm_vdec.c b/driver/vidc/src/msm_vdec.c index af9f82e6f5..f3ac13f539 100644 --- a/driver/vidc/src/msm_vdec.c +++ b/driver/vidc/src/msm_vdec.c @@ -1861,6 +1861,34 @@ int msm_vdec_g_param(struct msm_vidc_inst *inst, return 0; } +static int msm_vdec_check_colorformat_supported(struct msm_vidc_inst* inst, + enum msm_vidc_colorformat_type colorformat) +{ + bool supported = true; + + /* do not reject coloformats before streamon */ + if (!inst->vb2q[INPUT_PORT].streaming) + return true; + + /* + * bit_depth 8 bit supports 8 bit colorformats only + * bit_depth 10 bit supports 10 bit colorformats only + * interlace supports ubwc colorformats only + */ + if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_8 && + !is_8bit_colorformat(colorformat)) + supported = false; + if (inst->capabilities->cap[BIT_DEPTH].value == BIT_DEPTH_10 && + !is_10bit_colorformat(colorformat)) + supported = false; + if (inst->capabilities->cap[CODED_FRAMES].value == + CODED_FRAMES_ADAPTIVE_FIELDS && + !is_ubwc_colorformat(colorformat)) + supported = false; + + return supported; +} + int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) { int rc = 0; @@ -1900,8 +1928,11 @@ int msm_vdec_enum_fmt(struct msm_vidc_inst *inst, struct v4l2_fmtdesc *f) if (idx > 31) break; if (formats & BIT(i)) { - array[idx] = formats & BIT(i); - idx++; + if (msm_vdec_check_colorformat_supported(inst, + formats & BIT(i))) { + array[idx] = formats & BIT(i); + idx++; + } } i++; formats >>= 1; diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index d506e1aa38..31cbe069e2 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -700,18 +700,9 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) return NULL; } - if (core->state == MSM_VIDC_CORE_ERROR) { - d_vpr_e("%s: core invalid state\n", __func__); + rc = msm_vidc_core_init(core); + if (rc) return NULL; - } - - if (core->state == MSM_VIDC_CORE_DEINIT) { - rc = msm_vidc_core_init(core); - if (rc) { - msm_vidc_core_deinit(core); - return NULL; - } - } inst = kzalloc(sizeof(*inst), GFP_KERNEL); if (!inst) { diff --git a/driver/vidc/src/msm_vidc_debug.c b/driver/vidc/src/msm_vidc_debug.c index 28716e211a..1b32b790cc 100644 --- a/driver/vidc/src/msm_vidc_debug.c +++ b/driver/vidc/src/msm_vidc_debug.c @@ -5,7 +5,7 @@ #include "msm_vidc_debug.h" -int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK | +int msm_vidc_debug = VIDC_HIGH | VIDC_PKT | VIDC_ERR | VIDC_PRINTK | FW_ERROR | FW_FATAL | FW_FTRACE | FW_LOW | FW_MED | FW_HIGH | FW_PERF | FW_PRINTK; EXPORT_SYMBOL(msm_vidc_debug); @@ -18,3 +18,20 @@ EXPORT_SYMBOL(msm_vidc_syscache_disable); int msm_vidc_clock_voting = !1; +const char *level_str(u32 level) +{ + if (level & VIDC_ERR) + return "err "; + else if (level & VIDC_HIGH) + return "high"; + else if (level & VIDC_LOW) + return "low "; + else if (level & VIDC_PERF) + return "perf"; + else if (level & VIDC_PKT) + return "pkt "; + else if (level & VIDC_BUS) + return "bus "; + else + return "????"; +} \ No newline at end of file diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 762de355ea..1f7fb61734 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -415,6 +415,45 @@ struct msm_vidc_allocations *msm_vidc_get_allocations( } } +const char *core_state_name(enum msm_vidc_core_state state) +{ + const char* name = "UNKNOWN"; + + switch (state) { + case MSM_VIDC_CORE_INIT: + name = "CORE_INIT"; + break; + case MSM_VIDC_CORE_DEINIT: + name = "CORE_DEINIT"; + break; + default: + name = "UNKNOWN"; + break; + } + + return name; +} + +int msm_vidc_change_core_state(struct msm_vidc_core *core, + enum msm_vidc_core_state request_state, const char *func) +{ + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (!request_state) { + d_vpr_e("%s: invalid core request state\n", func); + return -EINVAL; + } + + d_vpr_h("%s: core state changed from %s to %s\n", + func, core_state_name(core->state), + core_state_name(request_state)); + core->state = request_state; + return 0; +} + const char *state_name(enum msm_vidc_inst_state state) { const char *name = "UNKNOWN"; @@ -1097,29 +1136,31 @@ int msm_vidc_get_fps(struct msm_vidc_inst *inst) return fps; } -int msm_vidc_num_queued_bufs(struct msm_vidc_inst *inst, u32 type) +int msm_vidc_num_buffers(struct msm_vidc_inst *inst, + enum msm_vidc_buffer_type type, enum msm_vidc_buffer_attributes attr) { int count = 0; struct msm_vidc_buffer *vbuf; - struct msm_vidc_buffers* buffers; + struct msm_vidc_buffers *buffers; if (!inst) { d_vpr_e("%s: invalid params\n", __func__); - return 0; + return count; } - if (type == OUTPUT_MPLANE) { + if (type == MSM_VIDC_BUF_OUTPUT) { buffers = &inst->buffers.output; - } else if (type == INPUT_MPLANE) { + } else if (type == MSM_VIDC_BUF_INPUT) { buffers = &inst->buffers.input; } else { - s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n", __func__, type); - return -EINVAL; + s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n", + __func__, type); + return count; } list_for_each_entry(vbuf, &buffers->list, list) { if (vbuf->type != type) continue; - if (!(vbuf->attr & MSM_VIDC_ATTR_QUEUED)) + if (!(vbuf->attr & attr)) continue; count++; } @@ -1565,7 +1606,6 @@ int msm_vidc_create_internal_buffer(struct msm_vidc_inst *inst, struct msm_vidc_alloc *alloc; struct msm_vidc_map *map; - d_vpr_h("%s()\n", __func__); if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; @@ -1650,7 +1690,6 @@ int msm_vidc_create_internal_buffers(struct msm_vidc_inst *inst, struct msm_vidc_buffers *buffers; int i; - d_vpr_h("%s()\n", __func__); if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; @@ -1679,7 +1718,6 @@ int msm_vidc_queue_internal_buffers(struct msm_vidc_inst *inst, struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buffer, *dummy; - d_vpr_h("%s()\n", __func__); if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; @@ -1727,7 +1765,6 @@ int msm_vidc_release_internal_buffers(struct msm_vidc_inst *inst, struct msm_vidc_buffers *buffers; struct msm_vidc_buffer *buffer, *dummy; - d_vpr_h("%s()\n", __func__); if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; @@ -1999,8 +2036,22 @@ int msm_vidc_session_open(struct msm_vidc_inst *inst) return -EINVAL; } - rc = venus_hfi_session_open(inst); + inst->packet_size = 4096; + inst->packet = kzalloc(inst->packet_size, GFP_KERNEL); + if (!inst->packet) { + s_vpr_e(inst->sid, "%s(): inst packet allocation failed\n", __func__); + return -ENOMEM; + } + rc = venus_hfi_session_open(inst); + if (rc) + goto error; + + return 0; +error: + s_vpr_e(inst->sid, "%s(): session open failed\n", __func__); + kfree(inst->packet); + inst->packet = NULL; return rc; } @@ -2043,8 +2094,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) { int rc = 0; + int count = 0; struct msm_vidc_core *core; enum signal_session_response signal_type; + enum msm_vidc_buffer_type buffer_type; if (!inst || !inst->core) { d_vpr_e("%s: invalid params\n", __func__); @@ -2053,8 +2106,10 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, if (port == INPUT_PORT) { signal_type = SIGNAL_CMD_STOP_INPUT; + buffer_type = MSM_VIDC_BUF_INPUT; } else if (port == OUTPUT_PORT) { signal_type = SIGNAL_CMD_STOP_OUTPUT; + buffer_type = MSM_VIDC_BUF_OUTPUT; } else { s_vpr_e(inst->sid, "%s: invalid port: %d\n", __func__, port); return -EINVAL; @@ -2072,19 +2127,31 @@ int msm_vidc_session_streamoff(struct msm_vidc_inst *inst, &inst->completions[signal_type], msecs_to_jiffies( core->capabilities[HW_RESPONSE_TIMEOUT].value)); - mutex_lock(&inst->lock); if (!rc) { s_vpr_e(inst->sid, "%s: session stop timed out for port: %d\n", __func__, port); - //msm_comm_kill_session(inst); - rc = -EIO; + rc = -ETIMEDOUT; + msm_vidc_core_timeout(inst->core); } else { rc = 0; - s_vpr_h(inst->sid, "%s: stop successful on port: %d\n", - __func__, port); } + mutex_lock(&inst->lock); - return rc; + /* no more queued buffers after streamoff */ + count = msm_vidc_num_buffers(inst, buffer_type, MSM_VIDC_ATTR_QUEUED); + if (count) { + s_vpr_e(inst->sid, "%s: %d buffers pending on port: %d\n", + __func__, count, port); + msm_vidc_kill_session(inst); + } + rc = msm_vidc_flush_buffers(inst, buffer_type); + if (rc) + return rc; + + s_vpr_h(inst->sid, "%s: stop successful on port: %d\n", + __func__, port); + + return 0; } int msm_vidc_session_close(struct msm_vidc_inst *inst) @@ -2109,19 +2176,43 @@ int msm_vidc_session_close(struct msm_vidc_inst *inst) &inst->completions[SIGNAL_CMD_CLOSE], msecs_to_jiffies( core->capabilities[HW_RESPONSE_TIMEOUT].value)); - mutex_lock(&inst->lock); if (!rc) { s_vpr_e(inst->sid, "%s: session close timed out\n", __func__); - //msm_comm_kill_session(inst); - rc = -EIO; + rc = -ETIMEDOUT; + msm_vidc_core_timeout(inst->core); } else { rc = 0; s_vpr_h(inst->sid, "%s: close successful\n", __func__); } + mutex_lock(&inst->lock); + + msm_vidc_remove_session(inst); + + s_vpr_h(inst->sid, "%s: free session packet data\n", __func__); + kfree(inst->packet); + inst->packet = NULL; return rc; } +int msm_vidc_kill_session(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + if (!inst->session_id) { + s_vpr_e(inst->sid, "%s: already killed\n", __func__); + return 0; + } + + s_vpr_e(inst->sid, "%s: killing session\n", __func__); + msm_vidc_session_close(inst); + msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + + return 0; +} + int msm_vidc_get_inst_capability(struct msm_vidc_inst *inst) { int rc = 0; @@ -2367,16 +2458,28 @@ error: int msm_vidc_core_deinit(struct msm_vidc_core *core) { int rc = 0; + struct msm_vidc_inst *inst, *dummy; - d_vpr_h("%s()\n", __func__); if (!core) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } mutex_lock(&core->lock); + d_vpr_h("%s()\n", __func__); + if (core->state == MSM_VIDC_CORE_DEINIT) + goto unlock; + venus_hfi_core_deinit(core); msm_vidc_deinit_instance_caps(core); msm_vidc_deinit_core_caps(core); + /* unlink all sessions from core, if any */ + list_for_each_entry_safe(inst, dummy, &core->instances, list) { + msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + list_del(&inst->list); + } + msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); + +unlock: mutex_unlock(&core->lock); return rc; } @@ -2385,18 +2488,12 @@ int msm_vidc_core_init(struct msm_vidc_core *core) { int rc = 0; - d_vpr_h("%s()\n", __func__); if (!core || !core->platform) { d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } mutex_lock(&core->lock); - if (core->state == MSM_VIDC_CORE_ERROR) { - d_vpr_e("%s: core invalid state\n", __func__); - rc = -EINVAL; - goto unlock; - } if (core->state == MSM_VIDC_CORE_INIT) { rc = 0; goto unlock; @@ -2409,7 +2506,7 @@ int msm_vidc_core_init(struct msm_vidc_core *core) if (rc) goto unlock; - core->state = MSM_VIDC_CORE_INIT; + msm_vidc_change_core_state(core, MSM_VIDC_CORE_INIT, __func__); init_completion(&core->init_done); core->smmu_fault_handled = false; core->ssr.trigger = false; @@ -2417,7 +2514,6 @@ int msm_vidc_core_init(struct msm_vidc_core *core) rc = venus_hfi_core_init(core); if (rc) { d_vpr_e("%s: core init failed\n", __func__); - core->state = MSM_VIDC_CORE_DEINIT; goto unlock; } @@ -2426,20 +2522,27 @@ int msm_vidc_core_init(struct msm_vidc_core *core) mutex_unlock(&core->lock); rc = wait_for_completion_timeout(&core->init_done, msecs_to_jiffies( core->capabilities[HW_RESPONSE_TIMEOUT].value)); + mutex_lock(&core->lock); if (!rc) { - d_vpr_e("%s: system init timed out\n", __func__); + d_vpr_e("%s: core init timed out\n", __func__); rc = -ETIMEDOUT; } else { d_vpr_h("%s: system init wait completed\n", __func__); rc = 0; } - mutex_lock(&core->lock); unlock: mutex_unlock(&core->lock); + if (rc) + msm_vidc_core_init(core); return rc; } +int msm_vidc_core_timeout(struct msm_vidc_core *core) +{ + return msm_vidc_core_deinit(core); +} + int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, struct device *dev, unsigned long iova, int flags, void *data) { @@ -2468,6 +2571,50 @@ void msm_vidc_batch_handler(struct work_struct *work) { } +int msm_vidc_flush_buffers(struct msm_vidc_inst* inst, + enum msm_vidc_buffer_type type) +{ + int rc = 0; + struct msm_vidc_buffers *buffers; + struct msm_vidc_buffer *buf, *dummy; + enum msm_vidc_buffer_type buffer_type[2]; + int i; + + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + if (type == MSM_VIDC_BUF_INPUT) { + buffer_type[0] = MSM_VIDC_BUF_INPUT_META; + buffer_type[1] = MSM_VIDC_BUF_INPUT; + } else if (type == MSM_VIDC_BUF_OUTPUT) { + buffer_type[0] = MSM_VIDC_BUF_OUTPUT_META; + buffer_type[1] = MSM_VIDC_BUF_OUTPUT; + } else { + s_vpr_h(inst->sid, "%s: invalid buffer type %d\n", + __func__, type); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(buffer_type); i++) { + buffers = msm_vidc_get_buffers(inst, buffer_type[i], __func__); + if (!buffers) + return -EINVAL; + + list_for_each_entry_safe(buf, dummy, &buffers->list, list) { + if (buf->attr & MSM_VIDC_ATTR_QUEUED || + buf->attr & MSM_VIDC_ATTR_DEFERRED) { + print_vidc_buffer(VIDC_ERR, "flushing buffer", inst, buf); + msm_vidc_vb2_buffer_done(inst, buf); + msm_vidc_put_driver_buf(inst, buf); + } + } + } + + return rc; +} + void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) { struct msm_vidc_buffers *buffers; @@ -2488,6 +2635,11 @@ void msm_vidc_destroy_buffers(struct msm_vidc_inst *inst) }; int i; + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + for (i = 0; i < ARRAY_SIZE(buf_types); i++) { buffers = msm_vidc_get_buffers(inst, buf_types[i], __func__); if (!buffers) @@ -2577,6 +2729,11 @@ void put_inst(struct msm_vidc_inst *inst) kref_put(&inst->kref, msm_vidc_close_helper); } +bool core_lock_check(struct msm_vidc_core *core, const char* func) +{ + return mutex_is_locked(&core->lock); +} + void core_lock(struct msm_vidc_core *core, const char *function) { mutex_lock(&core->lock); @@ -2587,6 +2744,11 @@ void core_unlock(struct msm_vidc_core *core, const char *function) mutex_unlock(&core->lock); } +bool inst_lock_check(struct msm_vidc_inst *inst, const char* func) +{ + return mutex_is_locked(&inst->lock); +} + void inst_lock(struct msm_vidc_inst *inst, const char *function) { mutex_lock(&inst->lock); diff --git a/driver/vidc/src/msm_vidc_power.c b/driver/vidc/src/msm_vidc_power.c index 458bafa9fd..e6cf258e25 100644 --- a/driver/vidc/src/msm_vidc_power.c +++ b/driver/vidc/src/msm_vidc_power.c @@ -425,9 +425,11 @@ static int msm_vidc_apply_dcvs(struct msm_vidc_inst *inst) power = &inst->power; if (is_decode_session(inst)) { - bufs_with_fw = msm_vidc_num_queued_bufs(inst, OUTPUT_MPLANE); + bufs_with_fw = msm_vidc_num_buffers(inst, + MSM_VIDC_BUF_OUTPUT, MSM_VIDC_ATTR_QUEUED); } else { - bufs_with_fw = msm_vidc_num_queued_bufs(inst, INPUT_MPLANE); + bufs_with_fw = msm_vidc_num_buffers(inst, + MSM_VIDC_BUF_INPUT, MSM_VIDC_ATTR_QUEUED); } /* +1 as one buffer is going to be queued after the function */ diff --git a/driver/vidc/src/msm_vidc_probe.c b/driver/vidc/src/msm_vidc_probe.c index a28d88594d..2bfaa2ad0f 100644 --- a/driver/vidc/src/msm_vidc_probe.c +++ b/driver/vidc/src/msm_vidc_probe.c @@ -178,7 +178,7 @@ static int msm_vidc_deinitialize_core(struct msm_vidc_core *core) d_vpr_h("%s()\n", __func__); mutex_destroy(&core->lock); - core->state = MSM_VIDC_CORE_DEINIT; + msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); if (core->pm_workq) destroy_workqueue(core->pm_workq); @@ -199,7 +199,7 @@ static int msm_vidc_initialize_core(struct msm_vidc_core *core) } d_vpr_h("%s()\n", __func__); - core->state = MSM_VIDC_CORE_DEINIT; + msm_vidc_change_core_state(core, MSM_VIDC_CORE_DEINIT, __func__); core->device_workq = create_singlethread_workqueue("device_workq"); if (!core->device_workq) { diff --git a/driver/vidc/src/msm_vidc_v4l2.c b/driver/vidc/src/msm_vidc_v4l2.c index 74fba3ef65..c2191c7dbf 100644 --- a/driver/vidc/src/msm_vidc_v4l2.c +++ b/driver/vidc/src/msm_vidc_v4l2.c @@ -12,7 +12,7 @@ static struct msm_vidc_inst *get_vidc_inst(struct file *filp, void *fh) { - if (!filp->private_data) + if (!filp || !filp->private_data) return NULL; return container_of(filp->private_data, struct msm_vidc_inst, event_handler); diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index f3542d544f..ca1112adc3 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -33,6 +33,8 @@ #define MAX_FIRMWARE_NAME_SIZE 128 +extern struct msm_vidc_core *g_core; + static int __resume(struct msm_vidc_core *core); static int __suspend(struct msm_vidc_core *core); @@ -161,7 +163,7 @@ static void __strict_check(struct msm_vidc_core *core) bool __core_in_valid_state(struct msm_vidc_core *core) { - return core->state != MSM_VIDC_CORE_ERROR; + return core->state == MSM_VIDC_CORE_INIT; } static bool is_sys_cache_present(struct msm_vidc_core *core) @@ -169,6 +171,30 @@ static bool is_sys_cache_present(struct msm_vidc_core *core) return core->dt->sys_cache_present; } +static bool valdiate_session(struct msm_vidc_inst* inst, const char *func) +{ + bool valid = false; + struct msm_vidc_inst *temp; + struct msm_vidc_core *core = g_core; + + if (!core) + return false; + + mutex_lock(&core->lock); + list_for_each_entry(temp, &core->instances, list) { + if (temp == inst) { + valid = true; + break; + } + } + mutex_unlock(&core->lock); + + if (!valid) + s_vpr_e(inst->sid, "%s: invalid session\n", func); + + return valid; +} + void __write_register(struct msm_vidc_core *core, u32 reg, u32 value) { @@ -879,8 +905,12 @@ int __iface_msgq_read(struct msm_vidc_core *core, void *pkt) } if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { - if (tx_req_is_set) - call_venus_op(core, raise_interrupt, core); + if (tx_req_is_set) { + //call_venus_op(core, raise_interrupt, core); + d_vpr_e("%s: queue is full\n", __func__); + rc = -EINVAL; + goto read_error_null; + } rc = 0; } else { rc = -ENODATA; @@ -911,11 +941,16 @@ int __iface_dbgq_read(struct msm_vidc_core *core, void *pkt) } if (!__read_queue(q_info, (u8 *)pkt, &tx_req_is_set)) { - if (tx_req_is_set) - call_venus_op(core, raise_interrupt, core); + if (tx_req_is_set) { + d_vpr_e("%s: queue is full\n", __func__); + //call_venus_op(core, raise_interrupt, core); + rc = -EINVAL; + goto dbg_error_null; + } rc = 0; - } else + } else { rc = -ENODATA; + } dbg_error_null: return rc; @@ -1909,6 +1944,24 @@ static int __set_ubwc_config(struct msm_vidc_core *core) return rc; } */ + +static int __venus_power_off(struct msm_vidc_core* core) +{ + int rc = 0; + + if (!core->power_enabled) + return 0; + + rc = call_venus_op(core, power_off, core); + if (rc) { + d_vpr_e("Failed to power off, err: %d\n", rc); + return rc; + } + core->power_enabled = false; + + return rc; +} + static int __venus_power_on(struct msm_vidc_core *core) { int rc = 0; @@ -2009,7 +2062,7 @@ static int __resume(struct msm_vidc_core *core) } else if (core->power_enabled) { goto exit; } else if (!__core_in_valid_state(core)) { - d_vpr_e("%s: core in deinit state\n", __func__); + d_vpr_e("%s: core not in valid state\n", __func__); return -EINVAL; } @@ -2394,9 +2447,7 @@ static void __unload_fw(struct msm_vidc_core *core) qcom_scm_pas_shutdown(core->dt->fw_cookie); core->dt->fw_cookie = 0; - __interface_queues_deinit(core); - call_venus_op(core, power_off, core); - + __venus_power_off(core); __deinit_resources(core); d_vpr_h("Firmware unloaded successfully\n"); @@ -2447,16 +2498,15 @@ void venus_hfi_work_handler(struct work_struct *work) mutex_lock(&core->lock); if (__resume(core)) { d_vpr_e("%s: Power on failed\n", __func__); + mutex_unlock(&core->lock); goto err_no_work; } - call_venus_op(core, clear_interrupt, core); mutex_unlock(&core->lock); num_responses = __response_handler(core); err_no_work: - mutex_unlock(&core->lock); if (!call_venus_op(core, watchdog, core, core->intr_status)) enable_irq(core->dt->irq); } @@ -2614,6 +2664,7 @@ int venus_hfi_core_deinit(struct msm_vidc_core *core) return -EINVAL; } d_vpr_h("%s(): core %pK\n", __func__, core); + __flush_debug_queue(core, core->packet, core->packet_size); __disable_subcaches(core); __interface_queues_deinit(core); __unload_fw(core); @@ -2655,13 +2706,6 @@ int venus_hfi_session_open(struct msm_vidc_inst *inst) return -EINVAL; } - inst->packet_size = 4096; - inst->packet = kzalloc(inst->packet_size, GFP_KERNEL); - if (!inst->packet) { - d_vpr_e("%s(): inst packet allocation failed\n", __func__); - return -ENOMEM; - } - rc = hfi_packet_session_command(inst, HFI_CMD_OPEN, (HFI_HOST_FLAGS_RESPONSE_REQUIRED | @@ -2672,13 +2716,13 @@ int venus_hfi_session_open(struct msm_vidc_inst *inst) &inst->session_id, /* payload */ sizeof(u32)); if (rc) - goto error; + return rc; rc = __iface_cmdq_write(inst->core, inst->packet); if (rc) - goto error; -error: - return rc; + return rc; + + return 0; } int venus_hfi_session_set_codec(struct msm_vidc_inst *inst) @@ -2690,6 +2734,8 @@ int venus_hfi_session_set_codec(struct msm_vidc_inst *inst) d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + if (!valdiate_session(inst, __func__)) + return -EINVAL; codec = get_hfi_codec(inst); rc = venus_hfi_session_property(inst, @@ -2719,6 +2765,9 @@ int venus_hfi_session_property(struct msm_vidc_inst *inst, } core = inst->core; + if (!valdiate_session(inst, __func__)) + return -EINVAL; + rc = hfi_create_header(inst->packet, inst->packet_size, inst->session_id, core->header_id++); if (rc) @@ -2753,6 +2802,8 @@ int venus_hfi_session_close(struct msm_vidc_inst *inst) d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + if (!valdiate_session(inst, __func__)) + return -EINVAL; rc = hfi_packet_session_command(inst, HFI_CMD_CLOSE, @@ -2767,8 +2818,6 @@ int venus_hfi_session_close(struct msm_vidc_inst *inst) if (!rc) __iface_cmdq_write(inst->core, inst->packet); - kfree(inst->packet); - return rc; } @@ -2780,6 +2829,9 @@ int venus_hfi_start(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + if (!valdiate_session(inst, __func__)) + return -EINVAL; + if (port != INPUT_PORT && port != OUTPUT_PORT) { s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port); return -EINVAL; @@ -2812,6 +2864,9 @@ int venus_hfi_stop(struct msm_vidc_inst *inst, enum msm_vidc_port_type port) d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + if (!valdiate_session(inst, __func__)) + return -EINVAL; + if (port != INPUT_PORT && port != OUTPUT_PORT) { s_vpr_e(inst->sid, "%s: invalid port %d\n", __func__, port); return -EINVAL; @@ -2850,6 +2905,9 @@ int venus_hfi_session_command(struct msm_vidc_inst *inst, } core = inst->core; + if (!valdiate_session(inst, __func__)) + return -EINVAL; + rc = hfi_create_header(inst->packet, inst->packet_size, inst->session_id, core->header_id++); @@ -2892,6 +2950,9 @@ int venus_hfi_queue_buffer(struct msm_vidc_inst *inst, } core = inst->core; + if (!valdiate_session(inst, __func__)) + return -EINVAL; + rc = get_hfi_buffer(inst, buffer, &hfi_buffer); if (rc) return rc; @@ -2948,6 +3009,9 @@ int venus_hfi_release_buffer(struct msm_vidc_inst *inst, d_vpr_e("%s: invalid params\n", __func__); return -EINVAL; } + if (!valdiate_session(inst, __func__)) + return -EINVAL; + if (!is_internal_buffer(buffer->type)) { s_vpr_e(inst->sid, "release not allowed for buffer type %d\n", buffer->type); diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index bf1408755a..92095e64c9 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -229,16 +229,8 @@ static int handle_session_error(struct msm_vidc_inst *inst, static int handle_system_error(struct msm_vidc_core *core, struct hfi_packet *pkt) { - mutex_lock(&core->lock); - if (core->state == MSM_VIDC_CORE_DEINIT) { - d_vpr_e("%s: core already deinitialized\n", __func__); - mutex_unlock(&core->lock); - return 0; - } - d_vpr_e("%s: system error received\n", __func__); - core->state = MSM_VIDC_CORE_DEINIT; - mutex_unlock(&core->lock); + msm_vidc_core_deinit(core); return 0; } @@ -264,6 +256,7 @@ static int handle_session_open(struct msm_vidc_inst *inst, if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) { s_vpr_e(inst->sid, "%s: received session error\n", __func__); msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + return 0; } if (pkt->flags & HFI_FW_FLAGS_SUCCESS) @@ -293,6 +286,7 @@ static int handle_session_start(struct msm_vidc_inst *inst, if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) { s_vpr_e(inst->sid, "%s: received session error\n", __func__); msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + return 0; } if (pkt->flags & HFI_FW_FLAGS_SUCCESS) @@ -351,6 +345,7 @@ static int handle_session_drain(struct msm_vidc_inst *inst, if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) { s_vpr_e(inst->sid, "%s: received session error\n", __func__); msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR, __func__); + return 0; } if (pkt->flags & HFI_FW_FLAGS_SUCCESS)