blob: 1c40c16d53f5110f8c542726f12a0ae2afa7890c [file] [log] [blame]
// 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;
}