You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2422 lines
75 KiB

/*
* Copyright (c) Hisilicon Technologies Co., Ltd. 2008-2020. All rights reserved.
* Description: stat drv
* Author: Hisilicon
* Create: 2008-12-16
*/
#include "drv_stat_ext.h"
#include "drv_stat.h"
#include <linux/sort.h>
#include <linux/file.h>
#include <linux/kfifo.h>
#include <linux/uaccess.h>
#include "linux/huanglong/securec.h"
#include "drv_ioctl_stat.h"
#include "drv_proc_ext.h"
#include "soc_log.h"
#include "td_type.h"
#include "osal_ext.h"
#include "drv_module_ext.h"
#include "drv_sys_ext.h"
#define EXT_STAT_PROC_NAME "stat"
#define EXT_STAT_FRAME_COUNT_DEFAULT 20
#define EXT_STAT_FRAME_COUNT_MAX 100
#define EXT_STAT_MAX_PRINTK_LEN 1024
#define EXT_STAT_PROC_BUF_RESERVED 1024
#define EXT_STAT_PROC_BUF_LEN (1024 * 16)
#define EXT_STAT_TASK_DELAY 8
#define EXT_STAT_FIFO_SIZE (1024 * 16)
#define EXT_STAT_PRINT_NUM_OF_LINE 5
#define stat_para_equel_null_return(para, desc, value) do { \
if ((para) == NULL) { \
soc_log_err("%s 0x%x\n", desc, value); \
return; \
} \
} while (0)
typedef struct {
td_char *buffer;
td_u32 len;
td_u32 write_len;
}drv_stat_buf;
typedef struct {
td_u32 mod_id;
td_char module_name[STAT_NAME_LEN_MAX];
/* calc the stat frame count: module cost max min avg */
td_u64 mod_total_cost_max;
td_u64 mod_total_cost_min;
td_u64 mod_total_cost_avg;
td_bool is_calc;
struct osal_list_head node;
}ext_drv_stat_cfg_node;
typedef struct {
td_char step_name[STAT_NAME_LEN_MAX];
td_u64 us_time;
td_bool value_invald;
}ext_drv_stat_step;
typedef struct {
td_u64 mod_total_cost;
td_u64 *step_cost;
}ext_drv_stat_calc;
typedef struct {
/* note: This module id is used for marking between modules on the DFX delay path,
64bit index is the same and the module that instance_id is not equal to 0xFF is the same path. */
td_u8 mod_id; /* index64:56~63bit */
td_u8 instance_id; /* index64:48~55bit */
td_u8 one2multi_id; /* index64:40~47bit */
td_u8 reserved; /* index64:32~39bit */
td_u32 frame_index; /* index64:0~31bit */
}ext_drv_stat_index;
typedef struct {
td_u32 mod_id;
td_char name[STAT_NAME_LEN_MAX];
td_s64 pts;
ext_drv_stat_index stat_index;
td_u32 step_max;
td_u32 step_index;
ext_drv_stat_step *step_info;
ext_drv_stat_calc *calc_result;
/* the stat_module add to the stat_frame module list */
struct osal_list_head node;
}ext_drv_stat_module;
typedef struct {
td_bool is_vaild;
td_bool data_vaild;
td_u32 frame_index;
td_u32 module_count;
osal_spinlock frame_lock;
/* stat module list */
struct osal_list_head module_list;
}ext_drv_stat_frame;
typedef struct {
stat_info info;
td_u64 current_time;
}ext_drv_stat_info;
typedef struct {
/* stat feature is disable for default */
td_bool stat_enable;
/* samping data, the stat_frame no vaild. */
td_bool finish;
td_bool calc;
/* the stat frame count default is 20, the max = 100 */
td_u32 stat_count;
/* The actual number of samples.
The actual number of samples is 2 times that of standard data */
td_u32 sampling_count;
osal_task *stat_task;
/* stat kfifo */
td_void *info_buf;
STRUCT_KFIFO_PTR(ext_drv_stat_info) stat_fifo;
osal_spinlock stat_control;
ext_drv_stat_frame *stat_frame;
}ext_drv_stat_control;
typedef struct {
td_u8 path_index;
td_u32 mod_id;
td_u64 in_mark;
ext_drv_stat_index stat_index;
}ext_drv_stat_mod_info;
typedef struct {
td_char *echo;
td_char *command;
td_char *para1;
td_char *para2;
td_char *path;
td_char *explanation;
}drv_stat_proc_help_info;
typedef struct {
td_u32 mod_step_count;
td_u32 frame_index;
}ext_drv_stat_mark;
static DEFINE_SPINLOCK(fifo_lock);
static DEFINE_SPINLOCK(mod_cfg_lock);
static OSAL_LIST_HEAD(mod_cfg_list);
static ext_drv_stat_control g_stat_control;
/* define module name */
const static td_char *g_mod_name[SOC_ID_TSFW + 1] = {
/* common */
[SOC_ID_SYS] = "sys", /* 0x00 */
[SOC_ID_MODULE] = "module",
[SOC_ID_LOG] = "log",
[SOC_ID_PROC] = "proc",
[SOC_ID_MEM] = "mem",
[SOC_ID_STAT] = "stat",
[SOC_ID_PDM] = "pdm",
[SOC_ID_MEMDEV] = "memdev",
[SOC_ID_MDDRC] = "mddrc",
[SOC_ID_MAILBOX] = "mailbox",
[SOC_ID_RM] = "rm",
[SOC_ID_PM] = "pm",
[SOC_ID_DVFS] = "dvfs",
[SOC_ID_RUNTIME] = "runtime",
[SOC_ID_SPREAD] = "spread",
[SOC_ID_CUSTOM] = "custom",
/* Peripheral */
[SOC_ID_FLASH] = "flash", /* 0x10 */
[SOC_ID_IR] = "ir",
[SOC_ID_I2C] = "i2c",
[SOC_ID_GPIO] = "gpio",
[SOC_ID_GPIO_I2C] = "gpio_i2c",
[SOC_ID_PWM] = "pwm",
[SOC_ID_LSADC] = "lsadc",
[SOC_ID_SPI] = "spi",
[SOC_ID_KEYLED] = "keyled",
[SOC_ID_WDG] = "wdg",
[SOC_ID_CI] = "ci",
[SOC_ID_SCI] = "sci",
[SOC_ID_BEIDOU] = "beidou",
[SOC_ID_BT] = "bt",
[SOC_ID_FRONTEND] = "frontend", /* 0x1E */
"unknown",
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
"unknown", "unknown", "unknown",
/* event */
[SOC_ID_EVENT] = "event", /* 0x2B */
/* Demux */
[SOC_ID_DEMUX] = "demux", /* 0X2C */
"unknown",
"unknown",
"unknown",
/* Security */
[SOC_ID_OTP] = "otp", /* 0x30 */
[SOC_ID_KLAD] = "klad",
[SOC_ID_KEYSLOT] = "keyslot",
[SOC_ID_CIPHER] = "cipher",
[SOC_ID_TSR2RCIPHER] = "tsr2rcipher",
[SOC_ID_CERT] = "cert",
[SOC_ID_TSIO] = "tsio",
[SOC_ID_SSM] = "ssm",
[SOC_ID_VMX_ULTRA] = "vmx_ultra",
[SOC_ID_CASIMAGE] = "casimage",
[SOC_ID_HDCP] = "hdcp", /* 0x3A */
"unknown", "unknown", "unknown", "unknown", "unknown",
/* Audio */
[SOC_ID_SIF] = "sif", /* 0x40 */
[SOC_ID_AIAO] = "aiao",
[SOC_ID_AI] = "ai",
[SOC_ID_AENC] = "aenc",
[SOC_ID_ADEC] = "adec",
[SOC_ID_AFLT] = "aflt",
[SOC_ID_ADSP] = "adsp",
[SOC_ID_ASR] = "asr",
[SOC_ID_TTS] = "tts",
[SOC_ID_AO] = "ao",
[SOC_ID_AMP] = "amp",
[SOC_ID_EARCTX] = "earctx", /* 0x4B */
"unknown", "unknown", "unknown", "unknown",
/* Video and input/output */
[SOC_ID_VFE] = "vfe", /* 0x50 */
[SOC_ID_TVD] = "tvd",
[SOC_ID_HDDEC] = "hddec",
[SOC_ID_VBI] = "vbi",
[SOC_ID_VICAP] = "vicap",
[SOC_ID_VI] = "vi",
[SOC_ID_VENC] = "venc",
[SOC_ID_VFMW] = "vfmw",
[SOC_ID_VDEC] = "vdec",
[SOC_ID_PQ] = "pq",
[SOC_ID_MEMC] = "memc",
[SOC_ID_FRC] = "frc",
[SOC_ID_VPSS] = "vpss",
[SOC_ID_VPLUGIN] = "vplugin",
[SOC_ID_WIN] = "win",
[SOC_ID_DISP] = "disp",
[SOC_ID_HDMIRX] = "hdmirx", /* 0x60 */
[SOC_ID_HDMITX] = "hdmitx",
[SOC_ID_PANEL] = "panel",
[SOC_ID_MIPI] = "mipi",
[SOC_ID_FDMNG] = "fdmng",
[SOC_ID_DISPMNG] = "dispmng",
[SOC_ID_DISPCTRL] = "dispctrl", /* 0x66 */
"unknown", "unknown", "unknown",
[SOC_ID_OMXVENC] = "omxvenc", /* 0x6A */
[SOC_ID_OMXVDEC] = "omxvdec", /* 0x6B */
"unknown", "unknown", "unknown", "unknown",
/* Graphics */
[SOC_ID_FB] = "fb", /* 0x70 */
[SOC_ID_GPU] = "gpu",
[SOC_ID_TDE] = "tde",
[SOC_ID_GFX2D] = "gfx2d",
[SOC_ID_JPGDEC] = "jpgdec",
[SOC_ID_JPGENC] = "jpgenc",
[SOC_ID_PNG] = "png",
[SOC_ID_FUX] = "fux", /* 0x77 */
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
/* Player */
[SOC_ID_AVPLAY] = "avplay", /* 0x80 */
[SOC_ID_SYNC] = "sync",
[SOC_ID_VSYNC] = "vsync",
[SOC_ID_ASYNC] = "async",
[SOC_ID_PVR] = "pvr", /* 0x84 */
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
"unknown", "unknown", "unknown",
/* Component */
[SOC_ID_SUBT] = "subt", /* 0x90 */
[SOC_ID_TTX] = "ttx",
[SOC_ID_CC] = "cc",
[SOC_ID_LOADER] = "loader",
[SOC_ID_KARAOKE] = "karaoke",
[SOC_ID_VP] = "vp",
[SOC_ID_TOKEN] = "token", /* 0x96 */
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
"unknown",
/* Middleware */
[SOC_ID_NETFLIX] = "netflix", /* 0xA0 */
[SOC_ID_TVMW] = "tvmw",
"unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown", "unknown",
/* NPU */
[SOC_ID_NPUDEV] = "npudev", /* 0xAA */
[SOC_ID_AICPU] = "aicpu",
[SOC_ID_NPUDFX] = "npudfx",
[SOC_ID_TSFW] = "tsfw", /* 0xAD */
};
static td_s32 drv_stat_get_module_name(td_u32 mod_id, td_char *name, td_u32 len)
{
td_s32 ret;
if (mod_id >= SOC_ID_MAX || name == TD_NULL) {
soc_log_err("drv stat get module name: input params is error .\n");
return TD_FAILURE;
}
if (mod_id > SOC_ID_TSFW && mod_id < SOC_ID_MAX) {
ret = sprintf_s(name, len - 1, "%s_0x%x", "unkown", mod_id);
if (ret < 0) {
soc_log_err("drv stat get module name: sprintf_s failed.\n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
if (memcpy_s(name, len,
g_mod_name[mod_id], strlen(g_mod_name[mod_id])) != EOK) {
soc_log_err("drv stat get module name: memcpy_s failed.\n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_s32 drv_stat_cmp(const td_void *a, const td_void *b)
{
return (td_s32)(*(td_u64 *)a - *(td_u64 *)b);
}
static td_s32 drv_stat_module_sampling_sort(td_u64 *sampling, td_u32 len)
{
if (sampling == TD_NULL || len == 0) {
soc_log_err("input params are invalid.\n");
return TD_FAILURE;
}
sort(sampling, len, sizeof(td_u64), drv_stat_cmp, TD_NULL);
return TD_SUCCESS;
}
static ext_drv_stat_cfg_node *drv_stat_module_find_node(const struct osal_list_head *list, td_u32 mod_id)
{
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
osal_list_for_each_entry(cfg_node, list, node) {
if (cfg_node->mod_id == mod_id) {
return cfg_node;
}
}
return TD_NULL;
}
static td_s32 drv_stat_module_list_find_node(td_u32 mod_id)
{
td_ulong flags;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
spin_lock_irqsave(&mod_cfg_lock, flags);
cfg_node = drv_stat_module_find_node(&mod_cfg_list, mod_id);
if (cfg_node != TD_NULL) {
spin_unlock_irqrestore(&mod_cfg_lock, flags);
return TD_SUCCESS;
}
spin_unlock_irqrestore(&mod_cfg_lock, flags);
return TD_FAILURE;
}
static td_void drv_stat_add_module(ext_drv_stat_cfg_node *mod_cfg)
{
td_ulong flags;
if (mod_cfg == NULL) {
soc_log_err("input params is null\n");
return;
}
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_add_tail(&mod_cfg->node, &mod_cfg_list);
spin_unlock_irqrestore(&mod_cfg_lock, flags);
}
static td_void drv_stat_remove_one_module(const ext_drv_stat_cfg_node *mod_cfg)
{
if (mod_cfg == TD_NULL) {
soc_log_err("mod_cfg is null\n");
return;
}
osal_kfree(mod_cfg);
mod_cfg = TD_NULL;
}
static td_void drv_stat_remove_all_module(td_void)
{
td_ulong flags;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_for_each_safe(pos, nex, &mod_cfg_list) {
cfg_node = osal_list_entry(pos, ext_drv_stat_cfg_node, node);
if (cfg_node != TD_NULL) {
drv_stat_remove_one_module(cfg_node);
cfg_node = TD_NULL;
osal_list_del_init(pos);
}
}
spin_unlock_irqrestore(&mod_cfg_lock, flags);
}
static td_void drv_stat_reset_module_calc_flag(td_void)
{
td_ulong flags;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
cfg_node->is_calc = TD_FALSE;
}
spin_unlock_irqrestore(&mod_cfg_lock, flags);
}
td_void drv_stat_module_cfg_release(const ext_drv_stat_cfg_node *module_node)
{
if (module_node == TD_NULL) {
soc_log_err("module_node is null.\n");
return;
}
osal_kfree(module_node);
module_node = TD_NULL;
}
ext_drv_stat_cfg_node *drv_stat_module_cfg_malloc(td_void)
{
ext_drv_stat_cfg_node *module_node = TD_NULL;
/* module configure */
module_node = osal_kmalloc(sizeof(ext_drv_stat_cfg_node), OSAL_GFP_KERNEL);
if (module_node == TD_NULL) {
soc_log_err("drv stat module cfg malloc: osal kmalloc for stat module node failed.\n");
return TD_NULL;
}
if (memset_s(module_node, sizeof(ext_drv_stat_cfg_node), 0x0, sizeof(ext_drv_stat_cfg_node)) != EOK) {
soc_log_err("drv_stat_module_cfg_malloc: memset_s failure .\n");
drv_stat_module_cfg_release(module_node);
module_node = TD_NULL;
return TD_NULL;
}
return module_node;
}
td_s32 drv_stat_module_cfg(td_u32 mod_id)
{
td_s32 ret;
ext_drv_stat_cfg_node *module_node = TD_NULL;
ret = drv_stat_module_list_find_node(mod_id);
if (ret == TD_SUCCESS) {
/* this mod & index is configured */
return TD_SUCCESS;
}
module_node = drv_stat_module_cfg_malloc();
if (module_node == TD_NULL) {
return TD_FAILURE;
}
module_node->mod_id = mod_id;
module_node->is_calc = TD_FALSE;
ret = drv_stat_get_module_name(mod_id, module_node->module_name, STAT_NAME_LEN_MAX);
if (ret != TD_SUCCESS) {
drv_stat_module_cfg_release(module_node);
module_node = TD_NULL;
return TD_FAILURE;
}
/* add node */
drv_stat_add_module(module_node);
return TD_SUCCESS;
}
static td_void drv_stat_index_transformation(td_u64 index, ext_drv_stat_index *stat_index)
{
if (stat_index == TD_NULL) {
soc_log_err("input param error.\n");
return;
}
stat_index->frame_index = (td_u32)(index & 0xffffffff);
/* note: This module id is used for marking between modules on the DFX delay path,
64bit index is the same and the module that reserved is not equal to 0xFF is the same path. */
stat_index->mod_id = (td_u8)(((index >> 0x20) & 0xff000000) >> 0x18);
stat_index->instance_id = (td_u8)(((index >> 0x20) & 0xff0000) >> 0x10);
stat_index->one2multi_id = (td_u8)(((index >> 0x20) & 0xff00) >> 0x8);
/* if reserved == 0xFF, Only in-module performance is counted. */
stat_index->reserved = (td_u8)((index >> 0x20) & 0xff);
}
static ext_drv_stat_module *drv_stat_list_get_module(const struct osal_list_head *list, const stat_info *info)
{
ext_drv_stat_index stat_index;
ext_drv_stat_module *mod_node = TD_NULL;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
drv_stat_index_transformation(info->index, &stat_index);
osal_list_for_each_safe(pos, nex, list) {
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
if (mod_node->mod_id == info->mod_id &&
mod_node->stat_index.mod_id == stat_index.mod_id &&
mod_node->stat_index.frame_index == stat_index.frame_index &&
mod_node->stat_index.instance_id == stat_index.instance_id &&
mod_node->stat_index.one2multi_id == stat_index.one2multi_id) {
return mod_node;
}
}
return TD_NULL;
}
static ext_drv_stat_module *drv_stat_list_get_module_by_module_id(const struct osal_list_head *list, td_u8 mod_id)
{
ext_drv_stat_module *mod_node = TD_NULL;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
osal_list_for_each_safe(pos, nex, list) {
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
if (mod_node->mod_id == mod_id) {
return mod_node;
}
}
return TD_NULL;
}
static ext_drv_stat_frame *drv_stat_get_frame_by_index(td_u32 frame_index)
{
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (g_stat_control.stat_frame == TD_NULL) {
soc_log_err("g_stat_frame is null.\n");
return TD_NULL;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->frame_index == frame_index) {
return stat_frame;
}
}
return TD_NULL;
}
static ext_drv_stat_frame *drv_stat_get_frame_valid(td_void)
{
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (g_stat_control.stat_frame == TD_NULL) {
soc_log_err("g_stat_frame is null.\n");
return TD_NULL;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->is_vaild == TD_TRUE) {
return stat_frame;
}
}
return TD_NULL;
}
static td_s32 drv_stat_calc_malloc(ext_drv_stat_module *stat_mod)
{
errno_t err_ret;
if (stat_mod == NULL) {
soc_log_err("drv stat calc malloc: input params is null\n");
return TD_FAILURE;
}
stat_mod->calc_result = osal_kmalloc(sizeof(ext_drv_stat_calc), OSAL_GFP_KERNEL);
if (stat_mod->calc_result == TD_NULL) {
soc_log_err("drv stat calc malloc: malloc failed.\n");
return TD_FAILURE;
}
err_ret = memset_s(stat_mod->calc_result, sizeof(ext_drv_stat_calc), 0x0, sizeof(ext_drv_stat_calc));
if (err_ret != EOK) {
soc_log_err("drv stat calc malloc: memset_s failure .\n");
osal_kfree(stat_mod->calc_result);
stat_mod->calc_result = TD_NULL;
return TD_FAILURE;
}
stat_mod->calc_result->step_cost = osal_kmalloc(sizeof(td_u64) * (stat_mod->step_max - 1),
OSAL_GFP_KERNEL);
if (stat_mod->calc_result->step_cost == TD_NULL) {
soc_log_err("drv stat calc malloc: step action malloc failed .\n");
osal_kfree(stat_mod->calc_result);
stat_mod->calc_result = TD_NULL;
return TD_FAILURE;
}
err_ret = memset_s(stat_mod->calc_result->step_cost, sizeof(td_u64) * (stat_mod->step_max - 1), 0x0,
sizeof(td_u64) * (stat_mod->step_max - 1));
if (err_ret != EOK) {
soc_log_err("drv stat calc malloc: memset_s failure .\n");
osal_kfree(stat_mod->calc_result->step_cost);
stat_mod->calc_result->step_cost = TD_NULL;
osal_kfree(stat_mod->calc_result);
stat_mod->calc_result = TD_NULL;
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_void drv_stat_calc_release(ext_drv_stat_module *stat_mod)
{
if (stat_mod == NULL || stat_mod->calc_result == TD_NULL) {
/* We only calculate the input sampling data, and not some of the data is involved in the calculation.
So there is no allocated space. */
return;
}
if (stat_mod->calc_result->step_cost != TD_NULL) {
osal_kfree(stat_mod->calc_result->step_cost);
stat_mod->calc_result->step_cost = TD_NULL;
}
if (stat_mod->calc_result != TD_NULL) {
osal_kfree(stat_mod->calc_result);
stat_mod->calc_result = TD_NULL;
}
}
static td_s32 drv_stat_step_cmp(const td_void *a, const td_void *b)
{
ext_drv_stat_step *tmp1 = (ext_drv_stat_step *)a;
ext_drv_stat_step *tmp2 = (ext_drv_stat_step *)b;
if (tmp1->us_time > tmp2->us_time) {
return 1;
} else if (tmp1->us_time == tmp2->us_time) {
return 0;
} else {
return -1;
}
return 0;
}
static td_void drv_stat_step_sort(ext_drv_stat_step *step, td_u32 size)
{
if (step == TD_NULL || size == 0) {
soc_log_err("input params are invalid.\n");
return;
}
sort(step, size, sizeof(ext_drv_stat_step), drv_stat_step_cmp, TD_NULL);
return;
}
static td_void drv_stat_calc_module_cost(ext_drv_stat_module *stat_mod)
{
td_u32 i;
ext_drv_stat_step *stat_step = TD_NULL;
ext_drv_stat_step *stat_step_n = TD_NULL;
ext_drv_stat_step *step_out = TD_NULL;
ext_drv_stat_step *step_in = TD_NULL;
td_bool in_flag = TD_FALSE;
if (stat_mod == NULL || stat_mod->step_info == TD_NULL) {
soc_log_err("input params is null\n");
return;
}
/* should sort, igore invalid value */
drv_stat_step_sort(stat_mod->step_info, stat_mod->step_max);
for (i = 0; i < stat_mod->step_max - 1; i++) {
stat_step = &stat_mod->step_info[i];
if (stat_step->value_invald == TD_FALSE) {
continue;
}
if (in_flag == TD_FALSE && stat_step->value_invald == TD_TRUE) {
in_flag = TD_TRUE;
step_in = stat_step;
}
stat_step_n = &stat_mod->step_info[i + 1];
step_out = stat_step_n;
if (stat_mod->calc_result == TD_NULL) {
return;
}
stat_mod->calc_result->step_cost[i] = stat_step_n->us_time - stat_step->us_time;
}
/* calc this module cost totaly */
if (step_out == TD_NULL || step_in == TD_NULL) {
soc_log_err("some error .. samping step data error.\n");
return;
}
stat_mod->calc_result->mod_total_cost = step_out->us_time - step_in->us_time;
}
static td_s32 drv_stat_step_action_malloc(ext_drv_stat_module *stat_mod)
{
ext_drv_stat_step *tmp = TD_NULL;
td_u32 i;
if (stat_mod == NULL) {
soc_log_err("input params is null\n");
return TD_FAILURE;
}
stat_mod->step_info = osal_kmalloc(sizeof(ext_drv_stat_step) * stat_mod->step_max, OSAL_GFP_KERNEL);
if (stat_mod->step_info == TD_NULL) {
soc_log_err("step action malloc failed .\n");
return TD_FAILURE;
}
for (i = 0; i < stat_mod->step_max; i++) {
tmp = &stat_mod->step_info[i];
if (memset_s(tmp->step_name, sizeof(tmp->step_name), 0x0, sizeof(tmp->step_name)) != EOK) {
osal_kfree(stat_mod->step_info);
stat_mod->step_info = TD_NULL;
soc_log_err("memset_s failure .\n");
return TD_FAILURE;
}
tmp->us_time = 0;
tmp->value_invald = TD_FALSE;
}
return TD_SUCCESS;
}
static td_void drv_stat_step_action_release(ext_drv_stat_module *stat_mod)
{
if (stat_mod == NULL) {
soc_log_err("input params is null\n");
return;
}
if (stat_mod->step_info != TD_NULL) {
osal_kfree(stat_mod->step_info);
stat_mod->step_info = TD_NULL;
}
}
static td_void drv_stat_step_action_mark(td_u64 cur_time, const stat_info *info, ext_drv_stat_module *stat_mod)
{
td_u32 i;
td_bool is_find_same_step = TD_FALSE;
ext_drv_stat_step *stat_step = TD_NULL;
if (info == TD_NULL || stat_mod == TD_NULL) {
soc_log_err("input params are invalild.\n");
return;
}
/* 1. Some events may be threaded, interrupted, and event messages are not sequential to trigger notify functions.
2. Some events may not be issued.
3. There is a case where a frame is processed or dropped multiple times, such as frame rate conversion */
/* the same events trigger notify function, we update the data. */
if (stat_mod->step_index < stat_mod->step_max) {
/* if step_name exists in the node of module, do not mark it.
It means it is only record the first same step. (Interlaced streams) */
for (i = 0; i < stat_mod->step_max; i++) {
stat_step = &stat_mod->step_info[i];
if (strcmp(info->step_name, stat_step->step_name) == 0) {
is_find_same_step = TD_TRUE;
break;
}
}
if (is_find_same_step == TD_FALSE) {
/* get this module end step information, then we should calc the step cost */
stat_step = &stat_mod->step_info[stat_mod->step_index];
stat_step->us_time = cur_time;
stat_step->value_invald = TD_TRUE;
if (memcpy_s(stat_step->step_name, STAT_NAME_LEN_MAX, info->step_name, strlen(info->step_name)) != EOK) {
soc_log_err("memcpy_s step_name failed.\n");
return;
}
stat_mod->step_index++;
}
}
}
static ext_drv_stat_module *drv_stat_module_create(const stat_info *info)
{
td_s32 ret;
ext_drv_stat_module *stat_mod = TD_NULL;
if (info == TD_NULL) {
return TD_NULL;
}
stat_mod = osal_kmalloc(sizeof(ext_drv_stat_module), OSAL_GFP_KERNEL);
if (stat_mod == TD_NULL) {
soc_log_err("malloc failed .\n");
return TD_NULL;
}
if (memset_s(stat_mod, sizeof(ext_drv_stat_module), 0x0, sizeof(ext_drv_stat_module)) != EOK) {
soc_log_err("memset-s failed.\n");
goto out0;
}
stat_mod->mod_id = info->mod_id;
stat_mod->pts = info->pts;
stat_mod->step_max = info->step_max;
stat_mod->step_index = 0;
ret = drv_stat_get_module_name(info->mod_id, stat_mod->name, STAT_NAME_LEN_MAX);
if (ret != TD_SUCCESS) {
soc_log_err("get mod name failed.\n");
goto out0;
}
drv_stat_index_transformation(info->index, &stat_mod->stat_index);
ret = drv_stat_step_action_malloc(stat_mod);
if (ret != TD_SUCCESS) {
soc_log_err("step action malloc failed\n");
goto out0;
}
return stat_mod;
out0:
osal_kfree(stat_mod);
stat_mod = TD_NULL;
return TD_NULL;
}
static td_void drv_stat_module_release(ext_drv_stat_frame *stat_frame)
{
ext_drv_stat_module *mod_node = TD_NULL;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
if (stat_frame == TD_NULL || stat_frame->module_list.next == TD_NULL) {
soc_log_err("stat module release:para is NULL. \n");
return;
}
osal_spin_lock(&stat_frame->frame_lock);
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
if (mod_node != TD_NULL) {
drv_stat_step_action_release(mod_node);
drv_stat_calc_release(mod_node);
osal_list_del_init(pos);
osal_kfree(mod_node);
mod_node = TD_NULL;
}
}
osal_spin_unlock(&stat_frame->frame_lock);
}
static td_void drv_stat_frame_calc_release(ext_drv_stat_frame *stat_frame)
{
ext_drv_stat_module *mod_node = TD_NULL;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
if (stat_frame == TD_NULL || stat_frame->module_list.next == TD_NULL) {
soc_log_err("stat frame calc release: para is NULL. \n");
return;
}
osal_spin_lock(&stat_frame->frame_lock);
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
mod_node = osal_list_entry(pos, ext_drv_stat_module, node);
if (mod_node != TD_NULL) {
drv_stat_calc_release(mod_node);
}
}
osal_spin_unlock(&stat_frame->frame_lock);
}
static td_s32 drv_stat_calc_module_avg(const td_u64 *sampling, td_u32 size, td_u64 *avg)
{
td_u32 i;
td_u64 total = 0;
if (sampling == TD_NULL || avg == TD_NULL) {
return TD_FAILURE;
}
if (size > g_stat_control.stat_count) {
soc_log_err("input size :0x%x error.\n", size);
return TD_FAILURE;
}
for (i = 0; i < size - 1; i++) {
total += sampling[size - 1] - sampling[i];
}
if (size != 0) {
*avg = (td_u64)(sampling[0] + ((total * 0xa) / size + 0x5) / 0xa);
}
return TD_SUCCESS;
}
static td_s32 drv_stat_calc_get_modulle_cost(
const ext_drv_stat_cfg_node *cfg_node, td_u64 *sampling, td_u32 *cost_count)
{
td_s32 ret;
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
ext_drv_stat_module *stat_module = TD_NULL;
td_u32 count = 0;
if (cfg_node == TD_NULL || sampling == TD_NULL || cost_count == TD_NULL) {
soc_log_err("input params null.\n");
return TD_FAILURE;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->data_vaild == TD_FALSE) {
continue;
}
if (count >= g_stat_control.stat_count) {
break;
}
osal_spin_lock(&stat_frame->frame_lock);
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, cfg_node->mod_id);
if (stat_module == TD_NULL) {
osal_spin_unlock(&stat_frame->frame_lock);
soc_log_err("donot find node by mod_id:0x%x\n", cfg_node->mod_id);
return TD_FAILURE;
}
ret = drv_stat_calc_malloc(stat_module);
if (ret != TD_SUCCESS) {
osal_spin_unlock(&stat_frame->frame_lock);
return TD_FAILURE;
}
drv_stat_calc_module_cost(stat_module);
if (stat_module->calc_result != TD_NULL) {
sampling[count++] = stat_module->calc_result->mod_total_cost;
} else {
soc_log_err("calc result is NULL : mod_id: 0x%x\n", cfg_node->mod_id);
}
osal_spin_unlock(&stat_frame->frame_lock);
}
if (count < g_stat_control.stat_count) {
soc_log_err("stat data some error, sample valid data %d < %d\n", count, g_stat_control.stat_count);
return TD_FAILURE;
}
*cost_count = count;
return TD_SUCCESS;
}
static td_s32 drv_stat_calc_by_module(td_u64 *sampling, ext_drv_stat_cfg_node *cfg_node)
{
td_s32 ret;
td_u64 avg;
td_u32 count = 0;
if (cfg_node == TD_NULL || sampling == TD_NULL) {
soc_log_err("input params null.\n");
return TD_FAILURE;
}
ret = drv_stat_calc_get_modulle_cost(cfg_node, sampling, &count);
if (ret != TD_SUCCESS) {
soc_log_err("calc module : 0x%x failed.\n", cfg_node->mod_id);
return TD_FAILURE;
}
ret = drv_stat_module_sampling_sort(sampling, count);
if (ret != TD_SUCCESS) {
soc_log_err("sort faile..\n");
return TD_FAILURE;
}
cfg_node->mod_total_cost_min = sampling[0];
cfg_node->mod_total_cost_max = sampling[count - 1];
ret = drv_stat_calc_module_avg(sampling, count, &avg);
if (ret != TD_SUCCESS) {
soc_log_err("calc avg failed.\n");
return TD_FAILURE;
}
cfg_node->mod_total_cost_avg = avg;
cfg_node->is_calc = TD_TRUE;
return TD_SUCCESS;
}
static ext_drv_stat_mark *drv_stat_malloc_mark(td_void)
{
td_u32 i;
td_u32 samp_count;
ext_drv_stat_mark *mark = TD_NULL;
samp_count = g_stat_control.sampling_count;
mark = osal_kmalloc(sizeof(ext_drv_stat_mark) * samp_count, OSAL_GFP_KERNEL);
if (mark == TD_NULL) {
soc_log_err("malloc failed .\n");
return TD_NULL;
}
for (i = 0; i < samp_count; i++) {
mark[i].frame_index = 0;
mark[i].mod_step_count = 0;
}
return mark;
}
static td_s32 drv_stat_mark_cmp(const td_void *a, const td_void *b)
{
ext_drv_stat_mark *tmp1 = (ext_drv_stat_mark *)a;
ext_drv_stat_mark *tmp2 = (ext_drv_stat_mark *)b;
return tmp1->mod_step_count - tmp2->mod_step_count;
}
static td_void drv_stat_mark_sort(ext_drv_stat_mark *step, td_u32 size)
{
if (step == TD_NULL || size == 0) {
soc_log_err("input params are invalid.\n");
return;
}
sort(step, size, sizeof(ext_drv_stat_mark), drv_stat_mark_cmp, TD_NULL);
return;
}
static td_void drv_stat_mark_process(const ext_drv_stat_cfg_node *cfg_node, ext_drv_stat_mark *mark)
{
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
ext_drv_stat_module *stat_module = TD_NULL;
td_u32 max_step_count;
if (cfg_node == TD_NULL || mark == TD_NULL) {
soc_log_err("input params null.\n");
return;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
osal_spin_lock(&stat_frame->frame_lock);
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, cfg_node->mod_id);
if (stat_module == TD_NULL) {
mark[i].frame_index = stat_frame->frame_index;
mark[i].mod_step_count = 0;
} else {
mark[i].frame_index = stat_module->stat_index.frame_index;
mark[i].mod_step_count = stat_module->step_index;
}
osal_spin_unlock(&stat_frame->frame_lock);
}
/* sort by step count */
drv_stat_mark_sort(mark, g_stat_control.sampling_count);
/* the last mark is the max step count after sort */
max_step_count = mark[g_stat_control.sampling_count - 1].mod_step_count;
/* mark invalid data */
for (i = 0; i < g_stat_control.sampling_count; i++) {
if (mark[i].mod_step_count != max_step_count) {
stat_frame = drv_stat_get_frame_by_index(mark[i].frame_index);
if (stat_frame != TD_NULL) {
stat_frame->data_vaild = TD_FALSE;
/* shoul make this stat_frame to vaild... */
}
}
}
}
static td_void drv_stat_mark_invalid_samping(td_void)
{
td_u32 samp_count;
ext_drv_stat_mark *mark = TD_NULL;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
td_ulong flags;
samp_count = g_stat_control.sampling_count;
mark = drv_stat_malloc_mark();
if (mark == TD_NULL) {
soc_log_err("malloc mark memory failed.\n");
return;
}
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
drv_stat_mark_process(cfg_node, mark);
}
spin_unlock_irqrestore(&mod_cfg_lock, flags);
osal_kfree(mark);
mark = TD_NULL;
return;
}
static td_s32 drv_stat_calc_all_module(td_void)
{
td_s32 ret;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
td_u32 frame_count;
td_u64 *mod_cost = TD_NULL;
td_ulong flags;
frame_count = g_stat_control.stat_count;
mod_cost = osal_kmalloc(sizeof(td_u64) * frame_count, OSAL_GFP_KERNEL);
if (mod_cost == TD_NULL) {
soc_log_err("malloc failed .\n");
return TD_FAILURE;
}
if (memset_s(mod_cost, sizeof(td_u64) * frame_count, 0x0, sizeof(td_u64) * frame_count) != EOK) {
soc_log_err("memset_s failed.\n");
osal_kfree(mod_cost);
mod_cost = TD_NULL;
return TD_FAILURE;
}
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_for_each_entry(cfg_node, &mod_cfg_list, node) {
if (cfg_node->is_calc == TD_TRUE) {
continue;
}
ret = drv_stat_calc_by_module(mod_cost, cfg_node);
if (ret != TD_SUCCESS) {
soc_log_err("clac avg mod :0x%x\n", cfg_node->mod_id);
ret = TD_FAILURE;
goto out;
}
}
ret = TD_SUCCESS;
out:
spin_unlock_irqrestore(&mod_cfg_lock, flags);
osal_kfree(mod_cost);
mod_cost = TD_NULL;
return ret;
}
static ext_drv_stat_frame *drv_stat_get_frame(const stat_info *info)
{
td_u32 frame_index;
ext_drv_stat_frame *stat_frame = TD_NULL;
/* get frame index */
frame_index = (td_u32)(info->index & 0xFFFFFFFF);
/* get stat_frame by index */
stat_frame = drv_stat_get_frame_by_index(frame_index);
if (stat_frame != TD_NULL) {
return stat_frame;
}
/* Determines whether the module info data is valid.
The judgment based on the first event must be step number is 0x1. */
/* find one vaild stat frame */
stat_frame = drv_stat_get_frame_valid();
if (stat_frame != TD_NULL) {
stat_frame->is_vaild = TD_FALSE;
return stat_frame;
}
/* Some modules get video frame processing and wait until the next dozen frames come out. */
g_stat_control.finish = TD_TRUE;
return TD_NULL;
}
static td_s32 drv_stat_info_notify_process(const stat_info *info, ext_drv_stat_frame *stat_frame, td_u64 current_us)
{
ext_drv_stat_module *module_node = TD_NULL;
if (info == TD_NULL || stat_frame == TD_NULL) {
return TD_FAILURE;
}
osal_spin_lock(&stat_frame->frame_lock);
/* find the stat module by frame index & mod id instance_id etc.. */
module_node = drv_stat_list_get_module(&stat_frame->module_list, info);
if (module_node != TD_NULL) {
/* mark other steps time */
drv_stat_step_action_mark(current_us, info, module_node);
osal_spin_unlock(&stat_frame->frame_lock);
return TD_SUCCESS;
}
osal_spin_unlock(&stat_frame->frame_lock);
/* the module id is not in the stat_frame module list.
so create new one and add to the module_list */
stat_frame->frame_index = (td_u32)(info->index & 0xFFFFFFFF);
module_node = drv_stat_module_create(info);
if (module_node == TD_NULL) {
soc_log_err("create stat module node failed.\n");
return TD_FAILURE;
}
/* mark first step time */
drv_stat_step_action_mark(current_us, info, module_node);
osal_spin_lock(&stat_frame->frame_lock);
/* add stat_mod to stat_frame_list */
osal_list_add_tail(&module_node->node, &(stat_frame->module_list));
stat_frame->module_count++;
osal_spin_unlock(&stat_frame->frame_lock);
return TD_SUCCESS;
}
static td_s32 drv_stat_info_notify(const ext_drv_stat_info *sampling_info)
{
td_s32 ret;
const stat_info *info = TD_NULL;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (sampling_info == TD_NULL) {
return TD_FAILURE;
}
info = &sampling_info->info;
ret = drv_stat_module_cfg(info->mod_id);
if (ret != TD_SUCCESS) {
soc_log_err("mod id:0x%x add module cfg list failed!\n", info->mod_id);
return TD_FAILURE;
}
stat_frame = drv_stat_get_frame(info);
if (stat_frame == TD_NULL) {
soc_log_info(" stat finish to get frame information.\n");
return TD_SUCCESS;
}
ret = drv_stat_info_notify_process(info, stat_frame, sampling_info->current_time);
if (ret != TD_SUCCESS) {
soc_log_err("notify process failed . \n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
td_s32 ext_drv_stat_info_notify(const stat_info *info)
{
ext_drv_stat_info notify_info;
td_u64 current_us = osal_sched_clock();
if (g_stat_control.stat_enable == TD_FALSE) {
/* the stat feature dose not affect business process, so we should return SUCCESS */
return TD_SUCCESS;
}
if (g_stat_control.calc == TD_TRUE) {
/* calc complete no need insert */
return TD_SUCCESS;
}
if (kfifo_is_full(&g_stat_control.stat_fifo)) {
/* Sampled data fills up the 4M memory of the kfifo malloced.
Later you need to implement real-time sampling data acquisition to kfifo_reset and reset related flags.
for example : kfifo_reset calc finish flag... */
return TD_SUCCESS;
}
if (info == TD_NULL) {
soc_log_err("invalid input params is null.\n");
return TD_FAILURE;
}
if (memcpy_s(&notify_info.info, sizeof(notify_info.info), info, sizeof(stat_info)) != EOK) {
soc_log_err("memcpy_s failed.\n");
return TD_FAILURE;
}
notify_info.info.index |= ((td_u64)(notify_info.info.mod_id & 0xFF)) << 56; /* bits[56~63] is mod_id */
notify_info.current_time = current_us + info->delta;
kfifo_in_spinlocked(&g_stat_control.stat_fifo, &notify_info, 1, &fifo_lock);
return TD_SUCCESS;
}
td_s32 drv_stat_ioctl(td_u32 cmd, td_void *arg, td_void *private_data)
{
switch (cmd) {
case STAT_CMPI_EVENT: {
break;
}
case STAT_CMPI_LD_EVENT: {
break;
}
case STAT_INFO_NOTIFY: {
if (arg != TD_NULL) {
return ext_drv_stat_info_notify((stat_info *)arg);
}
break;
}
default:
soc_log_err("unknown command 0x%x\n", cmd);
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_s32 drv_proc_buf_reset(drv_stat_buf *buf)
{
td_u32 buf_len = sizeof(td_char) * EXT_STAT_PROC_BUF_LEN;
if (buf == TD_NULL || buf->buffer == TD_NULL) {
soc_log_err("input params is null.\n");
return TD_FAILURE;
}
if (memset_s(buf->buffer, buf_len, 0x0, buf_len) != EOK) {
soc_log_err("memset_s failed ..\n");
return TD_FAILURE;
}
buf->len = buf_len;
buf->write_len = 0;
return TD_SUCCESS;
}
static td_s32 drv_proc_buf_malloc(drv_stat_buf *buf)
{
td_s32 ret;
td_u32 buf_len = sizeof(td_char) * EXT_STAT_PROC_BUF_LEN;
if (buf == TD_NULL) {
soc_log_err("input params is null.\n");
return TD_FAILURE;
}
buf->buffer = osal_kmalloc(buf_len, OSAL_GFP_KERNEL);
if (buf->buffer == TD_NULL) {
soc_log_err("malloc for mod details failed.\n");
return TD_FAILURE;
}
ret = drv_proc_buf_reset(buf);
if (ret != TD_SUCCESS) {
osal_kfree(buf->buffer);
buf->buffer = TD_NULL;
return TD_FAILURE;
}
return TD_SUCCESS;
}
static td_void drv_proc_buf_release(drv_stat_buf *buf)
{
if (buf == TD_NULL || buf->buffer == TD_NULL) {
return;
}
osal_kfree(buf->buffer);
buf->buffer = TD_NULL;
buf->len = 0;
buf->write_len = 0;
}
static td_void drv_stat_proc_print_module(td_void *s)
{
td_ulong flags;
ext_drv_stat_cfg_node *module_node = TD_NULL;
spin_lock_irqsave(&mod_cfg_lock, flags);
osal_list_for_each_entry(module_node, &mod_cfg_list, node) {
osal_seq_printf(s, "module_name:\t%-16s\tcost_avg:\t%-16llu\tcost_min:\t%-16llu\tcost_max:\t%-16llu\n",
module_node->module_name,
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_avg, 1000000), /* 1000000, ns to ms */
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_min, 1000000), /* 1000000, ns to ms */
DIV_ROUND_CLOSEST_ULL(module_node->mod_total_cost_max, 1000000)); /* 1000000, ns to ms */
}
spin_unlock_irqrestore(&mod_cfg_lock, flags);
}
static td_s32 drv_stat_cmp_info(const td_void *a, const td_void *b)
{
const ext_drv_stat_mod_info *tmp0 = (const ext_drv_stat_mod_info *)a;
const ext_drv_stat_mod_info *tmp1 = (const ext_drv_stat_mod_info *)b;
if ((tmp0->stat_index.instance_id != tmp1->stat_index.instance_id)) {
return tmp0->stat_index.instance_id - tmp1->stat_index.instance_id;
}
return (tmp0->in_mark - tmp1->in_mark);
}
static td_s32 drv_stat_module_info_sort(ext_drv_stat_mod_info *mod_info, td_u32 len)
{
if (mod_info == TD_NULL || len == 0) {
soc_log_err("input params are invalid.\n");
return TD_FAILURE;
}
sort(mod_info, len, sizeof(ext_drv_stat_mod_info), drv_stat_cmp_info, TD_NULL);
return TD_SUCCESS;
}
static td_s32 drv_stat_get_module_info_data(const ext_drv_stat_frame *stat_frame, ext_drv_stat_mod_info *mod_info)
{
td_u32 i = 0;
td_u32 j;
struct osal_list_head *pos = TD_NULL;
struct osal_list_head *nex = TD_NULL;
ext_drv_stat_module *stat_module = TD_NULL;
if (stat_frame == TD_NULL || mod_info == TD_NULL || stat_frame->module_list.next == TD_NULL) {
soc_log_err("input params is null.\n");
return TD_FAILURE;
}
osal_list_for_each_safe(pos, nex, &stat_frame->module_list) {
stat_module = osal_list_entry(pos, ext_drv_stat_module, node);
/* find the first valid step, and this step is the minimum step for sort before */
for (j = 0; j < stat_module->step_max; j++) {
if (stat_module->step_info[j].value_invald == TD_TRUE) {
break;
}
}
mod_info[i].in_mark = stat_module->step_info[j].us_time;
mod_info[i].path_index = 0xFF;
mod_info[i].mod_id = stat_module->mod_id;
mod_info[i].stat_index.frame_index = stat_module->stat_index.frame_index;
mod_info[i].stat_index.instance_id = stat_module->stat_index.instance_id;
mod_info[i].stat_index.mod_id = stat_module->stat_index.mod_id;
mod_info[i].stat_index.one2multi_id = stat_module->stat_index.one2multi_id;
mod_info[i].stat_index.reserved = stat_module->stat_index.reserved;
i++;
}
return TD_SUCCESS;
}
static ext_drv_stat_mod_info *drv_stat_proc_modinfo_malloc(td_u32 modinfo_size)
{
ext_drv_stat_mod_info *mod_info = TD_NULL;
mod_info = osal_kmalloc(sizeof(ext_drv_stat_mod_info) * modinfo_size, OSAL_GFP_KERNEL);
if (mod_info == TD_NULL) {
soc_log_err("malloc failed.\n");
return TD_NULL;
}
if (memset_s(mod_info, sizeof(ext_drv_stat_mod_info) * modinfo_size, 0x0,
sizeof(ext_drv_stat_mod_info) * modinfo_size) != EOK) {
soc_log_err("memset_s failed.\n");
osal_kfree(mod_info);
mod_info = TD_NULL;
return TD_NULL;
}
return mod_info;
}
static td_void drv_stat_proc_modinfo_release(const ext_drv_stat_mod_info *mod_info)
{
if (mod_info == TD_NULL) {
soc_log_err("mod_info is null.\n");
return;
}
osal_kfree(mod_info);
mod_info = TD_NULL;
}
static td_s32 drv_stat_calc_path_count(ext_drv_stat_mod_info *mod_info, td_u32 len, td_u32 *path_count)
{
td_u32 i;
td_u8 path_index = 0;
ext_drv_stat_mod_info *tmp = TD_NULL;
td_u8 instance_id = 0xFF;
if (mod_info == TD_NULL || len == 0 || path_count == TD_NULL) {
return TD_FAILURE;
}
for (i = 0; i < len; i++) {
tmp = &mod_info[i];
if (tmp->stat_index.instance_id == 0xFF) {
break;
}
if (instance_id != tmp->stat_index.instance_id) {
instance_id = tmp->stat_index.instance_id;
path_index++;
}
tmp->path_index = path_index;
}
*path_count = path_index;
return TD_SUCCESS;
}
static td_s32 drv_stat_proc_modinfo_data_process(
const ext_drv_stat_frame *stat_frame, ext_drv_stat_mod_info *mod_info, td_u32 *path_count)
{
td_s32 ret;
if (stat_frame == TD_NULL || mod_info == TD_NULL) {
return TD_FAILURE;
}
/* sort by instance one2mutil and mark time */
ret = drv_stat_module_info_sort(mod_info, stat_frame->module_count);
if (ret != TD_SUCCESS) {
soc_log_err("module info sort failed.\n");
return TD_FAILURE;
}
ret = drv_stat_calc_path_count(mod_info, stat_frame->module_count, path_count);
if (ret != TD_SUCCESS) {
soc_log_err("calc path count failed.\n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
static ext_drv_stat_mod_info *drv_stat_path(ext_drv_stat_frame *stat_frame, td_u32 *path_count)
{
td_s32 ret;
ext_drv_stat_mod_info *mod_info = TD_NULL;
if (stat_frame == TD_NULL) {
soc_log_err("input params is null\n");
return NULL;
}
osal_spin_lock(&stat_frame->frame_lock);
mod_info = drv_stat_proc_modinfo_malloc(stat_frame->module_count);
if (mod_info == TD_NULL) {
soc_log_err("mod info malloc failed.\n");
goto out0;
}
ret = drv_stat_get_module_info_data(stat_frame, mod_info);
if (ret != TD_SUCCESS) {
soc_log_err("get module info data failed.\n");
goto out1;
}
ret = drv_stat_proc_modinfo_data_process(stat_frame, mod_info, path_count);
if (ret != TD_SUCCESS) {
soc_log_err("process module info data failed.\n");
goto out1;
}
osal_spin_unlock(&stat_frame->frame_lock);
return mod_info;
out1:
drv_stat_proc_modinfo_release(mod_info);
mod_info = TD_NULL;
out0:
osal_spin_unlock(&stat_frame->frame_lock);
return mod_info;
}
static td_void drv_stat_show_frame_index(td_void *s)
{
td_u32 i;
td_s32 ret;
td_char tmp[0x20] = {0};
ext_drv_stat_frame *stat_frame = TD_NULL;
td_u32 count = 0;
osal_seq_printf(s, "%-16s\t", " ");
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->data_vaild == TD_FALSE) {
continue;
}
if (count >= g_stat_control.stat_count) {
break;
}
count++;
ret = sprintf_s(tmp, sizeof(tmp) - 1, "%s%03u", "mod(in-out)index", stat_frame->frame_index);
if (ret < 0) {
soc_log_err("frame sprintf_s failed.\n");
return;
}
osal_seq_printf(s, "%-24s\t", tmp);
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
osal_seq_printf(s, "\n%-16s\t", " ");
}
}
osal_seq_printf(s, "\n");
}
static td_void drv_stat_show_path_index(td_void *s, td_u32 path_index)
{
osal_seq_printf(s,
"------------------------------- the entire path %d take time ------------------------------------\n",
path_index);
}
static td_s32 drv_stat_show_module_data_inter(td_void *s, td_char *tmp, td_u32 tmp_len,
ext_drv_stat_module *stat_module)
{
td_s32 ret;
td_bool name_show = TD_FALSE;
/* show this mod info */
if (name_show == TD_FALSE) {
ret = sprintf_s(tmp, tmp_len - 1, "%s%s", stat_module->name, "(ns)");
if (ret < 0) {
soc_log_err("frame sprintf_s failed!\n");
return TD_FAILURE;
}
osal_seq_printf(s, "%-16s\t", tmp);
name_show = TD_TRUE;
}
return TD_SUCCESS;
}
static td_void drv_stat_show_module_data(td_void *s, td_u32 mod_id)
{
td_s32 ret;
td_u32 j, i;
ext_drv_stat_frame *stat_frame = TD_NULL;
ext_drv_stat_module *stat_module = TD_NULL;
td_char tmp[0x20] = {0};
ext_drv_stat_step *step_in = TD_NULL;
ext_drv_stat_step *step_out = TD_NULL;
td_u32 count = 0;
for (j = 0; j < g_stat_control.sampling_count; j++) {
stat_frame = &g_stat_control.stat_frame[j];
if (stat_frame->data_vaild == TD_FALSE) {
continue;
}
if (count >= g_stat_control.stat_count) {
break;
}
count++;
stat_module = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, mod_id);
stat_para_equel_null_return(stat_module, "not find mod_id", mod_id);
/* show this mod info */
ret = drv_stat_show_module_data_inter(s, tmp, sizeof(tmp), stat_module);
if (ret != TD_SUCCESS) {
return;
}
for (i = 0; i < stat_module->step_max; i++) {
if (stat_module->step_info[i].value_invald == TD_TRUE) {
step_in = &stat_module->step_info[i];
break;
}
}
step_out = &stat_module->step_info[stat_module->step_max - 1];
stat_para_equel_null_return(step_in, "step_in is NULL", 0);
ret = sprintf_s(tmp, sizeof(tmp) - 1, "0x%llx-0x%llx", step_in->us_time, step_out->us_time);
if (ret < 0) {
soc_log_err("frame sprintf_s failed .\n");
return;
}
osal_seq_printf(s, "%-24s\t", tmp);
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
osal_seq_printf(s, "\n%-16s\t", " ");
}
}
osal_seq_printf(s, "\n");
}
static td_void drv_stat_show_path_cost(td_void *s, td_u32 stat_id, td_u32 end_id)
{
td_u32 j, i;
td_bool name_show = TD_FALSE;
ext_drv_stat_frame *stat_frame = TD_NULL;
ext_drv_stat_module *module_in = TD_NULL;
ext_drv_stat_module *module_out = TD_NULL;
td_char tmp[0x20] = {0};
ext_drv_stat_step *step_in = TD_NULL;
ext_drv_stat_step *step_out = TD_NULL;
td_u32 count = 0;
td_u64 cut_time;
for (j = 0; j < g_stat_control.sampling_count; j++) {
stat_frame = &g_stat_control.stat_frame[j];
if (stat_frame->data_vaild == TD_FALSE) {
continue;
}
if (count >= g_stat_control.stat_count) {
break;
}
module_in = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, stat_id);
stat_para_equel_null_return(module_in, "not find start mod_id", stat_id);
module_out = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, end_id);
stat_para_equel_null_return(module_out, "not find end mod_id", end_id);
/* show this mod info */
if (name_show == TD_FALSE) {
osal_seq_printf(s, "%-16s\t", "path_cost_time(ms)");
name_show = TD_TRUE;
}
for (i = 0; i < module_in->step_max; i++) {
if (module_in->step_info[i].value_invald == TD_TRUE) {
step_in = &module_in->step_info[i];
break;
}
}
step_out = &module_out->step_info[module_out->step_max - 1];
stat_para_equel_null_return(step_in, "step_in is NULL", 0);
cut_time = DIV_ROUND_CLOSEST_ULL(step_out->us_time - step_in->us_time, 1000000); /* 1000000, ns to ms */
if (sprintf_s(tmp, sizeof(tmp) - 1, "%llu", cut_time) < 0) {
soc_log_err("sprintf_s failed...\n");
return;
}
osal_seq_printf(s, "%-24s\t", tmp);
count++;
if ((count % EXT_STAT_PRINT_NUM_OF_LINE) == 0) {
osal_seq_printf(s, "\n%-16s\t", " ");
}
}
osal_seq_printf(s, "\n");
}
static td_void drv_stat_proc_print_path(td_void *s)
{
td_u32 i, j;
td_u32 path_count = 0;
ext_drv_stat_mod_info *mod_info = TD_NULL;
ext_drv_stat_frame *stat_frame = TD_NULL;
td_u32 start_mod_id;
td_u32 end_mod_id = 0;
/* find a valid frame */
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->data_vaild == TD_TRUE) {
break;
}
}
/* calc the path info */
mod_info = drv_stat_path(stat_frame, &path_count);
if (mod_info == TD_NULL) {
soc_log_err("stat_path failed.\n");
return;
}
/* show all path data */
j = 0;
for (i = 0; i < path_count; i++) {
/* show path index */
drv_stat_show_path_index(s, i);
drv_stat_show_frame_index(s);
start_mod_id = mod_info[j].mod_id;
while (j < stat_frame->module_count) {
if (mod_info[j].path_index != i + 1) {
break;
}
drv_stat_show_module_data(s, mod_info[j].mod_id);
end_mod_id = mod_info[j].mod_id;
j++;
}
/* show entir path cost time */
drv_stat_show_path_cost(s, start_mod_id, end_mod_id);
}
/* release module info */
drv_stat_proc_modinfo_release(mod_info);
mod_info = TD_NULL;
}
static td_s32 drv_stat_init(td_void)
{
td_s32 ret;
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (g_stat_control.stat_count > EXT_STAT_FRAME_COUNT_MAX) {
soc_log_err(" g_stat_count %d > Count_MAX %d \n", g_stat_control.stat_count, EXT_STAT_FRAME_COUNT_MAX);
return TD_FAILURE;
}
g_stat_control.stat_frame = osal_kmalloc(
sizeof(ext_drv_stat_frame) * g_stat_control.sampling_count, OSAL_GFP_KERNEL);
if (g_stat_control.stat_frame == TD_NULL) {
soc_log_err("kmalloc stat_fram failed.\n");
return TD_FAILURE;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
stat_frame->frame_index = 0xffffffff;
stat_frame->is_vaild = TD_TRUE;
stat_frame->data_vaild = TD_TRUE;
stat_frame->module_count = 0;
OSAL_INIT_LIST_HEAD(&stat_frame->module_list);
ret = osal_spin_lock_init(&stat_frame->frame_lock);
if (ret != 0) {
soc_log_err("spin lock init failed .\n");
goto out0;
}
}
ret = kfifo_alloc(&g_stat_control.stat_fifo, EXT_STAT_FIFO_SIZE, GFP_KERNEL);
if (ret != TD_SUCCESS) {
soc_log_err("kfifo init failed.\n");
goto out0;
}
return TD_SUCCESS;
out0:
osal_kfree(g_stat_control.stat_frame);
g_stat_control.stat_frame = TD_NULL;
return TD_FAILURE;
}
static td_void drv_stat_deinit(td_void)
{
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (g_stat_control.stat_frame == TD_NULL) {
soc_log_info("stat feature is not enable .\n");
return;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
drv_stat_module_release(stat_frame);
osal_spin_lock_destroy(&stat_frame->frame_lock);
}
drv_stat_reset_module_calc_flag();
osal_kfree(g_stat_control.stat_frame);
g_stat_control.stat_frame = TD_NULL;
kfifo_free(&g_stat_control.stat_fifo);
}
static td_void drv_stat_reset_calc(td_void)
{
td_u32 i;
ext_drv_stat_frame *stat_frame = TD_NULL;
if (g_stat_control.stat_frame == TD_NULL) {
soc_log_info("stat feature is not enable .\n");
return;
}
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
drv_stat_frame_calc_release(stat_frame);
}
drv_stat_reset_module_calc_flag();
}
static td_s32 drv_stat_proc_read(td_void *s, td_void *arg)
{
osal_spin_lock(&g_stat_control.stat_control);
osal_seq_printf(s,
"=============================== common stat ===============================\n");
osal_seq_printf(s, "%-10s:\t%s\n", "g_stat_enable", (g_stat_control.stat_enable == TD_TRUE ? "true" : "false"));
if (g_stat_control.stat_enable != TD_TRUE) {
osal_seq_printf(s, "stat feature is not enable!\n");
goto out;
}
if (g_stat_control.finish != TD_TRUE || g_stat_control.calc != TD_TRUE) {
osal_seq_printf(s, "Data sampling or calc is not complete, please wait....\n");
goto out;
}
osal_seq_printf(s, "%-10s:\t%d\n", "g_stat_count", g_stat_control.stat_count);
drv_stat_proc_print_path(s);
osal_seq_printf(s,
"------------------------------- the module statistics take time (ms) -------------------------------\n");
drv_stat_proc_print_module(s);
out:
osal_seq_printf(s,
"================================ stat info end ================================\n");
osal_spin_unlock(&g_stat_control.stat_control);
return TD_SUCCESS;
}
static int stat_proc_cmd_help(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
td_u32 i;
td_u32 count = 0;
const td_char *format = "%-4s %-8s %-12s %-12s %-16s %s\n";
const drv_stat_proc_help_info help_info[] = {
{"echo", "command", "para1", "para2", "path", "explanation"},
{"echo", "help", "", "", "> /proc/msp/stat", "show help information"},
{"echo", "start", "20~100", "", "> /proc/msp/stat", "enable the stat feature"},
{"echo", "stop", "", "", "> /proc/msp/stat", "disable the stat feature"},
{"echo", "select", "instance_id", "", "> /proc/msp/stat", "show the specified entire path"},
{"echo", "details", "mod_name", "instance_id", "> /proc/msp/stat", "show one module details"},
};
ext_drv_proc_echo_helper("==============================common stat====================================\n");
for (i = 0; i < sizeof(help_info) / sizeof(drv_stat_proc_help_info); i++) {
ext_drv_proc_echo_helper(format,
help_info[i].echo, help_info[i].command, help_info[i].para1,
help_info[i].para2, help_info[i].path, help_info[i].explanation);
}
ext_drv_proc_echo_helper("\nmod_name -->\n");
for (i = 0; i < SOC_ID_TSFW + 1; i++) {
if (strcmp(g_mod_name[i], "unknown") == 0 || g_mod_name[i] == TD_NULL) {
continue;
}
ext_drv_proc_echo_helper("%-12s", g_mod_name[i]);
if (((++count) % 0x8) == 0) { /* 8 each line */
ext_drv_proc_echo_helper("\n");
}
}
ext_drv_proc_echo_helper("\n===========================================================================\n");
return TD_SUCCESS;
}
static int stat_proc_cmd_sampling(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
return TD_SUCCESS;
}
static td_s32 drv_stat_get_mod_instance_id(
unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_u8 *mod_id, td_u8 *instance_id)
{
td_s32 ret = TD_FAILURE;
td_u32 i;
if (argv == TD_NULL || mod_id == TD_NULL || instance_id == TD_NULL) {
return TD_FAILURE;
}
if (argc == 0x2 || argc == 0x3) {
for (i = 0; i < SOC_ID_TSFW + 1; i++) {
if (strcmp(argv[1], g_mod_name[i]) == 0) {
*mod_id = i;
ret = TD_SUCCESS;
break;
}
}
if (argc == 0x2) {
if (strstr(argv[0x2], "0x") || strstr(argv[0x2], "0X")) {
*instance_id = simple_strtoul(argv[0x2], TD_NULL, 0x10);
} else {
*instance_id = simple_strtoul(argv[0x2], TD_NULL, 0xa);
}
} else {
*instance_id = 0;
}
} else {
soc_log_err("param is wrong!");
return TD_FAILURE;
}
return ret;
}
static td_void drv_stat_show_module_name(drv_stat_buf *buf, td_u8 mod_id)
{
td_ulong flags;
ext_drv_stat_cfg_node *cfg_node = TD_NULL;
td_u32 write_len = 0;
td_s32 tmp_len;
td_char *s = TD_NULL;
const td_char *tmp1 = "---------------------------------- details module ";
const td_char *tmp2 = "------------------------------------";
const td_char *tmp3 = "================================== common stat ";
const td_char *tmp4 = "==========================================";
if (buf == TD_NULL) {
return;
}
spin_lock_irqsave(&mod_cfg_lock, flags);
cfg_node = drv_stat_module_find_node(&mod_cfg_list, mod_id);
if (cfg_node == TD_NULL) {
soc_log_err("can not find mod_id:0x%x\n", mod_id);
spin_unlock_irqrestore(&mod_cfg_lock, flags);
return;
}
s = buf->buffer + buf->write_len;
tmp_len = sprintf_s(s, buf->len, "\n%s%s\n", tmp3, tmp4);
if (tmp_len < 0) {
spin_unlock_irqrestore(&mod_cfg_lock, flags);
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s%s%s\n", tmp1, cfg_node->module_name, tmp2);
if (tmp_len < 0) {
spin_unlock_irqrestore(&mod_cfg_lock, flags);
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "module name:%-16s module id:0x%-4x\n",
cfg_node->module_name, cfg_node->mod_id);
if (tmp_len < 0) {
spin_unlock_irqrestore(&mod_cfg_lock, flags);
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
/* process s offset */
buf->len -= write_len;
buf->write_len += write_len;
spin_unlock_irqrestore(&mod_cfg_lock, flags);
}
static td_s32 drv_stat_proc_module_details_inter(drv_stat_buf *buf, td_char *s, const ext_drv_stat_module *mod,
td_u32 *write_len)
{
td_u32 i;
td_s32 tmp_len;
td_u32 tmp_write_len = *write_len;
td_bool title = TD_FALSE;
for (i = 1; i < mod->step_max; i++) {
if (mod->step_info[i].value_invald != TD_TRUE) {
continue;
}
if (title == TD_FALSE) {
tmp_len = sprintf_s(s + tmp_write_len, buf->len - tmp_write_len, "%-16u %-16llu %-16s 0x%-14llx %-16llu\n",
mod->stat_index.frame_index, mod->calc_result->mod_total_cost,
mod->step_info[i].step_name, mod->step_info[i].us_time, 0);
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
return TD_FAILURE;
}
tmp_write_len += (td_u32)tmp_len;
title = TD_TRUE;
} else {
tmp_len = sprintf_s(s + tmp_write_len, buf->len - tmp_write_len, "%-16s %-16s %-16s 0x%-14llx %-16llu\n",
"", "", mod->step_info[i].step_name, mod->step_info[i].us_time, mod->calc_result->step_cost[i - 1]);
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
return TD_FAILURE;
}
tmp_write_len += (td_u32)tmp_len;
}
}
*write_len = tmp_write_len;
return TD_SUCCESS;
}
static td_void drv_stat_proc_module_details(drv_stat_buf *buf, const ext_drv_stat_module *mod)
{
td_char *s = TD_NULL;
td_u32 write_len = 0;
td_s32 tmp_len;
td_s32 ret;
const td_char *frame_index = "frame index";
const td_char *total_time = "total time(ns)";
const td_char *step_action = "step action";
const td_char *step_value = "step value(ns)";
const td_char *step_cost = "step cost(ns)";
if (mod == TD_NULL || buf == TD_NULL || mod->calc_result == TD_NULL) {
soc_log_err("input params is null.\n");
return;
}
s = buf->buffer + buf->write_len;
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s\n",
"-----------------------------------------------------------------------------------------");
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%-16s %-16s %-16s %-16s %-16s\n",
frame_index, total_time, step_action, step_value, step_cost);
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
ret = drv_stat_proc_module_details_inter(buf, s, mod, &write_len);
if (ret != TD_SUCCESS) {
return;
}
tmp_len = sprintf_s(s + write_len, buf->len - write_len, "%s\n",
"-----------------------------------------------------------------------------------------");
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
return;
}
write_len += (td_u32)tmp_len;
/* process s offset */
buf->len -= write_len;
buf->write_len += write_len;
}
static td_s32 drv_proc_module_details_process_inter(const ext_drv_stat_index *stat_index, drv_stat_buf *mod_details_buf)
{
td_u32 i;
td_s32 ret;
td_u32 count = 0;
ext_drv_stat_frame *stat_frame = TD_NULL;
ext_drv_stat_module *mod_node = TD_NULL;
for (i = 0; i < g_stat_control.sampling_count; i++) {
stat_frame = &g_stat_control.stat_frame[i];
if (stat_frame->data_vaild != TD_TRUE) {
continue;
}
if (count >= g_stat_control.stat_count) {
break;
}
count++;
mod_node = drv_stat_list_get_module_by_module_id(&stat_frame->module_list, stat_index->mod_id);
if (mod_node == TD_NULL) {
soc_log_err("stat frame list can not find 0x%x\n", stat_index->mod_id);
return TD_FAILURE;
}
drv_stat_proc_module_details(mod_details_buf, mod_node);
/* Prevents buf overflow */
if (mod_details_buf->len - EXT_STAT_PROC_BUF_RESERVED < mod_details_buf->write_len) {
/* show proc info */
ext_drv_proc_echo_helper("%s", mod_details_buf->buffer);
/* reset buf */
if ((ret = drv_proc_buf_reset(mod_details_buf)) != TD_SUCCESS) {
soc_log_err("drv_proc_buf_reset failed, ret=%d\n", ret);
return TD_FAILURE;
}
}
}
return TD_SUCCESS;
}
static td_s32 drv_proc_module_details_process(const ext_drv_stat_index *stat_index)
{
td_s32 ret;
td_s32 tmp_len;
drv_stat_buf mod_details_buf;
const td_char *tmp1 = "=============================================";
if (stat_index == TD_NULL) {
soc_log_err("input params is null.\n");
return TD_FAILURE;
}
ret = drv_proc_buf_malloc(&mod_details_buf);
if (ret != TD_SUCCESS) {
return TD_FAILURE;
}
drv_stat_show_module_name(&mod_details_buf, stat_index->mod_id);
ret = drv_proc_module_details_process_inter(stat_index, &mod_details_buf);
if (ret != TD_SUCCESS) {
goto out;
}
tmp_len = sprintf_s(mod_details_buf.buffer + mod_details_buf.write_len,
mod_details_buf.len - mod_details_buf.write_len, "%s%s\n", tmp1, tmp1);
if (tmp_len < 0) {
soc_log_err("sprintf_s failed!\n");
ret = TD_FAILURE;
goto out;
}
mod_details_buf.write_len += (td_u32)tmp_len;
ext_drv_proc_echo_helper("%s", mod_details_buf.buffer);
ret = TD_SUCCESS;
out:
drv_proc_buf_release(&mod_details_buf);
return ret;
}
static int stat_proc_cmd_module_details(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
td_s32 ret;
td_u8 mod_id;
td_u8 instance_id;
ext_drv_stat_index stat_index;
if (g_stat_control.stat_enable != TD_TRUE) {
soc_log_err("the stat feature is not enable.\n");
return TD_SUCCESS;
}
ret = drv_stat_get_mod_instance_id(argc, argv, &mod_id, &instance_id);
if (ret != TD_SUCCESS) {
soc_log_err("get module & instance id failed. \n");
return ret;
}
stat_index.mod_id = mod_id;
stat_index.instance_id = instance_id;
if (g_stat_control.finish != TD_TRUE || g_stat_control.calc != TD_TRUE) {
ext_drv_proc_echo_helper("Data sampling or calculation is not completed, please wait....\n");
return TD_SUCCESS;
}
ret = drv_proc_module_details_process(&stat_index);
if (ret != TD_SUCCESS) {
soc_log_err("proc module details process failed. 0x%x\n", mod_id);
}
return ret;
}
static int stat_proc_cmd_clean(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
return TD_SUCCESS;
}
static int stat_proc_cmd_select(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
return TD_SUCCESS;
}
static int stat_proc_cmd_start(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
td_s32 ret;
td_u32 stat_count;
if (argv == TD_NULL) {
soc_log_err(" input is null \n");
return TD_FAILURE;
}
/* should add lock to protect global member */
osal_spin_lock(&g_stat_control.stat_control);
if (g_stat_control.stat_enable == TD_TRUE) {
soc_log_info("stat feature is enable.\n");
ret = TD_SUCCESS;
goto out;
}
g_stat_control.stat_enable = TD_TRUE;
g_stat_control.finish = TD_FALSE;
g_stat_control.calc = TD_FALSE;
if (argc == 0x2) {
/* the second params is stat count */
if (strstr(argv[1], "0x") || strstr(argv[1], "0X")) {
stat_count = simple_strtoul(argv[1], TD_NULL, 0x10);
} else {
stat_count = simple_strtoul(argv[1], TD_NULL, 0xa);
}
if (stat_count >= EXT_STAT_FRAME_COUNT_MAX) {
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_MAX;
} else if (stat_count <= EXT_STAT_FRAME_COUNT_DEFAULT) {
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
} else {
g_stat_control.stat_count = stat_count;
}
} else {
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
}
g_stat_control.sampling_count = 0x6 * g_stat_control.stat_count;
ret = drv_stat_init();
if (ret != TD_SUCCESS) {
g_stat_control.stat_enable = TD_FALSE;
soc_log_err("stat init failed .\n");
ret = TD_FAILURE;
}
out:
osal_spin_unlock(&g_stat_control.stat_control);
return ret;
}
static int stat_proc_cmd_stop(unsigned int argc, char (*argv)[PROC_CMD_SINGEL_LENGTH_MAX], td_void *private)
{
if (argv == TD_NULL) {
soc_log_err(" input is null \n");
return TD_FAILURE;
}
osal_spin_lock(&g_stat_control.stat_control);
if (g_stat_control.stat_enable == TD_TRUE) {
drv_stat_remove_all_module();
drv_stat_deinit();
g_stat_control.stat_enable = TD_FALSE;
g_stat_control.finish = TD_FALSE;
g_stat_control.calc = TD_FALSE;
g_stat_control.stat_count = EXT_STAT_FRAME_COUNT_DEFAULT;
g_stat_control.sampling_count = 0;
}
osal_spin_unlock(&g_stat_control.stat_control);
return TD_SUCCESS;
}
static td_s32 drv_stat_task(td_void *data)
{
td_s32 ret;
ext_drv_stat_info tmp_info;
while (!osal_kthread_should_stop()) {
if (g_stat_control.stat_enable == TD_TRUE && g_stat_control.calc == TD_TRUE) {
/* Waiting for the data to be updated */
osal_msleep(EXT_STAT_TASK_DELAY * 0x3);
continue;
}
/* make kfifo data can be readed by task. */
if (kfifo_is_empty(&g_stat_control.stat_fifo) == TD_TRUE) {
osal_msleep(EXT_STAT_TASK_DELAY * 0x3);
continue;
}
/* get stat_info data */
ret = (td_s32)kfifo_out_spinlocked(&g_stat_control.stat_fifo, &tmp_info, 1, &fifo_lock);
if (ret != 0x1) {
soc_log_err("got stat data error..%d -- %d\n", ret, sizeof(ext_drv_stat_info));
continue;
}
osal_spin_lock(&g_stat_control.stat_control);
ret = drv_stat_info_notify(&tmp_info);
if (ret != TD_SUCCESS) {
osal_spin_unlock(&g_stat_control.stat_control);
soc_log_err("stat info notify task process failed.\n");
return TD_FAILURE;
}
/* calc data */
if (g_stat_control.finish == TD_TRUE && g_stat_control.calc == TD_FALSE) {
drv_stat_mark_invalid_samping();
drv_stat_reset_calc();
/* calc the stat data */
ret = drv_stat_calc_all_module();
if (ret != TD_SUCCESS) {
osal_spin_unlock(&g_stat_control.stat_control);
soc_log_err("calc all module failed.\n");
return ret;
}
g_stat_control.calc = TD_TRUE;
soc_log_err("calc all modules finished!\n");
}
osal_spin_unlock(&g_stat_control.stat_control);
osal_msleep(EXT_STAT_TASK_DELAY);
}
return TD_SUCCESS;
}
static osal_proc_cmd g_stat_proc_cmd[] = {
{ "help", stat_proc_cmd_help },
{ "sampling", stat_proc_cmd_sampling },
{ "details", stat_proc_cmd_module_details },
{ "select", stat_proc_cmd_select },
{ "start", stat_proc_cmd_start },
{ "stop", stat_proc_cmd_stop },
{ "clean", stat_proc_cmd_clean }
};
td_s32 drv_stat_add_proc(td_void)
{
td_s32 ret;
osal_proc_entry *item = TD_NULL;
ret = osal_spin_lock_init(&g_stat_control.stat_control);
if (ret != 0) {
soc_log_err("spin lock init failed .\n");
return TD_FAILURE;
}
g_stat_control.stat_enable = TD_FALSE;
item = osal_proc_add(EXT_STAT_PROC_NAME, strlen(EXT_STAT_PROC_NAME));
if (item == TD_NULL) {
soc_log_err("can't add moudle for stat.\n");
return TD_FAILURE;
}
item->read = drv_stat_proc_read;
item->cmd_cnt = sizeof(g_stat_proc_cmd) / sizeof(osal_proc_cmd);
item->cmd_list = g_stat_proc_cmd;
g_stat_control.stat_task = osal_kthread_create(drv_stat_task, TD_NULL, "Stat_Task", 0);
if (g_stat_control.stat_task == TD_NULL) {
soc_log_err("stat task creat failed.\n");
return TD_FAILURE;
}
return TD_SUCCESS;
}
td_void drv_stat_remove_proc(td_void)
{
osal_kthread_destroy(g_stat_control.stat_task, TD_TRUE);
g_stat_control.stat_task = TD_NULL;
if (g_stat_control.stat_enable == TD_TRUE) {
drv_stat_remove_all_module();
drv_stat_deinit();
}
osal_proc_remove(EXT_STAT_PROC_NAME, strlen(EXT_STAT_PROC_NAME));
osal_spin_lock_destroy(&g_stat_control.stat_control);
return;
}
td_void ext_drv_stat_event(ext_stat_event event, td_u32 value)
{
return;
}
td_void ext_drv_stat_ld_notify_event(const ext_stat_ld_event_info *event_info)
{
return;
}
EXPORT_SYMBOL(ext_drv_stat_event);
EXPORT_SYMBOL(ext_drv_stat_ld_notify_event);
EXPORT_SYMBOL(ext_drv_stat_info_notify);