msm: vidc: response handling

add response handling for commands, properties,
system and session errors.

Change-Id: I87a8cba136979d425d978dfe55317a3deb081c53
Signed-off-by: Darshana Patil <darshana@codeaurora.org>
This commit is contained in:
Darshana Patil
2020-08-13 16:03:47 -07:00
committato da Maheshwar Ajja
parent 55efff9d9f
commit 9a854613cd
16 ha cambiato i file con 704 aggiunte e 20 eliminazioni

Vedi File

@@ -29,7 +29,8 @@ msm-vidc-objs := driver/vidc/src/msm_vidc_v4l2.o \
driver/vidc/src/msm_vidc_debug.o \
driver/vidc/src/msm_vidc_memory.o \
driver/vidc/src/venus_hfi.o \
driver/vidc/src/hfi_packet.o
driver/vidc/src/hfi_packet.o \
driver/vidc/src/venus_hfi_response.o
ifneq ($(CONFIG_ARCH_QTI_VM), y)
ifeq ($(CONFIG_ARCH_LAHAINA), y)

Vedi File

@@ -127,12 +127,13 @@ struct metapayload_header {
};
enum hfi_property_mode_type {
HFI_MODE_NONE = 0,
HFI_MODE_PORT_SETTINGS_CHANGE = BIT(0),
HFI_MODE_PROPERTY = BIT(1),
HFI_MODE_METADATA = BIT(2),
HFI_MODE_NONE = 0,
HFI_MODE_PORT_SETTINGS_CHANGE = BIT(0),
HFI_MODE_PROPERTY = BIT(1),
HFI_MODE_METADATA = BIT(2),
};
#define HFI_CMD_BEGIN 0x0
#define HFI_CMD_INIT 0x1
#define HFI_CMD_POWER_COLLAPSE 0x2
#define HFI_CMD_OPEN 0x3
@@ -145,6 +146,6 @@ enum hfi_property_mode_type {
#define HFI_CMD_DELIVERY_MODE 0xA
#define HFI_CMD_SUBSCRIBE_MODE 0xB
#define HFI_CMD_SETTINGS_CHANGE 0xC
#define HFI_CMD_END 0xD
#endif //__H_HFI_COMMAND_H__

Vedi File

@@ -43,4 +43,3 @@ int hfi_packet_session_property(struct msm_vidc_inst *inst,
u32 pkt_type, u32 flags, u32 port,
u32 payload_type, void *payload, u32 payload_size);
#endif // _HFI_PACKET_H_

Vedi File

@@ -96,6 +96,7 @@ struct msm_vidc_core {
u32 last_packet_type;
u8 *packet;
u32 packet_size;
u8 *response_packet;
struct v4l2_file_operations *v4l2_file_ops;
struct v4l2_ioctl_ops *v4l2_ioctl_ops;
struct v4l2_ctrl_ops *v4l2_ctrl_ops;
@@ -106,6 +107,7 @@ struct msm_vidc_core {
struct msm_vidc_memory_ops *mem_ops;
u32 header_id;
u32 packet_id;
struct completion init_done;
};
#endif // _MSM_VIDC_CORE_H_

Vedi File

@@ -87,6 +87,13 @@ enum vidc_msg_prio {
#define d_vpr_b(__fmt, ...) \
dprintk(VIDC_BUS, DEFAULT_SID, __fmt, ##__VA_ARGS__)
#define dprintk_firmware(__level, __fmt, ...) \
do { \
pr_err(FW_DBG_TAG __fmt, \
"fw", \
##__VA_ARGS__); \
} while (0)
#define MSM_VIDC_ERROR(value) \
do { if (value) \
d_vpr_e("BugOn"); \

Vedi File

@@ -103,7 +103,9 @@ struct msm_vidc_map_info *msm_vidc_get_map_info(struct msm_vidc_inst *inst,
enum msm_vidc_buffer_type buffer_type);
struct msm_vidc_alloc_info *msm_vidc_get_alloc_info(struct msm_vidc_inst *inst,
enum msm_vidc_buffer_type buffer_type);
struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
u32 session_id);
void put_inst(struct msm_vidc_inst *inst);
void core_lock(struct msm_vidc_core *core, const char *function);
void core_unlock(struct msm_vidc_core *core, const char *function);
void inst_lock(struct msm_vidc_inst *inst, const char *function);

Vedi File

@@ -110,6 +110,7 @@ struct msm_vidc_inst {
struct dentry *debugfs_root;
struct msm_vidc_debug debug;
struct msm_vidc_inst_capability *capabilities;
struct completion completions[MAX_SIGNAL];
};
#endif // _MSM_VIDC_INST_H_

Vedi File

@@ -299,6 +299,12 @@ enum profiling_points {
MAX_PROFILING_POINTS,
};
enum signal_session_response {
SIGNAL_CMD_STOP = 0,
SIGNAL_CMD_CLOSE,
MAX_SIGNAL,
};
#define HFI_MASK_QHDR_TX_TYPE 0xFF000000
#define HFI_MASK_QHDR_RX_TYPE 0x00FF0000
#define HFI_MASK_QHDR_PRI_TYPE 0x0000FF00

Vedi File

@@ -76,5 +76,6 @@ int __interrupt_init(struct msm_vidc_core *core);
int __setup_ucregion_memmap(struct msm_vidc_core *core);
int __raise_interrupt(struct msm_vidc_core *core);
int __power_off(struct msm_vidc_core *core);
bool __core_in_valid_state(struct msm_vidc_core *core);
#endif // _VENUS_HFI_H_

Vedi File

@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#ifndef __VENUS_HFI_RESPONSE_H__
#define __VENUS_HFI_RESPONSE_H__
int handle_response(struct msm_vidc_core *core,
void *response);
int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
u32 core_resp_pkt_size, const char *func);
bool is_valid_port(struct msm_vidc_inst *inst, u32 port,
const char *func);
bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
u32 buffer_type, const char *func);
#endif // __VENUS_HFI_RESPONSE_H__

Vedi File

@@ -429,7 +429,7 @@ int hfi_packet_sys_debug_config(struct msm_vidc_core *core,
goto err_debug;
/* HFI_PROP_DEBUG_CONFIG */
payload = debug_config; /*TODO:Change later*/
payload = 0; /*TODO:Change later*/
rc = hfi_create_packet(pkt, pkt_size,
HFI_PROP_DEBUG_CONFIG,
HFI_HOST_FLAGS_NONE,

Vedi File

@@ -589,6 +589,7 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
int rc = 0;
struct msm_vidc_inst *inst;
struct msm_vidc_core *core;
int i = 0;
d_vpr_h("%s()\n", __func__);
core = vidc_core;
@@ -667,6 +668,9 @@ void *msm_vidc_open(void *vidc_core, u32 session_type)
inst->domain = session_type;
inst->state = MSM_VIDC_OPEN;
inst->request = false;
for (i = 0; i < MAX_SIGNAL; i++)
init_completion(&inst->completions[i]);
//inst->debugfs_root =
// msm_vidc_debugfs_init_inst(inst, core->debugfs_root);

Vedi File

@@ -6,7 +6,8 @@
#include "msm_vidc_debug.h"
int msm_vidc_debug = VIDC_HIGH | VIDC_LOW | VIDC_PKT | VIDC_ERR | VIDC_PRINTK |
FW_ERROR | FW_FATAL | FW_FTRACE;
FW_ERROR | FW_FATAL | FW_FTRACE | FW_LOW | FW_MEDIUM | FW_HIGH |
FW_PERF | FW_PRINTK;
EXPORT_SYMBOL(msm_vidc_debug);
bool msm_vidc_lossless_encode = !true;

Vedi File

@@ -14,6 +14,7 @@
#include "msm_vidc_memory.h"
#include "msm_vidc_debug.h"
#include "venus_hfi.h"
#include "msm_vidc.h"
#define COUNT_BITS(a, out) ({ \
while ((a) >= 1) { \
@@ -901,6 +902,11 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
if (rc)
goto unlock;
core->state = MSM_VIDC_CORE_INIT;
init_completion(&core->init_done);
core->smmu_fault_handled = false;
core->ssr.trigger = false;
rc = venus_hfi_core_init(core);
if (rc) {
d_vpr_e("%s: core init failed\n", __func__);
@@ -908,9 +914,18 @@ int msm_vidc_core_init(struct msm_vidc_core *core)
goto unlock;
}
core->state = MSM_VIDC_CORE_INIT;
core->smmu_fault_handled = false;
core->ssr.trigger = false;
mutex_unlock(&core->lock);
/*TODO: acquire lock or not */
rc = wait_for_completion_timeout(&core->init_done, msecs_to_jiffies(
core->platform->data.core_data[DEBUG_TIMEOUT].value));
if (!rc) {
d_vpr_e("%s: system init timed out\n", __func__);
//msm_comm_kill_session(inst);
rc = -EIO;
} else {
rc = 0;
}
mutex_lock(&core->lock);
unlock:
mutex_unlock(&core->lock);
@@ -945,6 +960,47 @@ void msm_vidc_batch_handler(struct work_struct *work)
{
}
struct msm_vidc_inst *get_inst(struct msm_vidc_core *core,
u32 session_id)
{
struct msm_vidc_inst *inst = NULL;
bool matches = false;
if (!core) {
d_vpr_e("%s: invalid params\n", __func__);
return NULL;
}
mutex_lock(&core->lock);
list_for_each_entry(inst, &core->instances, list) {
if (inst->session_id == session_id) {
matches = true;
break;
}
}
inst = (matches && kref_get_unless_zero(&inst->kref)) ? inst : NULL;
mutex_unlock(&core->lock);
return inst;
}
static void put_inst_helper(struct kref *kref)
{
struct msm_vidc_inst *inst = container_of(kref,
struct msm_vidc_inst, kref);
msm_vidc_close(inst);
}
void put_inst(struct msm_vidc_inst *inst)
{
if (!inst) {
d_vpr_e("%s: invalid params\n", __func__);
return;
}
kref_put(&inst->kref, put_inst_helper);
}
void core_lock(struct msm_vidc_core *core, const char *function)
{
mutex_lock(&core->lock);
@@ -963,4 +1019,4 @@ void inst_lock(struct msm_vidc_inst *inst, const char *function)
void inst_unlock(struct msm_vidc_inst *inst, const char *function)
{
mutex_unlock(&inst->lock);
}
}

Vedi File

@@ -23,6 +23,9 @@
#include "msm_vidc_driver.h"
#include "msm_vidc_debug.h"
#include "hfi_packet.h"
#include "venus_hfi_response.h"
#define MIN_PAYLOAD_SIZE 3
static int __resume(struct msm_vidc_core *core);
static int __suspend(struct msm_vidc_core *core);
@@ -150,7 +153,7 @@ static void __strict_check(struct msm_vidc_core *core)
__fatal_error(core, !mutex_is_locked(&core->lock));
}
static bool __core_in_valid_state(struct msm_vidc_core *core)
bool __core_in_valid_state(struct msm_vidc_core *core)
{
return core->state != MSM_VIDC_CORE_ERROR;
}
@@ -566,6 +569,7 @@ static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
d_vpr_e("skip writing packet\n");
return 0;
packet_size_in_words = (*(u32 *)packet) >> 2;
if (!packet_size_in_words || packet_size_in_words >
qinfo->q_array.mem_size>>2) {
@@ -624,7 +628,7 @@ static int __write_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
mb();
return 0;
}
#if 0
static int __read_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
u32 *pb_tx_req_is_set)
{
@@ -748,7 +752,7 @@ static int __read_queue(struct msm_vidc_iface_q_info *qinfo, u8 *packet,
return rc;
}
#endif
/* Writes into cmdq without raising an interrupt */
static int __iface_cmdq_write_relaxed(struct msm_vidc_core *core,
void *pkt, bool *requires_interrupt)
@@ -814,7 +818,7 @@ static int __iface_cmdq_write(struct msm_vidc_core *core,
return rc;
}
/*
static int __iface_msgq_read(struct msm_vidc_core *core, void *pkt)
{
u32 tx_req_is_set = 0;
@@ -845,8 +849,9 @@ static int __iface_msgq_read(struct msm_vidc_core *core, void *pkt)
if (tx_req_is_set)
call_venus_op(core, raise_interrupt, core);
rc = 0;
} else
} else {
rc = -ENODATA;
}
read_error_null:
return rc;
@@ -882,7 +887,74 @@ static int __iface_dbgq_read(struct msm_vidc_core *core, void *pkt)
dbg_error_null:
return rc;
}
*/
/*TODO:darshana needs discussion*/
static void __flush_debug_queue(struct msm_vidc_core *core, u8 *header)
{
bool local_packet = false;
enum vidc_msg_prio log_level = msm_vidc_debug;
struct hfi_packet *pkt;
u32 payload = 0;
if (!header) {
header = kzalloc(VIDC_IFACEQ_VAR_HUGE_PKT_SIZE, GFP_KERNEL);
if (!header) {
d_vpr_e("%s: Fail to allocate mem\n", __func__);
return;
}
local_packet = true;
/*
* Local packet is used when error occurred.
* It is good to print these logs to printk as well.
*/
log_level |= FW_PRINTK;
}
#define SKIP_INVALID_PKT(pkt_size, payload_size, pkt_hdr_size) ({ \
if (pkt_size < pkt_hdr_size || \
payload_size < MIN_PAYLOAD_SIZE || \
payload_size > \
(pkt_size - pkt_hdr_size + sizeof(u8))) { \
d_vpr_e("%s: invalid msg size - %d\n", \
__func__, payload_size); \
continue; \
} \
})
while (!__iface_dbgq_read(core, header)) {
struct hfi_header *hdr =
(struct hfi_header *) header;
if (!validate_packet((u8 *)pkt, core->response_packet,
core->packet_size, __func__))
return;
pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
if (pkt->type == HFI_PROP_DEBUG_LOG_LEVEL) {
SKIP_INVALID_PKT(pkt->size,
sizeof(u32), sizeof(*pkt));
payload = (u32) *((u8 *)pkt + sizeof(struct hfi_packet));
/*
* All fw messages starts with new line character. This
* causes dprintk to print this message in two lines
* in the kernel log. Ignoring the first character
* from the message fixes this to print it in a single
* line.
*/
//pkt->rg_msg_data[sizeof(u32)-1] = '\0';
dprintk_firmware(log_level, "%s", &payload);
}
}
#undef SKIP_INVALID_PKT
if (local_packet)
kfree(header);
}
static int __sys_set_debug(struct msm_vidc_core *core, u32 debug)
{
int rc = 0;
@@ -2192,9 +2264,29 @@ static void __unload_fw(struct msm_vidc_core *core)
d_vpr_h("Firmware unloaded successfully\n");
}
static int __response_handler(struct msm_vidc_core *core)
{
int rc = 0;
while (!__iface_msgq_read(core, core->response_packet)) {
rc = handle_response(core, core->response_packet);
if (rc)
continue;
/* check for system error */
if (core->state != MSM_VIDC_CORE_INIT)
break;
}
__schedule_power_collapse_work(core);
__flush_debug_queue(core, core->response_packet);
return rc;
}
void venus_hfi_work_handler(struct work_struct *work)
{
struct msm_vidc_core *core;
int num_responses = 0;
core = container_of(work, struct msm_vidc_core, device_work);
if (!core) {
@@ -2202,6 +2294,21 @@ void venus_hfi_work_handler(struct work_struct *work)
return;
}
d_vpr_e("%s(): core %pK\n", __func__, core);
mutex_lock(&core->lock);
if (__resume(core)) {
d_vpr_e("%s: Power on failed\n", __func__);
goto err_no_work;
}
call_venus_op(core, clear_interrupt, core);
mutex_unlock(&core->lock);
num_responses = __response_handler(core);
err_no_work:
mutex_unlock(&core->lock);
if (!call_venus_op(core, watchdog, core, core->intr_status))
enable_irq(core->dt->irq);
}
void venus_hfi_pm_work_handler(struct work_struct *work)
@@ -2273,6 +2380,14 @@ int venus_hfi_core_init(struct msm_vidc_core *core)
return -ENOMEM;
}
core->response_packet = kzalloc(core->packet_size, GFP_KERNEL);
if (!core->response_packet) {
d_vpr_e("%s(): core response packet allocation failed\n",
__func__);
kfree(core->packet);
return -ENOMEM;
}
rc = __load_fw(core);
if (rc)
return rc;
@@ -2311,6 +2426,7 @@ int venus_hfi_core_init(struct msm_vidc_core *core)
error:
d_vpr_h("%s(): failed\n", __func__);
__unload_fw(core);
kfree(core->response_packet);
kfree(core->packet);
return rc;
}

Vedi File

@@ -0,0 +1,469 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
*/
#include "hfi_packet.h"
#include "venus_hfi.h"
#include "venus_hfi_response.h"
#include "msm_vidc_debug.h"
#include "msm_vidc_driver.h"
bool is_valid_hfi_port(struct msm_vidc_inst *inst, u32 port,
const char *func)
{
if (!inst) {
s_vpr_e(inst->sid, "%s: invalid params\n", func);
return false;
}
if (port != HFI_PORT_BITSTREAM && port != HFI_PORT_RAW) {
s_vpr_e(inst->sid, "%s: invalid port %#x\n", func, port);
return false;
}
return true;
}
bool is_valid_hfi_buffer_type(struct msm_vidc_inst *inst,
u32 buffer_type, const char *func)
{
if (!inst) {
s_vpr_e(inst->sid, "%s: invalid params\n", func);
return false;
}
if (buffer_type != HFI_BUFFER_BITSTREAM &&
buffer_type != HFI_BUFFER_RAW &&
buffer_type != HFI_BUFFER_METADATA) {
s_vpr_e(inst->sid, "%s: invalid buffer type %#x\n",
func, buffer_type);
return false;
}
return true;
}
static int signal_session_msg_receipt(struct msm_vidc_inst *inst,
enum signal_session_response cmd)
{
if (cmd < MAX_SIGNAL)
complete(&inst->completions[cmd]);
return 0;
}
int validate_packet(u8 *response_pkt, u8 *core_resp_pkt,
u32 core_resp_pkt_size, const char *func)
{
u8 *response_limit;
if (!response_pkt || !core_resp_pkt || !core_resp_pkt_size) {
d_vpr_e("%s: invalid params\n", func);
return -EINVAL;
}
response_limit = core_resp_pkt + core_resp_pkt_size -
max(sizeof(struct hfi_header), sizeof(struct hfi_packet));
if (response_pkt < core_resp_pkt || response_pkt > response_limit) {
d_vpr_e("%s: invalid packet address\n", func);
return -EINVAL;
}
if (response_pkt + *(u32 *)response_pkt > response_limit) {
d_vpr_e("%s: invalid packet size %d\n",
func, *(u32 *)response_pkt);
return -EINVAL;
}
return 0;
}
static int handle_session_error(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
int rc = 0;
char *error;
switch (pkt->type) {
case HFI_ERROR_MAX_SESSIONS:
error = "exceeded max sessions";
break;
case HFI_ERROR_UNSUPPORTED:
error = "unsupported bitstream";
break;
default:
error = "unknown";
break;
}
s_vpr_e(inst->sid, "session error (%#x): %s\n", pkt->type, error);
rc = msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
return rc;
}
static int handle_system_error(struct msm_vidc_core *core,
struct hfi_packet *pkt)
{
mutex_lock(&core->lock);
if (core->state == MSM_VIDC_CORE_DEINIT) {
d_vpr_e("%s: core already deinitialized\n", __func__);
mutex_unlock(&core->lock);
return 0;
}
d_vpr_e("%s: system error received\n", __func__);
core->state = MSM_VIDC_CORE_DEINIT;
mutex_unlock(&core->lock);
return 0;
}
static int handle_system_init(struct msm_vidc_core *core,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
d_vpr_e("%s: received system error\n", __func__);
return 0;
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS) {
d_vpr_h("%s: successful\n", __func__);
complete(&core->init_done);
}
return 0;
}
static int handle_session_open(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
s_vpr_h(inst->sid, "%s: successful\n", __func__);
return 0;
}
static int handle_session_close(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
s_vpr_h(inst->sid, "%s: successful\n", __func__);
signal_session_msg_receipt(inst, SIGNAL_CMD_CLOSE);
return 0;
}
static int handle_session_start(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
s_vpr_h(inst->sid, "%s: successful for port %d\n",
__func__, pkt->port);
return 0;
}
static int handle_session_stop(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
s_vpr_h(inst->sid, "%s: successful for port %d\n",
__func__, pkt->port);
signal_session_msg_receipt(inst, SIGNAL_CMD_STOP);
return 0;
}
static int handle_session_drain(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
}
if (pkt->flags & HFI_FW_FLAGS_SUCCESS)
s_vpr_h(inst->sid, "%s: successful\n", __func__);
return 0;
}
static void handle_input_buffer(struct msm_vidc_inst *inst,
struct hfi_buffer *buffer)
{
}
static void handle_output_buffer(struct msm_vidc_inst *inst,
struct hfi_buffer *buffer)
{
}
static void handle_input_metadata_buffer(struct msm_vidc_inst *inst,
struct hfi_buffer *buffer)
{
}
static void handle_output_metadata_buffer(struct msm_vidc_inst *inst,
struct hfi_buffer *buffer)
{
}
static int handle_session_buffer(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
struct hfi_buffer *buffer;
u32 buf_type = 0, port_type = 0;
if (pkt->flags & HFI_FW_FLAGS_SESSION_ERROR) {
s_vpr_e(inst->sid, "%s: received session error\n", __func__);
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
return 0;
}
port_type = pkt->port;
if (!is_valid_hfi_port(inst, port_type, __func__)) {
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
return 0;
}
buffer = (struct hfi_buffer *)(pkt + sizeof(struct hfi_packet));
buf_type = buffer->type;
if (!is_valid_hfi_buffer_type(inst, buf_type, __func__)) {
msm_vidc_change_inst_state(inst, MSM_VIDC_ERROR);
return 0;
}
s_vpr_h(inst->sid, "%s: Received buffer of type %#x\n",
__func__, buf_type);
if (is_encode_session(inst)) {
if (port_type == HFI_PORT_BITSTREAM) {
if (buf_type == HFI_BUFFER_METADATA)
handle_output_metadata_buffer(inst, buffer);
else if (buf_type == HFI_BUFFER_BITSTREAM)
handle_output_buffer(inst, buffer);
} else if (port_type == HFI_PORT_RAW) {
if (buf_type == HFI_BUFFER_METADATA)
handle_input_metadata_buffer(inst, buffer);
else if (buf_type == HFI_BUFFER_RAW)
handle_input_buffer(inst, buffer);
}
} else if (is_decode_session(inst)) {
if (port_type == HFI_PORT_BITSTREAM) {
if (buf_type == HFI_BUFFER_METADATA)
handle_input_metadata_buffer(inst, buffer);
else if (buf_type == HFI_BUFFER_BITSTREAM)
handle_input_buffer(inst, buffer);
} else if (port_type == HFI_PORT_RAW) {
if (buf_type == HFI_BUFFER_METADATA)
handle_output_metadata_buffer(inst, buffer);
else if (buf_type == HFI_BUFFER_RAW)
handle_output_buffer(inst, buffer);
}
} else {
s_vpr_e(inst->sid, "%s: invalid session\n", __func__);
}
return 0;
}
static int handle_port_settings_change(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
s_vpr_h(inst->sid, "%s: Received port settings change, type %d\n",
__func__, pkt->port);
return 0;
}
static int handle_session_command(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
switch (pkt->type) {
case HFI_CMD_OPEN:
return handle_session_open(inst, pkt);
case HFI_CMD_CLOSE:
return handle_session_close(inst, pkt);
case HFI_CMD_START:
return handle_session_start(inst, pkt);
case HFI_CMD_STOP:
return handle_session_stop(inst, pkt);
case HFI_CMD_DRAIN:
return handle_session_drain(inst, pkt);
case HFI_CMD_BUFFER:
return handle_session_buffer(inst, pkt);
case HFI_CMD_SETTINGS_CHANGE:
return handle_port_settings_change(inst, pkt);
default:
s_vpr_e(inst->sid, "%s: Unsupported command type: %#x\n",
__func__, pkt->type);
return -EINVAL;
}
return 0;
}
static int handle_session_property(struct msm_vidc_inst *inst,
struct hfi_packet *pkt)
{
s_vpr_h(inst->sid, "%s: property type %#x\n", __func__, pkt->type);
return 0;
}
static int handle_image_version_property(struct hfi_packet *pkt)
{
u32 i = 0;
char version[256];
const u32 version_string_size = 128;
u8 *str_image_version;
u32 req_bytes;
req_bytes = pkt->size - sizeof(*pkt);
if (req_bytes < version_string_size) {
d_vpr_e("%s: bad_pkt: %d\n", __func__, req_bytes);
return -EINVAL;
}
str_image_version = (u8 *)pkt + sizeof(struct hfi_packet);
/*
* 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';
d_vpr_h("%s: F/W version: %s\n", __func__, version);
return 0;
}
static int handle_system_property(struct msm_vidc_core *core,
struct hfi_packet *pkt)
{
int rc = 0;
if (pkt->flags & HFI_FW_FLAGS_SYSTEM_ERROR) {
d_vpr_e("%s: received system error for property type %#x\n",
__func__, pkt->type);
return handle_system_error(core, pkt);
}
switch (pkt->type) {
case HFI_PROP_IMAGE_VERSION:
rc = handle_image_version_property(pkt);
break;
default:
d_vpr_h("%s: property type %#x successful\n",
__func__, pkt->type);
break;
}
return rc;
}
static int handle_system_response(struct msm_vidc_core *core,
struct hfi_header *hdr)
{
int rc = 0;
struct hfi_packet *pkt;
int i;
pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
for (i = 0; i < hdr->num_packets; i++) {
if (!validate_packet((u8 *)pkt, core->response_packet,
core->packet_size, __func__))
return -EINVAL;
if (pkt->type == HFI_CMD_INIT) {
rc = handle_system_init(core, pkt);
} else if (pkt->type > HFI_SYSTEM_ERROR_BEGIN &&
pkt->type < HFI_SYSTEM_ERROR_END) {
rc = handle_system_error(core, pkt);
} else if (pkt->type > HFI_PROP_BEGIN &&
pkt->type < HFI_PROP_CODEC) {
rc = handle_system_property(core, pkt);
} else {
d_vpr_e("%s: Unknown packet type: %#x\n",
__func__, pkt->type);
return -EINVAL;
}
pkt += pkt->size;
}
return rc;
}
static int handle_session_response(struct msm_vidc_core *core,
struct hfi_header *hdr)
{
struct hfi_packet *pkt;
struct msm_vidc_inst *inst;
int i, rc = 0;
inst = get_inst(core, hdr->session_id);
if (!inst) {
d_vpr_e("%s: invalid params\n", __func__);
goto exit;
}
pkt = (struct hfi_packet *)(hdr + sizeof(struct hfi_header));
for (i = 0; i < hdr->num_packets; i++) {
if (!validate_packet((u8 *)pkt, core->response_packet,
core->packet_size, __func__))
goto exit;
if (pkt->type < HFI_CMD_END && pkt->type > HFI_CMD_BEGIN) {
rc = handle_session_command(inst, pkt);
} else if (pkt->type > HFI_PROP_BEGIN &&
pkt->type < HFI_PROP_END) {
rc = handle_session_property(inst, pkt);
} else if (pkt->type > HFI_SESSION_ERROR_BEGIN &&
pkt->type < HFI_SESSION_ERROR_END) {
rc = handle_session_error(inst, pkt);
} else {
s_vpr_e(inst->sid, "%s: Unknown packet type: %#x\n",
__func__, pkt->type);
goto exit;
}
pkt += pkt->size;
}
exit:
put_inst(inst);
return rc;
}
int handle_response(struct msm_vidc_core *core, void *response)
{
struct hfi_header *hdr;
if (!core || !response) {
d_vpr_e("%s: invalid params\n", __func__);
return -EINVAL;
}
hdr = (struct hfi_header *)response;
if (!validate_packet((u8 *)hdr, core->response_packet,
core->packet_size, __func__))
return -EINVAL;
if (!hdr->session_id)
return handle_system_response(core, hdr);
else
return handle_session_response(core, hdr);
return 0;
}