stp_dbg.c 51 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993
  1. #include <linux/kernel.h> /* GFP_KERNEL */
  2. #include <linux/timer.h> /* init_timer, add_time, del_timer_sync */
  3. #include <linux/time.h> /* gettimeofday */
  4. #include <linux/delay.h>
  5. #include <linux/slab.h> /* kzalloc */
  6. #include <linux/sched.h> /* task's status */
  7. #include <linux/vmalloc.h>
  8. #include <linux/err.h>
  9. #include <linux/workqueue.h>
  10. #include <linux/spinlock.h>
  11. #include <asm/atomic.h>
  12. #include <net/sock.h>
  13. #include <net/netlink.h>
  14. #include <linux/skbuff.h>
  15. #include <net/genetlink.h>
  16. #include <linux/zlib.h>
  17. #include <linux/uaccess.h>
  18. #include <linux/crc32.h>
  19. #include "osal_typedef.h"
  20. #include "stp_dbg.h"
  21. /* #include "stp_btm.h" */
  22. #include "btm_core.h"
  23. #define PFX_STP_DBG "[STPDbg]"
  24. #define STP_DBG_LOG_LOUD 4
  25. #define STP_DBG_LOG_DBG 3
  26. #define STP_DBG_LOG_INFO 2
  27. #define STP_DBG_LOG_WARN 1
  28. #define STP_DBG_LOG_ERR 0
  29. UINT32 gStpDbgDbgLevel = STP_DBG_LOG_INFO;
  30. UINT32 gStpDbgLogOut = 0;
  31. UINT32 gStpDbgDumpType = STP_DBG_PKT;
  32. #define STP_DBG_LOUD_FUNC(fmt, arg...) do { \
  33. if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \
  34. pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \
  35. } while (0)
  36. #define STP_DBG_DBG_FUNC(fmt, arg...) do { \
  37. if (gStpDbgDbgLevel >= STP_DBG_LOG_DBG) \
  38. pr_debug(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \
  39. } while (0)
  40. #define STP_DBG_INFO_FUNC(fmt, arg...) do { \
  41. if (gStpDbgDbgLevel >= STP_DBG_LOG_INFO) \
  42. pr_warn(PFX_STP_DBG fmt, ##arg); \
  43. } while (0)
  44. #define STP_DBG_WARN_FUNC(fmt, arg...) do { \
  45. if (gStpDbgDbgLevel >= STP_DBG_LOG_WARN) \
  46. pr_err(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \
  47. } while (0)
  48. #define STP_DBG_ERR_FUNC(fmt, arg...) do { \
  49. if (gStpDbgDbgLevel >= STP_DBG_LOG_ERR) \
  50. pr_err(PFX_STP_DBG "%s: " fmt, __func__ , ##arg); \
  51. } while (0)
  52. #define STP_DBG_TRC_FUNC(f) do { \
  53. if (gStpDbgDbgLevel >= STP_DBG_LOG_LOUD) \
  54. pr_debug(PFX_STP_DBG "<%s> <%d>\n", __func__, __LINE__); \
  55. } while (0)
  56. MTKSTP_DBG_T *g_stp_dbg = NULL;
  57. #define STP_DBG_FAMILY_NAME "STP_DBG"
  58. #define MAX_BIND_PROCESS (4)
  59. enum {
  60. __STP_DBG_ATTR_INVALID,
  61. STP_DBG_ATTR_MSG,
  62. __STP_DBG_ATTR_MAX,
  63. };
  64. #define STP_DBG_ATTR_MAX (__STP_DBG_ATTR_MAX - 1)
  65. enum {
  66. __STP_DBG_COMMAND_INVALID,
  67. STP_DBG_COMMAND_BIND,
  68. STP_DBG_COMMAND_RESET,
  69. __STP_DBG_COMMAND_MAX,
  70. };
  71. #define MTK_WIFI_COMMAND_MAX (__STP_DBG_COMMAND_MAX - 1)
  72. static struct genl_family stp_dbg_gnl_family = {
  73. .id = GENL_ID_GENERATE,
  74. .hdrsize = 0,
  75. .name = STP_DBG_FAMILY_NAME,
  76. .version = 1,
  77. .maxattr = STP_DBG_ATTR_MAX,
  78. };
  79. static void stp_dbg_nl_init(void);
  80. static void stp_dbg_nl_deinit(void);
  81. static int stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info);
  82. static int stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info);
  83. static INT32 _wcn_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp);
  84. static UINT32 stp_dbg_get_host_trigger_assert(VOID);
  85. /* attribute policy */
  86. static struct nla_policy stp_dbg_genl_policy[STP_DBG_ATTR_MAX + 1] = {
  87. [STP_DBG_ATTR_MSG] = {.type = NLA_NUL_STRING},
  88. };
  89. /* operation definition */
  90. static struct genl_ops stp_dbg_gnl_ops[] = {
  91. {
  92. .cmd = STP_DBG_COMMAND_BIND,
  93. .flags = 0,
  94. .policy = stp_dbg_genl_policy,
  95. .doit = stp_dbg_nl_bind,
  96. .dumpit = NULL,
  97. },
  98. {
  99. .cmd = STP_DBG_COMMAND_RESET,
  100. .flags = 0,
  101. .policy = stp_dbg_genl_policy,
  102. .doit = stp_dbg_nl_reset,
  103. .dumpit = NULL,
  104. },
  105. };
  106. static UINT32 stp_dbg_seqnum;
  107. static INT32 num_bind_process;
  108. static pid_t bind_pid[MAX_BIND_PROCESS];
  109. static P_WCN_CORE_DUMP_T g_core_dump;
  110. static P_STP_DBG_CPUPCR_T g_stp_dbg_cpupcr;
  111. /* core_dump_timeout_handler - handler of coredump timeout
  112. * @ data - core dump object's pointer
  113. *
  114. * No return value
  115. */
  116. static VOID core_dump_timeout_handler(unsigned long data)
  117. {
  118. P_WCN_CORE_DUMP_T dmp = (P_WCN_CORE_DUMP_T) data;
  119. STP_DBG_INFO_FUNC(" start\n");
  120. stp_btm_notify_coredump_timeout_wq(g_stp_dbg->btm);
  121. STP_DBG_INFO_FUNC(" end\n");
  122. if (dmp) {
  123. STP_DBG_WARN_FUNC
  124. (" coredump timer timeout, coredump maybe not finished successfully\n");
  125. dmp->sm = CORE_DUMP_TIMEOUT;
  126. }
  127. }
  128. /* wcn_core_dump_init - create core dump sys
  129. * @ timeout - core dump time out value
  130. *
  131. * Return object pointer if success, else NULL
  132. */
  133. P_WCN_CORE_DUMP_T wcn_core_dump_init(UINT32 timeout)
  134. {
  135. #define KBYTES (1024*sizeof(char))
  136. #define L1_BUF_SIZE (32*KBYTES)
  137. #define L2_BUF_SIZE (512*KBYTES)
  138. P_WCN_CORE_DUMP_T core_dmp = NULL;
  139. core_dmp = (P_WCN_CORE_DUMP_T) osal_malloc(sizeof(WCN_CORE_DUMP_T));
  140. if (!core_dmp) {
  141. STP_DBG_ERR_FUNC("alloc mem failed!\n");
  142. goto fail;
  143. }
  144. osal_memset(core_dmp, 0, sizeof(WCN_CORE_DUMP_T));
  145. core_dmp->compressor =
  146. wcn_compressor_init("core_dump_compressor", L1_BUF_SIZE, L2_BUF_SIZE);
  147. if (!core_dmp->compressor) {
  148. STP_DBG_ERR_FUNC("create compressor failed!\n");
  149. goto fail;
  150. }
  151. wcn_compressor_reset(core_dmp->compressor, 1, GZIP);
  152. core_dmp->dmp_timer.timeoutHandler = core_dump_timeout_handler;
  153. core_dmp->dmp_timer.timeroutHandlerData = (unsigned long)core_dmp;
  154. osal_timer_create(&core_dmp->dmp_timer);
  155. core_dmp->timeout = timeout;
  156. osal_sleepable_lock_init(&core_dmp->dmp_lock);
  157. core_dmp->sm = CORE_DUMP_INIT;
  158. STP_DBG_INFO_FUNC("create coredump object OK!\n");
  159. return core_dmp;
  160. fail:
  161. if (core_dmp && core_dmp->compressor) {
  162. wcn_compressor_deinit(core_dmp->compressor);
  163. core_dmp->compressor = NULL;
  164. }
  165. if (core_dmp)
  166. osal_free(core_dmp);
  167. osal_sleepable_lock_deinit(&core_dmp->dmp_lock);
  168. return NULL;
  169. }
  170. /* wcn_core_dump_deinit - destroy core dump object
  171. * @ dmp - pointer of object
  172. *
  173. * Retunr 0 if success, else error code
  174. */
  175. INT32 wcn_core_dump_deinit(P_WCN_CORE_DUMP_T dmp)
  176. {
  177. if (dmp && dmp->compressor) {
  178. wcn_compressor_deinit(dmp->compressor);
  179. dmp->compressor = NULL;
  180. }
  181. if (dmp) {
  182. if (NULL != dmp->p_head) {
  183. osal_free(dmp->p_head);
  184. dmp->p_head = NULL;
  185. }
  186. osal_sleepable_lock_deinit(&dmp->dmp_lock);
  187. osal_timer_stop(&dmp->dmp_timer);
  188. osal_free(dmp);
  189. }
  190. return 0;
  191. }
  192. static INT32 wcn_core_dump_check_end(PUINT8 buf, INT32 len)
  193. {
  194. if (strnstr(buf, "coredump end", len))
  195. return 1;
  196. else
  197. return 0;
  198. }
  199. /* wcn_core_dump_in - add a packet to compressor buffer
  200. * @ dmp - pointer of object
  201. * @ buf - input buffer
  202. * @ len - data length
  203. *
  204. * Retunr 0 if success; return 1 if find end string; else error code
  205. */
  206. INT32 wcn_core_dump_in(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
  207. {
  208. INT32 ret = 0;
  209. INT32 tmp;
  210. #define MAX_HEAD_LEN 512
  211. if ((!dmp) || (!buf)) {
  212. STP_DBG_ERR_FUNC("invalid pointer!\n");
  213. return -1;
  214. }
  215. ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
  216. if (ret) {
  217. STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
  218. return ret;
  219. }
  220. switch (dmp->sm) {
  221. case CORE_DUMP_INIT:
  222. wcn_compressor_reset(dmp->compressor, 1, GZIP);
  223. osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT);
  224. dmp->head_len = 0;
  225. if (NULL == dmp->p_head) {
  226. dmp->p_head = osal_malloc(MAX_HEAD_LEN);
  227. if (NULL == dmp->p_head) {
  228. STP_DBG_ERR_FUNC("alloc memory for head information failed\n");
  229. STP_DBG_ERR_FUNC("this may cause owner dispatch abnormal\n");
  230. }
  231. }
  232. if (NULL != dmp->p_head) {
  233. osal_memset(dmp->p_head, 0, MAX_HEAD_LEN);
  234. (dmp->p_head)[MAX_HEAD_LEN - 1] = '\n';
  235. }
  236. /* show coredump start info on UI */
  237. /* osal_dbg_assert_aee("MT662x f/w coredump start", "MT662x firmware coredump start"); */
  238. #ifdef CONFIG_MTK_AEE_FEATURE
  239. aee_kernel_dal_show("COMBO_CONSYS coredump start, please wait up to 5 minutes.\n");
  240. #endif
  241. /* parsing data, and check end srting */
  242. ret = wcn_core_dump_check_end(buf, len);
  243. if (ret == 1) {
  244. STP_DBG_INFO_FUNC("core dump end!\n");
  245. dmp->sm = CORE_DUMP_DONE;
  246. wcn_compressor_in(dmp->compressor, buf, len, 1);
  247. } else {
  248. dmp->sm = CORE_DUMP_DOING;
  249. wcn_compressor_in(dmp->compressor, buf, len, 0);
  250. }
  251. break;
  252. case CORE_DUMP_DOING:
  253. /* parsing data, and check end srting */
  254. ret = wcn_core_dump_check_end(buf, len);
  255. if (ret == 1) {
  256. STP_DBG_INFO_FUNC("core dump end!\n");
  257. dmp->sm = CORE_DUMP_DONE;
  258. wcn_compressor_in(dmp->compressor, buf, len, 1);
  259. } else {
  260. dmp->sm = CORE_DUMP_DOING;
  261. wcn_compressor_in(dmp->compressor, buf, len, 0);
  262. }
  263. break;
  264. case CORE_DUMP_DONE:
  265. wcn_compressor_reset(dmp->compressor, 1, GZIP);
  266. /*osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT); */
  267. osal_timer_stop(&dmp->dmp_timer);
  268. wcn_compressor_in(dmp->compressor, buf, len, 0);
  269. dmp->sm = CORE_DUMP_DOING;
  270. break;
  271. case CORE_DUMP_TIMEOUT:
  272. break;
  273. default:
  274. break;
  275. }
  276. if ((NULL != dmp->p_head) && (dmp->head_len < (MAX_HEAD_LEN - 1))) {
  277. tmp =
  278. (dmp->head_len + len) >
  279. (MAX_HEAD_LEN - 1) ? (MAX_HEAD_LEN - 1 - dmp->head_len) : len;
  280. osal_memcpy(dmp->p_head + dmp->head_len, buf, tmp);
  281. dmp->head_len += tmp;
  282. }
  283. osal_unlock_sleepable_lock(&dmp->dmp_lock);
  284. return ret;
  285. }
  286. INT32 _wcn_core_dump_post_handle(P_WCN_CORE_DUMP_T dmp)
  287. {
  288. #define INFO_HEAD ";COMBO_CONSYS FW CORE, "
  289. INT32 ret = 0;
  290. INT32 tmp = 0;
  291. ENUM_STP_FW_ISSUE_TYPE issue_type;
  292. STP_DBG_INFO_FUNC(" enters...\n");
  293. if ((NULL != dmp->p_head)
  294. && (NULL != (osal_strnstr(dmp->p_head, "<ASSERT>", dmp->head_len)))) {
  295. PINT8 pStr = dmp->p_head;
  296. PINT8 pDtr = NULL;
  297. STP_DBG_INFO_FUNC(" <ASSERT> string found\n");
  298. if (stp_dbg_get_host_trigger_assert())
  299. issue_type = STP_HOST_TRIGGER_FW_ASSERT;
  300. else
  301. issue_type = STP_FW_ASSERT_ISSUE;
  302. /*parse f/w assert additional informationi for f/w's analysis */
  303. ret = stp_dbg_set_fw_info(dmp->p_head, dmp->head_len, issue_type);
  304. if (ret) {
  305. STP_DBG_ERR_FUNC("set fw issue infor fail(%d),maybe fw warm reset...\n",
  306. ret);
  307. stp_dbg_set_fw_info("Fw Warm reset", osal_strlen("Fw Warm reset"),
  308. STP_FW_WARM_RST_ISSUE);
  309. }
  310. /* first package, copy to info buffer */
  311. osal_strcpy(&dmp->info[0], INFO_HEAD);
  312. /* set f/w assert information to warm reset */
  313. pStr = osal_strnstr(pStr, "<ASSERT>", dmp->head_len);
  314. if (NULL != pStr) {
  315. pDtr = osal_strchr(pStr, '-');
  316. if (NULL != pDtr) {
  317. tmp = pDtr - pStr;
  318. osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp);
  319. dmp->info[osal_strlen(dmp->info) + 1] = '\0';
  320. } else {
  321. tmp = STP_CORE_DUMP_INFO_SZ - osal_strlen(INFO_HEAD);
  322. tmp = (dmp->head_len > tmp) ? tmp : dmp->head_len;
  323. osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], pStr, tmp);
  324. dmp->info[STP_CORE_DUMP_INFO_SZ] = '\0';
  325. }
  326. }
  327. } else if ((NULL != dmp->p_head)
  328. && (NULL != (osal_strnstr(dmp->p_head, "ABT", dmp->head_len)))) {
  329. STP_DBG_ERR_FUNC("fw ABT happens, set to Fw ABT Exception\n");
  330. stp_dbg_set_fw_info("Fw ABT Exception", osal_strlen("Fw ABT Exception"),
  331. STP_FW_ABT);
  332. osal_strcpy(&dmp->info[0], INFO_HEAD);
  333. osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw ABT Exception...",
  334. osal_strlen("Fw ABT Exception..."));
  335. dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw ABT Exception...") + 1] = '\0';
  336. } else {
  337. STP_DBG_INFO_FUNC(" <ASSERT> string not found, dmp->head_len:%d\n", dmp->head_len);
  338. if (NULL == dmp->p_head)
  339. STP_DBG_INFO_FUNC(" dmp->p_head is NULL\n");
  340. else
  341. STP_DBG_INFO_FUNC(" dmp->p_head:%s\n", dmp->p_head);
  342. /* first package, copy to info buffer */
  343. osal_strcpy(&dmp->info[0], INFO_HEAD);
  344. /* set f/w assert information to warm reset */
  345. osal_memcpy(&dmp->info[osal_strlen(INFO_HEAD)], "Fw warm reset exception...",
  346. osal_strlen("Fw warm reset exception..."));
  347. dmp->info[osal_strlen(INFO_HEAD) + osal_strlen("Fw warm reset exception...") + 1] =
  348. '\0';
  349. }
  350. dmp->head_len = 0;
  351. /*set host trigger assert flag to 0 */
  352. stp_dbg_set_host_assert_info(0, 0, 0);
  353. #if 0
  354. if (NULL != dmp->p_head) {
  355. osal_free(dmp->p_head);
  356. dmp->p_head = NULL;
  357. }
  358. #endif
  359. /*set ret value to notify upper layer do dump flush operation */
  360. ret = 1;
  361. STP_DBG_INFO_FUNC(" exits...\n");
  362. return ret;
  363. }
  364. /* wcn_core_dump_out - get compressed data from compressor buffer
  365. * @ dmp - pointer of object
  366. * @ pbuf - target buffer's pointer
  367. * @ len - data length
  368. *
  369. * Retunr 0 if success; else error code
  370. */
  371. INT32 wcn_core_dump_out(P_WCN_CORE_DUMP_T dmp, PPUINT8 pbuf, PINT32 plen)
  372. {
  373. INT32 ret = 0;
  374. if ((!dmp) || (!pbuf) || (!plen)) {
  375. STP_DBG_ERR_FUNC("invalid pointer!\n");
  376. return -1;
  377. }
  378. ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
  379. if (ret) {
  380. STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
  381. return ret;
  382. }
  383. ret = wcn_compressor_out(dmp->compressor, pbuf, plen);
  384. osal_unlock_sleepable_lock(&dmp->dmp_lock);
  385. return ret;
  386. }
  387. /* wcn_core_dump_reset - reset core dump sys
  388. * @ dmp - pointer of object
  389. * @ timeout - core dump time out value
  390. *
  391. * Retunr 0 if success, else error code
  392. */
  393. INT32 wcn_core_dump_reset(P_WCN_CORE_DUMP_T dmp, UINT32 timeout)
  394. {
  395. if (!dmp) {
  396. STP_DBG_ERR_FUNC("invalid pointer!\n");
  397. return -1;
  398. }
  399. dmp->sm = CORE_DUMP_INIT;
  400. dmp->timeout = timeout;
  401. osal_timer_stop(&dmp->dmp_timer);
  402. wcn_compressor_reset(dmp->compressor, 1, GZIP);
  403. osal_memset(dmp->info, 0, STP_CORE_DUMP_INFO_SZ + 1);
  404. return 0;
  405. }
  406. /* wcn_core_dump_flush - Fulsh dump data and reset core dump sys
  407. *
  408. * Retunr 0 if success, else error code
  409. */
  410. INT32 wcn_core_dump_flush(INT32 rst)
  411. {
  412. PUINT8 pbuf = NULL;
  413. INT32 len = 0;
  414. if (!g_core_dump) {
  415. STP_DBG_ERR_FUNC("invalid pointer!\n");
  416. return -1;
  417. }
  418. osal_lock_sleepable_lock(&g_core_dump->dmp_lock);
  419. _wcn_core_dump_post_handle(g_core_dump);
  420. osal_unlock_sleepable_lock(&g_core_dump->dmp_lock);
  421. wcn_core_dump_out(g_core_dump, &pbuf, &len);
  422. STP_DBG_INFO_FUNC("buf 0x%p, len %d\n", pbuf, len);
  423. /* show coredump end info on UI */
  424. /* osal_dbg_assert_aee("MT662x f/w coredump end", "MT662x firmware coredump ends"); */
  425. #ifdef CONFIG_MTK_AEE_FEATURE
  426. /* call AEE driver API */
  427. aee_kernel_dal_show("COMBO_CONSYS coredump end\n");
  428. aed_combo_exception(NULL, 0, (const PINT32)pbuf, len, (const PINT8)g_core_dump->info);
  429. #endif
  430. /* reset */
  431. wcn_core_dump_reset(g_core_dump, STP_CORE_DUMP_TIMEOUT);
  432. return 0;
  433. }
  434. static INT32 wcn_gzip_compressor(PVOID worker, PUINT8 in_buf, INT32 in_sz, PUINT8 out_buf,
  435. PINT32 out_sz, INT32 finish)
  436. {
  437. INT32 ret = 0;
  438. z_stream *stream = NULL;
  439. INT32 tmp = *out_sz;
  440. STP_DBG_INFO_FUNC("in buf 0x%p, in sz %d\n", in_buf, in_sz);
  441. STP_DBG_INFO_FUNC("out buf 0x%p, out sz %d\n", out_buf, tmp);
  442. stream = (z_stream *) worker;
  443. if (!stream) {
  444. STP_DBG_ERR_FUNC("invalid workspace!\n");
  445. return -1;
  446. }
  447. if (in_sz > 0) {
  448. #if 0
  449. ret = zlib_deflateReset(stream);
  450. if (ret != Z_OK) {
  451. STP_DBG_ERR_FUNC("reset failed!\n");
  452. return -2;
  453. }
  454. #endif
  455. stream->next_in = in_buf;
  456. stream->avail_in = in_sz;
  457. stream->next_out = out_buf;
  458. stream->avail_out = tmp;
  459. zlib_deflate(stream, Z_FULL_FLUSH);
  460. if (finish) {
  461. while (1) {
  462. INT32 val = zlib_deflate(stream, Z_FINISH);
  463. if (val == Z_OK)
  464. continue;
  465. else if (val == Z_STREAM_END)
  466. break;
  467. STP_DBG_ERR_FUNC("finish operation failed %d\n", val);
  468. ret = -3;
  469. }
  470. }
  471. *out_sz = tmp - stream->avail_out;
  472. }
  473. STP_DBG_DBG_FUNC("out buf 0x%p, out sz %d\n", out_buf, *out_sz);
  474. return ret;
  475. }
  476. /* wcn_compressor_init - create a compressor and do init
  477. * @ name - compressor's name
  478. * @ L1_buf_sz - L1 buffer size
  479. * @ L2_buf_sz - L2 buffer size
  480. *
  481. * Retunr object's pointer if success, else NULL
  482. */
  483. P_WCN_COMPRESSOR_T wcn_compressor_init(PUINT8 name, INT32 L1_buf_sz, INT32 L2_buf_sz)
  484. {
  485. z_stream *pstream = NULL;
  486. P_WCN_COMPRESSOR_T compress = NULL;
  487. compress = (P_WCN_COMPRESSOR_T) osal_malloc(sizeof(WCN_COMPRESSOR_T));
  488. if (!compress) {
  489. STP_DBG_ERR_FUNC("alloc compressor failed!\n");
  490. goto fail;
  491. }
  492. osal_memset(compress, 0, sizeof(WCN_COMPRESSOR_T));
  493. osal_memcpy(compress->name, name, STP_OJB_NAME_SZ);
  494. compress->f_compress_en = 0;
  495. compress->compress_type = GZIP;
  496. if (compress->compress_type == GZIP) {
  497. compress->worker = osal_malloc(sizeof(z_stream));
  498. if (!compress->worker) {
  499. STP_DBG_ERR_FUNC("alloc stream failed!\n");
  500. goto fail;
  501. }
  502. pstream = (z_stream *) compress->worker;
  503. pstream->workspace =
  504. osal_malloc(zlib_deflate_workspacesize(MAX_WBITS, MAX_MEM_LEVEL));
  505. if (!pstream->workspace) {
  506. STP_DBG_ERR_FUNC("alloc workspace failed!\n");
  507. goto fail;
  508. }
  509. zlib_deflateInit2(pstream, Z_DEFAULT_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
  510. DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
  511. }
  512. compress->handler = wcn_gzip_compressor;
  513. compress->L1_buf_sz = L1_buf_sz;
  514. compress->L2_buf_sz = L2_buf_sz;
  515. compress->L1_pos = 0;
  516. compress->L2_pos = 0;
  517. compress->uncomp_size = 0;
  518. compress->crc32 = 0xffffffff;
  519. compress->L1_buf = osal_malloc(compress->L1_buf_sz);
  520. if (!compress->L1_buf) {
  521. STP_DBG_ERR_FUNC("alloc %d bytes for L1 buf failed!\n", compress->L1_buf_sz);
  522. goto fail;
  523. }
  524. compress->L2_buf = osal_malloc(compress->L2_buf_sz);
  525. if (!compress->L2_buf) {
  526. STP_DBG_ERR_FUNC("alloc %d bytes for L2 buf failed!\n", compress->L2_buf_sz);
  527. goto fail;
  528. }
  529. STP_DBG_INFO_FUNC("create compressor OK! L1 %d bytes, L2 %d bytes\n", L1_buf_sz, L2_buf_sz);
  530. return compress;
  531. fail:
  532. if (compress) {
  533. if (compress->L2_buf) {
  534. osal_free(compress->L2_buf);
  535. compress->L2_buf = NULL;
  536. }
  537. if (compress->L1_buf) {
  538. osal_free(compress->L1_buf);
  539. compress->L1_buf = NULL;
  540. }
  541. if (compress->worker) {
  542. pstream = (z_stream *) compress->worker;
  543. if ((compress->compress_type == GZIP) && pstream->workspace) {
  544. zlib_deflateEnd(pstream);
  545. osal_free(pstream->workspace);
  546. }
  547. osal_free(compress->worker);
  548. compress->worker = NULL;
  549. }
  550. if (compress->worker) {
  551. osal_free(compress->worker);
  552. compress->worker = NULL;
  553. }
  554. osal_free(compress);
  555. compress = NULL;
  556. }
  557. STP_DBG_ERR_FUNC("init failed!\n");
  558. return NULL;
  559. }
  560. /* wcn_compressor_deinit - distroy a compressor
  561. * @ cprs - compressor's pointer
  562. *
  563. * Retunr 0 if success, else NULL
  564. */
  565. INT32 wcn_compressor_deinit(P_WCN_COMPRESSOR_T cprs)
  566. {
  567. z_stream *pstream = NULL;
  568. if (cprs) {
  569. if (cprs->L2_buf) {
  570. osal_free(cprs->L2_buf);
  571. cprs->L2_buf = NULL;
  572. }
  573. if (cprs->L1_buf) {
  574. osal_free(cprs->L1_buf);
  575. cprs->L1_buf = NULL;
  576. }
  577. if (cprs->worker) {
  578. pstream = (z_stream *) cprs->worker;
  579. if ((cprs->compress_type == GZIP) && pstream->workspace) {
  580. zlib_deflateEnd(pstream);
  581. osal_free(pstream->workspace);
  582. }
  583. osal_free(cprs->worker);
  584. cprs->worker = NULL;
  585. }
  586. cprs->handler = NULL;
  587. osal_free(cprs);
  588. }
  589. STP_DBG_INFO_FUNC("destroy OK\n");
  590. return 0;
  591. }
  592. /* wcn_compressor_in - put in a raw data, and compress L1 buffer if need
  593. * @ cprs - compressor's pointer
  594. * @ buf - raw data buffer
  595. * @ len - raw data length
  596. * @ finish - core dump finish or not, 1: finished; 0: not finish
  597. *
  598. * Retunr 0 if success, else NULL
  599. */
  600. INT32 wcn_compressor_in(P_WCN_COMPRESSOR_T cprs, PUINT8 buf, INT32 len, INT32 finish)
  601. {
  602. INT32 tmp_len = 0;
  603. INT32 ret = 0;
  604. if (!cprs) {
  605. STP_DBG_ERR_FUNC("invalid para!\n");
  606. return -1;
  607. }
  608. cprs->uncomp_size += len;
  609. /* check L1 buf valid space */
  610. if (len > (cprs->L1_buf_sz - cprs->L1_pos)) {
  611. STP_DBG_INFO_FUNC("L1 buffer full\n");
  612. if (cprs->f_compress_en && cprs->handler) {
  613. /* need compress */
  614. /* compress L1 buffer, and put result to L2 buffer */
  615. tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
  616. ret =
  617. cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos,
  618. &cprs->L2_buf[cprs->L2_pos], &tmp_len, finish);
  619. if (!ret) {
  620. cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
  621. cprs->L2_pos += tmp_len;
  622. if (finish) {
  623. /* Add 8 byte suffix
  624. ===
  625. 32 bits UNCOMPRESS SIZE
  626. 32 bits CRC
  627. */
  628. *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) =
  629. (cprs->crc32 ^ 0xffffffff);
  630. *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) =
  631. cprs->uncomp_size;
  632. cprs->L2_pos += 8;
  633. }
  634. STP_DBG_INFO_FUNC("compress OK!\n");
  635. } else {
  636. STP_DBG_ERR_FUNC("compress error!\n");
  637. }
  638. } else {
  639. /* no need compress */
  640. /* Flush L1 buffer to L2 buffer */
  641. STP_DBG_INFO_FUNC("No need do compress, Put to L2 buf\n");
  642. tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
  643. tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
  644. osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
  645. cprs->L2_pos += tmp_len;
  646. }
  647. /* reset L1 buf pos */
  648. cprs->L1_pos = 0;
  649. /* put curren data to L1 buf */
  650. if (len > cprs->L1_buf_sz) {
  651. STP_DBG_ERR_FUNC("len=%d, too long err!\n", len);
  652. } else {
  653. STP_DBG_DBG_FUNC("L1 Flushed, and Put %d bytes to L1 buf\n", len);
  654. osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
  655. cprs->L1_pos += len;
  656. }
  657. } else {
  658. /* put to L1 buffer */
  659. STP_DBG_DBG_FUNC("Put %d bytes to L1 buf\n", len);
  660. osal_memcpy(&cprs->L1_buf[cprs->L1_pos], buf, len);
  661. cprs->L1_pos += len;
  662. }
  663. return ret;
  664. }
  665. /* wcn_compressor_out - get the result data from L2 buffer
  666. * @ cprs - compressor's pointer
  667. * @ pbuf - point to L2 buffer
  668. * @ plen - out len
  669. *
  670. * Retunr 0 if success, else NULL
  671. */
  672. INT32 wcn_compressor_out(P_WCN_COMPRESSOR_T cprs, PPUINT8 pbuf, PINT32 plen)
  673. {
  674. INT32 ret = 0;
  675. INT32 tmp_len = 0;
  676. if ((!cprs) || (!pbuf) || (!plen)) {
  677. STP_DBG_ERR_FUNC("invalid para!\n");
  678. return -1;
  679. }
  680. /* check if there's L1 data need flush to L2 buffer */
  681. if (cprs->L1_pos > 0) {
  682. tmp_len = cprs->L2_buf_sz - cprs->L2_pos;
  683. if (cprs->f_compress_en && cprs->handler) {
  684. /* need compress */
  685. ret =
  686. cprs->handler(cprs->worker, cprs->L1_buf, cprs->L1_pos,
  687. &cprs->L2_buf[cprs->L2_pos], &tmp_len, 1);
  688. if (!ret) {
  689. cprs->crc32 = (crc32(cprs->crc32, cprs->L1_buf, cprs->L1_pos));
  690. cprs->L2_pos += tmp_len;
  691. /* Add 8 byte suffix
  692. ===
  693. 32 bits UNCOMPRESS SIZE
  694. 32 bits CRC
  695. */
  696. *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos]) =
  697. (cprs->crc32 ^ 0xffffffff);
  698. *(uint32_t *) (&cprs->L2_buf[cprs->L2_pos + 4]) = cprs->uncomp_size;
  699. cprs->L2_pos += 8;
  700. STP_DBG_INFO_FUNC("compress OK!\n");
  701. } else {
  702. STP_DBG_ERR_FUNC("compress error!\n");
  703. }
  704. } else {
  705. /* no need compress */
  706. tmp_len = (cprs->L1_pos > tmp_len) ? tmp_len : cprs->L1_pos;
  707. osal_memcpy(&cprs->L2_buf[cprs->L2_pos], cprs->L1_buf, tmp_len);
  708. cprs->L2_pos += tmp_len;
  709. }
  710. cprs->L1_pos = 0;
  711. }
  712. *pbuf = cprs->L2_buf;
  713. *plen = cprs->L2_pos;
  714. STP_DBG_INFO_FUNC("0x%p, len %d\n", *pbuf, *plen);
  715. #if 1
  716. ret = zlib_deflateReset((z_stream *) cprs->worker);
  717. if (ret != Z_OK) {
  718. STP_DBG_ERR_FUNC("reset failed!\n");
  719. return -2;
  720. }
  721. #endif
  722. return 0;
  723. }
  724. /* wcn_compressor_reset - reset compressor
  725. * @ cprs - compressor's pointer
  726. * @ enable - enable/disable compress
  727. * @ type - compress algorithm
  728. *
  729. * Retunr 0 if success, else NULL
  730. */
  731. INT32 wcn_compressor_reset(P_WCN_COMPRESSOR_T cprs, UINT8 enable, WCN_COMPRESS_ALG_T type)
  732. {
  733. if (!cprs) {
  734. STP_DBG_ERR_FUNC("invalid para!\n");
  735. return -1;
  736. }
  737. cprs->f_compress_en = enable;
  738. /* cprs->f_compress_en = 0; // disable compress for test */
  739. cprs->compress_type = type;
  740. cprs->L1_pos = 0;
  741. cprs->L2_pos = 0;
  742. cprs->uncomp_size = 0;
  743. cprs->crc32 = 0xffffffff;
  744. STP_DBG_INFO_FUNC("OK! compress algorithm %d\n", type);
  745. return 0;
  746. }
  747. INT32 wcn_core_dump_nl(P_WCN_CORE_DUMP_T dmp, PUINT8 buf, INT32 len)
  748. {
  749. INT32 ret = 0;
  750. if ((!dmp) || (!buf)) {
  751. STP_DBG_ERR_FUNC("invalid pointer!\n");
  752. return -1;
  753. }
  754. ret = osal_lock_sleepable_lock(&dmp->dmp_lock);
  755. if (ret) {
  756. STP_DBG_ERR_FUNC("--->lock dmp->dmp_lock failed, ret=%d\n", ret);
  757. return ret;
  758. }
  759. switch (dmp->sm) {
  760. case CORE_DUMP_INIT:
  761. osal_timer_start(&dmp->dmp_timer, STP_CORE_DUMP_TIMEOUT);
  762. STP_DBG_WARN_FUNC("COMBO_CONSYS coredump start, please wait up to 1 minutes.\n");
  763. /* check end srting */
  764. ret = wcn_core_dump_check_end(buf, len);
  765. if (ret == 1) {
  766. STP_DBG_INFO_FUNC("core dump end!\n");
  767. osal_timer_stop(&dmp->dmp_timer);
  768. dmp->sm = CORE_DUMP_INIT;
  769. } else {
  770. dmp->sm = CORE_DUMP_DOING;
  771. }
  772. break;
  773. case CORE_DUMP_DOING:
  774. /* check end srting */
  775. ret = wcn_core_dump_check_end(buf, len);
  776. if (ret == 1) {
  777. STP_DBG_INFO_FUNC("core dump end!\n");
  778. osal_timer_stop(&dmp->dmp_timer);
  779. dmp->sm = CORE_DUMP_INIT;
  780. } else {
  781. dmp->sm = CORE_DUMP_DOING;
  782. }
  783. break;
  784. case CORE_DUMP_DONE:
  785. osal_timer_stop(&dmp->dmp_timer);
  786. dmp->sm = CORE_DUMP_INIT;
  787. break;
  788. case CORE_DUMP_TIMEOUT:
  789. ret = 32;
  790. break;
  791. default:
  792. break;
  793. }
  794. osal_unlock_sleepable_lock(&dmp->dmp_lock);
  795. return ret;
  796. }
  797. static VOID stp_dbg_dump_data(PUINT8 pBuf, PINT8 title, INT32 len)
  798. {
  799. INT32 k = 0;
  800. char str[240] = {""};
  801. INT32 strp = 0;
  802. INT32 strlen = 0;
  803. pr_warn(" %s-len:%d\n", title, len);
  804. /* pr_warn(" ", title, len); */
  805. for (k = 0; k < len; k++) {
  806. if (strp < 200) {
  807. strlen = osal_sprintf(&str[strp], "0x%02x ", pBuf[k]);
  808. strp += strlen;
  809. } else {
  810. pr_warn("More than 200 of the data is too much\n");
  811. break;
  812. }
  813. }
  814. osal_sprintf(&str[strp], "--end\n");
  815. pr_warn("%s", str);
  816. }
  817. static INT32 _stp_dbg_enable(MTKSTP_DBG_T *stp_dbg)
  818. {
  819. unsigned long flags;
  820. spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
  821. stp_dbg->pkt_trace_no = 0;
  822. stp_dbg->is_enable = 1;
  823. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  824. return 0;
  825. }
  826. static INT32 _stp_dbg_disable(MTKSTP_DBG_T *stp_dbg)
  827. {
  828. unsigned long flags;
  829. spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
  830. stp_dbg->pkt_trace_no = 0;
  831. stp_dbg->is_enable = 0;
  832. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  833. return 0;
  834. }
  835. static INT32 _stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len)
  836. {
  837. unsigned long flags;
  838. UINT32 internalFlag = stp_dbg->logsys->size < STP_DBG_LOG_ENTRY_NUM;
  839. UINT32 in_len = 0;
  840. /* #ifdef CONFIG_LOG_STP_INTERNAL */
  841. /* Here we record log in this circle buffer, if buffer is full ,
  842. select to overlap earlier log, logic should be okay */
  843. internalFlag = 1;
  844. /* #endif */
  845. spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
  846. if (internalFlag) {
  847. in_len = (len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len);
  848. stp_dbg->logsys->queue[stp_dbg->logsys->in].id = 0;
  849. stp_dbg->logsys->queue[stp_dbg->logsys->in].len = in_len;
  850. /* memset(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),0, STP_DBG_LOG_ENTRY_SZ); */
  851. memcpy(&(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]),
  852. buf, ((len >= STP_DBG_LOG_ENTRY_SZ) ? (STP_DBG_LOG_ENTRY_SZ) : (len)));
  853. stp_dbg->logsys->size++;
  854. stp_dbg->logsys->size =
  855. (stp_dbg->logsys->size >
  856. STP_DBG_LOG_ENTRY_NUM) ? STP_DBG_LOG_ENTRY_NUM : stp_dbg->logsys->size;
  857. if (0 != gStpDbgLogOut) {
  858. STP_DBG_HDR_T *pHdr = NULL;
  859. PINT8 pBuf = NULL;
  860. UINT32 len = 0;
  861. pHdr =
  862. (STP_DBG_HDR_T *) &(stp_dbg->logsys->
  863. queue[stp_dbg->logsys->in].buffer[0]);
  864. pBuf =
  865. (PINT8) &(stp_dbg->logsys->queue[stp_dbg->logsys->in].buffer[0]) +
  866. sizeof(STP_DBG_HDR_T);
  867. len =
  868. stp_dbg->logsys->queue[stp_dbg->logsys->in].len - sizeof(STP_DBG_HDR_T);
  869. pr_warn("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n", pHdr->sec,
  870. pHdr->usec, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
  871. gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack);
  872. if (0 < len)
  873. stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len);
  874. }
  875. stp_dbg->logsys->in =
  876. (stp_dbg->logsys->in >=
  877. (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->in + 1);
  878. STP_DBG_DBG_FUNC("logsys size = %d, in = %d\n", stp_dbg->logsys->size,
  879. stp_dbg->logsys->in);
  880. } else {
  881. STP_DBG_WARN_FUNC("logsys FULL!\n");
  882. }
  883. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  884. return 0;
  885. }
  886. INT32 stp_gdb_notify_btm_dmp_wq(MTKSTP_DBG_T *stp_dbg)
  887. {
  888. INT32 retval = 0;
  889. /* #ifndef CONFIG_LOG_STP_INTERNAL */
  890. if (stp_dbg->btm != NULL)
  891. retval += stp_btm_notify_wmt_dmp_wq((MTKSTP_BTM_T *) stp_dbg->btm);
  892. /* #endif */
  893. return retval;
  894. }
  895. INT32 stp_dbg_log_ctrl(UINT32 on)
  896. {
  897. if (on != 0) {
  898. gStpDbgLogOut = 1;
  899. pr_warn("STP-DBG: enable pkt log dump out.\n");
  900. } else {
  901. gStpDbgLogOut = 0;
  902. pr_warn("STP-DBG: disable pkt log dump out.\n");
  903. }
  904. return 0;
  905. }
  906. INT32 stp_dbg_dmp_in(MTKSTP_DBG_T *stp_dbg, PINT8 buf, INT32 len)
  907. {
  908. return _stp_dbg_dmp_in(stp_dbg, buf, len);
  909. }
  910. INT32 stp_dbg_dmp_print(MTKSTP_DBG_T *stp_dbg)
  911. {
  912. #define MAX_DMP_NUM 80
  913. unsigned long flags;
  914. PINT8 pBuf = NULL;
  915. INT32 len = 0;
  916. STP_DBG_HDR_T *pHdr = NULL;
  917. UINT32 dumpSize = 0;
  918. UINT32 inIndex = 0;
  919. UINT32 outIndex = 0;
  920. if (0 == spin_trylock_irqsave(&(stp_dbg->logsys->lock), flags)) {
  921. /*It is okay, because someone must have acquire this lock and
  922. it is dump print operation who are supposed to acquire this lock for much longer time */
  923. STP_DBG_WARN_FUNC("logsys log is locked by other, omit this dump request\n");
  924. return -1;
  925. }
  926. /*spin_lock_irqsave(&(stp_dbg->logsys->lock), flags); */
  927. /* Not to dequeue from loging system */
  928. inIndex = stp_dbg->logsys->in;
  929. dumpSize = stp_dbg->logsys->size;
  930. if (STP_DBG_LOG_ENTRY_NUM == dumpSize)
  931. outIndex = inIndex;
  932. else
  933. outIndex = ((inIndex + STP_DBG_LOG_ENTRY_NUM) - dumpSize) % STP_DBG_LOG_ENTRY_NUM;
  934. if (dumpSize > MAX_DMP_NUM) {
  935. outIndex += (dumpSize - MAX_DMP_NUM);
  936. outIndex %= STP_DBG_LOG_ENTRY_NUM;
  937. dumpSize = MAX_DMP_NUM;
  938. }
  939. STP_DBG_INFO_FUNC("loged packet size = %d, in(%d), out(%d)\n", dumpSize, inIndex, outIndex);
  940. while (dumpSize > 0) {
  941. pHdr = (STP_DBG_HDR_T *) &(stp_dbg->logsys->queue[outIndex].buffer[0]);
  942. pBuf = &(stp_dbg->logsys->queue[outIndex].buffer[0]) + sizeof(STP_DBG_HDR_T);
  943. len = stp_dbg->logsys->queue[outIndex].len - sizeof(STP_DBG_HDR_T);
  944. len = len > STP_PKT_SZ ? STP_PKT_SZ : len;
  945. pr_warn("STP-DBG:%d.%ds, %s:pT%sn(%d)l(%d)s(%d)a(%d)\n",
  946. pHdr->sec,
  947. pHdr->usec,
  948. pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx",
  949. gStpDbgType[pHdr->type], pHdr->no, pHdr->len, pHdr->seq, pHdr->ack);
  950. if (0 < len)
  951. stp_dbg_dump_data(pBuf, pHdr->dir == PKT_DIR_TX ? "Tx" : "Rx", len);
  952. outIndex = (outIndex >= (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (outIndex + 1);
  953. dumpSize--;
  954. }
  955. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  956. return 0;
  957. }
  958. INT32 stp_dbg_dmp_out_ex(PINT8 buf, PINT32 len)
  959. {
  960. return stp_dbg_dmp_out(g_stp_dbg, buf, len);
  961. }
  962. INT32 stp_dbg_dmp_out(MTKSTP_DBG_T *stp_dbg, PINT8 buf, PINT32 len)
  963. {
  964. unsigned long flags;
  965. INT32 remaining = 0;
  966. *len = 0;
  967. spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
  968. if (stp_dbg->logsys->size > 0) {
  969. memcpy(buf, &(stp_dbg->logsys->queue[stp_dbg->logsys->out].buffer[0]),
  970. stp_dbg->logsys->queue[stp_dbg->logsys->out].len);
  971. (*len) = stp_dbg->logsys->queue[stp_dbg->logsys->out].len;
  972. stp_dbg->logsys->out =
  973. (stp_dbg->logsys->out >=
  974. (STP_DBG_LOG_ENTRY_NUM - 1)) ? (0) : (stp_dbg->logsys->out + 1);
  975. stp_dbg->logsys->size--;
  976. STP_DBG_DBG_FUNC("logsys size = %d, out = %d\n", stp_dbg->logsys->size,
  977. stp_dbg->logsys->out);
  978. } else {
  979. STP_DBG_LOUD_FUNC("logsys EMPTY!\n");
  980. }
  981. remaining = (stp_dbg->logsys->size == 0) ? (0) : (1);
  982. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  983. return remaining;
  984. }
  985. static INT32 stp_dbg_get_avl_entry_num(MTKSTP_DBG_T *stp_dbg)
  986. {
  987. osal_bug_on(!stp_dbg);
  988. if (0 == stp_dbg->logsys->size) {
  989. return STP_DBG_LOG_ENTRY_NUM;
  990. } else {
  991. return (stp_dbg->logsys->in > stp_dbg->logsys->out) ?
  992. (STP_DBG_LOG_ENTRY_NUM - stp_dbg->logsys->in + stp_dbg->logsys->out) :
  993. (stp_dbg->logsys->out - stp_dbg->logsys->in);
  994. }
  995. }
  996. static INT32 stp_dbg_fill_hdr(struct stp_dbg_pkt_hdr *hdr, INT32 type, INT32 ack, INT32 seq,
  997. INT32 crc, INT32 dir, INT32 len, INT32 dbg_type)
  998. {
  999. INT32 ret = 0;
  1000. struct timeval now;
  1001. if (!hdr) {
  1002. STP_DBG_ERR_FUNC("function invalid\n");
  1003. ret = -EINVAL;
  1004. } else {
  1005. do_gettimeofday(&now);
  1006. hdr->last_dbg_type = gStpDbgDumpType;
  1007. gStpDbgDumpType = dbg_type;
  1008. hdr->dbg_type = dbg_type;
  1009. hdr->ack = ack;
  1010. hdr->seq = seq;
  1011. hdr->sec = now.tv_sec;
  1012. hdr->usec = now.tv_usec;
  1013. hdr->crc = crc;
  1014. hdr->dir = dir; /* rx */
  1015. hdr->dmy = 0xffffffff;
  1016. hdr->len = len;
  1017. hdr->type = type;
  1018. }
  1019. return ret;
  1020. }
  1021. static INT32 stp_dbg_add_pkt(MTKSTP_DBG_T *stp_dbg, struct stp_dbg_pkt_hdr *hdr, const PUINT8 body)
  1022. {
  1023. /* fix the frame size large issues. */
  1024. static struct stp_dbg_pkt stp_pkt;
  1025. UINT32 hdr_sz = sizeof(struct stp_dbg_pkt_hdr);
  1026. UINT32 body_sz = 0;
  1027. osal_bug_on(!stp_dbg);
  1028. if (hdr->dbg_type == STP_DBG_PKT)
  1029. body_sz = (hdr->len <= STP_PKT_SZ) ? (hdr->len) : (STP_PKT_SZ);
  1030. else
  1031. body_sz = (hdr->len <= STP_DMP_SZ) ? (hdr->len) : (STP_DMP_SZ);
  1032. hdr->no = stp_dbg->pkt_trace_no++;
  1033. memcpy((PUINT8) &stp_pkt.hdr, (PUINT8) hdr, hdr_sz);
  1034. if (body != NULL)
  1035. memcpy((PUINT8) &stp_pkt.raw[0], body, body_sz);
  1036. if (hdr->dbg_type == STP_DBG_FW_DMP) {
  1037. if (hdr->last_dbg_type != STP_DBG_FW_DMP) {
  1038. unsigned long flags;
  1039. STP_DBG_INFO_FUNC
  1040. ("reset stp_dbg logsys when queue fw coredump package(%d)\n",
  1041. hdr->last_dbg_type);
  1042. STP_DBG_INFO_FUNC("dump 1st fw coredump package len(%d) for confirming\n",
  1043. hdr->len);
  1044. spin_lock_irqsave(&(stp_dbg->logsys->lock), flags);
  1045. stp_dbg->logsys->in = 0;
  1046. stp_dbg->logsys->out = 0;
  1047. stp_dbg->logsys->size = 0;
  1048. spin_unlock_irqrestore(&(stp_dbg->logsys->lock), flags);
  1049. } else {
  1050. UINT32 avl_num = stp_dbg_get_avl_entry_num(stp_dbg);
  1051. if (!avl_num)
  1052. STP_DBG_ERR_FUNC("there is no avl entry stp_dbg logsys!!!\n");
  1053. }
  1054. }
  1055. _stp_dbg_dmp_in(stp_dbg, (PINT8) &stp_pkt, hdr_sz + body_sz);
  1056. if (hdr->dbg_type == STP_DBG_FW_DMP)
  1057. stp_gdb_notify_btm_dmp_wq(stp_dbg);
  1058. return 0;
  1059. }
  1060. INT32 stp_dbg_log_pkt(MTKSTP_DBG_T *stp_dbg, INT32 dbg_type,
  1061. INT32 type, INT32 ack_no, INT32 seq_no, INT32 crc, INT32 dir, INT32 len,
  1062. const PUINT8 body)
  1063. {
  1064. struct stp_dbg_pkt_hdr hdr;
  1065. if (stp_dbg->is_enable == 0) {
  1066. /*dbg is disable,and not to log */
  1067. } else {
  1068. stp_dbg_fill_hdr(&hdr,
  1069. (INT32) type,
  1070. (INT32) ack_no,
  1071. (INT32) seq_no, (INT32) crc, (INT32) dir, (INT32) len,
  1072. (INT32) dbg_type);
  1073. stp_dbg_add_pkt(stp_dbg, &hdr, body);
  1074. }
  1075. return 0;
  1076. }
  1077. INT32 stp_dbg_enable(MTKSTP_DBG_T *stp_dbg)
  1078. {
  1079. return _stp_dbg_enable(stp_dbg);
  1080. }
  1081. INT32 stp_dbg_disable(MTKSTP_DBG_T *stp_dbg)
  1082. {
  1083. return _stp_dbg_disable(stp_dbg);
  1084. }
  1085. static VOID stp_dbg_nl_init(VOID)
  1086. {
  1087. if (genl_register_family(&stp_dbg_gnl_family) != 0) {
  1088. STP_DBG_ERR_FUNC("%s(): GE_NELINK family registration fail\n", __func__);
  1089. } else {
  1090. if (genl_register_family_with_ops(&stp_dbg_gnl_family, stp_dbg_gnl_ops) != 0)
  1091. STP_DBG_ERR_FUNC("%s(): operation registration fail\n", __func__);
  1092. }
  1093. }
  1094. static VOID stp_dbg_nl_deinit(VOID)
  1095. {
  1096. genl_unregister_family(&stp_dbg_gnl_family);
  1097. }
  1098. static INT32 stp_dbg_nl_bind(struct sk_buff *skb, struct genl_info *info)
  1099. {
  1100. struct nlattr *na;
  1101. PINT8 mydata;
  1102. if (info == NULL)
  1103. goto out;
  1104. STP_DBG_INFO_FUNC("%s():->\n", __func__);
  1105. na = info->attrs[STP_DBG_ATTR_MSG];
  1106. if (na)
  1107. mydata = (PINT8) nla_data(na);
  1108. if (num_bind_process < MAX_BIND_PROCESS) {
  1109. bind_pid[num_bind_process] = info->snd_portid;
  1110. num_bind_process++;
  1111. STP_DBG_INFO_FUNC("%s():-> pid = %d\n", __func__, info->snd_portid);
  1112. } else {
  1113. STP_DBG_ERR_FUNC("%s(): exceeding binding limit %d\n", __func__, MAX_BIND_PROCESS);
  1114. }
  1115. out:
  1116. return 0;
  1117. }
  1118. static INT32 stp_dbg_nl_reset(struct sk_buff *skb, struct genl_info *info)
  1119. {
  1120. STP_DBG_ERR_FUNC("%s(): should not be invoked\n", __func__);
  1121. return 0;
  1122. }
  1123. INT32 stp_dbg_nl_send(PINT8 aucMsg, UINT8 cmd, INT32 len)
  1124. {
  1125. struct sk_buff *skb = NULL;
  1126. PVOID msg_head = NULL;
  1127. INT32 rc = -1;
  1128. INT32 i;
  1129. INT32 ret = 0;
  1130. if (num_bind_process == 0) {
  1131. /* no listening process */
  1132. STP_DBG_ERR_FUNC("%s(): the process is not invoked\n", __func__);
  1133. return 0;
  1134. }
  1135. ret = wcn_core_dump_nl(g_core_dump, aucMsg, len);
  1136. if (ret < 0)
  1137. return ret;
  1138. if (ret == 32) {
  1139. return ret;
  1140. }
  1141. for (i = 0; i < num_bind_process; i++) {
  1142. skb = genlmsg_new(2048, GFP_KERNEL);
  1143. if (skb) {
  1144. msg_head =
  1145. genlmsg_put(skb, 0, stp_dbg_seqnum++, &stp_dbg_gnl_family, 0, cmd);
  1146. if (msg_head == NULL) {
  1147. nlmsg_free(skb);
  1148. STP_DBG_DBG_FUNC("%s(): genlmsg_put fail...\n", __func__);
  1149. return -1;
  1150. }
  1151. rc = nla_put(skb, STP_DBG_ATTR_MSG, len, aucMsg);
  1152. if (rc != 0) {
  1153. nlmsg_free(skb);
  1154. STP_DBG_DBG_FUNC("%s(): nla_put_string fail...: %d\n", __func__, rc);
  1155. return rc;
  1156. }
  1157. /* finalize the message */
  1158. genlmsg_end(skb, msg_head);
  1159. /* sending message */
  1160. rc = genlmsg_unicast(&init_net, skb, bind_pid[i]);
  1161. if (rc != 0) {
  1162. STP_DBG_DBG_FUNC("%s(): genlmsg_unicast fail...: %d\n", __func__, rc);
  1163. return rc;
  1164. }
  1165. } else {
  1166. STP_DBG_ERR_FUNC("%s(): genlmsg_new fail...\n", __func__);
  1167. return -1;
  1168. }
  1169. }
  1170. return 0;
  1171. }
  1172. INT32 stp_dbg_aee_send(PUINT8 aucMsg, INT32 len, INT32 cmd)
  1173. {
  1174. INT32 ret = 0;
  1175. /* buffered to compressor */
  1176. ret = wcn_core_dump_in(g_core_dump, aucMsg, len);
  1177. if (ret == 1)
  1178. wcn_core_dump_flush(0);
  1179. return ret;
  1180. }
  1181. PUINT8 _stp_dbg_id_to_task(UINT32 id)
  1182. {
  1183. PUINT8 taskStr[] = {
  1184. "Task_WMT",
  1185. "Task_BT",
  1186. "Task_Wifi",
  1187. "Task_Tst",
  1188. "Task_FM",
  1189. "Task_Idle",
  1190. "Task_DrvStp",
  1191. "Task_DrvBtif",
  1192. "Task_NatBt",
  1193. };
  1194. return taskStr[id];
  1195. }
  1196. INT32 _stp_dbg_parser_assert_str(PINT8 str, ENUM_ASSERT_INFO_PARSER_TYPE type)
  1197. {
  1198. PINT8 pStr = NULL;
  1199. PINT8 pDtr = NULL;
  1200. PINT8 pTemp = NULL;
  1201. PINT8 pTemp2 = NULL;
  1202. INT8 tempBuf[64] = { 0 };
  1203. UINT32 len = 0;
  1204. long res;
  1205. PINT8 parser_sub_string[] = {
  1206. "<ASSERT> ",
  1207. "id=",
  1208. "isr=",
  1209. "irq=",
  1210. "rc="
  1211. };
  1212. if (!str) {
  1213. STP_DBG_ERR_FUNC("NULL string source\n");
  1214. return -1;
  1215. }
  1216. if (!g_stp_dbg_cpupcr) {
  1217. STP_DBG_ERR_FUNC("NULL pointer\n");
  1218. return -2;
  1219. }
  1220. pStr = str;
  1221. STP_DBG_DBG_FUNC("source infor:%s\n", pStr);
  1222. switch (type) {
  1223. case STP_DBG_ASSERT_INFO:
  1224. pDtr = osal_strstr(pStr, parser_sub_string[type]);
  1225. if (NULL != pDtr) {
  1226. pDtr += osal_strlen(parser_sub_string[type]);
  1227. pTemp = osal_strchr(pDtr, ' ');
  1228. } else {
  1229. STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",
  1230. parser_sub_string[type]);
  1231. return -3;
  1232. }
  1233. len = pTemp - pDtr;
  1234. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], "assert@", osal_strlen("assert@"));
  1235. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@")], pDtr, len);
  1236. g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len] = '_';
  1237. pTemp = osal_strchr(pDtr, '#');
  1238. pTemp += 1;
  1239. pTemp2 = osal_strchr(pTemp, ' ');
  1240. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1], pTemp,
  1241. pTemp2 - pTemp);
  1242. g_stp_dbg_cpupcr->assert_info[osal_strlen("assert@") + len + 1 + pTemp2 - pTemp] =
  1243. '\0';
  1244. STP_DBG_INFO_FUNC("assert info:%s\n", &g_stp_dbg_cpupcr->assert_info[0]);
  1245. break;
  1246. case STP_DBG_FW_TASK_ID:
  1247. pDtr = osal_strstr(pStr, parser_sub_string[type]);
  1248. if (NULL != pDtr) {
  1249. pDtr += osal_strlen(parser_sub_string[type]);
  1250. pTemp = osal_strchr(pDtr, ' ');
  1251. } else {
  1252. STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",
  1253. parser_sub_string[type]);
  1254. return -3;
  1255. }
  1256. len = pTemp - pDtr;
  1257. osal_memcpy(&tempBuf[0], pDtr, len);
  1258. tempBuf[len] = '\0';
  1259. osal_strtol(tempBuf, 16, &res);
  1260. g_stp_dbg_cpupcr->fwTaskId = (UINT32)res;
  1261. STP_DBG_INFO_FUNC("fw task id :%x\n", (UINT32)res);
  1262. break;
  1263. case STP_DBG_FW_ISR:
  1264. pDtr = osal_strstr(pStr, parser_sub_string[type]);
  1265. if (NULL != pDtr) {
  1266. pDtr += osal_strlen(parser_sub_string[type]);
  1267. pTemp = osal_strchr(pDtr, ',');
  1268. } else {
  1269. STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",
  1270. parser_sub_string[type]);
  1271. return -3;
  1272. }
  1273. len = pTemp - pDtr;
  1274. osal_memcpy(&tempBuf[0], pDtr, len);
  1275. tempBuf[len] = '\0';
  1276. osal_strtol(tempBuf, 16, &res);
  1277. g_stp_dbg_cpupcr->fwIsr = (UINT32)res;
  1278. STP_DBG_INFO_FUNC("fw isr str:%x\n", (UINT32)res);
  1279. break;
  1280. case STP_DBG_FW_IRQ:
  1281. pDtr = osal_strstr(pStr, parser_sub_string[type]);
  1282. if (NULL != pDtr) {
  1283. pDtr += osal_strlen(parser_sub_string[type]);
  1284. pTemp = osal_strchr(pDtr, ',');
  1285. } else {
  1286. STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",
  1287. parser_sub_string[type]);
  1288. return -3;
  1289. }
  1290. len = pTemp - pDtr;
  1291. osal_memcpy(&tempBuf[0], pDtr, len);
  1292. tempBuf[len] = '\0';
  1293. osal_strtol(tempBuf, 16, &res);
  1294. g_stp_dbg_cpupcr->fwRrq = (UINT32)res;
  1295. STP_DBG_INFO_FUNC("fw irq value:%x\n", (UINT32)res);
  1296. break;
  1297. case STP_DBG_ASSERT_TYPE:
  1298. pDtr = osal_strstr(pStr, parser_sub_string[type]);
  1299. if (NULL != pDtr) {
  1300. pDtr += osal_strlen(parser_sub_string[type]);
  1301. pTemp = osal_strchr(pDtr, ',');
  1302. } else {
  1303. STP_DBG_ERR_FUNC("parser str is NULL,substring(%s)\n",
  1304. parser_sub_string[type]);
  1305. return -3;
  1306. }
  1307. len = pTemp - pDtr;
  1308. osal_memcpy(&tempBuf[0], pDtr, len);
  1309. tempBuf[len] = '\0';
  1310. if (0 == osal_memcmp(tempBuf, "*", osal_strlen("*")))
  1311. osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "general assert",
  1312. osal_strlen("general assert"));
  1313. if (0 ==
  1314. osal_memcmp(tempBuf, "Watch Dog Timeout", osal_strlen("Watch Dog Timeout")))
  1315. osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], "wdt", osal_strlen("wdt"));
  1316. if (0 == osal_memcmp(tempBuf, "RB_FULL", osal_strlen("RB_FULL"))) {
  1317. osal_memcpy(&g_stp_dbg_cpupcr->assert_type[0], tempBuf, len);
  1318. pDtr = osal_strstr(&g_stp_dbg_cpupcr->assert_type[0], "RB_FULL(");
  1319. if (NULL != pDtr) {
  1320. pDtr += osal_strlen("RB_FULL(");
  1321. pTemp = osal_strchr(pDtr, ')');
  1322. } else {
  1323. STP_DBG_ERR_FUNC("parser str is NULL,substring(RB_FULL()\n");
  1324. return -4;
  1325. }
  1326. len = pTemp - pDtr;
  1327. osal_memcpy(&tempBuf[0], pDtr, len);
  1328. tempBuf[len] = '\0';
  1329. osal_strtol(tempBuf, 16, &res);
  1330. g_stp_dbg_cpupcr->fwTaskId = (UINT32)res;
  1331. STP_DBG_INFO_FUNC("update fw task id :%x\n",
  1332. (UINT32)res);
  1333. }
  1334. STP_DBG_INFO_FUNC("fw asert type:%s\n", g_stp_dbg_cpupcr->assert_type);
  1335. break;
  1336. default:
  1337. STP_DBG_ERR_FUNC("unknown parser type\n");
  1338. break;
  1339. }
  1340. return 0;
  1341. }
  1342. P_STP_DBG_CPUPCR_T stp_dbg_cpupcr_init(VOID)
  1343. {
  1344. P_STP_DBG_CPUPCR_T pSdCpupcr = NULL;
  1345. pSdCpupcr = (P_STP_DBG_CPUPCR_T) osal_malloc(osal_sizeof(STP_DBG_CPUPCR_T));
  1346. if (!pSdCpupcr) {
  1347. STP_DBG_ERR_FUNC("stp dbg cpupcr allocate memory fail!\n");
  1348. return NULL;
  1349. }
  1350. osal_memset(pSdCpupcr, 0, osal_sizeof(STP_DBG_CPUPCR_T));
  1351. osal_sleepable_lock_init(&pSdCpupcr->lock);
  1352. return pSdCpupcr;
  1353. }
  1354. VOID stp_dbg_cpupcr_deinit(P_STP_DBG_CPUPCR_T pCpupcr)
  1355. {
  1356. if (pCpupcr) {
  1357. osal_sleepable_lock_deinit(&pCpupcr->lock);
  1358. osal_free(pCpupcr);
  1359. pCpupcr = NULL;
  1360. }
  1361. }
  1362. INT32 stp_dbg_set_version_info(UINT32 chipid, PUINT8 pRomVer, PUINT8 wifiVer, PUINT8 pPatchVer,
  1363. PUINT8 pPatchBrh)
  1364. {
  1365. if (g_stp_dbg_cpupcr) {
  1366. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1367. g_stp_dbg_cpupcr->chipId = chipid;
  1368. if (wifiVer)
  1369. osal_memcpy(g_stp_dbg_cpupcr->wifiVer, wifiVer, 4);
  1370. if (pRomVer)
  1371. osal_memcpy(g_stp_dbg_cpupcr->romVer, pRomVer, 2);
  1372. if (pPatchVer)
  1373. osal_memcpy(g_stp_dbg_cpupcr->patchVer, pPatchVer, 8);
  1374. if (pPatchBrh)
  1375. osal_memcpy(g_stp_dbg_cpupcr->branchVer, pPatchBrh, 4);
  1376. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1377. } else {
  1378. STP_DBG_ERR_FUNC("NULL pointer\n");
  1379. return -1;
  1380. }
  1381. STP_DBG_INFO_FUNC("chipid(0x%x),wifiver(%s),romver(%s),patchver(%s),branchver(%s)\n",
  1382. g_stp_dbg_cpupcr->chipId, g_stp_dbg_cpupcr->wifiVer,
  1383. &g_stp_dbg_cpupcr->romVer[0], &g_stp_dbg_cpupcr->patchVer[0],
  1384. &g_stp_dbg_cpupcr->branchVer[0]);
  1385. return 0;
  1386. }
  1387. INT32 stp_dbg_set_host_assert_info(UINT32 drv_type, UINT32 reason, UINT32 en)
  1388. {
  1389. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1390. g_stp_dbg_cpupcr->host_assert_info.assert_from_host = en;
  1391. g_stp_dbg_cpupcr->host_assert_info.drv_type = drv_type;
  1392. g_stp_dbg_cpupcr->host_assert_info.reason = reason;
  1393. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1394. return 0;
  1395. }
  1396. UINT32 stp_dbg_get_host_trigger_assert(VOID)
  1397. {
  1398. return g_stp_dbg_cpupcr->host_assert_info.assert_from_host;
  1399. }
  1400. INT32 stp_dbg_set_fw_info(PUINT8 issue_info, UINT32 len, ENUM_STP_FW_ISSUE_TYPE issue_type)
  1401. {
  1402. ENUM_ASSERT_INFO_PARSER_TYPE type_index;
  1403. PUINT8 tempbuf = NULL;
  1404. UINT32 i = 0;
  1405. INT32 iRet = 0;
  1406. if (NULL == issue_info) {
  1407. STP_DBG_ERR_FUNC("null issue infor\n");
  1408. return -1;
  1409. }
  1410. STP_DBG_INFO_FUNC("issue type(%d)\n", issue_type);
  1411. g_stp_dbg_cpupcr->issue_type = issue_type;
  1412. osal_memset(&g_stp_dbg_cpupcr->assert_info[0], 0, STP_ASSERT_INFO_SIZE);
  1413. /*print patch version when assert happened */
  1414. STP_DBG_INFO_FUNC("=======================================\n");
  1415. STP_DBG_INFO_FUNC("[combo patch]patch version:%s\n", g_stp_dbg_cpupcr->patchVer);
  1416. STP_DBG_INFO_FUNC("[combo patch]ALPS branch:%s\n", g_stp_dbg_cpupcr->branchVer);
  1417. STP_DBG_INFO_FUNC("=======================================\n");
  1418. if (STP_FW_ASSERT_ISSUE == issue_type || (STP_HOST_TRIGGER_FW_ASSERT == issue_type)) {
  1419. tempbuf = osal_malloc(len);
  1420. if (!tempbuf)
  1421. return -2;
  1422. osal_memcpy(&tempbuf[0], issue_info, len);
  1423. for (i = 0; i < len; i++) {
  1424. if ((tempbuf[i] == '\0') || (tempbuf[i] == '\n'))
  1425. tempbuf[i] = '?';
  1426. }
  1427. tempbuf[len] = '\0';
  1428. STP_DBG_INFO_FUNC("tempbuf<%s>\n", tempbuf);
  1429. STP_DBG_INFO_FUNC("issue type(%d)\n", issue_type);
  1430. for (type_index = STP_DBG_ASSERT_INFO; type_index < STP_DBG_PARSER_TYPE_MAX;
  1431. type_index++) {
  1432. iRet += _stp_dbg_parser_assert_str(&tempbuf[0], type_index);
  1433. }
  1434. if (iRet)
  1435. STP_DBG_ERR_FUNC("passert assert infor fail(%d)\n", iRet);
  1436. if (STP_HOST_TRIGGER_FW_ASSERT == issue_type) {
  1437. switch (g_stp_dbg_cpupcr->host_assert_info.drv_type) {
  1438. case 0:
  1439. STP_DBG_INFO_FUNC("bt trigger assert\n");
  1440. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1441. if (31 != g_stp_dbg_cpupcr->host_assert_info.reason)
  1442. /*BT firmware trigger assert */
  1443. {
  1444. g_stp_dbg_cpupcr->fwTaskId = 1;
  1445. } else
  1446. /*BT stack trigger assert */
  1447. {
  1448. g_stp_dbg_cpupcr->fwTaskId = 8;
  1449. }
  1450. g_stp_dbg_cpupcr->host_assert_info.assert_from_host = 0;
  1451. /* g_stp_dbg_cpupcr->host_assert_info.drv_type = 0; */
  1452. /* g_stp_dbg_cpupcr->host_assert_info.reason = 0; */
  1453. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1454. break;
  1455. default:
  1456. break;
  1457. }
  1458. }
  1459. osal_free(tempbuf);
  1460. } else if (STP_FW_NOACK_ISSUE == issue_type) {
  1461. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1462. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
  1463. g_stp_dbg_cpupcr->fwTaskId = 6;
  1464. g_stp_dbg_cpupcr->fwRrq = 0;
  1465. g_stp_dbg_cpupcr->fwIsr = 0;
  1466. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1467. } else if (STP_DBG_PROC_TEST == issue_type) {
  1468. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1469. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
  1470. g_stp_dbg_cpupcr->fwTaskId = 0;
  1471. g_stp_dbg_cpupcr->fwRrq = 0;
  1472. g_stp_dbg_cpupcr->fwIsr = 0;
  1473. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1474. } else if (STP_FW_WARM_RST_ISSUE == issue_type) {
  1475. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1476. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
  1477. g_stp_dbg_cpupcr->fwTaskId = 0;
  1478. g_stp_dbg_cpupcr->fwRrq = 0;
  1479. g_stp_dbg_cpupcr->fwIsr = 0;
  1480. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1481. } else if (STP_FW_ABT == issue_type) {
  1482. osal_lock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1483. osal_memcpy(&g_stp_dbg_cpupcr->assert_info[0], issue_info, len);
  1484. g_stp_dbg_cpupcr->fwTaskId = 0;
  1485. g_stp_dbg_cpupcr->fwRrq = 0;
  1486. g_stp_dbg_cpupcr->fwIsr = 0;
  1487. osal_unlock_sleepable_lock(&g_stp_dbg_cpupcr->lock);
  1488. } else {
  1489. STP_DBG_ERR_FUNC("invalid issue type(%d)\n", issue_type);
  1490. return -3;
  1491. }
  1492. return iRet;
  1493. }
  1494. INT32 stp_dbg_cpupcr_infor_format(PPUINT8 buf, PUINT32 str_len)
  1495. {
  1496. UINT32 len = 0;
  1497. UINT32 i = 0;
  1498. if (!g_stp_dbg_cpupcr) {
  1499. STP_DBG_ERR_FUNC("NULL pointer\n");
  1500. return -1;
  1501. }
  1502. STP_DBG_INFO_FUNC("printf assert issue type(%d)\n", g_stp_dbg_cpupcr->issue_type);
  1503. /*format common information about issue */
  1504. len = osal_sprintf(*buf, "<main>\n\t");
  1505. len +=
  1506. osal_sprintf(*buf + len, "<chipid>\n\t\tMT%x\n\t</chipid>\n\t",
  1507. g_stp_dbg_cpupcr->chipId);
  1508. len += osal_sprintf(*buf + len, "<version>\n\t\t");
  1509. len += osal_sprintf(*buf + len, "<rom>%s</rom>\n\t\t", g_stp_dbg_cpupcr->romVer);
  1510. if (!(osal_memcmp(g_stp_dbg_cpupcr->branchVer, "ALPS", STP_PATCH_BRANCH_SZIE))) {
  1511. len +=
  1512. osal_sprintf(*buf + len, "<branch>Internal Dev</branch>\n\t\t",
  1513. g_stp_dbg_cpupcr->branchVer);
  1514. } else {
  1515. len +=
  1516. osal_sprintf(*buf + len, "<branch>W%sMP</branch>\n\t\t",
  1517. g_stp_dbg_cpupcr->branchVer);
  1518. }
  1519. len += osal_sprintf(*buf + len, "<patch>%s</patch>\n\t\t", g_stp_dbg_cpupcr->patchVer);
  1520. if (!g_stp_dbg_cpupcr->wifiVer[0])
  1521. len += osal_sprintf(*buf + len, "<wifi>NULL</wifi>\n\t");
  1522. else
  1523. len += osal_sprintf(*buf + len, "<wifi>%s</wifi>\n\t", g_stp_dbg_cpupcr->wifiVer);
  1524. len += osal_sprintf(*buf + len, "</version>\n\t");
  1525. /*format issue information: no ack, assert */
  1526. len += osal_sprintf(*buf + len, "<issue>\n\t\t<classification>\n\t\t\t");
  1527. if ((STP_FW_NOACK_ISSUE == g_stp_dbg_cpupcr->issue_type) ||
  1528. (STP_DBG_PROC_TEST == g_stp_dbg_cpupcr->issue_type) ||
  1529. (STP_FW_WARM_RST_ISSUE == g_stp_dbg_cpupcr->issue_type)) {
  1530. len +=
  1531. osal_sprintf(*buf + len, "%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t",
  1532. g_stp_dbg_cpupcr->assert_info);
  1533. len += osal_sprintf(*buf + len, "NULL\n\t\t</rc>\n\t</issue>\n\t");
  1534. len += osal_sprintf(*buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
  1535. len += osal_sprintf(*buf + len, "<host>NULL</host>\n\t\t");
  1536. len +=
  1537. osal_sprintf(*buf + len, "<client>\n\t\t\t<task>%s</task>\n\t\t\t",
  1538. _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
  1539. len +=
  1540. osal_sprintf(*buf + len, "<irqx>IRQ_0x%x</irqx>\n\t\t\t",
  1541. g_stp_dbg_cpupcr->fwRrq);
  1542. len += osal_sprintf(*buf + len, "<isr>0x%x</isr>\n\t\t\t", g_stp_dbg_cpupcr->fwIsr);
  1543. } else if (STP_FW_ASSERT_ISSUE == g_stp_dbg_cpupcr->issue_type) {
  1544. len +=
  1545. osal_sprintf(*buf + len, "%s\n\t\t</classification>\n\t\t<rc>\n\t\t\t",
  1546. g_stp_dbg_cpupcr->assert_info);
  1547. len +=
  1548. osal_sprintf(*buf + len, "%s\n\t\t</rc>\n\t</issue>\n\t",
  1549. g_stp_dbg_cpupcr->assert_type);
  1550. len += osal_sprintf(*buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
  1551. len += osal_sprintf(*buf + len, "<host>NULL</host>\n\t\t");
  1552. len +=
  1553. osal_sprintf(*buf + len, "<client>\n\t\t\t<task>%s</task>\n\t\t\t",
  1554. _stp_dbg_id_to_task(g_stp_dbg_cpupcr->fwTaskId));
  1555. len +=
  1556. osal_sprintf(*buf + len, "<irqx>IRQ_0x%x</irqx>\n\t\t\t",
  1557. g_stp_dbg_cpupcr->fwRrq);
  1558. len += osal_sprintf(*buf + len, "<isr>0x%x</isr>\n\t\t\t", g_stp_dbg_cpupcr->fwIsr);
  1559. } else {
  1560. len += osal_sprintf(*buf + len, "NULL\n\t\t</classification>\n\t\t<rc>\n\t\t\t");
  1561. len += osal_sprintf(*buf + len, "NULL\n\t\t</rc>\n\t</issue>\n\t");
  1562. len += osal_sprintf(*buf + len, "<hint>\n\t\t<time_align>NULL</time_align>\n\t\t");
  1563. len += osal_sprintf(*buf + len, "<host>NULL</host>\n\t\t");
  1564. len += osal_sprintf(*buf + len, "<client>\n\t\t\t<task>NULL</task>\n\t\t\t");
  1565. len += osal_sprintf(*buf + len, "<irqx>NULL</irqx>\n\t\t\t");
  1566. len += osal_sprintf(*buf + len, "<isr>NULL</isr>\n\t\t\t");
  1567. }
  1568. len += osal_sprintf(*buf + len, "<pctrace>");
  1569. STP_DBG_INFO_FUNC("stp-dbg:sub len1 for debug(%d)\n", len);
  1570. if (!g_stp_dbg_cpupcr->count) {
  1571. len += osal_sprintf(*buf + len, "NULL");
  1572. } else {
  1573. for (i = 0; i < g_stp_dbg_cpupcr->count; i++)
  1574. len += osal_sprintf(*buf + len, "%08x,", g_stp_dbg_cpupcr->buffer[i]);
  1575. }
  1576. STP_DBG_INFO_FUNC("stp-dbg:sub len2 for debug(%d)\n", len);
  1577. len += osal_sprintf(*buf + len, "</pctrace>\n\t\t\t");
  1578. len +=
  1579. osal_sprintf(*buf + len,
  1580. "<extension>NULL</extension>\n\t\t</client>\n\t</hint>\n</main>\n");
  1581. STP_DBG_INFO_FUNC("buffer len[%d]\n", len);
  1582. /* STP_DBG_INFO_FUNC("Format infor:\n%s\n",*buf); */
  1583. *str_len = len;
  1584. osal_memset(&g_stp_dbg_cpupcr->buffer[0], 0, STP_DBG_CPUPCR_NUM);
  1585. g_stp_dbg_cpupcr->count = 0;
  1586. return 0;
  1587. }
  1588. MTKSTP_DBG_T *stp_dbg_init(PVOID btm_half)
  1589. {
  1590. MTKSTP_DBG_T *stp_dbg = NULL;
  1591. STP_DBG_INFO_FUNC("stp-dbg init\n");
  1592. stp_dbg = kzalloc(sizeof(MTKSTP_DBG_T), GFP_KERNEL);
  1593. if (IS_ERR(stp_dbg)) {
  1594. STP_DBG_ERR_FUNC("-ENOMEM\n");
  1595. goto ERR_EXIT1;
  1596. }
  1597. stp_dbg->logsys = vmalloc(sizeof(MTKSTP_LOG_SYS_T));
  1598. if (IS_ERR(stp_dbg->logsys)) {
  1599. STP_DBG_ERR_FUNC("-ENOMEM stp_gdb->logsys\n");
  1600. goto ERR_EXIT2;
  1601. }
  1602. memset(stp_dbg->logsys, 0, sizeof(MTKSTP_LOG_SYS_T));
  1603. spin_lock_init(&(stp_dbg->logsys->lock));
  1604. stp_dbg->pkt_trace_no = 0;
  1605. stp_dbg->is_enable = 0;
  1606. g_stp_dbg = stp_dbg;
  1607. if (btm_half != NULL)
  1608. stp_dbg->btm = btm_half;
  1609. else
  1610. stp_dbg->btm = NULL;
  1611. /* bind to netlink */
  1612. stp_dbg_nl_init();
  1613. g_core_dump = wcn_core_dump_init(STP_CORE_DUMP_TIMEOUT);
  1614. g_stp_dbg_cpupcr = stp_dbg_cpupcr_init();
  1615. return stp_dbg;
  1616. ERR_EXIT2:
  1617. kfree(stp_dbg);
  1618. return NULL;
  1619. ERR_EXIT1:
  1620. return NULL;
  1621. }
  1622. INT32 stp_dbg_deinit(MTKSTP_DBG_T *stp_dbg)
  1623. {
  1624. STP_DBG_INFO_FUNC("stp-dbg deinit\n");
  1625. wcn_core_dump_deinit(g_core_dump);
  1626. stp_dbg_cpupcr_deinit(g_stp_dbg_cpupcr);
  1627. /* unbind with netlink */
  1628. stp_dbg_nl_deinit();
  1629. if (stp_dbg->logsys)
  1630. vfree(stp_dbg->logsys);
  1631. kfree(stp_dbg);
  1632. return 0;
  1633. }