| // SPDX-License-Identifier: GPL-2.0-only |
| /* |
| * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. |
| */ |
| |
| #include <linux/bitops.h> |
| #include <linux/slab.h> |
| #include <linux/list.h> |
| #include <linux/interrupt.h> |
| #include <linux/hash.h> |
| #include <linux/soc/qcom/smem.h> |
| #include <soc/qcom/socinfo.h> |
| #include "cvp_hfi_helper.h" |
| #include "cvp_hfi_io.h" |
| #include "msm_cvp_debug.h" |
| #include "cvp_hfi.h" |
| #include "msm_cvp_common.h" |
| |
| extern struct msm_cvp_drv *cvp_driver; |
| |
| static enum cvp_status hfi_map_err_status(u32 hfi_err) |
| { |
| enum cvp_status cvp_err; |
| |
| switch (hfi_err) { |
| case HFI_ERR_NONE: |
| case HFI_ERR_SESSION_SAME_STATE_OPERATION: |
| cvp_err = CVP_ERR_NONE; |
| break; |
| case HFI_ERR_SYS_FATAL: |
| cvp_err = CVP_ERR_HW_FATAL; |
| break; |
| case HFI_ERR_SYS_NOC_ERROR: |
| cvp_err = CVP_ERR_NOC_ERROR; |
| break; |
| case HFI_ERR_SYS_VERSION_MISMATCH: |
| case HFI_ERR_SYS_INVALID_PARAMETER: |
| case HFI_ERR_SYS_SESSION_ID_OUT_OF_RANGE: |
| case HFI_ERR_SESSION_INVALID_PARAMETER: |
| case HFI_ERR_SESSION_INVALID_SESSION_ID: |
| case HFI_ERR_SESSION_INVALID_STREAM_ID: |
| cvp_err = CVP_ERR_BAD_PARAM; |
| break; |
| case HFI_ERR_SYS_INSUFFICIENT_RESOURCES: |
| case HFI_ERR_SYS_UNSUPPORTED_DOMAIN: |
| case HFI_ERR_SYS_UNSUPPORTED_CODEC: |
| case HFI_ERR_SESSION_UNSUPPORTED_PROPERTY: |
| case HFI_ERR_SESSION_UNSUPPORTED_SETTING: |
| case HFI_ERR_SESSION_INSUFFICIENT_RESOURCES: |
| case HFI_ERR_SESSION_UNSUPPORTED_STREAM: |
| cvp_err = CVP_ERR_NOT_SUPPORTED; |
| break; |
| case HFI_ERR_SYS_MAX_SESSIONS_REACHED: |
| cvp_err = CVP_ERR_MAX_CLIENTS; |
| break; |
| case HFI_ERR_SYS_SESSION_IN_USE: |
| cvp_err = CVP_ERR_CLIENT_PRESENT; |
| break; |
| case HFI_ERR_SESSION_FATAL: |
| cvp_err = CVP_ERR_CLIENT_FATAL; |
| break; |
| case HFI_ERR_SESSION_BAD_POINTER: |
| cvp_err = CVP_ERR_BAD_PARAM; |
| break; |
| case HFI_ERR_SESSION_INCORRECT_STATE_OPERATION: |
| cvp_err = CVP_ERR_BAD_STATE; |
| break; |
| case HFI_ERR_SESSION_STREAM_CORRUPT: |
| case HFI_ERR_SESSION_STREAM_CORRUPT_OUTPUT_STALLED: |
| cvp_err = CVP_ERR_BITSTREAM_ERR; |
| break; |
| case HFI_ERR_SESSION_SYNC_FRAME_NOT_DETECTED: |
| cvp_err = CVP_ERR_IFRAME_EXPECTED; |
| break; |
| case HFI_ERR_SESSION_START_CODE_NOT_FOUND: |
| cvp_err = CVP_ERR_START_CODE_NOT_FOUND; |
| break; |
| case HFI_ERR_SESSION_EMPTY_BUFFER_DONE_OUTPUT_PENDING: |
| default: |
| cvp_err = CVP_ERR_FAIL; |
| break; |
| } |
| return cvp_err; |
| } |
| |
| static int hfi_process_evt_release_buffer_ref(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_event event_notify = {0}; |
| struct hfi_msg_release_buffer_ref_event_packet *data; |
| |
| dprintk(CVP_DBG, |
| "RECEIVED: EVENT_NOTIFY - release_buffer_reference\n"); |
| if (sizeof(struct hfi_msg_event_notify_packet) |
| > pkt->size) { |
| dprintk(CVP_ERR, |
| "hal_process_session_init_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| |
| data = (struct hfi_msg_release_buffer_ref_event_packet *) |
| pkt->rg_ext_event_data; |
| |
| event_notify.device_id = device_id; |
| event_notify.session_id = (void *)(uintptr_t)pkt->session_id; |
| event_notify.status = CVP_ERR_NONE; |
| event_notify.hal_event_type = HAL_EVENT_RELEASE_BUFFER_REFERENCE; |
| event_notify.packet_buffer = data->packet_buffer; |
| event_notify.extra_data_buffer = data->extra_data_buffer; |
| |
| info->response_type = HAL_SESSION_EVENT_CHANGE; |
| info->response.event = event_notify; |
| |
| return 0; |
| } |
| |
| static int hfi_process_sys_error(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| cmd_done.device_id = device_id; |
| cmd_done.status = hfi_map_err_status(pkt->event_data1); |
| |
| info->response_type = HAL_SYS_ERROR; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_error(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->event_data1); |
| info->response.cmd = cmd_done; |
| dprintk(CVP_INFO, "Received: SESSION_ERROR with event id : %#x %#x\n", |
| pkt->event_data1, pkt->event_data2); |
| switch (pkt->event_data1) { |
| /* Ignore below errors */ |
| case HFI_ERR_SESSION_INVALID_SCALE_FACTOR: |
| case HFI_ERR_SESSION_UPSCALE_NOT_SUPPORTED: |
| dprintk(CVP_INFO, "Non Fatal: HFI_EVENT_SESSION_ERROR\n"); |
| info->response_type = HAL_RESPONSE_UNUSED; |
| break; |
| default: |
| dprintk(CVP_ERR, |
| "%s: session %x data1 %#x, data2 %#x\n", __func__, |
| pkt->session_id, pkt->event_data1, pkt->event_data2); |
| info->response_type = HAL_SESSION_ERROR; |
| break; |
| } |
| |
| return 0; |
| } |
| |
| static int hfi_process_event_notify(u32 device_id, |
| struct hfi_msg_event_notify_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| dprintk(CVP_DBG, "Received: EVENT_NOTIFY\n"); |
| |
| if (pkt->size < sizeof(struct hfi_msg_event_notify_packet)) { |
| dprintk(CVP_ERR, "Invalid Params\n"); |
| return -E2BIG; |
| } |
| |
| switch (pkt->event_id) { |
| case HFI_EVENT_SYS_ERROR: |
| dprintk(CVP_ERR, "HFI_EVENT_SYS_ERROR: %d, %#x\n", |
| pkt->event_data1, pkt->event_data2); |
| return hfi_process_sys_error(device_id, pkt, info); |
| case HFI_EVENT_SESSION_ERROR: |
| dprintk(CVP_INFO, "HFI_EVENT_SESSION_ERROR[%#x]\n", |
| pkt->session_id); |
| return hfi_process_session_error(device_id, pkt, info); |
| |
| case HFI_EVENT_SESSION_SEQUENCE_CHANGED: |
| dprintk(CVP_WARN, "HFI_EVENT_SESSION_SEQUENCE_CHANGED [%#x]\n", |
| pkt->session_id); |
| return 0; |
| |
| case HFI_EVENT_RELEASE_BUFFER_REFERENCE: |
| dprintk(CVP_INFO, "HFI_EVENT_RELEASE_BUFFER_REFERENCE[%#x]\n", |
| pkt->session_id); |
| return hfi_process_evt_release_buffer_ref(device_id, pkt, info); |
| |
| case HFI_EVENT_SESSION_PROPERTY_CHANGED: |
| default: |
| *info = (struct msm_cvp_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| }; |
| |
| return 0; |
| } |
| } |
| |
| static int hfi_process_sys_init_done(u32 device_id, |
| struct hfi_msg_sys_init_done_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| enum cvp_status status = CVP_ERR_NONE; |
| |
| dprintk(CVP_DBG, "RECEIVED: SYS_INIT_DONE\n"); |
| if (sizeof(struct hfi_msg_sys_init_done_packet) > pkt->size) { |
| dprintk(CVP_ERR, "%s: bad_pkt_size: %d\n", __func__, |
| pkt->size); |
| return -E2BIG; |
| } |
| if (!pkt->num_properties) { |
| dprintk(CVP_ERR, |
| "hal_process_sys_init_done: no_properties\n"); |
| status = CVP_ERR_FAIL; |
| goto err_no_prop; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| if (status) { |
| dprintk(CVP_ERR, "%s: status %#x\n", |
| __func__, status); |
| goto err_no_prop; |
| } |
| |
| err_no_prop: |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = NULL; |
| cmd_done.status = (u32)status; |
| cmd_done.size = sizeof(struct cvp_hal_sys_init_done); |
| |
| info->response_type = HAL_SYS_INIT_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| enum hal_capability cvp_get_hal_cap_type(u32 capability_type) |
| { |
| enum hal_capability hal_cap = 0; |
| |
| switch (capability_type) { |
| case HFI_CAPABILITY_FRAME_WIDTH: |
| hal_cap = HAL_CAPABILITY_FRAME_WIDTH; |
| break; |
| case HFI_CAPABILITY_FRAME_HEIGHT: |
| hal_cap = HAL_CAPABILITY_FRAME_HEIGHT; |
| break; |
| case HFI_CAPABILITY_MBS_PER_FRAME: |
| hal_cap = HAL_CAPABILITY_MBS_PER_FRAME; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND: |
| hal_cap = HAL_CAPABILITY_MBS_PER_SECOND; |
| break; |
| case HFI_CAPABILITY_FRAMERATE: |
| hal_cap = HAL_CAPABILITY_FRAMERATE; |
| break; |
| case HFI_CAPABILITY_SCALE_X: |
| hal_cap = HAL_CAPABILITY_SCALE_X; |
| break; |
| case HFI_CAPABILITY_SCALE_Y: |
| hal_cap = HAL_CAPABILITY_SCALE_Y; |
| break; |
| case HFI_CAPABILITY_BITRATE: |
| hal_cap = HAL_CAPABILITY_BITRATE; |
| break; |
| case HFI_CAPABILITY_BFRAME: |
| hal_cap = HAL_CAPABILITY_BFRAME; |
| break; |
| case HFI_CAPABILITY_PEAKBITRATE: |
| hal_cap = HAL_CAPABILITY_PEAKBITRATE; |
| break; |
| case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_P_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_ENC_LTR_COUNT: |
| hal_cap = HAL_CAPABILITY_ENC_LTR_COUNT; |
| break; |
| case HFI_CAPABILITY_CP_OUTPUT2_THRESH: |
| hal_cap = HAL_CAPABILITY_SECURE_OUTPUT2_THRESHOLD; |
| break; |
| case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_B_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_LCU_SIZE: |
| hal_cap = HAL_CAPABILITY_LCU_SIZE; |
| break; |
| case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: |
| hal_cap = HAL_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: |
| hal_cap = HAL_CAPABILITY_MBS_PER_SECOND_POWER_SAVE; |
| break; |
| case HFI_CAPABILITY_EXTRADATA: |
| hal_cap = HAL_CAPABILITY_EXTRADATA; |
| break; |
| case HFI_CAPABILITY_PROFILE: |
| hal_cap = HAL_CAPABILITY_PROFILE; |
| break; |
| case HFI_CAPABILITY_LEVEL: |
| hal_cap = HAL_CAPABILITY_LEVEL; |
| break; |
| case HFI_CAPABILITY_I_FRAME_QP: |
| hal_cap = HAL_CAPABILITY_I_FRAME_QP; |
| break; |
| case HFI_CAPABILITY_P_FRAME_QP: |
| hal_cap = HAL_CAPABILITY_P_FRAME_QP; |
| break; |
| case HFI_CAPABILITY_B_FRAME_QP: |
| hal_cap = HAL_CAPABILITY_B_FRAME_QP; |
| break; |
| case HFI_CAPABILITY_RATE_CONTROL_MODES: |
| hal_cap = HAL_CAPABILITY_RATE_CONTROL_MODES; |
| break; |
| case HFI_CAPABILITY_BLUR_WIDTH: |
| hal_cap = HAL_CAPABILITY_BLUR_WIDTH; |
| break; |
| case HFI_CAPABILITY_BLUR_HEIGHT: |
| hal_cap = HAL_CAPABILITY_BLUR_HEIGHT; |
| break; |
| case HFI_CAPABILITY_SLICE_DELIVERY_MODES: |
| hal_cap = HAL_CAPABILITY_SLICE_DELIVERY_MODES; |
| break; |
| case HFI_CAPABILITY_SLICE_BYTE: |
| hal_cap = HAL_CAPABILITY_SLICE_BYTE; |
| break; |
| case HFI_CAPABILITY_SLICE_MB: |
| hal_cap = HAL_CAPABILITY_SLICE_MB; |
| break; |
| case HFI_CAPABILITY_SECURE: |
| hal_cap = HAL_CAPABILITY_SECURE; |
| break; |
| case HFI_CAPABILITY_MAX_NUM_B_FRAMES: |
| hal_cap = HAL_CAPABILITY_MAX_NUM_B_FRAMES; |
| break; |
| case HFI_CAPABILITY_MAX_VIDEOCORES: |
| hal_cap = HAL_CAPABILITY_MAX_VIDEOCORES; |
| break; |
| case HFI_CAPABILITY_MAX_WORKMODES: |
| hal_cap = HAL_CAPABILITY_MAX_WORKMODES; |
| break; |
| case HFI_CAPABILITY_UBWC_CR_STATS: |
| hal_cap = HAL_CAPABILITY_UBWC_CR_STATS; |
| break; |
| default: |
| dprintk(CVP_DBG, "%s: unknown capablity %#x\n", |
| __func__, capability_type); |
| break; |
| } |
| |
| return hal_cap; |
| } |
| |
| static inline void copy_cap_prop( |
| struct hfi_capability_supported *in, |
| struct msm_cvp_capability *capability) |
| { |
| struct hal_capability_supported *out = NULL; |
| |
| if (!in || !capability) { |
| dprintk(CVP_ERR, "%s Invalid input parameters\n", |
| __func__); |
| return; |
| } |
| |
| switch (in->capability_type) { |
| case HFI_CAPABILITY_FRAME_WIDTH: |
| out = &capability->width; |
| break; |
| case HFI_CAPABILITY_FRAME_HEIGHT: |
| out = &capability->height; |
| break; |
| case HFI_CAPABILITY_MBS_PER_FRAME: |
| out = &capability->mbs_per_frame; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND: |
| out = &capability->mbs_per_sec; |
| break; |
| case HFI_CAPABILITY_FRAMERATE: |
| out = &capability->frame_rate; |
| break; |
| case HFI_CAPABILITY_SCALE_X: |
| out = &capability->scale_x; |
| break; |
| case HFI_CAPABILITY_SCALE_Y: |
| out = &capability->scale_y; |
| break; |
| case HFI_CAPABILITY_BITRATE: |
| out = &capability->bitrate; |
| break; |
| case HFI_CAPABILITY_BFRAME: |
| out = &capability->bframe; |
| break; |
| case HFI_CAPABILITY_PEAKBITRATE: |
| out = &capability->peakbitrate; |
| break; |
| case HFI_CAPABILITY_HIER_P_NUM_ENH_LAYERS: |
| out = &capability->hier_p; |
| break; |
| case HFI_CAPABILITY_ENC_LTR_COUNT: |
| out = &capability->ltr_count; |
| break; |
| case HFI_CAPABILITY_CP_OUTPUT2_THRESH: |
| out = &capability->secure_output2_threshold; |
| break; |
| case HFI_CAPABILITY_HIER_B_NUM_ENH_LAYERS: |
| out = &capability->hier_b; |
| break; |
| case HFI_CAPABILITY_LCU_SIZE: |
| out = &capability->lcu_size; |
| break; |
| case HFI_CAPABILITY_HIER_P_HYBRID_NUM_ENH_LAYERS: |
| out = &capability->hier_p_hybrid; |
| break; |
| case HFI_CAPABILITY_MBS_PER_SECOND_POWERSAVE: |
| out = &capability->mbs_per_sec_power_save; |
| break; |
| case HFI_CAPABILITY_EXTRADATA: |
| out = &capability->extradata; |
| break; |
| case HFI_CAPABILITY_PROFILE: |
| out = &capability->profile; |
| break; |
| case HFI_CAPABILITY_LEVEL: |
| out = &capability->level; |
| break; |
| case HFI_CAPABILITY_I_FRAME_QP: |
| out = &capability->i_qp; |
| break; |
| case HFI_CAPABILITY_P_FRAME_QP: |
| out = &capability->p_qp; |
| break; |
| case HFI_CAPABILITY_B_FRAME_QP: |
| out = &capability->b_qp; |
| break; |
| case HFI_CAPABILITY_RATE_CONTROL_MODES: |
| out = &capability->rc_modes; |
| break; |
| case HFI_CAPABILITY_BLUR_WIDTH: |
| out = &capability->blur_width; |
| break; |
| case HFI_CAPABILITY_BLUR_HEIGHT: |
| out = &capability->blur_height; |
| break; |
| case HFI_CAPABILITY_SLICE_DELIVERY_MODES: |
| out = &capability->slice_delivery_mode; |
| break; |
| case HFI_CAPABILITY_SLICE_BYTE: |
| out = &capability->slice_bytes; |
| break; |
| case HFI_CAPABILITY_SLICE_MB: |
| out = &capability->slice_mbs; |
| break; |
| case HFI_CAPABILITY_SECURE: |
| out = &capability->secure; |
| break; |
| case HFI_CAPABILITY_MAX_NUM_B_FRAMES: |
| out = &capability->max_num_b_frames; |
| break; |
| case HFI_CAPABILITY_MAX_VIDEOCORES: |
| out = &capability->max_video_cores; |
| break; |
| case HFI_CAPABILITY_MAX_WORKMODES: |
| out = &capability->max_work_modes; |
| break; |
| case HFI_CAPABILITY_UBWC_CR_STATS: |
| out = &capability->ubwc_cr_stats; |
| break; |
| default: |
| dprintk(CVP_DBG, "%s: unknown capablity %#x\n", |
| __func__, in->capability_type); |
| break; |
| } |
| |
| if (out) { |
| out->capability_type = |
| cvp_get_hal_cap_type(in->capability_type); |
| out->min = in->min; |
| out->max = in->max; |
| out->step_size = in->step_size; |
| } |
| } |
| |
| enum cvp_status cvp_hfi_process_sys_init_done_prop_read( |
| struct hfi_msg_sys_init_done_packet *pkt, |
| struct cvp_hal_sys_init_done *sys_init_done) |
| { |
| enum cvp_status status = CVP_ERR_NONE; |
| u32 rem_bytes, num_properties; |
| u8 *data_ptr; |
| |
| if (!pkt || !sys_init_done) { |
| dprintk(CVP_ERR, |
| "hfi_msg_sys_init_done: Invalid input\n"); |
| return CVP_ERR_FAIL; |
| } |
| |
| rem_bytes = pkt->size - sizeof(struct |
| hfi_msg_sys_init_done_packet) + sizeof(u32); |
| |
| if (!rem_bytes) { |
| dprintk(CVP_ERR, |
| "hfi_msg_sys_init_done: missing_prop_info\n"); |
| return CVP_ERR_FAIL; |
| } |
| |
| status = hfi_map_err_status(pkt->error_type); |
| if (status) { |
| dprintk(CVP_ERR, "%s: status %#x\n", __func__, status); |
| return status; |
| } |
| |
| data_ptr = (u8 *) &pkt->rg_property_data[0]; |
| num_properties = pkt->num_properties; |
| dprintk(CVP_DBG, |
| "%s: data_start %pK, num_properties %#x\n", |
| __func__, data_ptr, num_properties); |
| |
| sys_init_done->capabilities = NULL; |
| return status; |
| } |
| |
| static int hfi_process_session_init_done(u32 device_id, |
| struct hfi_msg_sys_session_init_done_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| struct cvp_hal_session_init_done session_init_done = { {0} }; |
| |
| dprintk(CVP_DBG, "RECEIVED: SESSION_INIT_DONE[%x]\n", pkt->session_id); |
| |
| if (sizeof(struct hfi_msg_sys_session_init_done_packet) > pkt->size) { |
| dprintk(CVP_ERR, |
| "hal_process_session_init_done: bad_pkt_size\n"); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.data.session_init_done = session_init_done; |
| cmd_done.size = sizeof(struct cvp_hal_session_init_done); |
| |
| info->response_type = HAL_SESSION_INIT_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| static int hfi_process_session_end_done(u32 device_id, |
| struct hfi_msg_sys_session_end_done_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(CVP_DBG, "RECEIVED: SESSION_END_DONE[%#x]\n", pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_sys_session_end_done_packet)) { |
| dprintk(CVP_ERR, "%s: bad packet/packet size\n", __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| info->response_type = HAL_SESSION_END_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_abort_done(u32 device_id, |
| struct hfi_msg_sys_session_abort_done_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| dprintk(CVP_DBG, "RECEIVED: SESSION_ABORT_DONE[%#x]\n", |
| pkt->session_id); |
| |
| if (!pkt || pkt->size != |
| sizeof(struct hfi_msg_sys_session_abort_done_packet)) { |
| dprintk(CVP_ERR, "%s: bad packet/packet size: %d\n", |
| __func__, pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| info->response_type = HAL_SESSION_ABORT_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_set_buf_done(u32 device_id, |
| struct hfi_msg_session_cvp_set_buffers_done_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| unsigned int pkt_size = |
| sizeof(struct hfi_msg_session_cvp_set_buffers_done_packet); |
| |
| if (!pkt || pkt->size < pkt_size) { |
| dprintk(CVP_ERR, "bad packet/packet size %d\n", |
| pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| dprintk(CVP_DBG, "RECEIVED:CVP_SET_BUFFER_DONE[%#x]\n", |
| pkt->session_id); |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| info->response_type = HAL_SESSION_SET_BUFFER_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| |
| static int hfi_process_session_rel_buf_done(u32 device_id, |
| struct hfi_msg_session_hdr *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| unsigned int pkt_size = |
| sizeof(struct hfi_msg_session_hdr); |
| |
| if (!pkt || pkt->size < pkt_size) { |
| dprintk(CVP_ERR, "bad packet/packet size %d\n", |
| pkt ? pkt->size : 0); |
| return -E2BIG; |
| } |
| dprintk(CVP_DBG, "RECEIVED:CVP_RELEASE_BUFFER_DONE[%#x]\n", |
| pkt->session_id); |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| info->response_type = HAL_SESSION_RELEASE_BUFFER_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_cvp_operation_config(u32 device_id, |
| struct hfi_msg_session_cvp_operation_config_done_packet_type *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| int signal; |
| |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size < sizeof(*pkt)) { |
| dprintk(CVP_ERR, |
| "%s: bad_pkt_size\n", __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| dprintk(CVP_DBG, |
| "%s: device_id=%d status=%d, sessionid=%x config=%x\n", |
| __func__, device_id, cmd_done.status, |
| cmd_done.session_id, pkt->op_conf_id); |
| |
| signal = get_signal_from_pkt_type(pkt->op_conf_id); |
| if (signal < 0) { |
| dprintk(CVP_ERR, "%s Invalid op config id\n", __func__); |
| return -EINVAL; |
| } |
| |
| info->response_type = signal; |
| info->response.cmd = cmd_done; |
| return 0; |
| } |
| |
| static int hfi_process_session_cvp_dfs(u32 device_id, |
| struct hfi_msg_session_cvp_dfs_packet_type *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size < sizeof(*pkt)) { |
| dprintk(CVP_ERR, |
| "%s: bad_pkt_size\n", __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| dprintk(CVP_DBG, |
| "%s: device_id=%d cmd_done.status=%d sessionid=%x\n", |
| __func__, device_id, cmd_done.status, cmd_done.session_id); |
| info->response_type = HAL_SESSION_DFS_FRAME_CMD_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static struct msm_cvp_inst *cvp_get_inst_from_id(struct msm_cvp_core *core, |
| void *session_id) |
| { |
| struct msm_cvp_inst *inst = NULL; |
| bool match = false; |
| |
| if (!core || !session_id) |
| return NULL; |
| |
| mutex_lock(&core->lock); |
| list_for_each_entry(inst, &core->instances, list) { |
| if (hash32_ptr(inst->session) == (unsigned int)session_id) { |
| match = true; |
| break; |
| } |
| } |
| |
| inst = match ? inst : NULL; |
| mutex_unlock(&core->lock); |
| |
| return inst; |
| |
| } |
| |
| static int hfi_process_session_cvp_msg(u32 device_id, |
| struct hfi_msg_session_hdr *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct session_msg *sess_msg; |
| struct msm_cvp_inst *inst = NULL; |
| struct msm_cvp_core *core; |
| void *session_id; |
| |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size > MAX_HFI_PKT_SIZE * sizeof(unsigned int)) { |
| dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); |
| return -E2BIG; |
| } |
| session_id = (void *)(uintptr_t)pkt->session_id; |
| core = list_first_entry(&cvp_driver->cores, struct msm_cvp_core, list); |
| inst = cvp_get_inst_from_id(core, session_id); |
| |
| if (!inst) { |
| dprintk(CVP_ERR, "%s: invalid session\n", __func__); |
| return -EINVAL; |
| } |
| |
| sess_msg = kmem_cache_alloc(inst->session_queue.msg_cache, GFP_KERNEL); |
| if (sess_msg == NULL) { |
| dprintk(CVP_ERR, "%s runs out msg cache memory\n", __func__); |
| return -ENOMEM; |
| } |
| |
| memcpy(&sess_msg->pkt, pkt, sizeof(struct hfi_msg_session_hdr)); |
| |
| spin_lock(&inst->session_queue.lock); |
| if (inst->session_queue.msg_count >= MAX_NUM_MSGS_PER_SESSION) { |
| dprintk(CVP_ERR, "Reached session queue size limit\n"); |
| goto error_handle_msg; |
| } |
| list_add_tail(&sess_msg->node, &inst->session_queue.msgs); |
| inst->session_queue.msg_count++; |
| spin_unlock(&inst->session_queue.lock); |
| |
| wake_up_all(&inst->session_queue.wq); |
| |
| info->response_type = HAL_NO_RESP; |
| |
| return 0; |
| |
| error_handle_msg: |
| spin_unlock(&inst->session_queue.lock); |
| kmem_cache_free(inst->session_queue.msg_cache, sess_msg); |
| return -ENOMEM; |
| } |
| |
| static int hfi_process_session_cvp_dme(u32 device_id, |
| struct hfi_msg_session_cvp_dme_packet_type *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size > sizeof(*pkt)) { |
| dprintk(CVP_ERR, "%s: bad_pkt_size %d\n", __func__, pkt->size); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| dprintk(CVP_DBG, |
| "%s: device_id=%d cmd_done.status=%d sessionid=%x\n", |
| __func__, device_id, cmd_done.status, cmd_done.session_id); |
| info->response_type = HAL_SESSION_DME_FRAME_CMD_DONE; |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static int hfi_process_session_cvp_persist(u32 device_id, |
| struct hfi_msg_session_cvp_persist_packet_type *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| struct msm_cvp_cb_cmd_done cmd_done = {0}; |
| |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size < sizeof(*pkt)) { |
| dprintk(CVP_ERR, |
| "%s: bad_pkt_size\n", __func__); |
| return -E2BIG; |
| } |
| |
| cmd_done.device_id = device_id; |
| cmd_done.session_id = (void *)(uintptr_t)pkt->session_id; |
| cmd_done.status = hfi_map_err_status(pkt->error_type); |
| cmd_done.size = 0; |
| |
| dprintk(CVP_DBG, |
| "%s: device_id=%d cmd_done.status=%d sessionid=%x\n", |
| __func__, device_id, cmd_done.status, cmd_done.session_id); |
| info->response_type = HAL_SESSION_PERSIST_CMD_DONE, |
| info->response.cmd = cmd_done; |
| |
| return 0; |
| } |
| |
| static void hfi_process_sys_get_prop_image_version( |
| struct hfi_msg_sys_property_info_packet *pkt) |
| { |
| int i = 0; |
| size_t smem_block_size = 0; |
| u8 *smem_table_ptr; |
| char version[256]; |
| const u32 version_string_size = 128; |
| const u32 smem_image_index_venus = 14 * 128; |
| u8 *str_image_version; |
| int req_bytes; |
| |
| req_bytes = pkt->size - sizeof(*pkt); |
| if (req_bytes < version_string_size || |
| !pkt->rg_property_data[1] || |
| pkt->num_properties > 1) { |
| dprintk(CVP_ERR, "%s: bad_pkt: %d\n", __func__, req_bytes); |
| return; |
| } |
| str_image_version = (u8 *)&pkt->rg_property_data[1]; |
| /* |
| * The version string returned by firmware includes null |
| * characters at the start and in between. Replace the null |
| * characters with space, to print the version info. |
| */ |
| for (i = 0; i < version_string_size; i++) { |
| if (str_image_version[i] != '\0') |
| version[i] = str_image_version[i]; |
| else |
| version[i] = ' '; |
| } |
| version[i] = '\0'; |
| dprintk(CVP_DBG, "F/W version: %s\n", version); |
| |
| smem_table_ptr = qcom_smem_get(QCOM_SMEM_HOST_ANY, |
| SMEM_IMAGE_VERSION_TABLE, &smem_block_size); |
| if ((smem_image_index_venus + version_string_size) <= smem_block_size && |
| smem_table_ptr) |
| memcpy(smem_table_ptr + smem_image_index_venus, |
| str_image_version, version_string_size); |
| } |
| |
| static int hfi_process_sys_property_info(u32 device_id, |
| struct hfi_msg_sys_property_info_packet *pkt, |
| struct msm_cvp_cb_info *info) |
| { |
| if (!pkt) { |
| dprintk(CVP_ERR, "%s: invalid param\n", __func__); |
| return -EINVAL; |
| } else if (pkt->size < sizeof(*pkt)) { |
| dprintk(CVP_ERR, |
| "%s: bad_pkt_size\n", __func__); |
| return -E2BIG; |
| } else if (!pkt->num_properties) { |
| dprintk(CVP_WARN, |
| "%s: no_properties\n", __func__); |
| return -EINVAL; |
| } |
| |
| switch (pkt->rg_property_data[0]) { |
| case HFI_PROPERTY_SYS_IMAGE_VERSION: |
| hfi_process_sys_get_prop_image_version(pkt); |
| |
| *info = (struct msm_cvp_cb_info) { |
| .response_type = HAL_RESPONSE_UNUSED, |
| }; |
| return 0; |
| default: |
| dprintk(CVP_DBG, |
| "%s: unknown_prop_id: %x\n", |
| __func__, pkt->rg_property_data[0]); |
| return -ENOTSUPP; |
| } |
| |
| } |
| |
| int cvp_hfi_process_msg_packet(u32 device_id, |
| struct cvp_hal_msg_pkt_hdr *msg_hdr, |
| struct msm_cvp_cb_info *info) |
| { |
| typedef int (*pkt_func_def)(u32, void *, struct msm_cvp_cb_info *info); |
| pkt_func_def pkt_func = NULL; |
| |
| if (!info || !msg_hdr || msg_hdr->size < CVP_IFACEQ_MIN_PKT_SIZE) { |
| dprintk(CVP_ERR, "%s: bad packet/packet size\n", |
| __func__); |
| return -EINVAL; |
| } |
| |
| dprintk(CVP_DBG, "Received HFI MSG with type %d\n", msg_hdr->packet); |
| switch (msg_hdr->packet) { |
| case HFI_MSG_EVENT_NOTIFY: |
| pkt_func = (pkt_func_def)hfi_process_event_notify; |
| break; |
| case HFI_MSG_SYS_INIT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_sys_init_done; |
| break; |
| case HFI_MSG_SYS_SESSION_INIT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_init_done; |
| break; |
| case HFI_MSG_SYS_PROPERTY_INFO: |
| pkt_func = (pkt_func_def)hfi_process_sys_property_info; |
| break; |
| case HFI_MSG_SYS_SESSION_END_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_end_done; |
| break; |
| case HFI_MSG_SESSION_CVP_SET_BUFFERS: |
| pkt_func = (pkt_func_def) hfi_process_session_set_buf_done; |
| break; |
| case HFI_MSG_SESSION_CVP_RELEASE_BUFFERS: |
| pkt_func = (pkt_func_def)hfi_process_session_rel_buf_done; |
| break; |
| case HFI_MSG_SYS_SESSION_ABORT_DONE: |
| pkt_func = (pkt_func_def)hfi_process_session_abort_done; |
| break; |
| case HFI_MSG_SESSION_CVP_OPERATION_CONFIG: |
| pkt_func = |
| (pkt_func_def)hfi_process_session_cvp_operation_config; |
| break; |
| case HFI_MSG_SESSION_CVP_DFS: |
| pkt_func = (pkt_func_def)hfi_process_session_cvp_dfs; |
| break; |
| case HFI_MSG_SESSION_CVP_DME: |
| pkt_func = (pkt_func_def)hfi_process_session_cvp_dme; |
| break; |
| case HFI_MSG_SESSION_CVP_SET_PERSIST_BUFFERS: |
| pkt_func = (pkt_func_def)hfi_process_session_cvp_persist; |
| break; |
| case HFI_MSG_SESSION_CVP_DS: |
| pkt_func = (pkt_func_def)hfi_process_session_cvp_msg; |
| break; |
| default: |
| dprintk(CVP_DBG, "Unable to parse message: %#x\n", |
| msg_hdr->packet); |
| pkt_func = (pkt_func_def)hfi_process_session_cvp_msg; |
| break; |
| } |
| |
| return pkt_func ? pkt_func(device_id, msg_hdr, info) : -ENOTSUPP; |
| } |