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:

committato da
Maheshwar Ajja

parent
55efff9d9f
commit
9a854613cd
3
Makefile
3
Makefile
@@ -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)
|
||||
|
@@ -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__
|
||||
|
@@ -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_
|
||||
|
||||
|
@@ -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_
|
||||
|
@@ -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"); \
|
||||
|
@@ -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);
|
||||
|
@@ -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_
|
||||
|
@@ -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
|
||||
|
@@ -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_
|
||||
|
18
driver/vidc/inc/venus_hfi_response.h
Normal file
18
driver/vidc/inc/venus_hfi_response.h
Normal 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__
|
@@ -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,
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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;
|
||||
|
@@ -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);
|
||||
}
|
||||
}
|
||||
|
@@ -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;
|
||||
}
|
||||
|
469
driver/vidc/src/venus_hfi_response.c
Normal file
469
driver/vidc/src/venus_hfi_response.c
Normal 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;
|
||||
}
|
Fai riferimento in un nuovo problema
Block a user