diff --git a/driver/vidc/inc/msm_vidc_driver.h b/driver/vidc/inc/msm_vidc_driver.h index 9050a561e9..db2322d171 100644 --- a/driver/vidc/inc/msm_vidc_driver.h +++ b/driver/vidc/inc/msm_vidc_driver.h @@ -319,6 +319,10 @@ int msm_vidc_smmu_fault_handler(struct iommu_domain *domain, int msm_vidc_trigger_ssr(struct msm_vidc_core *core, u64 trigger_ssr_val); void msm_vidc_ssr_handler(struct work_struct *work); +int msm_vidc_trigger_stability(struct msm_vidc_core *core, + u64 trigger_stability_val); +void msm_vidc_stability_handler(struct work_struct *work); +int cancel_stability_work_sync(struct msm_vidc_inst *inst); void msm_vidc_fw_unload_handler(struct work_struct *work); int msm_vidc_suspend(struct msm_vidc_core *core); void msm_vidc_batch_handler(struct work_struct *work); diff --git a/driver/vidc/inc/msm_vidc_inst.h b/driver/vidc/inc/msm_vidc_inst.h index 0a9ed474c6..b18727c21f 100644 --- a/driver/vidc/inc/msm_vidc_inst.h +++ b/driver/vidc/inc/msm_vidc_inst.h @@ -129,6 +129,8 @@ struct msm_vidc_inst { struct msm_vidc_session_idle session_idle; struct delayed_work response_work; struct delayed_work stats_work; + struct work_struct stability_work; + struct msm_vidc_stability stability; struct workqueue_struct *response_workq; struct list_head response_works; /* list of struct response_work */ struct list_head enc_input_crs; diff --git a/driver/vidc/inc/msm_vidc_internal.h b/driver/vidc/inc/msm_vidc_internal.h index 275d060e3e..ef93c33351 100644 --- a/driver/vidc/inc/msm_vidc_internal.h +++ b/driver/vidc/inc/msm_vidc_internal.h @@ -555,6 +555,11 @@ enum msm_vidc_ssr_trigger_type { SSR_HW_WDOG_IRQ, }; +enum msm_vidc_stability_trigger_type { + STABILITY_VCODEC_HUNG = 1, + STABILITY_ENC_BUFFER_FULL, +}; + enum msm_vidc_cache_op { MSM_VIDC_CACHE_CLEAN, MSM_VIDC_CACHE_INVALIDATE, @@ -873,6 +878,12 @@ struct msm_vidc_ssr { u32 test_addr; }; +struct msm_vidc_stability { + enum msm_vidc_stability_trigger_type stability_type; + u32 sub_client_id; + u32 value; +}; + struct msm_vidc_sfr { u32 bufSize; u8 rg_data[1]; diff --git a/driver/vidc/inc/venus_hfi.h b/driver/vidc/inc/venus_hfi.h index 4a7c3ae963..48c9a85235 100644 --- a/driver/vidc/inc/venus_hfi.h +++ b/driver/vidc/inc/venus_hfi.h @@ -52,6 +52,8 @@ int venus_hfi_noc_error_info(struct msm_vidc_core *core); int venus_hfi_suspend(struct msm_vidc_core *core); int venus_hfi_trigger_ssr(struct msm_vidc_core *core, u32 type, u32 client_id, u32 addr); +int venus_hfi_trigger_stability(struct msm_vidc_inst *inst, u32 type, + u32 client_id, u32 val); int venus_hfi_scale_clocks(struct msm_vidc_inst* inst, u64 freq); int venus_hfi_scale_buses(struct msm_vidc_inst* inst, u64 bw_ddr, u64 bw_llcc); diff --git a/driver/vidc/src/msm_vidc.c b/driver/vidc/src/msm_vidc.c index 10fd4b7ce5..d25e812415 100644 --- a/driver/vidc/src/msm_vidc.c +++ b/driver/vidc/src/msm_vidc.c @@ -889,6 +889,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type) INIT_DELAYED_WORK(&inst->response_work, handle_session_response_work_handler); INIT_DELAYED_WORK(&inst->stats_work, msm_vidc_stats_handler); + INIT_WORK(&inst->stability_work, msm_vidc_stability_handler); inst->capabilities = kzalloc(sizeof(struct msm_vidc_inst_capability), GFP_KERNEL); if (!inst->capabilities) { @@ -960,6 +961,7 @@ int msm_vidc_close(void *instance) msm_vidc_destroy_buffers(inst); inst_unlock(inst, __func__); cancel_response_work_sync(inst); + cancel_stability_work_sync(inst); cancel_stats_work_sync(inst); msm_vidc_show_stats(inst); put_inst(inst); diff --git a/driver/vidc/src/msm_vidc_debug.c b/driver/vidc/src/msm_vidc_debug.c index b1c8b1fc9f..3f476ab1ad 100644 --- a/driver/vidc/src/msm_vidc_debug.c +++ b/driver/vidc/src/msm_vidc_debug.c @@ -15,6 +15,7 @@ extern struct msm_vidc_core *g_core; #define MAX_SSR_STRING_LEN 64 +#define MAX_STABILITY_STRING_LEN 64 #define MAX_DEBUG_LEVEL_STRING_LEN 15 #define MSM_VIDC_MIN_STATS_DELAY_MS 200 #define MSM_VIDC_MAX_STATS_DELAY_MS 10000 @@ -296,6 +297,47 @@ static const struct file_operations ssr_fops = { .write = trigger_ssr_write, }; +static ssize_t trigger_stability_write(struct file *filp, const char __user *buf, + size_t count, loff_t *ppos) +{ + unsigned long stability_trigger_val = 0; + int rc = 0; + struct msm_vidc_core *core = filp->private_data; + size_t size = MAX_STABILITY_STRING_LEN; + char kbuf[MAX_STABILITY_STRING_LEN + 1] = { 0 }; + + if (!buf) + return -EINVAL; + + if (!count) + goto exit; + + if (count < size) + size = count; + + if (copy_from_user(kbuf, buf, size)) { + d_vpr_e("%s: User memory fault\n", __func__); + rc = -EFAULT; + goto exit; + } + + rc = kstrtoul(kbuf, 0, &stability_trigger_val); + if (rc) { + d_vpr_e("%s: returning error err %d\n", __func__, rc); + rc = -EINVAL; + } else { + msm_vidc_trigger_stability(core, stability_trigger_val); + rc = count; + } +exit: + return rc; +} + +static const struct file_operations stability_fops = { + .open = simple_open, + .write = trigger_stability_write, +}; + struct dentry* msm_vidc_debugfs_init_drv() { struct dentry *dir = NULL; @@ -359,6 +401,10 @@ struct dentry *msm_vidc_debugfs_init_core(void *core_in) d_vpr_e("debugfs_create_file: fail\n"); goto failed_create_dir; } + if (!debugfs_create_file("trigger_stability", 0200, dir, core, &stability_fops)) { + d_vpr_e("trigger_stability debugfs_create_file: fail\n"); + goto failed_create_dir; + } if (!debugfs_create_file("stats_delay_ms", 0644, dir, core, &stats_delay_fops)) { d_vpr_e("debugfs_create_file: fail\n"); goto failed_create_dir; diff --git a/driver/vidc/src/msm_vidc_driver.c b/driver/vidc/src/msm_vidc_driver.c index 6e879767d2..c0a6c68f23 100644 --- a/driver/vidc/src/msm_vidc_driver.c +++ b/driver/vidc/src/msm_vidc_driver.c @@ -42,6 +42,13 @@ extern struct msm_vidc_core *g_core; #define SSR_ADDR_ID 0xFFFFFFFF00000000 #define SSR_ADDR_SHIFT 32 +#define STABILITY_TYPE 0x0000000F +#define STABILITY_TYPE_SHIFT 0 +#define STABILITY_SUB_CLIENT_ID 0x000000F0 +#define STABILITY_SUB_CLIENT_ID_SHIFT 4 +#define STABILITY_PAYLOAD_ID 0xFFFFFFFF00000000 +#define STABILITY_PAYLOAD_SHIFT 32 + struct msm_vidc_cap_name { enum msm_vidc_inst_capability_type cap; char *name; @@ -4677,6 +4684,77 @@ void msm_vidc_ssr_handler(struct work_struct *work) core_unlock(core, __func__); } +int msm_vidc_trigger_stability(struct msm_vidc_core *core, + u64 trigger_stability_val) +{ + struct msm_vidc_inst *inst = NULL; + struct msm_vidc_stability stability; + + if (!core) { + d_vpr_e("%s: invalid params\n", __func__); + return -EINVAL; + } + + /* + * + * stability_type: 0-3 bits + * sub_client_id: 4-7 bits + * reserved: 8-31 bits + * payload: 32-63 bits + */ + memset(&stability, 0, sizeof(struct msm_vidc_stability)); + stability.stability_type = (trigger_stability_val & + (unsigned long)STABILITY_TYPE) >> STABILITY_TYPE_SHIFT; + stability.sub_client_id = (trigger_stability_val & + (unsigned long)STABILITY_SUB_CLIENT_ID) >> STABILITY_SUB_CLIENT_ID_SHIFT; + stability.value = (trigger_stability_val & + (unsigned long)STABILITY_PAYLOAD_ID) >> STABILITY_PAYLOAD_SHIFT; + + core_lock(core, __func__); + list_for_each_entry(inst, &core->instances, list) { + memcpy(&inst->stability, &stability, sizeof(struct msm_vidc_stability)); + schedule_work(&inst->stability_work); + } + core_unlock(core, __func__); + + return 0; +} + +void msm_vidc_stability_handler(struct work_struct *work) +{ + int rc; + struct msm_vidc_inst *inst; + struct msm_vidc_stability *stability; + + inst = container_of(work, struct msm_vidc_inst, stability_work); + inst = get_inst_ref(g_core, inst); + if (!inst) { + d_vpr_e("%s: invalid params\n", __func__); + return; + } + + inst_lock(inst, __func__); + stability = &inst->stability; + rc = venus_hfi_trigger_stability(inst, stability->stability_type, + stability->sub_client_id, stability->value); + if (rc) + i_vpr_e(inst, "%s: trigger_stability failed\n", __func__); + inst_unlock(inst, __func__); + + put_inst(inst); +} + +int cancel_stability_work_sync(struct msm_vidc_inst *inst) +{ + if (!inst) { + d_vpr_e("%s: Invalid arguments\n", __func__); + return -EINVAL; + } + cancel_work_sync(&inst->stability_work); + + return 0; +} + void msm_vidc_fw_unload_handler(struct work_struct *work) { struct msm_vidc_core *core = NULL; diff --git a/driver/vidc/src/venus_hfi.c b/driver/vidc/src/venus_hfi.c index 20a480dae0..2b1d9fc59d 100644 --- a/driver/vidc/src/venus_hfi.c +++ b/driver/vidc/src/venus_hfi.c @@ -2871,6 +2871,53 @@ exit: return rc; } +int venus_hfi_trigger_stability(struct msm_vidc_inst *inst, u32 type, + u32 client_id, u32 val) +{ + struct msm_vidc_core *core; + u32 payload[2]; + int rc = 0; + + if (!inst || !inst->core || !inst->packet) { + d_vpr_e("%s: Invalid params\n", __func__); + return -EINVAL; + } + core = inst->core; + core_lock(core, __func__); + + if (!__valdiate_session(core, inst, __func__)) { + rc = -EINVAL; + goto unlock; + } + + payload[0] = client_id << 4 | type; + payload[1] = val; + rc = hfi_create_header(inst->packet, inst->packet_size, + inst->session_id, core->header_id++); + if (rc) + goto unlock; + + /* HFI_CMD_STABILITY */ + rc = hfi_create_packet(inst->packet, inst->packet_size, + HFI_CMD_STABILITY, + HFI_HOST_FLAGS_RESPONSE_REQUIRED | + HFI_HOST_FLAGS_INTR_REQUIRED, + HFI_PAYLOAD_U64, + HFI_PORT_NONE, + core->packet_id++, + &payload, sizeof(u64)); + if (rc) + goto unlock; + + rc = __iface_cmdq_write(core, inst->packet); + if (rc) + goto unlock; + +unlock: + core_unlock(core, __func__); + return rc; +} + int venus_hfi_session_open(struct msm_vidc_inst *inst) { int rc = 0; diff --git a/driver/vidc/src/venus_hfi_response.c b/driver/vidc/src/venus_hfi_response.c index 8dabb9f5bc..6dbadc76d3 100644 --- a/driver/vidc/src/venus_hfi_response.c +++ b/driver/vidc/src/venus_hfi_response.c @@ -1254,6 +1254,14 @@ static int handle_session_resume(struct msm_vidc_inst *inst, return 0; } +static int handle_session_stability(struct msm_vidc_inst *inst, + struct hfi_packet *pkt) +{ + if (pkt->flags & HFI_FW_FLAGS_SUCCESS) + i_vpr_h(inst, "%s: successful\n", __func__); + return 0; +} + static int handle_session_command(struct msm_vidc_inst *inst, struct hfi_packet *pkt) { @@ -1269,6 +1277,7 @@ static int handle_session_command(struct msm_vidc_inst *inst, {HFI_CMD_SUBSCRIBE_MODE, handle_session_subscribe_mode }, {HFI_CMD_DELIVERY_MODE, handle_session_delivery_mode }, {HFI_CMD_RESUME, handle_session_resume }, + {HFI_CMD_STABILITY, handle_session_stability }, }; /* handle session pkt */