--- /dev/null
+/*
+* Copyright (C) 2011-2014 MediaTek Inc.
+*
+* This program is free software: you can redistribute it and/or modify it under the terms of the
+* GNU General Public License version 2 as published by the Free Software Foundation.
+*
+* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+* See the GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License along with this program.
+* If not, see <http://www.gnu.org/licenses/>.
+*/
+#include <linux/kernel.h> // GFP_KERNEL
+#include <linux/timer.h> //init_timer, add_time, del_timer_sync
+#include <linux/time.h> //gettimeofday
+#include <linux/delay.h>
+#include <linux/slab.h> //kzalloc
+#include <linux/sched.h> //task's status
+#include <linux/vmalloc.h>
+#include <linux/err.h>
+#include <linux/workqueue.h>
+#include <asm/atomic.h>
+
+#include <net/sock.h>
+#include <net/netlink.h>
+#include <linux/skbuff.h>
+#include <net/genetlink.h>
+
+#include <linux/zlib.h>
+#include <linux/uaccess.h>
+#include <linux/crc32.h>
+
+#include "osal_typedef.h"
+#include "stp_dbg.h"
+//#include "stp_btm.h"
+#include "btm_core.h"
+#include "wmt_plat.h"
+
+#define PFX_STP_DBG "[STPDbg]"
+#define STP_DBG_LOG_LOUD 4
+#define STP_DBG_LOG_DBG 3
+#define STP_DBG_LOG_INFO 2
+#define STP_DBG_LOG_WARN 1
+#define STP_DBG_LOG_ERR 0
+
+unsigned int gStpDbgDbgLevel = STP_DBG_LOG_INFO;
+unsigned int gStpDbgLogOut = 0;
+
+#define STP_DBG_LOUD_FUNC(fmt, arg...) if(gStpDbgDbgLevel >= STP_DBG_LOG_LOUD){ printk(KERN_DEBUG PFX_STP_DBG "%s: " fmt, __FUNCTION__ ,##arg);}
+#define STP_DBG_DBG_FUNC(fmt, arg...) if(gStpDbgDbgLevel >= STP_DBG_LOG_DBG){ printk(KERN_DEBUG PFX_STP_DBG "%s: " fmt, __FUNCTION__ ,##arg);}
+#define STP_DBG_INFO_FUNC(fmt, arg...) if(gStpDbgDbgLevel >= STP_DBG_LOG_INFO){ printk(PFX_STP_DBG "%s: " fmt, __FUNCTION__ ,##arg);}
+#define STP_DBG_WARN_FUNC(fmt, arg...) if(gStpDbgDbgLevel >= STP_DBG_LOG_WARN){ printk(PFX_STP_DBG "%s: " fmt, __FUNCTION__ ,##arg);}
+#define STP_DBG_ERR_FUNC(fmt, arg...) if(gStpDbgDbgLevel >= STP_DBG_LOG_ERR){ printk(PFX_STP_DBG "%s: " fmt, __FUNCTION__ ,##arg);}
+#define STP_DBG_TRC_FUNC(f) if(gStpDbgDbgLevel >= STP_DBG_LOG_DBG){ printk(KERN_DEBUG PFX_STP_DBG "<%s> <%d>\n", __FUNCTION__, __LINE__);}
+
+
+MTKSTP_DBG_T *g_stp_dbg = NULL;
+
+#define STP_DBG_FAMILY_NAME "STP_DBG"
+#define MAX_BIND_PROCESS (4)
+#ifdef WMT_PLAT_ALPS
+#define STP_DBG_AEE_EXP_API (1)
+#else
+#define STP_DBG_AEE_EXP_API (0)
+#endif
+enum {
+ __STP_DBG_ATTR_INVALID,
+ STP_DBG_ATTR_MSG,
+ __STP_DBG_ATTR_MAX,
+};
+#define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1)
+
+enum {
+ __STP_DBG_COMMAND_INVALID,
+ STP_DBG_COMMAND_BIND,
+ STP_DBG_COMMAND_RESET,
+ __STP_DBG_COMMAND_MAX,
+};
+#define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1)
+
+static struct genl_family stp_dbg_gnl_family = {
+ .id = GENL_ID_GENERATE,
+ .hdrsize = 0,
+ .name = STP_DBG_FAMILY_NAME,
+ .version = 1,
+ .maxattr = STP_DBG_ATTR_MAX,
+};
+
+static void stp_dbg_nl_init(void);
+static void stp_dbg_nl_deinit(void);
+static int stp_dbg_nl_bind(
+ struct sk_buff *skb,
+ struct genl_info *info
+ );
+static int stp_dbg_nl_reset(
+ struct sk_buff *skb,
+ struct genl_info *info
+ );
+
+/* attribute policy */
+static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = {
+ [STP_DBG_ATTR_MSG] = { .type = NLA_NUL_STRING },
+};
+
+/* operation definition */
+static struct genl_ops stp_dbg_gnl_ops_bind = {
+ .cmd = STP_DBG_COMMAND_BIND,
+ .flags = 0,
+ .policy = stp_dbg_genl_policy,
+ .doit = stp_dbg_nl_bind,
+ .dumpit = NULL,
+};
+
+static struct genl_ops stp_dbg_gnl_ops_reset = {
+ .cmd = STP_DBG_COMMAND_RESET,
+ .flags = 0,
+ .policy = stp_dbg_genl_policy,
+ .doit = stp_dbg_nl_reset,
+ .dumpit = NULL,
+};
+
+#define E2S(x) #x
+static char* dmaRegsStr[] = {
+ E2S(CONNSYS_CLK_GATE_STATUS),
+ E2S(CONSYS_EMI_STATUS),
+ E2S(SYSRAM1),
+ E2S(SYSRAM2),
+ E2S(SYSRAM3)
+};
+static unsigned int stp_dbg_seqnum = 0;
+static int num_bind_process = 0;
+static pid_t bind_pid[MAX_BIND_PROCESS];
+
+static P_WCN_CORE_DUMP_T g_core_dump = NULL;
+
+static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr = NULL;
+
+//just show in log at present
+static P_STP_DBG_DMAREGS_T g_stp_dbg_dmaregs = NULL;
+
+/* core_dump_timeout_handler - handler of coredump timeout
+ * @ data - core dump object's pointer
+ *
+ * No return value
+ */
+static void core_dump_timeout_handler(unsigned long data)
+{
+ P_WCN_CORE_DUMP_T dmp = (P_WCN_CORE_DUMP_T)data;
+
+ STP_DBG_INFO_FUNC(" start\n");
+
+ stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm);
+
+ STP_DBG_INFO_FUNC(" end\n");
+
+ if (dmp) {
+ dmp->sm = CORE_DUMP_TIMEOUT;
+ }
+}
+
+
+/* wcn_core_dump_init - create core dump sys
+ * @ timeout - core dump time out value
+ *
+ * Return object pointer if success, else NULL
+ */
+P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 timeout)
+{
+ #define KBYTES (1024*sizeof(char))
+ #define L1_BUF_SIZE (32*KBYTES)
+ #define L2_BUF_SIZE (384*KBYTES)
+
+ P_WCN_CORE_DUMP_T core_dmp = NULL;
+
+ core_dmp = (P_WCN_CORE_DUMP_T)osal_malloc(sizeof(WCN_CORE_DUMP_T));
+ if (!core_dmp) {
+ STP_DBG_ERR_FUNC("alloc mem failed!\n");
+ goto fail;
+ }
+
+ osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T));
+
+ core_dmp->compressor = wcn_compressor_init("core_dump_compressor", L1_BUF_SIZE, L2_BUF_SIZE);
+ if (!core_dmp->compressor) {
+ STP_DBG_ERR_FUNC("create compressor failed!\n");
+ goto fail;
+ }
+ wcn_compressor_reset(core_dmp->compressor, 1, GZIP);
+
+ core_dmp->dmp_timer.timeoutHandler = core_dump_timeout_handler;
+ core_dmp->dmp_timer.timeroutHandlerData = (unsigned long)core_dmp;
+ osal_timer_create(&core_dmp->dmp_timer);
+ core_dmp->timeout = timeout;
+
+ osal_sleepable_lock_init(&core_dmp->dmp_lock);
+
+ core_dmp->sm = CORE_DUMP_INIT;
+ STP_DBG_INFO_FUNC("create coredump object OK!\n");
+
+ return core_dmp;
+
+fail:
+ if (core_dmp && core_dmp->compressor) {
+ wcn_compressor_deinit(core_dmp->compressor);
+ core_dmp->compressor = NULL;
+ }
+
+ if (core_dmp) {
+ osal_free(core_dmp);
+ }
+
+ osal_sleepable_lock_deinit(&core_dmp->dmp_lock);
+
+ return NULL;
+}
+
+
+/* wcn_core_dump_deinit - destroy core dump object
+ * @ dmp - pointer of object
+ *
+ * Retunr 0 if success, else error code
+ */
+INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp)
+{
+ if (dmp && dmp->compressor) {
+ wcn_compressor_deinit(dmp->compressor);
+ dmp->compressor = NULL;
+ }
+
+ if (dmp) {
+ osal_sleepable_lock_deinit(&dmp->dmp_lock);
+ osal_timer_stop(&dmp->dmp_timer);
+ osal_free(dmp);
+ }
+
+ return 0;
+}
+
+
+static INT32 wcn_core_dump_check_end(PUINT8 buf, INT32 len)
+{
+ if (strnstr(buf, "coredump end", len)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
+/* wcn_core_dump_in - add a packet to compressor buffer
+ * @ dmp - pointer of object
+ * @ buf - input buffer
+ * @ len - data length
+ *
+ * Retunr 0 if success; return 1 if find end string; else error code
+ */
+INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
+{
+ INT32 ret = 0;
+ INT32 tmp;
+
+ #define INFO_HEAD ";SOC_CONSYS FW CORE, "
+
+ if ((!dmp) || (!buf)) {
+ STP_DBG_ERR_FUNC("invalid pointer!\n");
+ return -1;
+ }
+
+ ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
+ if (ret) {
+ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ switch (dmp->sm) {
+ case CORE_DUMP_INIT:
+ wcn_compressor_reset(dmp->compressor, 1, GZIP);
+ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT);
+
+ // first package, copy to info buffer
+ osal_strcpy(&dmp->info[0], INFO_HEAD);
+
+ if(NULL == (strnstr(buf,"<ASSERT>",32)))
+ {
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...", osal_strlen("Fw warm reset exception..."));
+ dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] = '\0';
+ }else{
+ char *pStr = buf;
+ char *pDtr = NULL;
+
+ pDtr = osal_strchr(pStr,'-');
+ if(NULL != pDtr)
+ {
+ tmp = pDtr - pStr;
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp);
+ dmp->info[osal_strlen(dmp->info) + 1] = '\0';
+ }else
+ {
+ tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD);
+ tmp = (len > tmp) ? tmp : len;
+ osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], buf, tmp);
+ dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0';
+ }
+
+ }
+ // show coredump start info on UI
+ //osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start");
+#if STP_DBG_AEE_EXP_API
+ aee_kernel_dal_show("SOC_CONSYS coredump start ....\n");
+#endif
+ // parsing data, and check end srting
+ ret = wcn_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_INFO_FUNC("core dump end!\n");
+ dmp->sm = CORE_DUMP_DONE;
+ wcn_compressor_in(dmp->compressor, buf, len, 0);
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ wcn_compressor_in(dmp->compressor, buf, len, 0);
+ }
+ break;
+
+ case CORE_DUMP_DOING:
+ // parsing data, and check end srting
+ ret = wcn_core_dump_check_end(buf, len);
+ if (ret == 1) {
+ STP_DBG_INFO_FUNC("core dump end!\n");
+ dmp->sm = CORE_DUMP_DONE;
+ wcn_compressor_in(dmp->compressor, buf, len, 0);
+ } else {
+ dmp->sm = CORE_DUMP_DOING;
+ wcn_compressor_in(dmp->compressor, buf, len, 0);
+ }
+ break;
+
+ case CORE_DUMP_DONE:
+ wcn_compressor_reset(dmp->compressor, 1, GZIP);
+ osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT);
+ wcn_compressor_in(dmp->compressor, buf, len, 0);
+ dmp->sm = CORE_DUMP_DOING;
+ break;
+
+ case CORE_DUMP_TIMEOUT:
+ break;
+ default:
+ break;
+ }
+
+ osal_unlock_sleepable_lock(&dmp->dmp_lock);
+
+ return ret;
+}
+
+
+/* wcn_core_dump_out - get compressed data from compressor buffer
+ * @ dmp - pointer of object
+ * @ pbuf - target buffer's pointer
+ * @ len - data length
+ *
+ * Retunr 0 if success; else error code
+ */
+INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PUINT8 *pbuf, PINT32 plen)
+{
+ INT32 ret = 0;
+
+ if ((!dmp) || (!pbuf) || (!plen)) {
+ STP_DBG_ERR_FUNC("invalid pointer!\n");
+ return -1;
+ }
+
+ ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
+ if (ret) {
+ STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
+ return ret;
+ }
+
+ ret = wcn_compressor_out(dmp->compressor, pbuf, plen);
+
+ osal_unlock_sleepable_lock(&dmp->dmp_lock);
+
+ return ret;
+}
+
+
+/* wcn_core_dump_reset - reset core dump sys
+ * @ dmp - pointer of object
+ * @ timeout - core dump time out value
+ *
+ * Retunr 0 if success, else error code
+ */
+INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout)
+{
+ if (!dmp) {
+ STP_DBG_ERR_FUNC("invalid pointer!\n");
+ return -1;
+ }
+
+ dmp->sm = CORE_DUMP_INIT;
+ dmp->timeout = timeout;
+ osal_timer_stop(&dmp->dmp_timer);
+ wcn_compressor_reset(dmp->compressor, 1, GZIP);
+ osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1);
+
+ wcn_core_dump_deinit(dmp);
+ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_TIMEOUT);
+
+ return 0;
+}
+
+/* wcn_core_dump_timeout - wait for FW assert info timeout ,this func can collect SYS_FTRACE
+ *
+ * Retunr 0 if success
+ */
+ #define TIMEOUT_INFO_HEAD "Trigger assert timeout ,just collect SYS_FTRACE to DB"
+INT32 wcn_core_dump_timeout(void)
+{
+ PUINT8 pbuf;
+ INT32 len;
+
+ pbuf = "Trigger assert timeout";
+ len = osal_strlen("Trigger assert timeout");
+ osal_strcpy(&g_core_dump->info[0], TIMEOUT_INFO_HEAD);
+ aed_combo_exception(NULL, 0, (const int*)pbuf, len, (const char*)g_core_dump->info);
+ return 0;
+}
+
+#define ENABLE_F_TRACE 0
+/* wcn_core_dump_flush - Fulsh dump data and reset core dump sys
+ *
+ * Retunr 0 if success, else error code
+ */
+INT32 wcn_core_dump_flush(INT32 rst)
+{
+ PUINT8 pbuf = NULL;
+ INT32 len = 0;
+
+ if (!g_core_dump) {
+ STP_DBG_ERR_FUNC("invalid pointer!\n");
+ return -1;
+ }
+
+ wcn_core_dump_out(g_core_dump, &pbuf, &len);
+ STP_DBG_INFO_FUNC("buf 0x%zx, len %d\n", (SIZE_T)pbuf, len);
+
+ // show coredump end info on UI
+ //osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends");
+#if STP_DBG_AEE_EXP_API
+ aee_kernel_dal_show("++ SOC_CONSYS coredump get successfully ++\n");
+ // call AEE driver API
+#if ENABLE_F_TRACE
+ aed_combo_exception_api(NULL, 0, (const int*)pbuf, len, (const char*)g_core_dump->info,DB_OPT_FTRACE);
+#else
+ aed_combo_exception(NULL, 0, (const int*)pbuf, len, (const char*)g_core_dump->info);
+#endif
+
+#endif
+
+ // reset
+ wcn_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT);
+
+ return 0;
+}
+
+
+static INT32 wcn_gzip_compressor(void *worker, UINT8 *in_buf, INT32 in_sz, UINT8 *out_buf, INT32 *out_sz, INT32 finish)
+{
+ INT32 ret = 0;
+ z_stream *stream = NULL;
+ INT32 tmp = *out_sz;
+
+ STP_DBG_INFO_FUNC("in buf 0x%zx, in sz %d\n", (SIZE_T)in_buf, in_sz);
+ STP_DBG_INFO_FUNC("out buf 0x%zx, out sz %d\n", (SIZE_T)out_buf, tmp);
+
+ stream = (z_stream*)worker;
+ if (!stream) {
+ STP_DBG_ERR_FUNC("invalid workspace!\n");
+ return -1;
+ }
+
+ if (in_sz > 0) {
+ #if 0
+ ret = zlib_deflateReset(stream);
+ if (ret != Z_OK) {
+ STP_DBG_ERR_FUNC("reset failed!\n");
+ return -2;
+ }
+ #endif
+
+ stream->next_in = in_buf;
+ stream->avail_in = in_sz;
+ stream->next_out = out_buf;
+ stream->avail_out = tmp;
+
+ zlib_deflate(stream, Z_FULL_FLUSH);
+
+ if (finish) {
+ while (1) {
+ int val = zlib_deflate(stream, Z_FINISH);
+ if (val == Z_OK) {
+ continue;
+ } else if (val == Z_STREAM_END) {
+ break;
+ } else {
+ STP_DBG_ERR_FUNC("finish operation failed %d\n", val);
+ return -3;
+ }
+ }
+ }
+
+ *out_sz = tmp - stream->avail_out;
+ }
+
+ STP_DBG_INFO_FUNC("out buf 0x%zx, out sz %d\n", (SIZE_T)out_buf, *out_sz);
+
+ return ret;
+}
+
+
+/* wcn_compressor_init - create a compressor and do init
+ * @ name - compressor's name
+ * @ L1_buf_sz - L1 buffer size
+ * @ L2_buf_sz - L2 buffer size
+ *
+ * Retunr object's pointer if success, else NULL
+ */
+P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz)
+{
+ z_stream *pstream = NULL;
+ P_WCN_COMPRESSOR_T compress = NULL;
+
+ compress = (P_WCN_COMPRESSOR_T)osal_malloc(sizeof(WCN_COMPRESSOR_T));
+ if (!compress) {
+ STP_DBG_ERR_FUNC("alloc compressor failed!\n");
+ goto fail;
+ }
+
+ osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T));
+ osal_memcpy(compress->name, name, STP_OJB_NAME_SZ);
+
+ compress->f_compress_en = 0;
+ compress->compress_type = GZIP;
+
+ if (compress->compress_type == GZIP) {
+ compress->worker = osal_malloc(sizeof(z_stream));
+ if (!compress->worker) {
+ STP_DBG_ERR_FUNC("alloc stream failed!\n");
+ goto fail;
+ }
+ pstream = (z_stream*)compress->worker;
+
+ pstream->workspace = osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
+ if (!pstream->workspace) {
+ STP_DBG_ERR_FUNC("alloc workspace failed!\n");
+ goto fail;
+ }
+ zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
+ DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
+ }
+
+ compress->handler = wcn_gzip_compressor;
+ compress->L1_buf_sz = L1_buf_sz;
+ compress->L2_buf_sz = L2_buf_sz;
+ compress->L1_pos = 0;
+ compress->L2_pos = 0;
+ compress->uncomp_size = 0;
+ compress->crc32 = 0xffffffffUL;
+
+ compress->L1_buf = osal_malloc(compress->L1_buf_sz);
+ if (!compress->L1_buf) {
+ STP_DBG_ERR_FUNC("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz);
+ goto fail;
+ }
+
+ compress->L2_buf = osal_malloc(compress->L2_buf_sz);
+ if (!compress->L2_buf) {
+ STP_DBG_ERR_FUNC("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz);
+ goto fail;
+ }
+
+ STP_DBG_INFO_FUNC("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz);
+ return compress;
+
+fail:
+ if (compress) {
+ if (compress->L2_buf) {
+ osal_free(compress->L2_buf);
+ compress->L2_buf = NULL;
+ }
+
+ if (compress->L1_buf) {
+ osal_free(compress->L1_buf);
+ compress->L1_buf = NULL;
+ }
+
+ if (compress->worker) {
+ pstream = (z_stream*)compress->worker;
+ if ((compress->compress_type == GZIP) && pstream->workspace) {
+ zlib_deflateEnd(pstream);
+ osal_free(pstream->workspace);
+ }
+ osal_free(compress->worker);
+ compress->worker = NULL;
+ }
+
+ if (compress->worker) {
+ osal_free(compress->worker);
+ compress->worker = NULL;
+ }
+
+ osal_free(compress);
+ compress = NULL;
+ }
+
+ STP_DBG_ERR_FUNC("init failed!\n");
+
+ return NULL;
+}
+
+
+/* wcn_compressor_deinit - distroy a compressor
+ * @ cprs - compressor's pointer
+ *
+ * Retunr 0 if success, else NULL
+ */
+INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T cprs)
+{
+ z_stream *pstream = NULL;
+
+ if (cprs) {
+ if (cprs->L2_buf) {
+ osal_free(cprs->L2_buf);
+ cprs->L2_buf = NULL;
+ }
+
+ if (cprs->L1_buf) {
+ osal_free(cprs->L1_buf);
+ cprs->L1_buf = NULL;
+ }
+
+ if (cprs->worker) {
+ pstream = (z_stream*)cprs->worker;
+ if ((cprs->compress_type == GZIP) && pstream->workspace) {
+ zlib_deflateEnd(pstream);
+ osal_free(pstream->workspace);
+ }
+ osal_free(cprs->worker);
+ cprs->worker = NULL;
+ }
+
+ cprs->handler = NULL;
+
+ osal_free(cprs);
+ }
+
+ STP_DBG_INFO_FUNC("destroy OK\n");
+
+ return 0;
+}
+
+
+/* wcn_compressor_in - put in a raw data, and compress L1 buffer if need
+ * @ cprs - compressor's pointer
+ * @ buf - raw data buffer
+ * @ len - raw data length
+ * @ finish - core dump finish or not, 1: finished; 0: not finish
+ *
+ * Retunr 0 if success, else NULL
+ */
+INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, INT32 finish)
+{
+ INT32 tmp_len = 0;
+ INT32 ret = 0;
+
+ if (!cprs) {
+ STP_DBG_ERR_FUNC("invalid para!\n");
+ return -1;
+ }
+
+ cprs->uncomp_size += len;
+
+ // check L1 buf valid space
+ if (len > (cprs->L1_buf_sz - cprs->L1_pos)) {
+ STP_DBG_INFO_FUNC("L1 buffer full\n");
+
+ if (cprs->f_compress_en && cprs->handler) {
+ // need compress
+ // compress L1 buffer, and put result to L2 buffer
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+ ret = cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], &tmp_len, finish);
+ if (!ret) {
+ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
+ cprs->L2_pos += tmp_len;
+
+ if (finish) {
+ /* Add 8 byte suffix
+ ===
+ 32 bits UNCOMPRESS SIZE
+ 32 bits CRC
+ */
+ *(uint32_t *)(&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL);
+ *(uint32_t *)(&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size;
+ cprs->L2_pos += 8;
+ }
+ STP_DBG_INFO_FUNC("compress OK!\n");
+ } else {
+ STP_DBG_ERR_FUNC("compress error!\n");
+ }
+ } else {
+ // no need compress
+ // Flush L1 buffer to L2 buffer
+ STP_DBG_INFO_FUNC("No need do compress, Put to L2 buf\n");
+
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
+ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
+ cprs->L2_pos += tmp_len;
+ }
+
+ // reset L1 buf pos
+ cprs->L1_pos = 0;
+
+ // put curren data to L1 buf
+ if (len > cprs->L1_buf_sz) {
+ STP_DBG_ERR_FUNC("len=%d, too long err!\n", len);
+ } else {
+ STP_DBG_INFO_FUNC("L1 Flushed, and Put %d bytes to L1 buf\n", len);
+ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ cprs->L1_pos += len;
+ }
+ } else {
+ // put to L1 buffer
+ STP_DBG_INFO_FUNC("Put %d bytes to L1 buf\n", len);
+
+ osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
+ cprs->L1_pos += len;
+ }
+
+ return ret;
+}
+
+
+/* wcn_compressor_out - get the result data from L2 buffer
+ * @ cprs - compressor's pointer
+ * @ pbuf - point to L2 buffer
+ * @ plen - out len
+ *
+ * Retunr 0 if success, else NULL
+ */
+INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T cprs, PUINT8 *pbuf, PINT32 plen)
+{
+ INT32 ret = 0;
+ INT32 tmp_len = 0;
+
+ if ((!cprs) || (!pbuf) || (!plen)) {
+ STP_DBG_ERR_FUNC("invalid para!\n");
+ return -1;
+ }
+
+ // check if there's L1 data need flush to L2 buffer
+ if (cprs->L1_pos > 0) {
+ tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
+
+ if (cprs->f_compress_en && cprs->handler) {
+ // need compress
+ ret = cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos, &cprs->L2_buf[cprs->L2_pos], &tmp_len, 1);
+
+ if (!ret) {
+ cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
+ cprs->L2_pos += tmp_len;
+
+ /* Add 8 byte suffix
+ ===
+ 32 bits UNCOMPRESS SIZE
+ 32 bits CRC
+ */
+ *(uint32_t *)(&cprs->L2_buf[cprs->L2_pos]) = (cprs->crc32 ^ 0xffffffffUL);
+ *(uint32_t *)(&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size;
+ cprs->L2_pos += 8;
+
+ STP_DBG_INFO_FUNC("compress OK!\n");
+ } else {
+ STP_DBG_ERR_FUNC("compress error!\n");
+ }
+ } else {
+ // no need compress
+ tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
+ osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
+ cprs->L2_pos += tmp_len;
+ }
+
+ cprs->L1_pos = 0;
+ }
+
+
+ *pbuf = cprs->L2_buf;
+ *plen = cprs->L2_pos;
+
+ STP_DBG_INFO_FUNC("0x%zx, len %d\n", (SIZE_T)*pbuf, *plen);
+
+ return 0;
+}
+
+
+/* wcn_compressor_reset - reset compressor
+ * @ cprs - compressor's pointer
+ * @ enable - enable/disable compress
+ * @ type - compress algorithm
+ *
+ * Retunr 0 if success, else NULL
+ */
+INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type)
+{
+ if (!cprs) {
+ STP_DBG_ERR_FUNC("invalid para!\n");
+ return -1;
+ }
+
+ cprs->f_compress_en = enable;
+ //cprs->f_compress_en = 0; // disable compress for test
+ cprs->compress_type = type;
+ cprs->L1_pos = 0;
+ cprs->L2_pos = 0;
+ cprs->uncomp_size = 0;
+ cprs->crc32 = 0xffffffffUL;
+
+ //zlib_deflateEnd((z_stream*)cprs->worker);
+
+ STP_DBG_INFO_FUNC("OK! compress algorithm %d\n", type);
+
+ return 0;
+}
+
+
+static void stp_dbg_dump_data(unsigned char *pBuf, char * title, int len)
+{
+ int k = 0;
+ printk(" %s-len:%d\n", title, len);
+ //printk(" ", title, len);
+ for(k=0; k < len ; k++){
+ if(k%16 == 0 && k != 0) printk("\n ");
+ printk("0x%02x ", pBuf[k]);
+ }
+ printk("--end\n");
+}
+
+
+static int _stp_dbg_enable(MTKSTP_DBG_T *stp_dbg){
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ stp_dbg->pkt_trace_no=0;
+ stp_dbg->is_enable=1;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+static int _stp_dbg_disable(MTKSTP_DBG_T *stp_dbg){
+
+ unsigned long flags;
+
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ stp_dbg->pkt_trace_no=0;
+ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T));
+ stp_dbg->is_enable=0;
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+static int _stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len){
+
+ unsigned long flags;
+ unsigned int internalFlag = stp_dbg->logsys->size < STP_DBG_LOG_ENTRY_NUM;
+ //#ifdef CONFIG_LOG_STP_INTERNAL
+ //Here we record log in this circle buffer, if buffer is full , select to overlap earlier log, logic should be okay
+ internalFlag = 1;
+ //#endif
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+
+ if(internalFlag){
+ stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0;
+ stp_dbg->logsys->queue[stp_dbg->logsys->in].len = len;
+ memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),
+ 0, ((len >= STP_DBG_LOG_ENTRY_SZ)? (STP_DBG_LOG_ENTRY_SZ):(len)));
+ memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),
+ buf, ((len >= STP_DBG_LOG_ENTRY_SZ)? (STP_DBG_LOG_ENTRY_SZ):(len)));
+
+ stp_dbg->logsys->size++;
+ stp_dbg->logsys->size = (stp_dbg->logsys->size > STP_DBG_LOG_ENTRY_NUM) ? STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size;
+
+ if (0 != gStpDbgLogOut)
+ {
+ STP_DBG_HDR_T *pHdr = NULL;
+ char* pBuf = NULL;
+ unsigned int len =0;
+ pHdr = (STP_DBG_HDR_T *)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]);
+ pBuf = (char *)&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) + sizeof (STP_DBG_HDR_T);
+ len = stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof (STP_DBG_HDR_T);
+ printk("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", \
+ pHdr->sec,
+ pHdr->usec,
+ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
+ gStpDbgType[pHdr->type],
+ pHdr->no,
+ pHdr->len,
+ pHdr->seq,
+ pHdr->ack
+
+ );
+ if (0 < len){
+ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len);
+ }
+
+ }
+ stp_dbg->logsys->in = (stp_dbg->logsys->in >= (STP_DBG_LOG_ENTRY_NUM - 1))?(0):(stp_dbg->logsys->in + 1);
+ STP_DBG_DBG_FUNC("logsys size = %d, in = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->in);
+ } else {
+ STP_DBG_WARN_FUNC("logsys FULL!\n");
+ }
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+int stp_gdb_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg){
+ int retval = 0;
+//#ifndef CONFIG_LOG_STP_INTERNAL
+
+ if(stp_dbg->btm != NULL){
+ retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *)stp_dbg->btm);
+ }
+
+//#endif
+
+ return retval;
+}
+
+int stp_dbg_log_ctrl (unsigned int on)
+{
+ if (on != 0)
+ {
+ gStpDbgLogOut = 1;
+ printk ("STP-DBG: enable pkt log dump out.\n");
+ }
+ else
+ {
+ gStpDbgLogOut = 0;
+ printk ("STP-DBG: disable pkt log dump out.\n");
+ }
+ return 0;
+}
+
+int stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, char *buf, int len){
+ return _stp_dbg_dmp_in(stp_dbg, buf, len);
+}
+
+
+int stp_dbg_dmp_printk(MTKSTP_DBG_T *stp_dbg)
+{
+ #define MAX_DMP_NUM 80
+ unsigned long flags;
+ char *pBuf = NULL;
+ int len = 0;
+ STP_DBG_HDR_T *pHdr = NULL;
+ UINT32 dumpSize = 0;
+ UINT32 inIndex = 0;
+ UINT32 outIndex = 0;
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+ //Not to dequeue from loging system
+ inIndex = stp_dbg->logsys->in;
+ dumpSize = stp_dbg->logsys->size;
+ if (STP_DBG_LOG_ENTRY_NUM == dumpSize)
+ {
+ outIndex = inIndex;
+ }
+ else
+ {
+ outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM;
+ }
+
+ if (dumpSize > MAX_DMP_NUM)
+ {
+
+ outIndex += (dumpSize - MAX_DMP_NUM);
+ outIndex %= STP_DBG_LOG_ENTRY_NUM;
+ dumpSize = MAX_DMP_NUM;
+
+ }
+ STP_DBG_INFO_FUNC("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex);
+ while(dumpSize > 0){
+ pHdr = (STP_DBG_HDR_T *)&(stp_dbg->logsys->queue[outIndex].buffer[0]);
+ pBuf = &(stp_dbg->logsys->queue[outIndex].buffer[0]) + sizeof (STP_DBG_HDR_T);
+ len = stp_dbg->logsys->queue[outIndex].len - sizeof (STP_DBG_HDR_T);
+ len = len > STP_PKT_SZ ? STP_PKT_SZ : len;
+ printk("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", \
+ pHdr->sec,
+ pHdr->usec,
+ pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
+ gStpDbgType[pHdr->type],
+ pHdr->no,
+ pHdr->len,
+ pHdr->seq,
+ pHdr->ack
+ );
+
+
+ if (0 < len){
+ stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len);
+ }
+ outIndex = (outIndex >= (STP_DBG_LOG_ENTRY_NUM - 1))?(0):(outIndex + 1);
+ dumpSize--;
+
+ }
+
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return 0;
+}
+
+int stp_dbg_dmp_out_ex (char *buf, int *len){
+ return stp_dbg_dmp_out(g_stp_dbg, buf, len);
+}
+
+int stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, char *buf, int *len){
+
+ unsigned long flags;
+ int remaining = 0;
+ *len = 0;
+ spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
+
+ if(stp_dbg->logsys->size > 0){
+ memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]),
+ stp_dbg->logsys->queue[stp_dbg->logsys->out].len);
+
+ (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len;
+ stp_dbg->logsys->out = (stp_dbg->logsys->out >= (STP_DBG_LOG_ENTRY_NUM - 1))?(0):(stp_dbg->logsys->out + 1);
+ stp_dbg->logsys->size--;
+
+ STP_DBG_DBG_FUNC("logsys size = %d, out = %d\n", stp_dbg->logsys->size, stp_dbg->logsys->out);
+ } else {
+ STP_DBG_LOUD_FUNC("logsys EMPTY!\n");
+ }
+
+ remaining = (stp_dbg->logsys->size == 0)?(0):(1);
+
+ spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
+
+ return remaining;
+}
+
+static int stp_dbg_fill_hdr(struct stp_dbg_pkt_hdr *hdr, int type, int ack, int seq, int crc, int dir, int len, int dbg_type){
+
+ struct timeval now;
+
+ if(!hdr){
+ STP_DBG_ERR_FUNC("function invalid\n");
+ return -EINVAL;
+ } else {
+ do_gettimeofday(&now);
+ hdr->dbg_type = dbg_type;
+ hdr->ack = ack;
+ hdr->seq = seq;
+ hdr->sec = now.tv_sec;
+ hdr->usec = now.tv_usec;
+ hdr->crc = crc;
+ hdr->dir = dir;//rx
+ hdr->dmy = 0xffffffff;
+ hdr->len = len;
+ hdr->type = type;
+ return 0;
+ }
+}
+
+static int
+stp_dbg_add_pkt (
+ MTKSTP_DBG_T*stp_dbg,
+ struct stp_dbg_pkt_hdr *hdr,
+ const unsigned char *body
+ )
+{
+ //fix the frame size large issues.
+ static struct stp_dbg_pkt stp_pkt;
+ uint32_t hdr_sz = sizeof(struct stp_dbg_pkt_hdr);
+ uint32_t body_sz = 0;
+
+ BUG_ON(!stp_dbg);
+
+ if(hdr->dbg_type == STP_DBG_PKT){
+ body_sz = (hdr->len <= STP_PKT_SZ)?(hdr->len):(STP_PKT_SZ);
+ }else{
+ body_sz = (hdr->len <= STP_DMP_SZ)?(hdr->len):(STP_DMP_SZ);
+ }
+
+ hdr->no = stp_dbg->pkt_trace_no++;
+ memcpy((uint8_t *)&stp_pkt.hdr, (uint8_t*)hdr, hdr_sz);
+ if(body != NULL){
+ memcpy((uint8_t *)&stp_pkt.raw[0], body, body_sz);
+ }
+ _stp_dbg_dmp_in(stp_dbg, (char *) &stp_pkt, hdr_sz + body_sz);
+ //Only FW DMP MSG should inform BTM-CORE to dump packet to native process
+ if(hdr->dbg_type == STP_DBG_FW_DMP)
+ {
+ stp_gdb_notify_btm_dmp_wq(stp_dbg);
+ }
+
+ return 0;
+}
+
+int stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, int dbg_type,
+ int type, int ack_no, int seq_no, int crc, int dir, int len, const unsigned char *body) {
+
+ struct stp_dbg_pkt_hdr hdr;
+
+ if (stp_dbg->is_enable == 0) {
+ /*dbg is disable,and not to log*/
+ }
+ else {
+ stp_dbg_fill_hdr(&hdr,
+ (int) type,
+ (int) ack_no,
+ (int) seq_no,
+ (int) crc,
+ (int) dir,
+ (int) len,
+ (int) dbg_type);
+
+ stp_dbg_add_pkt(stp_dbg, &hdr, body);
+ }
+
+ return 0;
+}
+
+int stp_dbg_enable(MTKSTP_DBG_T *stp_dbg){
+ return _stp_dbg_enable(stp_dbg);
+}
+
+int stp_dbg_disable(MTKSTP_DBG_T *stp_dbg){
+ return _stp_dbg_disable(stp_dbg);
+}
+
+static void stp_dbg_nl_init(void)
+{
+ if(genl_register_family(&stp_dbg_gnl_family) != 0)
+ {
+ STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__);
+ }
+ else
+ {
+ if(genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_bind) != 0)
+ {
+ STP_DBG_ERR_FUNC("%s(): BIND operation registration fail\n", __func__);
+ }
+
+ if(genl_register_ops(&stp_dbg_gnl_family, &stp_dbg_gnl_ops_reset) != 0)
+ {
+ STP_DBG_ERR_FUNC("%s(): RESET operation registration fail\n", __func__);
+ }
+ }
+
+ return;
+}
+
+static void stp_dbg_nl_deinit(void)
+{
+ genl_unregister_family(&stp_dbg_gnl_family);
+ return;
+}
+
+static int stp_dbg_nl_bind(
+ struct sk_buff *skb,
+ struct genl_info *info
+ )
+{
+ struct nlattr *na;
+ char * mydata;
+
+ if (info == NULL)
+ {
+ goto out;
+ }
+
+ STP_DBG_INFO_FUNC("%s():->\n", __func__);
+
+ na = info->attrs[STP_DBG_ATTR_MSG];
+
+ if (na)
+ {
+ mydata = (char *)nla_data(na);
+ }
+
+ if(num_bind_process < MAX_BIND_PROCESS)
+ {
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0))
+ bind_pid[num_bind_process] = info->snd_pid;
+ num_bind_process++;
+ STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_pid);
+#else
+ bind_pid[num_bind_process] = info->snd_portid;
+ num_bind_process++;
+ STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_portid);
+#endif
+ }
+ else
+ {
+ STP_DBG_ERR_FUNC("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS);
+ }
+
+out:
+ return 0;
+}
+
+static int stp_dbg_nl_reset(
+ struct sk_buff *skb,
+ struct genl_info *info
+ )
+{
+ STP_DBG_ERR_FUNC("%s(): should not be invoked\n", __func__);
+
+ return 0;
+}
+
+char
+stp_dbg_nl_send(
+ char * aucMsg,
+ unsigned char cmd
+ )
+{
+ struct sk_buff *skb = NULL;
+ void *msg_head = NULL;
+ int rc = -1;
+ int i;
+
+ if(num_bind_process == 0)
+ {
+ /* no listening process */
+ STP_DBG_ERR_FUNC("%s(): the process is not invoked\n", __func__);
+ return 0;
+ }
+
+ for(i = 0 ; i < num_bind_process ; i++)
+ {
+ skb = genlmsg_new(2048, GFP_KERNEL);
+
+ if(skb)
+ {
+ msg_head = genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd);
+ if(msg_head == NULL)
+ {
+ nlmsg_free(skb);
+ STP_DBG_ERR_FUNC("%s(): genlmsg_put fail...\n", __func__);
+ return -1;
+ }
+
+ rc = nla_put_string(skb, STP_DBG_ATTR_MSG, aucMsg);
+ if(rc != 0)
+ {
+ nlmsg_free(skb);
+ STP_DBG_ERR_FUNC("%s(): nla_put_string fail...\n", __func__);
+ return -1;
+ }
+
+ /* finalize the message */
+ genlmsg_end(skb, msg_head);
+
+ /* sending message */
+ rc = genlmsg_unicast(&init_net, skb, bind_pid[i]);
+ if(rc != 0)
+ {
+ STP_DBG_ERR_FUNC("%s(): genlmsg_unicast fail...\n", __func__);
+ return -1;
+ }
+ }
+ else
+ {
+ STP_DBG_ERR_FUNC("%s(): genlmsg_new fail...\n", __func__);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+INT32 stp_dbg_aee_send(unsigned char *aucMsg, INT32 len, INT32 cmd)
+{
+ INT32 ret = 0;
+
+ // buffered to compressor
+ ret = wcn_core_dump_in(g_core_dump, aucMsg, len);
+ if (ret == 1) {
+ wcn_core_dump_flush(0);
+ }
+
+ return ret;
+}
+UINT8 *_stp_dbg_id_to_task(UINT32 id)
+{
+ UINT8 *taskStr[] =
+ {
+ "Task_WMT",
+ "Task_BT",
+ "Task_Wifi",
+ "Task_Tst",
+ "Task_FM",
+ "Task_Idle",
+ "Task_DrvStp",
+ "Task_DrvBtif",
+ "Task_NatBt"
+ };
+ return taskStr[id];
+}
+INT32 _stp_dbg_parser_assert_str(PINT8 str,ENUM_ASSERT_INFO_PARSER_TYPE type)
+{
+ char *pStr = NULL;
+ char *pDtr = NULL;
+ char *pTemp = NULL;
+ char *pTemp2 = NULL;
+ char tempBuf[64] = {0};
+ UINT32 len = 0;
+
+ char *parser_sub_string[] =
+ {
+ "<ASSERT> ",
+ "id=",
+ "isr=",
+ "irq=",
+ "rc="
+ };
+
+ if(!str)
+ {
+ STP_DBG_ERR_FUNC("NULL string source\n");
+ return -1;
+ }
+
+ if(!g_stp_dbg_cpupcr)
+ {
+ STP_DBG_ERR_FUNC("NULL pointer\n");
+ return -2;
+ }
+
+ pStr = str;
+ STP_DBG_DBG_FUNC("source infor:%s\n",pStr);
+ switch(type){
+ case STP_DBG_ASSERT_INFO:
+ pDtr = osal_strstr(pStr,parser_sub_string[type]);
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr,' ');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",parser_sub_string[type]);
+ return -3;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0],"assert@",osal_strlen("assert@"));
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")],pDtr,len);
+ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_';
+
+ pTemp = osal_strchr(pDtr,'#');
+ pTemp += 1;
+
+ pTemp2 = osal_strchr(pTemp,' ');
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1],pTemp,pTemp2 - pTemp);
+ g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] = '\0';
+ STP_DBG_INFO_FUNC("assert info:%s\n",&g_stp_dbg_cpupcr->assert_info[0]);
+ break;
+ case STP_DBG_FW_TASK_ID:
+ pDtr = osal_strstr(pStr,parser_sub_string[type]);
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr,' ');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",parser_sub_string[type]);
+ return -3;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0],pDtr,len);
+ tempBuf[len] = '\0';
+ g_stp_dbg_cpupcr->fwTaskId = osal_strtol(tempBuf, NULL, 16);
+
+ STP_DBG_INFO_FUNC("fw task id :%x\n",(UINT32)osal_strtol(tempBuf, NULL, 16));
+ break;
+ case STP_DBG_FW_ISR:
+ pDtr = osal_strstr(pStr,parser_sub_string[type]);
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr,',');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",parser_sub_string[type]);
+ return -3;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0],pDtr,len);
+ tempBuf[len] = '\0';
+
+ g_stp_dbg_cpupcr->fwIsr = osal_strtol(tempBuf, NULL, 16);
+
+ STP_DBG_INFO_FUNC("fw isr str:%x\n",(UINT32)osal_strtol(tempBuf, NULL, 16));
+ break;
+ case STP_DBG_FW_IRQ:
+ pDtr = osal_strstr(pStr,parser_sub_string[type]);
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr,',');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",parser_sub_string[type]);
+ return -3;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0],pDtr,len);
+ tempBuf[len] = '\0';
+ g_stp_dbg_cpupcr->fwRrq = osal_strtol(tempBuf, NULL, 16);
+
+ STP_DBG_INFO_FUNC("fw irq value:%x\n",(UINT32)osal_strtol(tempBuf, NULL, 16));
+ break;
+ case STP_DBG_ASSERT_TYPE:
+ pDtr = osal_strstr(pStr,parser_sub_string[type]);
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen(parser_sub_string[type]);
+ pTemp = osal_strchr(pDtr,',');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",parser_sub_string[type]);
+ return -3;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0],pDtr,len);
+ tempBuf[len] = '\0';
+
+ if(0 == osal_memcmp(tempBuf,"*",len))
+ {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0],"general assert",osal_strlen("general assert"));
+ }
+ if(0 == osal_memcmp(tempBuf,"Watch Dog Timeout",len))
+ {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0],"wdt",osal_strlen("wdt"));
+ }
+ if(0 == osal_memcmp(tempBuf,"RB_FULL",osal_strlen("RB_FULL")))
+ {
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0],tempBuf,len);
+
+ pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0],"RB_FULL(");
+ if(NULL != pDtr)
+ {
+ pDtr += osal_strlen("RB_FULL(");
+ pTemp = osal_strchr(pDtr,')');
+ }else
+ {
+ STP_DBG_ERR_FUNC("parser str is NULL,substring(RB_FULL()\n");
+ return -4;
+ }
+ len = pTemp - pDtr;
+ osal_memcpy(&tempBuf[0],pDtr,len);
+ tempBuf[len] = '\0';
+
+ g_stp_dbg_cpupcr->fwTaskId = osal_strtol(tempBuf, NULL, 16);
+
+ STP_DBG_INFO_FUNC("update fw task id :%x\n",(UINT32)osal_strtol(tempBuf, NULL, 16));
+ }
+
+ STP_DBG_INFO_FUNC("fw asert type:%s\n",g_stp_dbg_cpupcr->assert_type);
+ break;
+ default:
+ STP_DBG_ERR_FUNC("unknow parser type\n");
+ break;
+ }
+
+ return 0;
+}
+P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID)
+{
+ P_STP_DBG_CPUPCR_T pSdCpupcr = NULL;
+
+ pSdCpupcr = (P_STP_DBG_CPUPCR_T)osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T));
+ if(!pSdCpupcr){
+ STP_DBG_ERR_FUNC("stp dbg cpupcr allocate memory fail!\n");
+ return NULL;
+ }
+
+ osal_memset(pSdCpupcr,0,osal_sizeof(STP_DBG_CPUPCR_T));
+
+ osal_sleepable_lock_init(&pSdCpupcr->lock);
+
+ return pSdCpupcr;
+}
+
+P_STP_DBG_DMAREGS_T stp_dbg_dmaregs_init(VOID)
+{
+ P_STP_DBG_DMAREGS_T pDmaRegs = NULL;
+
+ pDmaRegs = (P_STP_DBG_DMAREGS_T)osal_malloc(osal_sizeof(STP_DBG_DMAREGS_T));
+ if(!pDmaRegs){
+ STP_DBG_ERR_FUNC("stp dbg dmareg allocate memory fail!\n");
+ return NULL;
+ }
+
+ osal_memset(pDmaRegs,0,osal_sizeof(STP_DBG_DMAREGS_T));
+
+ osal_sleepable_lock_init(&pDmaRegs->lock);
+
+ return pDmaRegs;
+}
+
+VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr)
+{
+ if(pCpupcr)
+ {
+ osal_sleepable_lock_deinit(&pCpupcr->lock);
+ osal_free(pCpupcr);
+ pCpupcr = NULL;
+ }
+}
+VOID stp_dbg_dmaregs_deinit(P_STP_DBG_DMAREGS_T pDmaRegs)
+{
+ if(pDmaRegs)
+ {
+ osal_sleepable_lock_deinit(&pDmaRegs->lock);
+ osal_free(pDmaRegs);
+ pDmaRegs = NULL;
+ }
+}
+INT32 stp_dbg_poll_cpupcr(UINT32 times,UINT32 sleep,UINT32 cmd)
+{
+ INT32 i = 0;
+
+ if(!g_stp_dbg_cpupcr)
+ {
+ STP_DBG_ERR_FUNC("NULL reference pointer\n");
+ return -1;
+ }
+
+ if(!cmd)
+ {
+ if(g_stp_dbg_cpupcr->count + times > STP_DBG_CPUPCR_NUM)
+ {
+ times = STP_DBG_CPUPCR_NUM - g_stp_dbg_cpupcr->count;
+ }
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ for(i = 0;i < times;i++)
+ {
+ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n",i,wmt_plat_read_cpupcr());
+ //osal_memcpy(&g_stp_dbg_cpupcr->buffer[i],(UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)),osal_sizeof(UINT32));
+ g_stp_dbg_cpupcr->buffer[g_stp_dbg_cpupcr->count + i] = wmt_plat_read_cpupcr();
+ osal_sleep_ms(sleep);
+ }
+ g_stp_dbg_cpupcr->count += times;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }else
+ {
+ STP_DBG_INFO_FUNC("stp-dbg: for proc test polling cpupcr\n");
+ if(times > STP_DBG_CPUPCR_NUM)
+ {
+ times = STP_DBG_CPUPCR_NUM;
+ }
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->count = 0;
+ for(i = 0;i < times;i++)
+ {
+ STP_DBG_INFO_FUNC("i:%d,cpupcr:%08x\n",i,wmt_plat_read_cpupcr());
+ //osal_memcpy(&g_stp_dbg_cpupcr->buffer[i],(UINT8*)(CONSYS_REG_READ(CONSYS_CPUPCR_REG)),osal_sizeof(UINT32));
+ g_stp_dbg_cpupcr->buffer[i] = wmt_plat_read_cpupcr();
+ osal_sleep_ms(sleep);
+ }
+ g_stp_dbg_cpupcr->count = times;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ }
+ return 0;
+}
+
+INT32 stp_dbg_poll_dmaregs(UINT32 times, UINT32 sleep)
+{
+ INT32 i = 0;
+
+ if(!g_stp_dbg_dmaregs)
+ {
+ STP_DBG_ERR_FUNC("NULL reference pointer\n");
+ return -1;
+ }
+
+ if(g_stp_dbg_dmaregs->count + times > STP_DBG_DMAREGS_NUM)
+ {
+ times = STP_DBG_DMAREGS_NUM - g_stp_dbg_dmaregs->count;
+ }
+
+ osal_lock_sleepable_lock(&g_stp_dbg_dmaregs->lock);
+
+ STP_DBG_WARN_FUNC("---------Now Polling DMA relative Regs ------------- \n");
+ for(i = 0;i < times;i++)
+ {
+ INT32 k = 0;
+ for(; k < DMA_REGS_MAX; k++)
+ {
+ STP_DBG_WARN_FUNC("times:%d,i:%d reg: %s, regs:%08x\n",times, i, dmaRegsStr[k], wmt_plat_read_dmaregs(k));
+ //g_stp_dbg_dmaregs->dmaIssue[k][g_stp_dbg_dmaregs->count + i] = wmt_plat_read_dmaregs(k);
+ }
+ osal_sleep_ms(sleep);
+ }
+ STP_DBG_WARN_FUNC("---------Polling DMA relative Regs End------------- \n");
+ g_stp_dbg_dmaregs->count += times;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_dmaregs->lock);
+ return 0;
+}
+
+INT32 stp_dbg_poll_cuppcr_ctrl(UINT32 en)
+{
+
+ STP_DBG_INFO_FUNC("%s polling cpupcr\n",en == 0? "start":"stop");
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->stop_flag = en;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ return 0;
+}
+
+INT32 stp_dbg_set_version_info(UINT32 chipid,UINT8 *pRomVer,UINT8 *wifiVer,UINT8 *pPatchVer,UINT8 *pPatchBrh)
+{
+ if(g_stp_dbg_cpupcr)
+ {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ g_stp_dbg_cpupcr->chipId = chipid;
+
+ if(wifiVer)
+ {
+ osal_memcpy(g_stp_dbg_cpupcr->wifiVer,wifiVer,4);
+ }
+ if(pRomVer)
+ {
+ osal_memcpy(g_stp_dbg_cpupcr->romVer,pRomVer,2);
+ }
+ if(pPatchVer)
+ {
+ osal_memcpy(g_stp_dbg_cpupcr->patchVer,pPatchVer,8);
+ }
+ if(pPatchBrh)
+ {
+ osal_memcpy(g_stp_dbg_cpupcr->branchVer,pPatchBrh,4);
+ }
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }
+ else
+ {
+ STP_DBG_ERR_FUNC("NULL pointer\n");
+ return -1;
+ }
+ STP_DBG_INFO_FUNC("chipid(0x%x),wifiver(%s),romver(%s),patchver(%s),branchver(%s)\n",
+ g_stp_dbg_cpupcr->chipId,g_stp_dbg_cpupcr->wifiVer,&g_stp_dbg_cpupcr->romVer[0],
+ &g_stp_dbg_cpupcr->patchVer[0],&g_stp_dbg_cpupcr->branchVer[0]);
+ return 0;
+}
+
+INT32 stp_dbg_set_host_assert_info(UINT32 drv_type,UINT32 reason,UINT32 en)
+{
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en;
+ g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type;
+ g_stp_dbg_cpupcr->host_assert_info.reason = reason;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ return 0;
+}
+
+UINT32 stp_dbg_get_host_trigger_assert(VOID)
+{
+ return g_stp_dbg_cpupcr->host_assert_info.assert_from_host;
+}
+
+
+INT32 stp_dbg_set_fw_info(UINT8 *issue_info,UINT32 len,ENUM_STP_FW_ISSUE_TYPE issue_type)
+{
+ ENUM_ASSERT_INFO_PARSER_TYPE type_index;
+ PUINT8 tempbuf = NULL;
+ UINT32 i = 0;
+ INT32 iRet = 0;
+
+ if(NULL == issue_info)
+ {
+ STP_DBG_ERR_FUNC("null issue infor\n");
+ return -1;
+ }
+ STP_DBG_INFO_FUNC("issue type(%d)\n",issue_type);
+ g_stp_dbg_cpupcr->issue_type = issue_type;
+ osal_memset(&g_stp_dbg_cpupcr->assert_info[0],0,STP_ASSERT_INFO_SIZE);
+
+ /*print patch version when assert happened*/
+ STP_DBG_INFO_FUNC("=======================================\n");
+ STP_DBG_INFO_FUNC("[consys patch]patch version:%s\n",g_stp_dbg_cpupcr->patchVer);
+ STP_DBG_INFO_FUNC("[consys patch]ALPS branch:%s\n",g_stp_dbg_cpupcr->branchVer);
+ STP_DBG_INFO_FUNC("=======================================\n");
+
+ if((STP_FW_ASSERT_ISSUE == issue_type) || (STP_HOST_TRIGGER_FW_ASSERT == issue_type))
+ {
+ tempbuf = osal_malloc(len);
+ if(!tempbuf)
+ {
+ return -2;
+ }
+ osal_memcpy(&tempbuf[0],issue_info,len);
+
+ for(i = 0;i < len;i++)
+ {
+ if(tempbuf[i] == '\0')
+ tempbuf[i] = '?';
+ }
+
+ tempbuf[len] = '\0';
+#if 0
+ STP_DBG_INFO_FUNC("FW assert infor len(%d)\n",len);
+ for(i = 0;i < len;i++)
+ {
+ if(0 == len%64)
+ printk("\n");
+ printk("%c",tempbuf[i]);
+ }
+ printk("\n");
+#endif
+ for(type_index = STP_DBG_ASSERT_INFO;type_index < STP_DBG_PARSER_TYPE_MAX;type_index ++)
+ {
+ iRet += _stp_dbg_parser_assert_str(&tempbuf[0],type_index);
+ }
+ if(iRet)
+ {
+ STP_DBG_ERR_FUNC("passert assert infor fail(%d)\n",iRet);
+ }
+
+ if(STP_HOST_TRIGGER_FW_ASSERT == issue_type)
+ {
+ switch(g_stp_dbg_cpupcr->host_assert_info.drv_type) {
+ case 0:
+ STP_DBG_INFO_FUNC("bt trigger assert\n");
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ if(31 != g_stp_dbg_cpupcr->host_assert_info.reason)
+ /*BT firmware trigger assert*/
+ {
+ g_stp_dbg_cpupcr->fwTaskId = 1;
+
+ }else
+ /*BT stack trigger assert*/
+ {
+ g_stp_dbg_cpupcr->fwTaskId = 8;
+ }
+
+ g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0;
+ //g_stp_dbg_cpupcr->host_assert_info.drv_type = 0;
+ //g_stp_dbg_cpupcr->host_assert_info.reason = 0;
+
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ break;
+ default:
+ break;
+ }
+
+ }
+ osal_free(tempbuf);
+ }
+ else if(STP_FW_NOACK_ISSUE == issue_type)
+ {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0],issue_info,len);
+ g_stp_dbg_cpupcr->fwTaskId = 6;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }else if(STP_DBG_PROC_TEST == issue_type)
+ {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0],issue_info,len);
+ g_stp_dbg_cpupcr->fwTaskId = 0;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }else if(STP_FW_WARM_RST_ISSUE == issue_type)
+ {
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0],issue_info,len);
+ g_stp_dbg_cpupcr->fwTaskId = 0;
+ g_stp_dbg_cpupcr->fwRrq = 0;
+ g_stp_dbg_cpupcr->fwIsr = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ }
+ else
+ {
+ STP_DBG_ERR_FUNC("invalid issue type(%d)\n",issue_type);
+ return -3;
+ }
+
+ return iRet;
+}
+
+
+INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf,PUINT32 str_len)
+{
+ UINT32 len = 0;
+ UINT32 i = 0;
+ if(!g_stp_dbg_cpupcr)
+ {
+ STP_DBG_ERR_FUNC("NULL pointer\n");
+ return -1;
+ }
+
+ /*format common information about issue*/
+ len = osal_sprintf(*buf,"<main>\n\t");
+ len += osal_sprintf(*buf + len,"<chipid>\n\t\tMT%x\n\t</chipid>\n\t",g_stp_dbg_cpupcr->chipId);
+ len += osal_sprintf(*buf + len,"<version>\n\t\t");
+ len += osal_sprintf(*buf + len,"<rom>%s</rom>\n\t\t",g_stp_dbg_cpupcr->romVer);
+ if(!(osal_memcmp(g_stp_dbg_cpupcr->branchVer,"ALPS",STP_PATCH_BRANCH_SZIE)))
+ {
+ len += osal_sprintf(*buf + len,"<branch>Internal Dev</branch>\n\t\t",g_stp_dbg_cpupcr->branchVer);
+ }else
+ {
+ len += osal_sprintf(*buf + len,"<branch>W%sMP</branch>\n\t\t",g_stp_dbg_cpupcr->branchVer);
+ }
+ len += osal_sprintf(*buf + len,"<patch>%s</patch>\n\t\t",g_stp_dbg_cpupcr->patchVer);
+
+ if(!g_stp_dbg_cpupcr->wifiVer[0])
+ {
+ len += osal_sprintf(*buf + len,"<wifi>NULL</wifi>\n\t");
+ }else
+ {
+ len += osal_sprintf(*buf + len,"<wifi>%s</wifi>\n\t",g_stp_dbg_cpupcr->wifiVer);
+ }
+ len += osal_sprintf(*buf + len,"</version>\n\t");
+
+ /*format issue information: no ack, assert*/
+ len += osal_sprintf(*buf + len,"<issue>\n\t\t<classification>\n\t\t\t");
+ if((STP_FW_NOACK_ISSUE == g_stp_dbg_cpupcr->issue_type) ||
+ (STP_DBG_PROC_TEST == g_stp_dbg_cpupcr->issue_type) ||
+ (STP_FW_WARM_RST_ISSUE == g_stp_dbg_cpupcr->issue_type))
+ {
+ len += osal_sprintf(*buf + len,"%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t",g_stp_dbg_cpupcr->assert_info);
+ len += osal_sprintf(*buf + len,"NULL\n\t\t</rc>\n\t</issue>\n\t");
+ len += osal_sprintf(*buf + len,"<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
+ len += osal_sprintf(*buf + len,"<host>NULL</host>\n\t\t");
+ len += osal_sprintf(*buf + len,"<client>\n\t\t\t<task>%s</task>\n\t\t\t",_stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
+ len += osal_sprintf(*buf + len,"<irqx>IRQ_0x%x</irqx>\n\t\t\t",g_stp_dbg_cpupcr->fwRrq);
+ len += osal_sprintf(*buf + len,"<isr>0x%x</isr>\n\t\t\t",g_stp_dbg_cpupcr->fwIsr);
+ len += osal_sprintf(*buf + len,"<drv_type>NULL</drv_type>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<reason>NULL</reason>\n\t\t\t");
+ }else if((STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) ||
+ (STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type))
+ {
+ len += osal_sprintf(*buf + len,"%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t",g_stp_dbg_cpupcr->assert_info);
+ len += osal_sprintf(*buf + len,"%s\n\t\t</rc>\n\t</issue>\n\t",g_stp_dbg_cpupcr->assert_type);
+ len += osal_sprintf(*buf + len,"<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
+ len += osal_sprintf(*buf + len,"<host>NULL</host>\n\t\t");
+ len += osal_sprintf(*buf + len,"<client>\n\t\t\t<task>%s</task>\n\t\t\t",_stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
+ if(32 == g_stp_dbg_cpupcr->host_assert_info.reason)
+ {
+ /*handling wmt turn on/off bt cmd has ack but no evt issue*/
+ len += osal_sprintf(*buf + len,"<irqx>NULL</irqx>\n\t\t\t");
+ }else
+ {
+ len += osal_sprintf(*buf + len,"<irqx>IRQ_0x%x</irqx>\n\t\t\t",g_stp_dbg_cpupcr->fwRrq);
+ }
+ len += osal_sprintf(*buf + len,"<isr>0x%x</isr>\n\t\t\t",g_stp_dbg_cpupcr->fwIsr);
+
+ if(STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type)
+ {
+ len += osal_sprintf(*buf + len,"<drv_type>NULL</drv_type>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<reason>NULL</reason>\n\t\t\t");
+ }
+
+ if(STP_HOST_TRIGGER_FW_ASSERT == g_stp_dbg_cpupcr->issue_type)
+ {
+ len += osal_sprintf(*buf + len,"<drv_type>%d</drv_type>\n\t\t\t",g_stp_dbg_cpupcr->host_assert_info.drv_type);
+ len += osal_sprintf(*buf + len,"<reason>%d</reason>\n\t\t\t",g_stp_dbg_cpupcr->host_assert_info.reason);
+ }
+ }else
+ {
+ len += osal_sprintf(*buf + len,"NULL\n\t\t</classification>\n\t\t<rc>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"NULL\n\t\t</rc>\n\t</issue>\n\t");
+ len += osal_sprintf(*buf + len,"<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
+ len += osal_sprintf(*buf + len,"<host>NULL</host>\n\t\t");
+ len += osal_sprintf(*buf + len,"<client>\n\t\t\t<task>NULL</task>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<irqx>NULL</irqx>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<isr>NULL</isr>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<drv_type>NULL</drv_type>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<reason>NULL</reason>\n\t\t\t");
+ }
+
+ len += osal_sprintf(*buf + len,"<pctrace>");
+ STP_DBG_INFO_FUNC("stp-dbg:sub len1 for debug(%d)\n",len);
+
+ if(!g_stp_dbg_cpupcr->count)
+ {
+ len += osal_sprintf(*buf + len,"NULL");
+ }
+ else
+ {
+ for(i = 0;i < g_stp_dbg_cpupcr->count;i++)
+ {
+ len += osal_sprintf(*buf + len,"%08x,",g_stp_dbg_cpupcr->buffer[i]);
+ }
+ }
+ STP_DBG_INFO_FUNC("stp-dbg:sub len2 for debug(%d)\n",len);
+ len += osal_sprintf(*buf + len,"</pctrace>\n\t\t\t");
+ len += osal_sprintf(*buf + len,"<extension>NULL</extension>\n\t\t</client>\n\t</hint>\n</main>\n");
+ STP_DBG_INFO_FUNC("buffer len[%d]\n",len);
+ //STP_DBG_INFO_FUNC("Format infor:\n%s\n",*buf);
+ *str_len = len;
+
+ osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+ osal_memset(&g_stp_dbg_cpupcr->buffer[0],0,STP_DBG_CPUPCR_NUM);
+ g_stp_dbg_cpupcr->count = 0;
+ g_stp_dbg_cpupcr->host_assert_info.reason = 0;
+ g_stp_dbg_cpupcr->host_assert_info.drv_type = 0;
+ osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
+
+ return 0;
+
+}
+
+MTKSTP_DBG_T *stp_dbg_init(void *btm_half){
+
+ MTKSTP_DBG_T *stp_dbg= NULL;
+ STP_DBG_INFO_FUNC("stp-dbg init\n");
+
+ stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL);
+ if(IS_ERR(stp_dbg)){
+ STP_DBG_ERR_FUNC("-ENOMEM\n");
+ goto ERR_EXIT1;
+ }
+
+ stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T));
+ if(IS_ERR(stp_dbg->logsys)){
+ STP_DBG_ERR_FUNC("-ENOMEM stp_gdb->logsys\n");
+ goto ERR_EXIT2;
+ }
+ memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T));
+ spin_lock_init(&(stp_dbg->logsys->lock));
+ stp_dbg->pkt_trace_no=0;
+ stp_dbg->is_enable=0;
+ g_stp_dbg = stp_dbg;
+
+ if(btm_half != NULL){
+ stp_dbg->btm = btm_half;
+ } else {
+ stp_dbg->btm = NULL;
+ }
+
+ //bind to netlink
+ stp_dbg_nl_init();
+
+ g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_TIMEOUT);
+
+ g_stp_dbg_cpupcr = stp_dbg_cpupcr_init();
+ g_stp_dbg_dmaregs = stp_dbg_dmaregs_init();
+
+ return stp_dbg;
+
+ERR_EXIT2:
+ kfree(stp_dbg);
+ return NULL;
+
+ERR_EXIT1:
+ return NULL;
+}
+
+int stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg){
+
+ STP_DBG_INFO_FUNC("stp-dbg deinit\n");
+
+ wcn_core_dump_deinit(g_core_dump);
+
+ stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr);
+ stp_dbg_dmaregs_deinit(g_stp_dbg_dmaregs);
+ //unbind with netlink
+ stp_dbg_nl_deinit();
+
+ if(stp_dbg->logsys){
+ vfree(stp_dbg->logsys);
+ }
+
+ if(stp_dbg){
+ kfree(stp_dbg);
+ }
+
+ return 0;
+}
+
+
+
+
+
+
+