Loading drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +47 −3 Original line number Diff line number Diff line Loading @@ -388,6 +388,49 @@ static ssize_t show_pwr_collapse_delay(struct device *dev, static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay, store_pwr_collapse_delay); static ssize_t show_thermal_level(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level); } static ssize_t store_thermal_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc = 0, val = 0; rc = kstrtoint(buf, 0, &val); if (rc || val < 0) { dprintk(VIDC_WARN, "Invalid thermal level value: %s\n", buf); return -EINVAL; } dprintk(VIDC_DBG, "Thermal level old %d new %d\n", vidc_driver->thermal_level, val); if (val == vidc_driver->thermal_level) return count; vidc_driver->thermal_level = val; msm_comm_handle_thermal_event(); return count; } static DEVICE_ATTR(thermal_level, S_IRUGO | S_IWUSR, show_thermal_level, store_thermal_level); static struct attribute *msm_vidc_core_attrs[] = { &dev_attr_pwr_collapse_delay.attr, &dev_attr_thermal_level.attr, NULL }; static struct attribute_group msm_vidc_core_attr_group = { .attrs = msm_vidc_core_attrs, }; static int msm_vidc_probe(struct platform_device *pdev) { int rc = 0; Loading @@ -407,10 +450,10 @@ static int msm_vidc_probe(struct platform_device *pdev) dprintk(VIDC_ERR, "Failed to init core\n"); goto err_core_init; } rc = device_create_file(&pdev->dev, &dev_attr_pwr_collapse_delay); rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); if (rc) { dprintk(VIDC_ERR, "Failed to create pwr_collapse_delay sysfs node"); "Failed to create attributes\n"); goto err_core_init; } if (core->hfi_type == VIDC_HFI_Q6) { Loading Loading @@ -513,7 +556,7 @@ err_dec_attr_link_name: err_dec_register: v4l2_device_unregister(&core->v4l2_dev); err_v4l2_register: device_remove_file(&pdev->dev, &dev_attr_pwr_collapse_delay); sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); err_core_init: kfree(core); err_no_mem: Loading Loading @@ -546,6 +589,7 @@ static int msm_vidc_remove(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); msm_vidc_free_platform_resources(&core->resources); sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); kfree(core); return rc; } Loading drivers/media/platform/msm/vidc/msm_vidc_common.c +215 −51 Original line number Diff line number Diff line Loading @@ -1080,6 +1080,43 @@ static void handle_session_error(enum command_response cmd, void *data) } } static void msm_comm_clean_notify_client(struct msm_vidc_core *core) { int rc = 0; struct msm_vidc_inst *inst = NULL; struct hfi_device *hdev = NULL; if (!core || !core->device) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); return; } dprintk(VIDC_WARN, "%s: Core %p\n", __func__, core); mutex_lock(&core->lock); core->state = VIDC_CORE_INVALID; list_for_each_entry(inst, &core->instances, list) { mutex_lock(&inst->lock); inst->state = MSM_VIDC_CORE_INVALID; hdev = inst->core->device; if (hdev && inst->session) { dprintk(VIDC_DBG, "cleaning up inst: 0x%p\n", inst); rc = call_hfi_op(hdev, session_clean, (void *) inst->session); if (rc) dprintk(VIDC_ERR, "Sess clean failed :%p\n", inst); } inst->session = NULL; mutex_unlock(&inst->lock); dprintk(VIDC_WARN, "%s Send sys error for inst %p\n", __func__, inst); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } mutex_unlock(&core->lock); } struct sys_err_handler_data { struct msm_vidc_core *core; struct delayed_work work; Loading Loading @@ -1133,9 +1170,6 @@ static void handle_sys_error(enum command_response cmd, void *data) struct msm_vidc_cb_cmd_done *response = data; struct msm_vidc_core *core = NULL; struct sys_err_handler_data *handler = NULL; struct hfi_device *hdev = NULL; struct msm_vidc_inst *inst = NULL; int rc = 0; subsystem_crashed("venus"); if (!response) { Loading @@ -1152,35 +1186,7 @@ static void handle_sys_error(enum command_response cmd, void *data) } dprintk(VIDC_WARN, "SYS_ERROR %d received for core %p\n", cmd, core); mutex_lock(&core->lock); core->state = VIDC_CORE_INVALID; /* * 1. Delete each instance session from hfi list * 2. Notify all clients about hardware error. */ list_for_each_entry(inst, &core->instances, list) { mutex_lock(&inst->lock); inst->state = MSM_VIDC_CORE_INVALID; if (inst->core) hdev = inst->core->device; if (hdev && inst->session) { dprintk(VIDC_DBG, "cleaning up inst: 0x%p\n", inst); rc = call_hfi_op(hdev, session_clean, (void *) inst->session); if (rc) dprintk(VIDC_ERR, "Sess clean failed :%p\n", inst); } inst->session = NULL; mutex_unlock(&inst->lock); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } mutex_unlock(&core->lock); msm_comm_clean_notify_client(core); handler = kzalloc(sizeof(*handler), GFP_KERNEL); if (!handler) { Loading Loading @@ -2143,6 +2149,167 @@ void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst) } } static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level) { switch (level) { case 0: return VIDC_THERMAL_NORMAL; case 1: return VIDC_THERMAL_LOW; case 2: return VIDC_THERMAL_HIGH; default: return VIDC_THERMAL_CRITICAL; } } static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core) { struct hfi_device *hdev; unsigned long freq = 0; if (!core || !core->device) { dprintk(VIDC_ERR, "%s Invalid params\n", __func__); return -EINVAL; } hdev = core->device; freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data); dprintk(VIDC_DBG, "clock freq %ld\n", freq); return freq; } static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq) { int i = 0; struct msm_vidc_platform_resources *res = &core->resources; struct load_freq_table *table = res->load_freq_tbl; u32 max_freq = 0; for (i = 0; i < res->load_freq_tbl_size; i++) { if (max_freq < table[i].freq) max_freq = table[i].freq; } return freq >= max_freq; } static bool is_thermal_permissible(struct msm_vidc_core *core) { enum msm_vidc_thermal_level tl; unsigned long freq = 0; bool is_turbo = false; tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level); freq = msm_comm_get_clock_rate(core); is_turbo = is_core_turbo(core, freq); dprintk(VIDC_DBG, "Core freq %ld Thermal level %d Turbo mode %d\n", freq, tl, is_turbo); if ((!is_turbo && tl >= VIDC_THERMAL_CRITICAL) || (is_turbo && tl >= VIDC_THERMAL_LOW)) { dprintk(VIDC_ERR, "Video session not allowed. Turbo mode %d Thermal level %d\n", is_turbo, tl); return false; } return true; } static int msm_comm_session_abort(struct msm_vidc_inst *inst) { int rc = 0, abort_completion = 0; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { dprintk(VIDC_ERR, "%s session_abort failed rc: %d\n", __func__, rc); return rc; } abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE); init_completion(&inst->completions[abort_completion]); rc = wait_for_completion_timeout( &inst->completions[abort_completion], msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timed out [%p]: %d\n", __func__, inst, abort_completion); rc = -EBUSY; } else { rc = 0; } return rc; } static void handle_thermal_event(struct msm_vidc_core *core) { int rc = 0; struct msm_vidc_inst *inst; if (!core || !core->device) { dprintk(VIDC_ERR, "%s Invalid params\n", __func__); return; } mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { if (!inst->session) continue; mutex_unlock(&core->lock); if (inst->state >= MSM_VIDC_OPEN_DONE && inst->state < MSM_VIDC_CLOSE_DONE) { dprintk(VIDC_WARN, "%s: abort inst %p\n", __func__, inst); rc = msm_comm_session_abort(inst); if (rc) { dprintk(VIDC_ERR, "%s session_abort failed rc: %d\n", __func__, rc); goto err_sess_abort; } change_inst_state(inst, MSM_VIDC_CORE_INVALID); dprintk(VIDC_WARN, "%s Send sys error for inst %p\n", __func__, inst); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } else { msm_comm_generate_session_error(inst); } mutex_lock(&core->lock); } mutex_unlock(&core->lock); return; err_sess_abort: msm_comm_clean_notify_client(core); return; } void msm_comm_handle_thermal_event() { struct msm_vidc_core *core; list_for_each_entry(core, &vidc_driver->cores, list) { if (!is_thermal_permissible(core)) { dprintk(VIDC_WARN, "Thermal level critical, stop all active sessions!\n"); handle_thermal_event(core); } } } static int msm_comm_init_core_done(struct msm_vidc_inst *inst) { struct msm_vidc_core *core = inst->core; Loading Loading @@ -3031,6 +3198,7 @@ int msm_comm_try_state(struct msm_vidc_inst *inst, int state) if (rc || state <= get_flipped_state(inst->state, state)) break; case MSM_VIDC_CORE_UNINIT: case MSM_VIDC_CORE_INVALID: dprintk(VIDC_DBG, "Sending core uninit\n"); rc = msm_vidc_deinit_core(inst); if (rc || state == get_flipped_state(inst->state, state)) Loading Loading @@ -4377,6 +4545,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) struct msm_vidc_core_capability *capability; int rc = 0; struct hfi_device *hdev; struct msm_vidc_core *core; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); Loading @@ -4384,6 +4553,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) } capability = &inst->capability; hdev = inst->core->device; core = inst->core; rc = msm_vidc_load_supported(inst); if (rc) { change_inst_state(inst, MSM_VIDC_CORE_INVALID); Loading @@ -4391,6 +4561,13 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) "%s: Hardware is overloaded\n", __func__); return rc; } if (!is_thermal_permissible(core)) { dprintk(VIDC_WARN, "Thermal level critical, stop all active sessions!\n"); return -ENOTSUPP; } if (!rc && inst->capability.capability_set) { if (inst->prop.width[CAPTURE_PORT] < capability->width.min || inst->prop.height[CAPTURE_PORT] < Loading Loading @@ -4481,27 +4658,14 @@ int msm_comm_kill_session(struct msm_vidc_inst *inst) */ if (inst->state >= MSM_VIDC_OPEN_DONE && inst->state < MSM_VIDC_CLOSE_DONE) { struct hfi_device *hdev = inst->core->device; int abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE); rc = call_hfi_op(hdev, session_abort, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc); rc = msm_comm_session_abort(inst); if (rc == -EBUSY) { msm_comm_generate_sys_error(inst); return 0; } else if (rc) return rc; } init_completion(&inst->completions[abort_completion]); rc = wait_for_completion_timeout( &inst->completions[abort_completion], msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timed out [%p]: %d\n", __func__, inst, abort_completion); msm_comm_generate_sys_error(inst); } else { change_inst_state(inst, MSM_VIDC_CLOSE_DONE); } } else { dprintk(VIDC_WARN, "Inactive session %p, triggering an internal session error\n", Loading drivers/media/platform/msm/vidc/msm_vidc_internal.h +2 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ struct msm_vidc_drv { struct list_head cores; int num_cores; struct dentry *debugfs_root; int thermal_level; }; struct msm_video_device { Loading Loading @@ -389,6 +390,7 @@ int qbuf_dynamic_buf(struct msm_vidc_inst *inst, int unmap_and_deregister_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo); void msm_comm_handle_thermal_event(void); void *msm_smem_new_client(enum smem_type mtype, void *platform_resources); struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags, Loading drivers/media/platform/msm/vidc/venus_hfi.c +32 −0 Original line number Diff line number Diff line Loading @@ -1352,6 +1352,20 @@ static inline int venus_hfi_reset_core(struct venus_hfi_device *device) return rc; } static struct clock_info *venus_hfi_get_clock(struct venus_hfi_device *device, char *name) { struct clock_info *vc; venus_hfi_for_each_clock(device, vc) { if (!strcmp(vc->name, name)) return vc; } dprintk(VIDC_WARN, "%s Clock %s not found\n", __func__, name); return NULL; } static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, int num_mbs_per_sec, int codecs_enabled) { Loading @@ -1376,6 +1390,23 @@ static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, return freq; } static unsigned long venus_hfi_get_core_clock_rate(void *dev) { struct venus_hfi_device *device = (struct venus_hfi_device *) dev; struct clock_info *vc; if (!device) { dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, device); return -EINVAL; } vc = venus_hfi_get_clock(device, "core_clk"); if (vc) return clk_get_rate(vc->clk); else return 0; } static int venus_hfi_suspend(void *dev) { int rc = 0; Loading Loading @@ -4193,6 +4224,7 @@ static void venus_init_hfi_callbacks(struct hfi_device *hdev) hdev->get_core_capabilities = venus_hfi_get_core_capabilities; hdev->power_enable = venus_hfi_power_enable; hdev->suspend = venus_hfi_suspend; hdev->get_core_clock_rate = venus_hfi_get_core_clock_rate; } int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id, Loading drivers/media/platform/msm/vidc/vidc_hfi_api.h +8 −0 Original line number Diff line number Diff line Loading @@ -1259,6 +1259,13 @@ enum fw_info { FW_INFO_MAX, }; enum msm_vidc_thermal_level { VIDC_THERMAL_NORMAL = 0, VIDC_THERMAL_LOW, VIDC_THERMAL_HIGH, VIDC_THERMAL_CRITICAL }; enum vidc_bus_vote_data_session { VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0, /* No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL Loading Loading @@ -1340,6 +1347,7 @@ struct hfi_device { int (*get_core_capabilities)(void); int (*power_enable)(void *dev); int (*suspend)(void *dev); unsigned long (*get_core_clock_rate)(void *dev); }; typedef void (*hfi_cmd_response_callback) (enum command_response cmd, Loading Loading
drivers/media/platform/msm/vidc/msm_v4l2_vidc.c +47 −3 Original line number Diff line number Diff line Loading @@ -388,6 +388,49 @@ static ssize_t show_pwr_collapse_delay(struct device *dev, static DEVICE_ATTR(pwr_collapse_delay, 0644, show_pwr_collapse_delay, store_pwr_collapse_delay); static ssize_t show_thermal_level(struct device *dev, struct device_attribute *attr, char *buf) { return snprintf(buf, PAGE_SIZE, "%d\n", vidc_driver->thermal_level); } static ssize_t store_thermal_level(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int rc = 0, val = 0; rc = kstrtoint(buf, 0, &val); if (rc || val < 0) { dprintk(VIDC_WARN, "Invalid thermal level value: %s\n", buf); return -EINVAL; } dprintk(VIDC_DBG, "Thermal level old %d new %d\n", vidc_driver->thermal_level, val); if (val == vidc_driver->thermal_level) return count; vidc_driver->thermal_level = val; msm_comm_handle_thermal_event(); return count; } static DEVICE_ATTR(thermal_level, S_IRUGO | S_IWUSR, show_thermal_level, store_thermal_level); static struct attribute *msm_vidc_core_attrs[] = { &dev_attr_pwr_collapse_delay.attr, &dev_attr_thermal_level.attr, NULL }; static struct attribute_group msm_vidc_core_attr_group = { .attrs = msm_vidc_core_attrs, }; static int msm_vidc_probe(struct platform_device *pdev) { int rc = 0; Loading @@ -407,10 +450,10 @@ static int msm_vidc_probe(struct platform_device *pdev) dprintk(VIDC_ERR, "Failed to init core\n"); goto err_core_init; } rc = device_create_file(&pdev->dev, &dev_attr_pwr_collapse_delay); rc = sysfs_create_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); if (rc) { dprintk(VIDC_ERR, "Failed to create pwr_collapse_delay sysfs node"); "Failed to create attributes\n"); goto err_core_init; } if (core->hfi_type == VIDC_HFI_Q6) { Loading Loading @@ -513,7 +556,7 @@ err_dec_attr_link_name: err_dec_register: v4l2_device_unregister(&core->v4l2_dev); err_v4l2_register: device_remove_file(&pdev->dev, &dev_attr_pwr_collapse_delay); sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); err_core_init: kfree(core); err_no_mem: Loading Loading @@ -546,6 +589,7 @@ static int msm_vidc_remove(struct platform_device *pdev) v4l2_device_unregister(&core->v4l2_dev); msm_vidc_free_platform_resources(&core->resources); sysfs_remove_group(&pdev->dev.kobj, &msm_vidc_core_attr_group); kfree(core); return rc; } Loading
drivers/media/platform/msm/vidc/msm_vidc_common.c +215 −51 Original line number Diff line number Diff line Loading @@ -1080,6 +1080,43 @@ static void handle_session_error(enum command_response cmd, void *data) } } static void msm_comm_clean_notify_client(struct msm_vidc_core *core) { int rc = 0; struct msm_vidc_inst *inst = NULL; struct hfi_device *hdev = NULL; if (!core || !core->device) { dprintk(VIDC_ERR, "%s: Invalid params\n", __func__); return; } dprintk(VIDC_WARN, "%s: Core %p\n", __func__, core); mutex_lock(&core->lock); core->state = VIDC_CORE_INVALID; list_for_each_entry(inst, &core->instances, list) { mutex_lock(&inst->lock); inst->state = MSM_VIDC_CORE_INVALID; hdev = inst->core->device; if (hdev && inst->session) { dprintk(VIDC_DBG, "cleaning up inst: 0x%p\n", inst); rc = call_hfi_op(hdev, session_clean, (void *) inst->session); if (rc) dprintk(VIDC_ERR, "Sess clean failed :%p\n", inst); } inst->session = NULL; mutex_unlock(&inst->lock); dprintk(VIDC_WARN, "%s Send sys error for inst %p\n", __func__, inst); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } mutex_unlock(&core->lock); } struct sys_err_handler_data { struct msm_vidc_core *core; struct delayed_work work; Loading Loading @@ -1133,9 +1170,6 @@ static void handle_sys_error(enum command_response cmd, void *data) struct msm_vidc_cb_cmd_done *response = data; struct msm_vidc_core *core = NULL; struct sys_err_handler_data *handler = NULL; struct hfi_device *hdev = NULL; struct msm_vidc_inst *inst = NULL; int rc = 0; subsystem_crashed("venus"); if (!response) { Loading @@ -1152,35 +1186,7 @@ static void handle_sys_error(enum command_response cmd, void *data) } dprintk(VIDC_WARN, "SYS_ERROR %d received for core %p\n", cmd, core); mutex_lock(&core->lock); core->state = VIDC_CORE_INVALID; /* * 1. Delete each instance session from hfi list * 2. Notify all clients about hardware error. */ list_for_each_entry(inst, &core->instances, list) { mutex_lock(&inst->lock); inst->state = MSM_VIDC_CORE_INVALID; if (inst->core) hdev = inst->core->device; if (hdev && inst->session) { dprintk(VIDC_DBG, "cleaning up inst: 0x%p\n", inst); rc = call_hfi_op(hdev, session_clean, (void *) inst->session); if (rc) dprintk(VIDC_ERR, "Sess clean failed :%p\n", inst); } inst->session = NULL; mutex_unlock(&inst->lock); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } mutex_unlock(&core->lock); msm_comm_clean_notify_client(core); handler = kzalloc(sizeof(*handler), GFP_KERNEL); if (!handler) { Loading Loading @@ -2143,6 +2149,167 @@ void msm_comm_scale_clocks_and_bus(struct msm_vidc_inst *inst) } } static inline enum msm_vidc_thermal_level msm_comm_vidc_thermal_level(int level) { switch (level) { case 0: return VIDC_THERMAL_NORMAL; case 1: return VIDC_THERMAL_LOW; case 2: return VIDC_THERMAL_HIGH; default: return VIDC_THERMAL_CRITICAL; } } static unsigned long msm_comm_get_clock_rate(struct msm_vidc_core *core) { struct hfi_device *hdev; unsigned long freq = 0; if (!core || !core->device) { dprintk(VIDC_ERR, "%s Invalid params\n", __func__); return -EINVAL; } hdev = core->device; freq = call_hfi_op(hdev, get_core_clock_rate, hdev->hfi_device_data); dprintk(VIDC_DBG, "clock freq %ld\n", freq); return freq; } static bool is_core_turbo(struct msm_vidc_core *core, unsigned long freq) { int i = 0; struct msm_vidc_platform_resources *res = &core->resources; struct load_freq_table *table = res->load_freq_tbl; u32 max_freq = 0; for (i = 0; i < res->load_freq_tbl_size; i++) { if (max_freq < table[i].freq) max_freq = table[i].freq; } return freq >= max_freq; } static bool is_thermal_permissible(struct msm_vidc_core *core) { enum msm_vidc_thermal_level tl; unsigned long freq = 0; bool is_turbo = false; tl = msm_comm_vidc_thermal_level(vidc_driver->thermal_level); freq = msm_comm_get_clock_rate(core); is_turbo = is_core_turbo(core, freq); dprintk(VIDC_DBG, "Core freq %ld Thermal level %d Turbo mode %d\n", freq, tl, is_turbo); if ((!is_turbo && tl >= VIDC_THERMAL_CRITICAL) || (is_turbo && tl >= VIDC_THERMAL_LOW)) { dprintk(VIDC_ERR, "Video session not allowed. Turbo mode %d Thermal level %d\n", is_turbo, tl); return false; } return true; } static int msm_comm_session_abort(struct msm_vidc_inst *inst) { int rc = 0, abort_completion = 0; struct hfi_device *hdev; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_ERR, "%s invalid params\n", __func__); return -EINVAL; } hdev = inst->core->device; rc = call_hfi_op(hdev, session_abort, (void *)inst->session); if (rc) { dprintk(VIDC_ERR, "%s session_abort failed rc: %d\n", __func__, rc); return rc; } abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE); init_completion(&inst->completions[abort_completion]); rc = wait_for_completion_timeout( &inst->completions[abort_completion], msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timed out [%p]: %d\n", __func__, inst, abort_completion); rc = -EBUSY; } else { rc = 0; } return rc; } static void handle_thermal_event(struct msm_vidc_core *core) { int rc = 0; struct msm_vidc_inst *inst; if (!core || !core->device) { dprintk(VIDC_ERR, "%s Invalid params\n", __func__); return; } mutex_lock(&core->lock); list_for_each_entry(inst, &core->instances, list) { if (!inst->session) continue; mutex_unlock(&core->lock); if (inst->state >= MSM_VIDC_OPEN_DONE && inst->state < MSM_VIDC_CLOSE_DONE) { dprintk(VIDC_WARN, "%s: abort inst %p\n", __func__, inst); rc = msm_comm_session_abort(inst); if (rc) { dprintk(VIDC_ERR, "%s session_abort failed rc: %d\n", __func__, rc); goto err_sess_abort; } change_inst_state(inst, MSM_VIDC_CORE_INVALID); dprintk(VIDC_WARN, "%s Send sys error for inst %p\n", __func__, inst); msm_vidc_queue_v4l2_event(inst, V4L2_EVENT_MSM_VIDC_SYS_ERROR); } else { msm_comm_generate_session_error(inst); } mutex_lock(&core->lock); } mutex_unlock(&core->lock); return; err_sess_abort: msm_comm_clean_notify_client(core); return; } void msm_comm_handle_thermal_event() { struct msm_vidc_core *core; list_for_each_entry(core, &vidc_driver->cores, list) { if (!is_thermal_permissible(core)) { dprintk(VIDC_WARN, "Thermal level critical, stop all active sessions!\n"); handle_thermal_event(core); } } } static int msm_comm_init_core_done(struct msm_vidc_inst *inst) { struct msm_vidc_core *core = inst->core; Loading Loading @@ -3031,6 +3198,7 @@ int msm_comm_try_state(struct msm_vidc_inst *inst, int state) if (rc || state <= get_flipped_state(inst->state, state)) break; case MSM_VIDC_CORE_UNINIT: case MSM_VIDC_CORE_INVALID: dprintk(VIDC_DBG, "Sending core uninit\n"); rc = msm_vidc_deinit_core(inst); if (rc || state == get_flipped_state(inst->state, state)) Loading Loading @@ -4377,6 +4545,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) struct msm_vidc_core_capability *capability; int rc = 0; struct hfi_device *hdev; struct msm_vidc_core *core; if (!inst || !inst->core || !inst->core->device) { dprintk(VIDC_WARN, "%s: Invalid parameter\n", __func__); Loading @@ -4384,6 +4553,7 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) } capability = &inst->capability; hdev = inst->core->device; core = inst->core; rc = msm_vidc_load_supported(inst); if (rc) { change_inst_state(inst, MSM_VIDC_CORE_INVALID); Loading @@ -4391,6 +4561,13 @@ int msm_vidc_check_session_supported(struct msm_vidc_inst *inst) "%s: Hardware is overloaded\n", __func__); return rc; } if (!is_thermal_permissible(core)) { dprintk(VIDC_WARN, "Thermal level critical, stop all active sessions!\n"); return -ENOTSUPP; } if (!rc && inst->capability.capability_set) { if (inst->prop.width[CAPTURE_PORT] < capability->width.min || inst->prop.height[CAPTURE_PORT] < Loading Loading @@ -4481,27 +4658,14 @@ int msm_comm_kill_session(struct msm_vidc_inst *inst) */ if (inst->state >= MSM_VIDC_OPEN_DONE && inst->state < MSM_VIDC_CLOSE_DONE) { struct hfi_device *hdev = inst->core->device; int abort_completion = SESSION_MSG_INDEX(SESSION_ABORT_DONE); rc = call_hfi_op(hdev, session_abort, (void *) inst->session); if (rc) { dprintk(VIDC_ERR, "session_abort failed rc: %d\n", rc); rc = msm_comm_session_abort(inst); if (rc == -EBUSY) { msm_comm_generate_sys_error(inst); return 0; } else if (rc) return rc; } init_completion(&inst->completions[abort_completion]); rc = wait_for_completion_timeout( &inst->completions[abort_completion], msecs_to_jiffies(msm_vidc_hw_rsp_timeout)); if (!rc) { dprintk(VIDC_ERR, "%s: Wait interrupted or timed out [%p]: %d\n", __func__, inst, abort_completion); msm_comm_generate_sys_error(inst); } else { change_inst_state(inst, MSM_VIDC_CLOSE_DONE); } } else { dprintk(VIDC_WARN, "Inactive session %p, triggering an internal session error\n", Loading
drivers/media/platform/msm/vidc/msm_vidc_internal.h +2 −0 Original line number Diff line number Diff line Loading @@ -169,6 +169,7 @@ struct msm_vidc_drv { struct list_head cores; int num_cores; struct dentry *debugfs_root; int thermal_level; }; struct msm_video_device { Loading Loading @@ -389,6 +390,7 @@ int qbuf_dynamic_buf(struct msm_vidc_inst *inst, int unmap_and_deregister_buf(struct msm_vidc_inst *inst, struct buffer_info *binfo); void msm_comm_handle_thermal_event(void); void *msm_smem_new_client(enum smem_type mtype, void *platform_resources); struct msm_smem *msm_smem_alloc(void *clt, size_t size, u32 align, u32 flags, Loading
drivers/media/platform/msm/vidc/venus_hfi.c +32 −0 Original line number Diff line number Diff line Loading @@ -1352,6 +1352,20 @@ static inline int venus_hfi_reset_core(struct venus_hfi_device *device) return rc; } static struct clock_info *venus_hfi_get_clock(struct venus_hfi_device *device, char *name) { struct clock_info *vc; venus_hfi_for_each_clock(device, vc) { if (!strcmp(vc->name, name)) return vc; } dprintk(VIDC_WARN, "%s Clock %s not found\n", __func__, name); return NULL; } static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, int num_mbs_per_sec, int codecs_enabled) { Loading @@ -1376,6 +1390,23 @@ static unsigned long venus_hfi_get_clock_rate(struct clock_info *clock, return freq; } static unsigned long venus_hfi_get_core_clock_rate(void *dev) { struct venus_hfi_device *device = (struct venus_hfi_device *) dev; struct clock_info *vc; if (!device) { dprintk(VIDC_ERR, "%s Invalid args: %p\n", __func__, device); return -EINVAL; } vc = venus_hfi_get_clock(device, "core_clk"); if (vc) return clk_get_rate(vc->clk); else return 0; } static int venus_hfi_suspend(void *dev) { int rc = 0; Loading Loading @@ -4193,6 +4224,7 @@ static void venus_init_hfi_callbacks(struct hfi_device *hdev) hdev->get_core_capabilities = venus_hfi_get_core_capabilities; hdev->power_enable = venus_hfi_power_enable; hdev->suspend = venus_hfi_suspend; hdev->get_core_clock_rate = venus_hfi_get_core_clock_rate; } int venus_hfi_initialize(struct hfi_device *hdev, u32 device_id, Loading
drivers/media/platform/msm/vidc/vidc_hfi_api.h +8 −0 Original line number Diff line number Diff line Loading @@ -1259,6 +1259,13 @@ enum fw_info { FW_INFO_MAX, }; enum msm_vidc_thermal_level { VIDC_THERMAL_NORMAL = 0, VIDC_THERMAL_LOW, VIDC_THERMAL_HIGH, VIDC_THERMAL_CRITICAL }; enum vidc_bus_vote_data_session { VIDC_BUS_VOTE_DATA_SESSION_INVALID = 0, /* No declarations exist. Values generated by VIDC_VOTE_DATA_SESSION_VAL Loading Loading @@ -1340,6 +1347,7 @@ struct hfi_device { int (*get_core_capabilities)(void); int (*power_enable)(void *dev); int (*suspend)(void *dev); unsigned long (*get_core_clock_rate)(void *dev); }; typedef void (*hfi_cmd_response_callback) (enum command_response cmd, Loading