dhd_debug.c 66 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222
  1. /*
  2. * DHD debugability support
  3. *
  4. * <<Broadcom-WL-IPTag/Open:>>
  5. *
  6. * Portions of this code are copyright (c) 2020 Cypress Semiconductor Corporation
  7. *
  8. * Copyright (C) 1999-2020, Broadcom Corporation
  9. *
  10. * Unless you and Broadcom execute a separate written software license
  11. * agreement governing use of this software, this software is licensed to you
  12. * under the terms of the GNU General Public License version 2 (the "GPL"),
  13. * available at http://www.broadcom.com/licenses/GPLv2.php, with the
  14. * following added to such license:
  15. *
  16. * As a special exception, the copyright holders of this software give you
  17. * permission to link this software with independent modules, and to copy and
  18. * distribute the resulting executable under terms of your choice, provided that
  19. * you also meet, for each linked independent module, the terms and conditions of
  20. * the license of that module. An independent module is a module which is not
  21. * derived from this software. The special exception does not apply to any
  22. * modifications of the software.
  23. *
  24. * Notwithstanding the above, under no circumstances may you combine this
  25. * software in any way with any other Broadcom software provided under a license
  26. * other than the GPL, without Broadcom's express prior written consent.
  27. *
  28. * $Id: dhd_debug.c 701420 2017-05-24 23:20:58Z $
  29. */
  30. #include <typedefs.h>
  31. #include <osl.h>
  32. #include <bcmutils.h>
  33. #include <bcmendian.h>
  34. #include <dngl_stats.h>
  35. #include <dhd.h>
  36. #include <dhd_dbg.h>
  37. #include <dhd_dbg_ring.h>
  38. #include <dhd_debug.h>
  39. #include <dhd_mschdbg.h>
  40. #include <dhd_bus.h>
  41. #include <event_log.h>
  42. #include <event_trace.h>
  43. #include <msgtrace.h>
  44. #if defined(DHD_EVENT_LOG_FILTER)
  45. #include <dhd_event_log_filter.h>
  46. #endif /* DHD_EVENT_LOG_FILTER */
  47. #define DHD_PKT_INFO DHD_ERROR
  48. struct map_table {
  49. uint16 fw_id;
  50. uint16 host_id;
  51. char *desc;
  52. };
  53. struct map_table event_map[] = {
  54. {WLC_E_AUTH, WIFI_EVENT_AUTH_COMPLETE, "AUTH_COMPLETE"},
  55. {WLC_E_ASSOC, WIFI_EVENT_ASSOC_COMPLETE, "ASSOC_COMPLETE"},
  56. {TRACE_FW_AUTH_STARTED, WIFI_EVENT_FW_AUTH_STARTED, "AUTH STARTED"},
  57. {TRACE_FW_ASSOC_STARTED, WIFI_EVENT_FW_ASSOC_STARTED, "ASSOC STARTED"},
  58. {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_FW_RE_ASSOC_STARTED, "REASSOC STARTED"},
  59. {TRACE_G_SCAN_STARTED, WIFI_EVENT_G_SCAN_STARTED, "GSCAN STARTED"},
  60. {WLC_E_PFN_SCAN_COMPLETE, WIFI_EVENT_G_SCAN_COMPLETE, "GSCAN COMPLETE"},
  61. {WLC_E_DISASSOC, WIFI_EVENT_DISASSOCIATION_REQUESTED, "DIASSOC REQUESTED"},
  62. {WLC_E_REASSOC, WIFI_EVENT_RE_ASSOCIATION_REQUESTED, "REASSOC REQUESTED"},
  63. {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_REQUESTED, "ROAM REQUESTED"},
  64. {WLC_E_BEACON_FRAME_RX, WIFI_EVENT_BEACON_RECEIVED, "BEACON Received"},
  65. {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_SCAN_STARTED, "ROAM SCAN STARTED"},
  66. {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"},
  67. {TRACE_ROAM_AUTH_STARTED, WIFI_EVENT_ROAM_AUTH_STARTED, "ROAM AUTH STARTED"},
  68. {WLC_E_AUTH, WIFI_EVENT_ROAM_AUTH_COMPLETE, "ROAM AUTH COMPLETED"},
  69. {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_ROAM_ASSOC_STARTED, "ROAM ASSOC STARTED"},
  70. {WLC_E_ASSOC, WIFI_EVENT_ROAM_ASSOC_COMPLETE, "ROAM ASSOC COMPLETED"},
  71. {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"},
  72. {TRACE_BT_COEX_BT_SCO_START, WIFI_EVENT_BT_COEX_BT_SCO_START, "BT SCO START"},
  73. {TRACE_BT_COEX_BT_SCO_STOP, WIFI_EVENT_BT_COEX_BT_SCO_STOP, "BT SCO STOP"},
  74. {TRACE_BT_COEX_BT_SCAN_START, WIFI_EVENT_BT_COEX_BT_SCAN_START, "BT COEX SCAN START"},
  75. {TRACE_BT_COEX_BT_SCAN_STOP, WIFI_EVENT_BT_COEX_BT_SCAN_STOP, "BT COEX SCAN STOP"},
  76. {TRACE_BT_COEX_BT_HID_START, WIFI_EVENT_BT_COEX_BT_HID_START, "BT HID START"},
  77. {TRACE_BT_COEX_BT_HID_STOP, WIFI_EVENT_BT_COEX_BT_HID_STOP, "BT HID STOP"},
  78. {WLC_E_EAPOL_MSG, WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED, "FW EAPOL PKT RECEIVED"},
  79. {TRACE_FW_EAPOL_FRAME_TRANSMIT_START, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START,
  80. "FW EAPOL PKT TRANSMITED"},
  81. {TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP,
  82. "FW EAPOL PKT TX STOPPED"},
  83. {TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE, WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE,
  84. "BLOCK ACK NEGO COMPLETED"},
  85. };
  86. struct map_table event_tag_map[] = {
  87. {TRACE_TAG_VENDOR_SPECIFIC, WIFI_TAG_VENDOR_SPECIFIC, "VENDOR SPECIFIC DATA"},
  88. {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"},
  89. {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"},
  90. {TRACE_TAG_SSID, WIFI_TAG_SSID, "SSID"},
  91. {TRACE_TAG_STATUS, WIFI_TAG_STATUS, "STATUS"},
  92. {TRACE_TAG_CHANNEL_SPEC, WIFI_TAG_CHANNEL_SPEC, "CHANSPEC"},
  93. {TRACE_TAG_WAKE_LOCK_EVENT, WIFI_TAG_WAKE_LOCK_EVENT, "WAKELOCK EVENT"},
  94. {TRACE_TAG_ADDR1, WIFI_TAG_ADDR1, "ADDR_1"},
  95. {TRACE_TAG_ADDR2, WIFI_TAG_ADDR2, "ADDR_2"},
  96. {TRACE_TAG_ADDR3, WIFI_TAG_ADDR3, "ADDR_3"},
  97. {TRACE_TAG_ADDR4, WIFI_TAG_ADDR4, "ADDR_4"},
  98. {TRACE_TAG_TSF, WIFI_TAG_TSF, "TSF"},
  99. {TRACE_TAG_IE, WIFI_TAG_IE, "802.11 IE"},
  100. {TRACE_TAG_INTERFACE, WIFI_TAG_INTERFACE, "INTERFACE"},
  101. {TRACE_TAG_REASON_CODE, WIFI_TAG_REASON_CODE, "REASON CODE"},
  102. {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"},
  103. };
  104. /* define log level per ring type */
  105. struct log_level_table fw_verbose_level_map[] = {
  106. {1, EVENT_LOG_TAG_PCI_ERROR, "PCI_ERROR"},
  107. {1, EVENT_LOG_TAG_PCI_WARN, "PCI_WARN"},
  108. {2, EVENT_LOG_TAG_PCI_INFO, "PCI_INFO"},
  109. {3, EVENT_LOG_TAG_PCI_DBG, "PCI_DEBUG"},
  110. {3, EVENT_LOG_TAG_BEACON_LOG, "BEACON_LOG"},
  111. {2, EVENT_LOG_TAG_WL_ASSOC_LOG, "ASSOC_LOG"},
  112. {2, EVENT_LOG_TAG_WL_ROAM_LOG, "ROAM_LOG"},
  113. {1, EVENT_LOG_TAG_TRACE_WL_INFO, "WL INFO"},
  114. {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, "BTCOEX INFO"},
  115. #ifdef CUSTOMER_HW4_DEBUG
  116. {3, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"},
  117. #else
  118. {1, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"},
  119. #endif /* CUSTOMER_HW4_DEBUG */
  120. {1, EVENT_LOG_TAG_SCAN_ERROR, "SCAN_ERROR"},
  121. {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, "SCAN_TRACE_LOW"},
  122. {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, "SCAN_TRACE_HIGH"}
  123. };
  124. /* reference tab table */
  125. uint ref_tag_tbl[EVENT_LOG_TAG_MAX + 1] = {0};
  126. typedef struct dhddbg_loglist_item {
  127. dll_t list;
  128. prcd_event_log_hdr_t prcd_log_hdr;
  129. } loglist_item_t;
  130. typedef struct dhbdbg_pending_item {
  131. dll_t list;
  132. dhd_dbg_ring_status_t ring_status;
  133. dhd_dbg_ring_entry_t *ring_entry;
  134. } pending_item_t;
  135. /* trace log entry header user space processing */
  136. struct tracelog_header {
  137. int magic_num;
  138. int buf_size;
  139. int seq_num;
  140. };
  141. #define TRACE_LOG_MAGIC_NUMBER 0xEAE47C06
  142. int
  143. dhd_dbg_push_to_ring(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data)
  144. {
  145. dhd_dbg_ring_t *ring;
  146. int ret = 0;
  147. uint32 pending_len = 0;
  148. if (!dhdp || !dhdp->dbg) {
  149. return BCME_BADADDR;
  150. }
  151. if (!VALID_RING(ring_id)) {
  152. DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
  153. return BCME_RANGE;
  154. }
  155. ring = &dhdp->dbg->dbg_rings[ring_id];
  156. ret = dhd_dbg_ring_push(ring, hdr, data);
  157. if (ret != BCME_OK)
  158. return ret;
  159. pending_len = dhd_dbg_ring_get_pending_len(ring);
  160. dhd_dbg_ring_sched_pull(ring, pending_len, dhdp->dbg->pullreq,
  161. dhdp->dbg->private, ring->id);
  162. return ret;
  163. }
  164. dhd_dbg_ring_t *
  165. dhd_dbg_get_ring_from_ring_id(dhd_pub_t *dhdp, int ring_id)
  166. {
  167. if (!dhdp || !dhdp->dbg) {
  168. return NULL;
  169. }
  170. if (!VALID_RING(ring_id)) {
  171. DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
  172. return NULL;
  173. }
  174. return &dhdp->dbg->dbg_rings[ring_id];
  175. }
  176. int
  177. dhd_dbg_pull_single_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len,
  178. bool strip_header)
  179. {
  180. dhd_dbg_ring_t *ring;
  181. if (!dhdp || !dhdp->dbg) {
  182. return 0;
  183. }
  184. if (!VALID_RING(ring_id)) {
  185. DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
  186. return BCME_RANGE;
  187. }
  188. ring = &dhdp->dbg->dbg_rings[ring_id];
  189. return dhd_dbg_ring_pull_single(ring, data, buf_len, strip_header);
  190. }
  191. int
  192. dhd_dbg_pull_from_ring(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len)
  193. {
  194. dhd_dbg_ring_t *ring;
  195. if (!dhdp || !dhdp->dbg)
  196. return 0;
  197. if (!VALID_RING(ring_id)) {
  198. DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
  199. return BCME_RANGE;
  200. }
  201. ring = &dhdp->dbg->dbg_rings[ring_id];
  202. return dhd_dbg_ring_pull(ring, data, buf_len, FALSE);
  203. }
  204. static int
  205. dhd_dbg_msgtrace_seqchk(uint32 *prev, uint32 cur)
  206. {
  207. /* normal case including wrap around */
  208. if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) {
  209. goto done;
  210. } else if (cur == *prev) {
  211. DHD_EVENT(("%s duplicate trace\n", __FUNCTION__));
  212. return -1;
  213. } else if (cur > *prev) {
  214. DHD_EVENT(("%s lost %d packets\n", __FUNCTION__, cur - *prev));
  215. } else {
  216. DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n",
  217. __FUNCTION__, *prev, cur));
  218. }
  219. done:
  220. *prev = cur;
  221. return 0;
  222. }
  223. #ifndef MACOSX_DHD
  224. static void
  225. dhd_dbg_msgtrace_msg_parser(void *event_data)
  226. {
  227. msgtrace_hdr_t *hdr;
  228. char *data, *s;
  229. static uint32 seqnum_prev = 0;
  230. if (!event_data) {
  231. DHD_ERROR(("%s: event_data is NULL\n", __FUNCTION__));
  232. return;
  233. }
  234. hdr = (msgtrace_hdr_t *)event_data;
  235. data = (char *)event_data + MSGTRACE_HDRLEN;
  236. /* There are 2 bytes available at the end of data */
  237. data[ntoh16(hdr->len)] = '\0';
  238. if (ntoh32(hdr->discarded_bytes) || ntoh32(hdr->discarded_printf)) {
  239. DHD_DBGIF(("WLC_E_TRACE: [Discarded traces in dongle -->"
  240. "discarded_bytes %d discarded_printf %d]\n",
  241. ntoh32(hdr->discarded_bytes),
  242. ntoh32(hdr->discarded_printf)));
  243. }
  244. if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum)))
  245. return;
  246. /* Display the trace buffer. Advance from
  247. * \n to \n to avoid display big
  248. * printf (issue with Linux printk )
  249. */
  250. while (*data != '\0' && (s = strstr(data, "\n")) != NULL) {
  251. *s = '\0';
  252. DHD_FWLOG(("[FWLOG] %s\n", data));
  253. data = s+1;
  254. }
  255. if (*data)
  256. DHD_FWLOG(("[FWLOG] %s", data));
  257. }
  258. #endif /* MACOSX_DHD */
  259. #ifdef SHOW_LOGTRACE
  260. #define DATA_UNIT_FOR_LOG_CNT 4
  261. #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
  262. #pragma GCC diagnostic pop
  263. #endif // endif
  264. int
  265. replace_percent_p_to_x(char *fmt)
  266. {
  267. int p_to_x_done = FALSE;
  268. while (*fmt != '\0')
  269. {
  270. /* Skip characters will we see a % */
  271. if (*fmt++ != '%')
  272. {
  273. continue;
  274. }
  275. /*
  276. * Skip any flags, field width and precision:
  277. *Flags: Followed by %
  278. * #, 0, -, ' ', +
  279. */
  280. if (*fmt == '#')
  281. fmt++;
  282. if (*fmt == '0' || *fmt == '-' || *fmt == '+')
  283. fmt++;
  284. /*
  285. * Field width:
  286. * An optional decimal digit string (with non-zero first digit)
  287. * specifying a minimum field width
  288. */
  289. while (*fmt && bcm_isdigit(*fmt))
  290. fmt++;
  291. /*
  292. * Precision:
  293. * An optional precision, in the form of a period ('.') followed by an
  294. * optional decimal digit string.
  295. */
  296. if (*fmt == '.')
  297. {
  298. fmt++;
  299. while (*fmt && bcm_isdigit(*fmt)) fmt++;
  300. }
  301. /* If %p is seen, change it to %x */
  302. if (*fmt == 'p')
  303. {
  304. *fmt = 'x';
  305. p_to_x_done = TRUE;
  306. }
  307. if (*fmt)
  308. fmt++;
  309. }
  310. return p_to_x_done;
  311. }
  312. /* To identify format of types %Ns where N >= 0 is a number */
  313. bool
  314. check_valid_string_format(char *curr_ptr)
  315. {
  316. char *next_ptr;
  317. if ((next_ptr = bcmstrstr(curr_ptr, "s")) != NULL) {
  318. /* Default %s format */
  319. if (curr_ptr == next_ptr) {
  320. return TRUE;
  321. }
  322. /* Verify each charater between '%' and 's' is a valid number */
  323. while (curr_ptr < next_ptr) {
  324. if (bcm_isdigit(*curr_ptr) == FALSE) {
  325. return FALSE;
  326. }
  327. curr_ptr++;
  328. }
  329. return TRUE;
  330. } else {
  331. return FALSE;
  332. }
  333. }
  334. /* To identify format of non string format types */
  335. bool
  336. check_valid_non_string_format(char *curr_ptr)
  337. {
  338. char *next_ptr;
  339. char *next_fmt_stptr;
  340. char valid_fmt_types[17] = {'d', 'i', 'x', 'X', 'c', 'p', 'u',
  341. 'f', 'F', 'e', 'E', 'g', 'G', 'o',
  342. 'a', 'A', 'n'};
  343. int i;
  344. bool valid = FALSE;
  345. /* Check for next % in the fmt str */
  346. next_fmt_stptr = bcmstrstr(curr_ptr, "%");
  347. for (next_ptr = curr_ptr; *next_ptr != '\0'; next_ptr++) {
  348. for (i = 0; i < (int)((sizeof(valid_fmt_types))/sizeof(valid_fmt_types[0])); i++) {
  349. if (*next_ptr == valid_fmt_types[i]) {
  350. /* Check whether format type found corresponds to current %
  351. * and not the next one, if exists.
  352. */
  353. if ((next_fmt_stptr == NULL) ||
  354. (next_fmt_stptr && (next_ptr < next_fmt_stptr))) {
  355. /* Not validating for length/width fields in
  356. * format specifier.
  357. */
  358. valid = TRUE;
  359. }
  360. goto done;
  361. }
  362. }
  363. }
  364. done:
  365. return valid;
  366. }
  367. #define MAX_NO_OF_ARG 16
  368. #define FMTSTR_SIZE 200
  369. #define ROMSTR_SIZE 268
  370. #define SIZE_LOC_STR 50
  371. #define LOG_PRINT_CNT_MAX 16u
  372. #define EL_PARSE_VER "V02"
  373. #define EL_MSEC_PER_SEC 1000
  374. #ifdef DHD_LOG_PRINT_RATE_LIMIT
  375. #define MAX_LOG_PRINT_COUNT 100u
  376. #define LOG_PRINT_THRESH (1u * USEC_PER_SEC)
  377. #endif // endif
  378. bool
  379. dhd_dbg_process_event_log_hdr(event_log_hdr_t *log_hdr, prcd_event_log_hdr_t *prcd_log_hdr)
  380. {
  381. event_log_extended_hdr_t *ext_log_hdr;
  382. uint16 event_log_fmt_num;
  383. uint8 event_log_hdr_type;
  384. /* Identify the type of event tag, payload type etc.. */
  385. event_log_hdr_type = log_hdr->fmt_num & DHD_EVENT_LOG_HDR_MASK;
  386. event_log_fmt_num = (log_hdr->fmt_num >> DHD_EVENT_LOG_FMT_NUM_OFFSET) &
  387. DHD_EVENT_LOG_FMT_NUM_MASK;
  388. switch (event_log_hdr_type) {
  389. case DHD_OW_NB_EVENT_LOG_HDR:
  390. prcd_log_hdr->ext_event_log_hdr = FALSE;
  391. prcd_log_hdr->binary_payload = FALSE;
  392. break;
  393. case DHD_TW_NB_EVENT_LOG_HDR:
  394. prcd_log_hdr->ext_event_log_hdr = TRUE;
  395. prcd_log_hdr->binary_payload = FALSE;
  396. break;
  397. case DHD_BI_EVENT_LOG_HDR:
  398. if (event_log_fmt_num == DHD_OW_BI_EVENT_FMT_NUM) {
  399. prcd_log_hdr->ext_event_log_hdr = FALSE;
  400. prcd_log_hdr->binary_payload = TRUE;
  401. } else if (event_log_fmt_num == DHD_TW_BI_EVENT_FMT_NUM) {
  402. prcd_log_hdr->ext_event_log_hdr = TRUE;
  403. prcd_log_hdr->binary_payload = TRUE;
  404. } else {
  405. DHD_ERROR(("%s: invalid format number 0x%X\n",
  406. __FUNCTION__, event_log_fmt_num));
  407. return FALSE;
  408. }
  409. break;
  410. case DHD_INVALID_EVENT_LOG_HDR:
  411. default:
  412. DHD_ERROR(("%s: invalid event log header type 0x%X\n",
  413. __FUNCTION__, event_log_hdr_type));
  414. return FALSE;
  415. }
  416. /* Parse extended and legacy event log headers and populate prcd_event_log_hdr_t */
  417. if (prcd_log_hdr->ext_event_log_hdr) {
  418. ext_log_hdr = (event_log_extended_hdr_t *)
  419. ((uint8 *)log_hdr - sizeof(event_log_hdr_t));
  420. prcd_log_hdr->tag = ((ext_log_hdr->extended_tag &
  421. DHD_TW_VALID_TAG_BITS_MASK) << DHD_TW_EVENT_LOG_TAG_OFFSET) | log_hdr->tag;
  422. } else {
  423. prcd_log_hdr->tag = log_hdr->tag;
  424. }
  425. prcd_log_hdr->count = log_hdr->count;
  426. prcd_log_hdr->fmt_num_raw = log_hdr->fmt_num;
  427. prcd_log_hdr->fmt_num = event_log_fmt_num;
  428. /* update arm cycle */
  429. /*
  430. * For loegacy event tag :-
  431. * |payload........|Timestamp| Tag
  432. *
  433. * For extended event tag:-
  434. * |payload........|Timestamp|extended Tag| Tag.
  435. *
  436. */
  437. prcd_log_hdr->armcycle = prcd_log_hdr->ext_event_log_hdr ?
  438. *(uint32 *)(log_hdr - EVENT_TAG_TIMESTAMP_EXT_OFFSET) :
  439. *(uint32 *)(log_hdr - EVENT_TAG_TIMESTAMP_OFFSET);
  440. /* update event log data pointer address */
  441. prcd_log_hdr->log_ptr =
  442. (uint32 *)log_hdr - log_hdr->count - prcd_log_hdr->ext_event_log_hdr;
  443. /* handle error cases above this */
  444. return TRUE;
  445. }
  446. static void
  447. dhd_dbg_verboselog_handler(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr,
  448. void *raw_event_ptr, uint32 logset, uint16 block, uint32* data)
  449. {
  450. event_log_hdr_t *ts_hdr;
  451. uint32 *log_ptr = plog_hdr->log_ptr;
  452. char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 };
  453. uint32 rom_str_len = 0;
  454. uint32 *ts_data;
  455. if (!raw_event_ptr) {
  456. return;
  457. }
  458. if (log_ptr < data) {
  459. DHD_ERROR(("Invalid log pointer, logptr : %p data : %p \n", log_ptr, data));
  460. return;
  461. }
  462. BCM_REFERENCE(ts_hdr);
  463. BCM_REFERENCE(ts_data);
  464. if (log_ptr > data) {
  465. /* Get time stamp if it's updated */
  466. ts_hdr = (event_log_hdr_t *)((char *)log_ptr - sizeof(event_log_hdr_t));
  467. if (ts_hdr->tag == EVENT_LOG_TAG_TS) {
  468. ts_data = (uint32 *)ts_hdr - ts_hdr->count;
  469. if (ts_data >= data) {
  470. DHD_MSGTRACE_LOG(("EVENT_LOG_TS[0x%08x]: SYS:%08x CPU:%08x\n",
  471. ts_data[ts_hdr->count - 1], ts_data[0], ts_data[1]));
  472. }
  473. }
  474. }
  475. if (plog_hdr->tag == EVENT_LOG_TAG_ROM_PRINTF) {
  476. rom_str_len = (plog_hdr->count - 1) * sizeof(uint32);
  477. if (rom_str_len >= (ROMSTR_SIZE -1))
  478. rom_str_len = ROMSTR_SIZE - 1;
  479. /* copy all ascii data for ROM printf to local string */
  480. memcpy(fmtstr_loc_buf, log_ptr, rom_str_len);
  481. /* add end of line at last */
  482. fmtstr_loc_buf[rom_str_len] = '\0';
  483. DHD_MSGTRACE_LOG(("EVENT_LOG_ROM[0x%08x]: %s",
  484. log_ptr[plog_hdr->count - 1], fmtstr_loc_buf));
  485. /* Add newline if missing */
  486. if (fmtstr_loc_buf[strlen(fmtstr_loc_buf) - 1] != '\n')
  487. DHD_MSGTRACE_LOG(("\n"));
  488. return;
  489. }
  490. if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE ||
  491. plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE_TLV) {
  492. wl_mschdbg_verboselog_handler(dhdp, raw_event_ptr, plog_hdr, log_ptr);
  493. return;
  494. }
  495. /* print the message out in a logprint */
  496. dhd_dbg_verboselog_printf(dhdp, plog_hdr, raw_event_ptr, log_ptr, logset, block);
  497. }
  498. void
  499. dhd_dbg_verboselog_printf(dhd_pub_t *dhdp, prcd_event_log_hdr_t *plog_hdr,
  500. void *raw_event_ptr, uint32 *log_ptr, uint32 logset, uint16 block)
  501. {
  502. dhd_event_log_t *raw_event = (dhd_event_log_t *)raw_event_ptr;
  503. uint16 count;
  504. int log_level, id;
  505. char fmtstr_loc_buf[ROMSTR_SIZE] = { 0 };
  506. char (*str_buf)[SIZE_LOC_STR] = NULL;
  507. char *str_tmpptr = NULL;
  508. uint32 addr = 0;
  509. typedef union {
  510. uint32 val;
  511. char * addr;
  512. } u_arg;
  513. u_arg arg[MAX_NO_OF_ARG] = {{0}};
  514. char *c_ptr = NULL;
  515. struct bcmstrbuf b;
  516. #ifdef DHD_LOG_PRINT_RATE_LIMIT
  517. static int log_print_count = 0;
  518. static uint64 ts0 = 0;
  519. uint64 ts1 = 0;
  520. #endif /* DHD_LOG_PRINT_RATE_LIMIT */
  521. BCM_REFERENCE(arg);
  522. #ifdef DHD_LOG_PRINT_RATE_LIMIT
  523. if (!ts0)
  524. ts0 = OSL_SYSUPTIME_US();
  525. ts1 = OSL_SYSUPTIME_US();
  526. if (((ts1 - ts0) <= LOG_PRINT_THRESH) && (log_print_count >= MAX_LOG_PRINT_COUNT)) {
  527. log_print_threshold = 1;
  528. ts0 = 0;
  529. log_print_count = 0;
  530. DHD_ERROR(("%s: Log print water mark is reached,"
  531. " console logs are dumped only to debug_dump file\n", __FUNCTION__));
  532. } else if ((ts1 - ts0) > LOG_PRINT_THRESH) {
  533. log_print_threshold = 0;
  534. ts0 = 0;
  535. log_print_count = 0;
  536. }
  537. #endif /* DHD_LOG_PRINT_RATE_LIMIT */
  538. /* print the message out in a logprint. Logprint expects raw format number */
  539. if (!(raw_event->fmts)) {
  540. if (dhdp->dbg) {
  541. log_level = dhdp->dbg->dbg_rings[FW_VERBOSE_RING_ID].log_level;
  542. for (id = 0; id < ARRAYSIZE(fw_verbose_level_map); id++) {
  543. if ((fw_verbose_level_map[id].tag == plog_hdr->tag) &&
  544. (fw_verbose_level_map[id].log_level > log_level))
  545. return;
  546. }
  547. }
  548. if (plog_hdr->binary_payload) {
  549. DHD_ECNTR_LOG(("%06d.%03d EL:tag=%d len=%d fmt=0x%x",
  550. (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
  551. (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
  552. plog_hdr->tag,
  553. plog_hdr->count,
  554. plog_hdr->fmt_num_raw));
  555. for (count = 0; count < (plog_hdr->count - 1); count++) {
  556. if (count && (count % LOG_PRINT_CNT_MAX == 0)) {
  557. DHD_ECNTR_LOG(("\n\t%08x", log_ptr[count]));
  558. } else {
  559. DHD_ECNTR_LOG((" %08x", log_ptr[count]));
  560. }
  561. }
  562. DHD_ECNTR_LOG(("\n"));
  563. }
  564. else {
  565. bcm_binit(&b, fmtstr_loc_buf, FMTSTR_SIZE);
  566. #ifndef OEM_ANDROID
  567. bcm_bprintf(&b, "%06d.%03d EL: %d 0x%x",
  568. (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
  569. (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
  570. plog_hdr->tag,
  571. plog_hdr->fmt_num_raw);
  572. #else
  573. bcm_bprintf(&b, "%06d.%03d EL:%s:%u:%u %d %d 0x%x",
  574. (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
  575. (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
  576. EL_PARSE_VER, logset, block,
  577. plog_hdr->tag,
  578. plog_hdr->count,
  579. plog_hdr->fmt_num_raw);
  580. #endif /* !OEM_ANDROID */
  581. for (count = 0; count < (plog_hdr->count - 1); count++) {
  582. bcm_bprintf(&b, " %x", log_ptr[count]);
  583. }
  584. /* ensure preserve fw logs go to debug_dump only in case of customer4 */
  585. if (logset < dhdp->event_log_max_sets &&
  586. ((0x01u << logset) & dhdp->logset_prsrv_mask)) {
  587. DHD_PRSRV_MEM(("%s\n", b.origbuf));
  588. } else {
  589. DHD_FWLOG(("%s\n", b.origbuf));
  590. #ifdef DHD_LOG_PRINT_RATE_LIMIT
  591. log_print_count++;
  592. #endif /* DHD_LOG_PRINT_RATE_LIMIT */
  593. }
  594. }
  595. return;
  596. }
  597. str_buf = MALLOCZ(dhdp->osh, (MAX_NO_OF_ARG * SIZE_LOC_STR));
  598. if (!str_buf) {
  599. DHD_ERROR(("%s: malloc failed str_buf\n", __FUNCTION__));
  600. return;
  601. }
  602. if ((plog_hdr->fmt_num) < raw_event->num_fmts) {
  603. if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) {
  604. snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "%s",
  605. raw_event->fmts[plog_hdr->fmt_num]);
  606. plog_hdr->count++;
  607. } else {
  608. snprintf(fmtstr_loc_buf, FMTSTR_SIZE, "CONSOLE_E:%u:%u %06d.%03d %s",
  609. logset, block,
  610. (uint32)(log_ptr[plog_hdr->count - 1] / EL_MSEC_PER_SEC),
  611. (uint32)(log_ptr[plog_hdr->count - 1] % EL_MSEC_PER_SEC),
  612. raw_event->fmts[plog_hdr->fmt_num]);
  613. }
  614. c_ptr = fmtstr_loc_buf;
  615. } else {
  616. /* for ecounters, don't print the error as it will flood */
  617. if ((plog_hdr->fmt_num != DHD_OW_BI_EVENT_FMT_NUM) &&
  618. (plog_hdr->fmt_num != DHD_TW_BI_EVENT_FMT_NUM)) {
  619. DHD_ERROR(("%s: fmt number: 0x%x out of range\n",
  620. __FUNCTION__, plog_hdr->fmt_num));
  621. } else {
  622. DHD_INFO(("%s: fmt number: 0x%x out of range\n",
  623. __FUNCTION__, plog_hdr->fmt_num));
  624. }
  625. goto exit;
  626. }
  627. if (plog_hdr->count > MAX_NO_OF_ARG) {
  628. DHD_ERROR(("%s: plog_hdr->count(%d) out of range\n",
  629. __FUNCTION__, plog_hdr->count));
  630. goto exit;
  631. }
  632. /* print the format string which will be needed for debugging incorrect formats */
  633. DHD_INFO(("%s: fmtstr_loc_buf = %s\n", __FUNCTION__, fmtstr_loc_buf));
  634. /* Replace all %p to %x to handle 32 bit %p */
  635. replace_percent_p_to_x(fmtstr_loc_buf);
  636. for (count = 0; count < (plog_hdr->count - 1); count++) {
  637. if (c_ptr != NULL)
  638. if ((c_ptr = bcmstrstr(c_ptr, "%")) != NULL)
  639. c_ptr++;
  640. if (c_ptr != NULL) {
  641. if (check_valid_string_format(c_ptr)) {
  642. if ((raw_event->raw_sstr) &&
  643. ((log_ptr[count] > raw_event->rodata_start) &&
  644. (log_ptr[count] < raw_event->rodata_end))) {
  645. /* ram static string */
  646. addr = log_ptr[count] - raw_event->rodata_start;
  647. str_tmpptr = raw_event->raw_sstr + addr;
  648. memcpy(str_buf[count], str_tmpptr,
  649. SIZE_LOC_STR);
  650. str_buf[count][SIZE_LOC_STR-1] = '\0';
  651. arg[count].addr = str_buf[count];
  652. } else if ((raw_event->rom_raw_sstr) &&
  653. ((log_ptr[count] >
  654. raw_event->rom_rodata_start) &&
  655. (log_ptr[count] <
  656. raw_event->rom_rodata_end))) {
  657. /* rom static string */
  658. addr = log_ptr[count] - raw_event->rom_rodata_start;
  659. str_tmpptr = raw_event->rom_raw_sstr + addr;
  660. memcpy(str_buf[count], str_tmpptr,
  661. SIZE_LOC_STR);
  662. str_buf[count][SIZE_LOC_STR-1] = '\0';
  663. arg[count].addr = str_buf[count];
  664. } else {
  665. /*
  666. * Dynamic string OR
  667. * No data for static string.
  668. * So store all string's address as string.
  669. */
  670. snprintf(str_buf[count], SIZE_LOC_STR,
  671. "(s)0x%x", log_ptr[count]);
  672. arg[count].addr = str_buf[count];
  673. }
  674. } else if (check_valid_non_string_format(c_ptr)) {
  675. /* Other than string format */
  676. arg[count].val = log_ptr[count];
  677. } else {
  678. *(c_ptr - 1) = '\0';
  679. break;
  680. }
  681. }
  682. }
  683. /* ensure preserve fw logs go to debug_dump only in case of customer4 */
  684. if (logset < dhdp->event_log_max_sets &&
  685. ((0x01u << logset) & dhdp->logset_prsrv_mask)) {
  686. DHD_PRSRV_MEM((fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3],
  687. arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10],
  688. arg[11], arg[12], arg[13], arg[14], arg[15]));
  689. } else {
  690. DHD_FWLOG((fmtstr_loc_buf, arg[0], arg[1], arg[2], arg[3],
  691. arg[4], arg[5], arg[6], arg[7], arg[8], arg[9], arg[10],
  692. arg[11], arg[12], arg[13], arg[14], arg[15]));
  693. #ifdef DHD_LOG_PRINT_RATE_LIMIT
  694. log_print_count++;
  695. #endif /* DHD_LOG_PRINT_RATE_LIMIT */
  696. }
  697. exit:
  698. MFREE(dhdp->osh, str_buf, (MAX_NO_OF_ARG * SIZE_LOC_STR));
  699. }
  700. void
  701. dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp, void *event_data,
  702. void *raw_event_ptr, uint datalen, bool msgtrace_hdr_present,
  703. uint32 msgtrace_seqnum)
  704. {
  705. msgtrace_hdr_t *hdr;
  706. char *data, *tmpdata;
  707. const uint32 log_hdr_len = sizeof(event_log_hdr_t);
  708. uint32 log_pyld_len;
  709. static uint32 seqnum_prev = 0;
  710. event_log_hdr_t *log_hdr;
  711. bool msg_processed = FALSE;
  712. prcd_event_log_hdr_t prcd_log_hdr;
  713. prcd_event_log_hdr_t *plog_hdr;
  714. dll_t list_head, *cur;
  715. loglist_item_t *log_item;
  716. dhd_dbg_ring_entry_t msg_hdr;
  717. char *logbuf;
  718. struct tracelog_header *logentry_header;
  719. uint ring_data_len = 0;
  720. bool ecntr_pushed = FALSE;
  721. bool rtt_pushed = FALSE;
  722. bool dll_inited = FALSE;
  723. uint32 logset = 0;
  724. uint16 block = 0;
  725. bool event_log_max_sets_queried;
  726. uint32 event_log_max_sets;
  727. uint min_expected_len = 0;
  728. uint16 len_chk = 0;
  729. BCM_REFERENCE(ecntr_pushed);
  730. BCM_REFERENCE(rtt_pushed);
  731. BCM_REFERENCE(len_chk);
  732. /* store event_logset_queried and event_log_max_sets in local variables
  733. * to avoid race conditions as they were set from different contexts(preinit)
  734. */
  735. event_log_max_sets_queried = dhdp->event_log_max_sets_queried;
  736. /* Make sure queried is read first with wmb and then max_sets,
  737. * as it is done in reverse order during preinit ioctls.
  738. */
  739. OSL_SMP_WMB();
  740. event_log_max_sets = dhdp->event_log_max_sets;
  741. if (msgtrace_hdr_present)
  742. min_expected_len = (MSGTRACE_HDRLEN + EVENT_LOG_BLOCK_LEN);
  743. else
  744. min_expected_len = EVENT_LOG_BLOCK_LEN;
  745. /* log trace event consists of:
  746. * msgtrace header
  747. * event log block header
  748. * event log payload
  749. */
  750. if (!event_data || (datalen <= min_expected_len)) {
  751. DHD_ERROR(("%s: Not processing due to invalid event_data : %p or length : %d\n",
  752. __FUNCTION__, event_data, datalen));
  753. if (event_data && msgtrace_hdr_present) {
  754. prhex("event_data dump", event_data, datalen);
  755. tmpdata = (char *)event_data + MSGTRACE_HDRLEN;
  756. if (tmpdata) {
  757. DHD_ERROR(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
  758. ltoh16(*((uint16 *)(tmpdata+2))),
  759. ltoh32(*((uint32 *)(tmpdata + 4))),
  760. ltoh16(*((uint16 *)(tmpdata)))));
  761. }
  762. } else if (!event_data) {
  763. DHD_ERROR(("%s: event_data is NULL, cannot dump prhex\n", __FUNCTION__));
  764. }
  765. return;
  766. }
  767. if (msgtrace_hdr_present) {
  768. hdr = (msgtrace_hdr_t *)event_data;
  769. data = (char *)event_data + MSGTRACE_HDRLEN;
  770. datalen -= MSGTRACE_HDRLEN;
  771. msgtrace_seqnum = ntoh32(hdr->seqnum);
  772. } else {
  773. data = (char *)event_data;
  774. }
  775. if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, msgtrace_seqnum))
  776. return;
  777. /* Save the whole message to event log ring */
  778. memset(&msg_hdr, 0, sizeof(dhd_dbg_ring_entry_t));
  779. logbuf = VMALLOC(dhdp->osh, sizeof(*logentry_header) + datalen);
  780. if (logbuf == NULL)
  781. return;
  782. logentry_header = (struct tracelog_header *)logbuf;
  783. logentry_header->magic_num = TRACE_LOG_MAGIC_NUMBER;
  784. logentry_header->buf_size = datalen;
  785. logentry_header->seq_num = msgtrace_seqnum;
  786. msg_hdr.type = DBG_RING_ENTRY_DATA_TYPE;
  787. ring_data_len = datalen + sizeof(*logentry_header);
  788. if ((sizeof(*logentry_header) + datalen) > PAYLOAD_MAX_LEN) {
  789. DHD_ERROR(("%s:Payload len=%u exceeds max len\n", __FUNCTION__,
  790. ((uint)sizeof(*logentry_header) + datalen)));
  791. goto exit;
  792. }
  793. msg_hdr.len = sizeof(*logentry_header) + datalen;
  794. memcpy(logbuf + sizeof(*logentry_header), data, datalen);
  795. DHD_DBGIF(("%s: datalen %d %d\n", __FUNCTION__, msg_hdr.len, datalen));
  796. dhd_dbg_push_to_ring(dhdp, FW_VERBOSE_RING_ID, &msg_hdr, logbuf);
  797. /* Print sequence number, originating set and length of received
  798. * event log buffer. Refer to event log buffer structure in
  799. * event_log.h
  800. */
  801. DHD_MSGTRACE_LOG(("EVENT_LOG_HDR[0x%x]: Set: 0x%08x length = %d\n",
  802. ltoh16(*((uint16 *)(data+2))), ltoh32(*((uint32 *)(data + 4))),
  803. ltoh16(*((uint16 *)(data)))));
  804. logset = ltoh32(*((uint32 *)(data + 4)));
  805. if (logset >= event_log_max_sets) {
  806. DHD_ERROR(("%s logset: %d max: %d out of range queried: %d\n",
  807. __FUNCTION__, logset, event_log_max_sets, event_log_max_sets_queried));
  808. #ifdef DHD_FW_COREDUMP
  809. if (event_log_max_sets_queried) {
  810. DHD_ERROR(("%s: collect socram for DUMP_TYPE_LOGSET_BEYOND_RANGE\n",
  811. __FUNCTION__));
  812. dhdp->memdump_type = DUMP_TYPE_LOGSET_BEYOND_RANGE;
  813. dhd_bus_mem_dump(dhdp);
  814. }
  815. #endif /* DHD_FW_COREDUMP */
  816. }
  817. block = ltoh16(*((uint16 *)(data+2)));
  818. data += EVENT_LOG_BLOCK_HDRLEN;
  819. datalen -= EVENT_LOG_BLOCK_HDRLEN;
  820. /* start parsing from the tail of packet
  821. * Sameple format of a meessage
  822. * 001d3c54 00000064 00000064 001d3c54 001dba08 035d6ce1 0c540639
  823. * 001d3c54 00000064 00000064 035d6d89 0c580439
  824. * 0x0c580439 -- 39 is tag, 04 is count, 580c is format number
  825. * all these uint32 values comes in reverse order as group as EL data
  826. * while decoding we can only parse from last to first
  827. * |<- datalen ->|
  828. * |----(payload and maybe more logs)----|event_log_hdr_t|
  829. * data log_hdr
  830. */
  831. dll_init(&list_head);
  832. dll_inited = TRUE;
  833. while (datalen > log_hdr_len) {
  834. log_hdr = (event_log_hdr_t *)(data + datalen - log_hdr_len);
  835. memset(&prcd_log_hdr, 0, sizeof(prcd_log_hdr));
  836. if (!dhd_dbg_process_event_log_hdr(log_hdr, &prcd_log_hdr)) {
  837. DHD_ERROR(("%s: Error while parsing event log header\n",
  838. __FUNCTION__));
  839. }
  840. /* skip zero padding at end of frame */
  841. if (prcd_log_hdr.tag == EVENT_LOG_TAG_NULL) {
  842. datalen -= log_hdr_len;
  843. continue;
  844. }
  845. /* Check argument count (for non-ecounter events only),
  846. * any event log should contain at least
  847. * one argument (4 bytes) for arm cycle count and up to 16
  848. * arguments except EVENT_LOG_TAG_STATS which could use the
  849. * whole payload of 256 words
  850. */
  851. if (prcd_log_hdr.count == 0) {
  852. break;
  853. }
  854. /* Both tag_stats and proxd are binary payloads so skip
  855. * argument count check for these.
  856. */
  857. if ((prcd_log_hdr.tag != EVENT_LOG_TAG_STATS) &&
  858. (prcd_log_hdr.tag != EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
  859. (prcd_log_hdr.count > MAX_NO_OF_ARG)) {
  860. break;
  861. }
  862. log_pyld_len = (prcd_log_hdr.count + prcd_log_hdr.ext_event_log_hdr) *
  863. DATA_UNIT_FOR_LOG_CNT;
  864. /* log data should not cross the event data boundary */
  865. if ((uint32)((char *)log_hdr - data) < log_pyld_len) {
  866. break;
  867. }
  868. /* skip 4 bytes time stamp packet */
  869. if (prcd_log_hdr.tag == EVENT_LOG_TAG_TS) {
  870. datalen -= (log_pyld_len + log_hdr_len);
  871. continue;
  872. }
  873. if (!(log_item = MALLOC(dhdp->osh, sizeof(*log_item)))) {
  874. DHD_ERROR(("%s allocating log list item failed\n",
  875. __FUNCTION__));
  876. break;
  877. }
  878. log_item->prcd_log_hdr.tag = prcd_log_hdr.tag;
  879. log_item->prcd_log_hdr.count = prcd_log_hdr.count;
  880. log_item->prcd_log_hdr.fmt_num = prcd_log_hdr.fmt_num;
  881. log_item->prcd_log_hdr.fmt_num_raw = prcd_log_hdr.fmt_num_raw;
  882. log_item->prcd_log_hdr.armcycle = prcd_log_hdr.armcycle;
  883. log_item->prcd_log_hdr.log_ptr = prcd_log_hdr.log_ptr;
  884. log_item->prcd_log_hdr.payload_len = prcd_log_hdr.payload_len;
  885. log_item->prcd_log_hdr.ext_event_log_hdr = prcd_log_hdr.ext_event_log_hdr;
  886. log_item->prcd_log_hdr.binary_payload = prcd_log_hdr.binary_payload;
  887. dll_insert(&log_item->list, &list_head);
  888. datalen -= (log_pyld_len + log_hdr_len);
  889. }
  890. while (!dll_empty(&list_head)) {
  891. msg_processed = FALSE;
  892. cur = dll_head_p(&list_head);
  893. #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
  894. #pragma GCC diagnostic push
  895. #pragma GCC diagnostic ignored "-Wcast-qual"
  896. #endif // endif
  897. log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
  898. #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
  899. #pragma GCC diagnostic pop
  900. #endif // endif
  901. plog_hdr = &log_item->prcd_log_hdr;
  902. #if defined(EWP_ECNTRS_LOGGING) && defined(DHD_LOG_DUMP)
  903. /* Ecounter tag can be time_data or log_stats+binary paloaod */
  904. if ((plog_hdr->tag == EVENT_LOG_TAG_ECOUNTERS_TIME_DATA) ||
  905. ((plog_hdr->tag == EVENT_LOG_TAG_STATS) &&
  906. (plog_hdr->binary_payload))) {
  907. if (!ecntr_pushed && dhd_log_dump_ecntr_enabled()) {
  908. /*
  909. * check msg hdr len before pushing.
  910. * FW msg_hdr.len includes length of event log hdr,
  911. * logentry header and payload.
  912. */
  913. len_chk = (sizeof(*logentry_header) + sizeof(*log_hdr) +
  914. PAYLOAD_ECNTR_MAX_LEN);
  915. /* account extended event log header(extended_event_log_hdr) */
  916. if (plog_hdr->ext_event_log_hdr) {
  917. len_chk += sizeof(*log_hdr);
  918. }
  919. if (msg_hdr.len > len_chk) {
  920. DHD_ERROR(("%s: EVENT_LOG_VALIDATION_FAILS: "
  921. "msg_hdr.len=%u, max allowed for ecntrs=%u\n",
  922. __FUNCTION__, msg_hdr.len, len_chk));
  923. goto exit;
  924. }
  925. dhd_dbg_ring_push(dhdp->ecntr_dbg_ring, &msg_hdr, logbuf);
  926. ecntr_pushed = TRUE;
  927. }
  928. }
  929. #endif /* EWP_ECNTRS_LOGGING && DHD_LOG_DUMP */
  930. #if defined(EWP_RTT_LOGGING) && defined(DHD_LOG_DUMP)
  931. if ((plog_hdr->tag == EVENT_LOG_TAG_PROXD_SAMPLE_COLLECT) &&
  932. plog_hdr->binary_payload) {
  933. if (!rtt_pushed && dhd_log_dump_rtt_enabled()) {
  934. /*
  935. * check msg hdr len before pushing.
  936. * FW msg_hdr.len includes length of event log hdr,
  937. * logentry header and payload.
  938. */
  939. len_chk = (sizeof(*logentry_header) + sizeof(*log_hdr) +
  940. PAYLOAD_RTT_MAX_LEN);
  941. /* account extended event log header(extended_event_log_hdr) */
  942. if (plog_hdr->ext_event_log_hdr) {
  943. len_chk += sizeof(*log_hdr);
  944. }
  945. if (msg_hdr.len > len_chk) {
  946. DHD_ERROR(("%s: EVENT_LOG_VALIDATION_FAILS: "
  947. "msg_hdr.len=%u, max allowed for ecntrs=%u\n",
  948. __FUNCTION__, msg_hdr.len, len_chk));
  949. goto exit;
  950. }
  951. dhd_dbg_ring_push(dhdp->rtt_dbg_ring, &msg_hdr, logbuf);
  952. rtt_pushed = TRUE;
  953. }
  954. }
  955. #endif /* EWP_RTT_LOGGING && DHD_LOG_DUMP */
  956. #if defined(DHD_EVENT_LOG_FILTER)
  957. if (plog_hdr->tag == EVENT_LOG_TAG_STATS) {
  958. dhd_event_log_filter_event_handler(dhdp, plog_hdr, plog_hdr->log_ptr);
  959. }
  960. #endif /* DHD_EVENT_LOG_FILTER */
  961. if (!msg_processed) {
  962. dhd_dbg_verboselog_handler(dhdp, plog_hdr, raw_event_ptr,
  963. logset, block, (uint32 *)data);
  964. }
  965. dll_delete(cur);
  966. MFREE(dhdp->osh, log_item, sizeof(*log_item));
  967. }
  968. BCM_REFERENCE(log_hdr);
  969. exit:
  970. while (dll_inited && (!dll_empty(&list_head))) {
  971. cur = dll_head_p(&list_head);
  972. #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
  973. #pragma GCC diagnostic push
  974. #pragma GCC diagnostic ignored "-Wcast-qual"
  975. #endif // endif
  976. log_item = (loglist_item_t *)container_of(cur, loglist_item_t, list);
  977. #if defined(STRICT_GCC_WARNINGS) && defined(__GNUC__)
  978. #pragma GCC diagnostic pop
  979. #endif // endif
  980. dll_delete(cur);
  981. MFREE(dhdp->osh, log_item, sizeof(*log_item));
  982. }
  983. VMFREE(dhdp->osh, logbuf, ring_data_len);
  984. }
  985. #else /* !SHOW_LOGTRACE */
  986. static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp,
  987. prcd_event_log_hdr_t *plog_hdr, void *raw_event_ptr, uint32 logset, uint16 block,
  988. uint32 *data) {};
  989. INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp,
  990. void *event_data, void *raw_event_ptr, uint datalen,
  991. bool msgtrace_hdr_present, uint32 msgtrace_seqnum) {};
  992. #endif /* SHOW_LOGTRACE */
  993. #ifndef MACOSX_DHD
  994. void
  995. dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
  996. void *raw_event_ptr, uint datalen)
  997. {
  998. msgtrace_hdr_t *hdr;
  999. hdr = (msgtrace_hdr_t *)event_data;
  1000. if (hdr->version != MSGTRACE_VERSION) {
  1001. DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n",
  1002. __FUNCTION__, MSGTRACE_VERSION, hdr->version));
  1003. return;
  1004. }
  1005. if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG)
  1006. dhd_dbg_msgtrace_msg_parser(event_data);
  1007. else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG)
  1008. dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen,
  1009. TRUE, 0);
  1010. }
  1011. #endif /* MACOSX_DHD */
  1012. /*
  1013. * dhd_dbg_set_event_log_tag : modify the state of an event log tag
  1014. */
  1015. void
  1016. dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set)
  1017. {
  1018. wl_el_tag_params_t pars;
  1019. char *cmd = "event_log_tag_control";
  1020. char iovbuf[WLC_IOCTL_SMLEN] = { 0 };
  1021. int ret;
  1022. memset(&pars, 0, sizeof(pars));
  1023. pars.tag = tag;
  1024. pars.set = set;
  1025. pars.flags = EVENT_LOG_TAG_FLAG_LOG;
  1026. if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) {
  1027. DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__));
  1028. return;
  1029. }
  1030. ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
  1031. if (ret) {
  1032. DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret));
  1033. }
  1034. }
  1035. int
  1036. dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags, uint32 threshold)
  1037. {
  1038. dhd_dbg_ring_t *ring;
  1039. uint8 set = 1;
  1040. int i, array_len = 0;
  1041. struct log_level_table *log_level_tbl = NULL;
  1042. if (!dhdp || !dhdp->dbg)
  1043. return BCME_BADADDR;
  1044. if (!VALID_RING(ring_id)) {
  1045. DHD_ERROR(("%s : invalid ring_id : %d\n", __FUNCTION__, ring_id));
  1046. return BCME_RANGE;
  1047. }
  1048. ring = &dhdp->dbg->dbg_rings[ring_id];
  1049. dhd_dbg_ring_config(ring, log_level, threshold);
  1050. if (log_level > 0)
  1051. set = TRUE;
  1052. if (ring->id == FW_VERBOSE_RING_ID) {
  1053. log_level_tbl = fw_verbose_level_map;
  1054. array_len = ARRAYSIZE(fw_verbose_level_map);
  1055. }
  1056. for (i = 0; i < array_len; i++) {
  1057. if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) {
  1058. /* clear the reference per ring */
  1059. ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id);
  1060. } else {
  1061. /* set the reference per ring */
  1062. ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id);
  1063. }
  1064. set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0;
  1065. DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__,
  1066. log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name));
  1067. dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set);
  1068. }
  1069. return BCME_OK;
  1070. }
  1071. int
  1072. __dhd_dbg_get_ring_status(dhd_dbg_ring_t *ring, dhd_dbg_ring_status_t *get_ring_status)
  1073. {
  1074. dhd_dbg_ring_status_t ring_status;
  1075. int ret = BCME_OK;
  1076. if (ring == NULL) {
  1077. return BCME_BADADDR;
  1078. }
  1079. bzero(&ring_status, sizeof(dhd_dbg_ring_status_t));
  1080. RING_STAT_TO_STATUS(ring, ring_status);
  1081. *get_ring_status = ring_status;
  1082. return ret;
  1083. }
  1084. /*
  1085. * dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer
  1086. * Return: An error code or 0 on success.
  1087. */
  1088. int
  1089. dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status)
  1090. {
  1091. int ret = BCME_OK;
  1092. int id = 0;
  1093. dhd_dbg_t *dbg;
  1094. dhd_dbg_ring_t *dbg_ring;
  1095. if (!dhdp || !dhdp->dbg)
  1096. return BCME_BADADDR;
  1097. dbg = dhdp->dbg;
  1098. for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
  1099. dbg_ring = &dbg->dbg_rings[id];
  1100. if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) {
  1101. __dhd_dbg_get_ring_status(dbg_ring, dbg_ring_status);
  1102. break;
  1103. }
  1104. }
  1105. if (!VALID_RING(id)) {
  1106. DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id));
  1107. ret = BCME_NOTFOUND;
  1108. }
  1109. return ret;
  1110. }
  1111. #ifdef SHOW_LOGTRACE
  1112. void
  1113. dhd_dbg_read_ring_into_trace_buf(dhd_dbg_ring_t *ring, trace_buf_info_t *trace_buf_info)
  1114. {
  1115. dhd_dbg_ring_status_t ring_status;
  1116. uint32 rlen = 0;
  1117. rlen = dhd_dbg_ring_pull_single(ring, trace_buf_info->buf, TRACE_LOG_BUF_MAX_SIZE, TRUE);
  1118. trace_buf_info->size = rlen;
  1119. trace_buf_info->availability = NEXT_BUF_NOT_AVAIL;
  1120. if (rlen == 0) {
  1121. trace_buf_info->availability = BUF_NOT_AVAILABLE;
  1122. return;
  1123. }
  1124. __dhd_dbg_get_ring_status(ring, &ring_status);
  1125. if (ring_status.written_bytes != ring_status.read_bytes) {
  1126. trace_buf_info->availability = NEXT_BUF_AVAIL;
  1127. }
  1128. }
  1129. #endif /* SHOW_LOGTRACE */
  1130. /*
  1131. * dhd_dbg_find_ring_id : return ring_id based on ring_name
  1132. * Return: An invalid ring id for failure or valid ring id on success.
  1133. */
  1134. int
  1135. dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name)
  1136. {
  1137. int id;
  1138. dhd_dbg_t *dbg;
  1139. dhd_dbg_ring_t *ring;
  1140. if (!dhdp || !dhdp->dbg)
  1141. return BCME_BADADDR;
  1142. dbg = dhdp->dbg;
  1143. for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
  1144. ring = &dbg->dbg_rings[id];
  1145. if (!strncmp((char *)ring->name, ring_name, sizeof(ring->name) - 1))
  1146. break;
  1147. }
  1148. return id;
  1149. }
  1150. /*
  1151. * dhd_dbg_get_priv : get the private data of dhd dbugability module
  1152. * Return : An NULL on failure or valid data address
  1153. */
  1154. void *
  1155. dhd_dbg_get_priv(dhd_pub_t *dhdp)
  1156. {
  1157. if (!dhdp || !dhdp->dbg)
  1158. return NULL;
  1159. return dhdp->dbg->private;
  1160. }
  1161. /*
  1162. * dhd_dbg_start : start and stop All of Ring buffers
  1163. * Return: An error code or 0 on success.
  1164. */
  1165. int
  1166. dhd_dbg_start(dhd_pub_t *dhdp, bool start)
  1167. {
  1168. int ret = BCME_OK;
  1169. int ring_id;
  1170. dhd_dbg_t *dbg;
  1171. dhd_dbg_ring_t *dbg_ring;
  1172. if (!dhdp)
  1173. return BCME_BADARG;
  1174. dbg = dhdp->dbg;
  1175. for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
  1176. dbg_ring = &dbg->dbg_rings[ring_id];
  1177. if (!start) {
  1178. if (VALID_RING(dbg_ring->id)) {
  1179. dhd_dbg_ring_start(dbg_ring);
  1180. }
  1181. }
  1182. }
  1183. return ret;
  1184. }
  1185. /*
  1186. * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer
  1187. *
  1188. * Return: An error code or 0 on success.
  1189. */
  1190. int
  1191. dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len)
  1192. {
  1193. dhd_dbg_t *dbg;
  1194. int ret = BCME_OK;
  1195. if (!dhdp || !dhdp->dbg)
  1196. return BCME_BADADDR;
  1197. dbg = dhdp->dbg;
  1198. if (dbg->urgent_notifier) {
  1199. dbg->urgent_notifier(dhdp, data, len);
  1200. }
  1201. return ret;
  1202. }
  1203. #if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING)
  1204. uint32
  1205. __dhd_dbg_pkt_hash(uintptr_t pkt, uint32 pktid)
  1206. {
  1207. uint32 __pkt;
  1208. uint32 __pktid;
  1209. __pkt = ((int)pkt) >= 0 ? (2 * pkt) : (-2 * pkt - 1);
  1210. __pktid = ((int)pktid) >= 0 ? (2 * pktid) : (-2 * pktid - 1);
  1211. return (__pkt >= __pktid ? (__pkt * __pkt + __pkt + __pktid) :
  1212. (__pkt + __pktid * __pktid));
  1213. }
  1214. #define __TIMESPEC_TO_US(ts) \
  1215. (((uint32)(ts).tv_sec * USEC_PER_SEC) + ((ts).tv_nsec / NSEC_PER_USEC))
  1216. uint32
  1217. __dhd_dbg_driver_ts_usec(void)
  1218. {
  1219. struct timespec ts;
  1220. get_monotonic_boottime(&ts);
  1221. return ((uint32)(__TIMESPEC_TO_US(ts)));
  1222. }
  1223. wifi_tx_packet_fate
  1224. __dhd_dbg_map_tx_status_to_pkt_fate(uint16 status)
  1225. {
  1226. wifi_tx_packet_fate pkt_fate;
  1227. switch (status) {
  1228. case WLFC_CTL_PKTFLAG_DISCARD:
  1229. pkt_fate = TX_PKT_FATE_ACKED;
  1230. break;
  1231. case WLFC_CTL_PKTFLAG_D11SUPPRESS:
  1232. /* intensional fall through */
  1233. case WLFC_CTL_PKTFLAG_WLSUPPRESS:
  1234. pkt_fate = TX_PKT_FATE_FW_QUEUED;
  1235. break;
  1236. case WLFC_CTL_PKTFLAG_TOSSED_BYWLC:
  1237. pkt_fate = TX_PKT_FATE_FW_DROP_INVALID;
  1238. break;
  1239. case WLFC_CTL_PKTFLAG_DISCARD_NOACK:
  1240. pkt_fate = TX_PKT_FATE_SENT;
  1241. break;
  1242. case WLFC_CTL_PKTFLAG_EXPIRED:
  1243. pkt_fate = TX_PKT_FATE_FW_DROP_EXPTIME;
  1244. break;
  1245. case WLFC_CTL_PKTFLAG_MKTFREE:
  1246. pkt_fate = TX_PKT_FATE_FW_PKT_FREE;
  1247. break;
  1248. default:
  1249. pkt_fate = TX_PKT_FATE_FW_DROP_OTHER;
  1250. break;
  1251. }
  1252. return pkt_fate;
  1253. }
  1254. #endif /* DBG_PKT_MON || DHD_PKT_LOGGING */
  1255. #ifdef DBG_PKT_MON
  1256. static int
  1257. __dhd_dbg_free_tx_pkts(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkts,
  1258. uint16 pkt_count)
  1259. {
  1260. uint16 count;
  1261. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1262. count = 0;
  1263. while ((count < pkt_count) && tx_pkts) {
  1264. if (tx_pkts->info.pkt) {
  1265. PKTFREE(dhdp->osh, tx_pkts->info.pkt, TRUE);
  1266. }
  1267. tx_pkts++;
  1268. count++;
  1269. }
  1270. return BCME_OK;
  1271. }
  1272. static int
  1273. __dhd_dbg_free_rx_pkts(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkts,
  1274. uint16 pkt_count)
  1275. {
  1276. uint16 count;
  1277. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1278. count = 0;
  1279. while ((count < pkt_count) && rx_pkts) {
  1280. if (rx_pkts->info.pkt) {
  1281. PKTFREE(dhdp->osh, rx_pkts->info.pkt, TRUE);
  1282. }
  1283. rx_pkts++;
  1284. count++;
  1285. }
  1286. return BCME_OK;
  1287. }
  1288. void
  1289. __dhd_dbg_dump_pkt_info(dhd_pub_t *dhdp, dhd_dbg_pkt_info_t *info)
  1290. {
  1291. if (DHD_PKT_MON_DUMP_ON()) {
  1292. DHD_PKT_MON(("payload type = %d\n", info->payload_type));
  1293. DHD_PKT_MON(("driver ts = %u\n", info->driver_ts));
  1294. DHD_PKT_MON(("firmware ts = %u\n", info->firmware_ts));
  1295. DHD_PKT_MON(("packet hash = %u\n", info->pkt_hash));
  1296. DHD_PKT_MON(("packet length = %zu\n", info->pkt_len));
  1297. DHD_PKT_MON(("packet address = %p\n", info->pkt));
  1298. DHD_PKT_MON(("packet data = \n"));
  1299. if (DHD_PKT_MON_ON()) {
  1300. prhex(NULL, PKTDATA(dhdp->osh, info->pkt), info->pkt_len);
  1301. }
  1302. }
  1303. }
  1304. void
  1305. __dhd_dbg_dump_tx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_tx_info_t *tx_pkt,
  1306. uint16 count)
  1307. {
  1308. if (DHD_PKT_MON_DUMP_ON()) {
  1309. DHD_PKT_MON(("\nTX (count: %d)\n", ++count));
  1310. DHD_PKT_MON(("packet fate = %d\n", tx_pkt->fate));
  1311. __dhd_dbg_dump_pkt_info(dhdp, &tx_pkt->info);
  1312. }
  1313. }
  1314. void
  1315. __dhd_dbg_dump_rx_pkt_info(dhd_pub_t *dhdp, dhd_dbg_rx_info_t *rx_pkt,
  1316. uint16 count)
  1317. {
  1318. if (DHD_PKT_MON_DUMP_ON()) {
  1319. DHD_PKT_MON(("\nRX (count: %d)\n", ++count));
  1320. DHD_PKT_MON(("packet fate = %d\n", rx_pkt->fate));
  1321. __dhd_dbg_dump_pkt_info(dhdp, &rx_pkt->info);
  1322. }
  1323. }
  1324. int
  1325. dhd_dbg_attach_pkt_monitor(dhd_pub_t *dhdp,
  1326. dbg_mon_tx_pkts_t tx_pkt_mon,
  1327. dbg_mon_tx_status_t tx_status_mon,
  1328. dbg_mon_rx_pkts_t rx_pkt_mon)
  1329. {
  1330. dhd_dbg_tx_report_t *tx_report = NULL;
  1331. dhd_dbg_rx_report_t *rx_report = NULL;
  1332. dhd_dbg_tx_info_t *tx_pkts = NULL;
  1333. dhd_dbg_rx_info_t *rx_pkts = NULL;
  1334. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1335. dhd_dbg_pkt_mon_state_t tx_status_state;
  1336. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1337. uint32 alloc_len;
  1338. int ret = BCME_OK;
  1339. unsigned long flags;
  1340. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1341. if (!dhdp || !dhdp->dbg) {
  1342. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1343. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1344. return -EINVAL;
  1345. }
  1346. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1347. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1348. tx_status_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1349. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1350. if (PKT_MON_ATTACHED(tx_pkt_state) || PKT_MON_ATTACHED(tx_status_state) ||
  1351. PKT_MON_ATTACHED(rx_pkt_state)) {
  1352. DHD_PKT_MON(("%s(): packet monitor is already attached, "
  1353. "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
  1354. __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
  1355. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1356. /* return success as the intention was to initialize packet monitor */
  1357. return BCME_OK;
  1358. }
  1359. /* allocate and initialize tx packet monitoring */
  1360. alloc_len = sizeof(*tx_report);
  1361. tx_report = (dhd_dbg_tx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
  1362. if (unlikely(!tx_report)) {
  1363. DHD_ERROR(("%s(): could not allocate memory for - "
  1364. "dhd_dbg_tx_report_t\n", __FUNCTION__));
  1365. ret = -ENOMEM;
  1366. goto fail;
  1367. }
  1368. alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
  1369. tx_pkts = (dhd_dbg_tx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
  1370. if (unlikely(!tx_pkts)) {
  1371. DHD_ERROR(("%s(): could not allocate memory for - "
  1372. "dhd_dbg_tx_info_t\n", __FUNCTION__));
  1373. ret = -ENOMEM;
  1374. goto fail;
  1375. }
  1376. dhdp->dbg->pkt_mon.tx_report = tx_report;
  1377. dhdp->dbg->pkt_mon.tx_report->tx_pkts = tx_pkts;
  1378. dhdp->dbg->pkt_mon.tx_pkt_mon = tx_pkt_mon;
  1379. dhdp->dbg->pkt_mon.tx_status_mon = tx_status_mon;
  1380. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_ATTACHED;
  1381. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_ATTACHED;
  1382. /* allocate and initialze rx packet monitoring */
  1383. alloc_len = sizeof(*rx_report);
  1384. rx_report = (dhd_dbg_rx_report_t *)MALLOCZ(dhdp->osh, alloc_len);
  1385. if (unlikely(!rx_report)) {
  1386. DHD_ERROR(("%s(): could not allocate memory for - "
  1387. "dhd_dbg_rx_report_t\n", __FUNCTION__));
  1388. ret = -ENOMEM;
  1389. goto fail;
  1390. }
  1391. alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
  1392. rx_pkts = (dhd_dbg_rx_info_t *)MALLOCZ(dhdp->osh, alloc_len);
  1393. if (unlikely(!rx_pkts)) {
  1394. DHD_ERROR(("%s(): could not allocate memory for - "
  1395. "dhd_dbg_rx_info_t\n", __FUNCTION__));
  1396. ret = -ENOMEM;
  1397. goto fail;
  1398. }
  1399. dhdp->dbg->pkt_mon.rx_report = rx_report;
  1400. dhdp->dbg->pkt_mon.rx_report->rx_pkts = rx_pkts;
  1401. dhdp->dbg->pkt_mon.rx_pkt_mon = rx_pkt_mon;
  1402. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_ATTACHED;
  1403. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1404. DHD_PKT_MON(("%s(): packet monitor attach succeeded\n", __FUNCTION__));
  1405. return ret;
  1406. fail:
  1407. /* tx packet monitoring */
  1408. if (tx_pkts) {
  1409. alloc_len = (sizeof(*tx_pkts) * MAX_FATE_LOG_LEN);
  1410. MFREE(dhdp->osh, tx_pkts, alloc_len);
  1411. }
  1412. if (tx_report) {
  1413. alloc_len = sizeof(*tx_report);
  1414. MFREE(dhdp->osh, tx_report, alloc_len);
  1415. }
  1416. dhdp->dbg->pkt_mon.tx_report = NULL;
  1417. dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
  1418. dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
  1419. dhdp->dbg->pkt_mon.tx_status_mon = NULL;
  1420. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
  1421. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
  1422. /* rx packet monitoring */
  1423. if (rx_pkts) {
  1424. alloc_len = (sizeof(*rx_pkts) * MAX_FATE_LOG_LEN);
  1425. MFREE(dhdp->osh, rx_pkts, alloc_len);
  1426. }
  1427. if (rx_report) {
  1428. alloc_len = sizeof(*rx_report);
  1429. MFREE(dhdp->osh, rx_report, alloc_len);
  1430. }
  1431. dhdp->dbg->pkt_mon.rx_report = NULL;
  1432. dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
  1433. dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
  1434. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
  1435. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1436. DHD_ERROR(("%s(): packet monitor attach failed\n", __FUNCTION__));
  1437. return ret;
  1438. }
  1439. int
  1440. dhd_dbg_start_pkt_monitor(dhd_pub_t *dhdp)
  1441. {
  1442. dhd_dbg_tx_report_t *tx_report;
  1443. dhd_dbg_rx_report_t *rx_report;
  1444. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1445. dhd_dbg_pkt_mon_state_t tx_status_state;
  1446. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1447. unsigned long flags;
  1448. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1449. if (!dhdp || !dhdp->dbg) {
  1450. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1451. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1452. return -EINVAL;
  1453. }
  1454. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1455. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1456. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1457. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1458. if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
  1459. PKT_MON_DETACHED(rx_pkt_state)) {
  1460. DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
  1461. "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
  1462. __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
  1463. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1464. return -EINVAL;
  1465. }
  1466. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTING;
  1467. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTING;
  1468. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTING;
  1469. tx_report = dhdp->dbg->pkt_mon.tx_report;
  1470. rx_report = dhdp->dbg->pkt_mon.rx_report;
  1471. if (!tx_report || !rx_report) {
  1472. DHD_PKT_MON(("%s(): tx_report=%p, rx_report=%p\n",
  1473. __FUNCTION__, tx_report, rx_report));
  1474. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1475. return -EINVAL;
  1476. }
  1477. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1478. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1479. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1480. /* Safe to free packets as state pkt_state is STARTING */
  1481. __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts, tx_report->pkt_pos);
  1482. __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts, rx_report->pkt_pos);
  1483. /* reset array postion */
  1484. tx_report->pkt_pos = 0;
  1485. tx_report->status_pos = 0;
  1486. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STARTED;
  1487. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STARTED;
  1488. rx_report->pkt_pos = 0;
  1489. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STARTED;
  1490. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1491. DHD_PKT_MON(("%s(): packet monitor started\n", __FUNCTION__));
  1492. return BCME_OK;
  1493. }
  1494. int
  1495. dhd_dbg_monitor_tx_pkts(dhd_pub_t *dhdp, void *pkt, uint32 pktid)
  1496. {
  1497. dhd_dbg_tx_report_t *tx_report;
  1498. dhd_dbg_tx_info_t *tx_pkts;
  1499. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1500. uint32 pkt_hash, driver_ts;
  1501. uint16 pkt_pos;
  1502. unsigned long flags;
  1503. if (!dhdp || !dhdp->dbg) {
  1504. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1505. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1506. return -EINVAL;
  1507. }
  1508. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1509. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1510. if (PKT_MON_STARTED(tx_pkt_state)) {
  1511. tx_report = dhdp->dbg->pkt_mon.tx_report;
  1512. pkt_pos = tx_report->pkt_pos;
  1513. if (!PKT_MON_PKT_FULL(pkt_pos)) {
  1514. tx_pkts = tx_report->tx_pkts;
  1515. pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
  1516. driver_ts = __dhd_dbg_driver_ts_usec();
  1517. tx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
  1518. tx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
  1519. tx_pkts[pkt_pos].info.pkt_hash = pkt_hash;
  1520. tx_pkts[pkt_pos].info.driver_ts = driver_ts;
  1521. tx_pkts[pkt_pos].info.firmware_ts = 0U;
  1522. tx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
  1523. tx_pkts[pkt_pos].fate = TX_PKT_FATE_DRV_QUEUED;
  1524. tx_report->pkt_pos++;
  1525. } else {
  1526. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
  1527. DHD_PKT_MON(("%s(): tx pkt logging stopped, reached "
  1528. "max limit\n", __FUNCTION__));
  1529. }
  1530. }
  1531. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1532. return BCME_OK;
  1533. }
  1534. int
  1535. dhd_dbg_monitor_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
  1536. uint16 status)
  1537. {
  1538. dhd_dbg_tx_report_t *tx_report;
  1539. dhd_dbg_tx_info_t *tx_pkt;
  1540. dhd_dbg_pkt_mon_state_t tx_status_state;
  1541. wifi_tx_packet_fate pkt_fate;
  1542. uint32 pkt_hash, temp_hash;
  1543. uint16 pkt_pos, status_pos;
  1544. int16 count;
  1545. bool found = FALSE;
  1546. unsigned long flags;
  1547. if (!dhdp || !dhdp->dbg) {
  1548. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1549. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1550. return -EINVAL;
  1551. }
  1552. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1553. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1554. if (PKT_MON_STARTED(tx_status_state)) {
  1555. tx_report = dhdp->dbg->pkt_mon.tx_report;
  1556. pkt_pos = tx_report->pkt_pos;
  1557. status_pos = tx_report->status_pos;
  1558. if (!PKT_MON_STATUS_FULL(pkt_pos, status_pos)) {
  1559. pkt_hash = __dhd_dbg_pkt_hash((uintptr_t)pkt, pktid);
  1560. pkt_fate = __dhd_dbg_map_tx_status_to_pkt_fate(status);
  1561. /* best bet (in-order tx completion) */
  1562. count = status_pos;
  1563. tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + status_pos);
  1564. while ((count < pkt_pos) && tx_pkt) {
  1565. temp_hash = tx_pkt->info.pkt_hash;
  1566. if (temp_hash == pkt_hash) {
  1567. tx_pkt->fate = pkt_fate;
  1568. tx_report->status_pos++;
  1569. found = TRUE;
  1570. break;
  1571. }
  1572. tx_pkt++;
  1573. count++;
  1574. }
  1575. /* search until beginning (handles out-of-order completion) */
  1576. if (!found) {
  1577. count = status_pos - 1;
  1578. tx_pkt = (((dhd_dbg_tx_info_t *)tx_report->tx_pkts) + count);
  1579. while ((count >= 0) && tx_pkt) {
  1580. temp_hash = tx_pkt->info.pkt_hash;
  1581. if (temp_hash == pkt_hash) {
  1582. tx_pkt->fate = pkt_fate;
  1583. tx_report->status_pos++;
  1584. found = TRUE;
  1585. break;
  1586. }
  1587. tx_pkt--;
  1588. count--;
  1589. }
  1590. if (!found) {
  1591. /* still couldn't match tx_status */
  1592. DHD_ERROR(("%s(): couldn't match tx_status, pkt_pos=%u, "
  1593. "status_pos=%u, pkt_fate=%u\n", __FUNCTION__,
  1594. pkt_pos, status_pos, pkt_fate));
  1595. }
  1596. }
  1597. } else {
  1598. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
  1599. DHD_PKT_MON(("%s(): tx_status logging stopped, reached "
  1600. "max limit\n", __FUNCTION__));
  1601. }
  1602. }
  1603. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1604. return BCME_OK;
  1605. }
  1606. int
  1607. dhd_dbg_monitor_rx_pkts(dhd_pub_t *dhdp, void *pkt)
  1608. {
  1609. dhd_dbg_rx_report_t *rx_report;
  1610. dhd_dbg_rx_info_t *rx_pkts;
  1611. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1612. uint32 driver_ts;
  1613. uint16 pkt_pos;
  1614. unsigned long flags;
  1615. if (!dhdp || !dhdp->dbg) {
  1616. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1617. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1618. return -EINVAL;
  1619. }
  1620. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1621. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1622. if (PKT_MON_STARTED(rx_pkt_state)) {
  1623. rx_report = dhdp->dbg->pkt_mon.rx_report;
  1624. pkt_pos = rx_report->pkt_pos;
  1625. if (!PKT_MON_PKT_FULL(pkt_pos)) {
  1626. rx_pkts = rx_report->rx_pkts;
  1627. driver_ts = __dhd_dbg_driver_ts_usec();
  1628. rx_pkts[pkt_pos].info.pkt = PKTDUP(dhdp->osh, pkt);
  1629. rx_pkts[pkt_pos].info.pkt_len = PKTLEN(dhdp->osh, pkt);
  1630. rx_pkts[pkt_pos].info.pkt_hash = 0U;
  1631. rx_pkts[pkt_pos].info.driver_ts = driver_ts;
  1632. rx_pkts[pkt_pos].info.firmware_ts = 0U;
  1633. rx_pkts[pkt_pos].info.payload_type = FRAME_TYPE_ETHERNET_II;
  1634. rx_pkts[pkt_pos].fate = RX_PKT_FATE_SUCCESS;
  1635. rx_report->pkt_pos++;
  1636. } else {
  1637. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
  1638. DHD_PKT_MON(("%s(): rx pkt logging stopped, reached "
  1639. "max limit\n", __FUNCTION__));
  1640. }
  1641. }
  1642. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1643. return BCME_OK;
  1644. }
  1645. int
  1646. dhd_dbg_stop_pkt_monitor(dhd_pub_t *dhdp)
  1647. {
  1648. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1649. dhd_dbg_pkt_mon_state_t tx_status_state;
  1650. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1651. unsigned long flags;
  1652. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1653. if (!dhdp || !dhdp->dbg) {
  1654. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1655. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1656. return -EINVAL;
  1657. }
  1658. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1659. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1660. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1661. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1662. if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
  1663. PKT_MON_DETACHED(rx_pkt_state)) {
  1664. DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
  1665. "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
  1666. __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
  1667. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1668. return -EINVAL;
  1669. }
  1670. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_STOPPED;
  1671. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_STOPPED;
  1672. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_STOPPED;
  1673. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1674. DHD_PKT_MON(("%s(): packet monitor stopped\n", __FUNCTION__));
  1675. return BCME_OK;
  1676. }
  1677. #define __COPY_TO_USER(to, from, n) \
  1678. do { \
  1679. int __ret; \
  1680. __ret = copy_to_user((void __user *)(to), (void *)(from), \
  1681. (unsigned long)(n)); \
  1682. if (unlikely(__ret)) { \
  1683. DHD_ERROR(("%s():%d: copy_to_user failed, ret=%d\n", \
  1684. __FUNCTION__, __LINE__, __ret)); \
  1685. return __ret; \
  1686. } \
  1687. } while (0);
  1688. int
  1689. dhd_dbg_monitor_get_tx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
  1690. uint16 req_count, uint16 *resp_count)
  1691. {
  1692. dhd_dbg_tx_report_t *tx_report;
  1693. dhd_dbg_tx_info_t *tx_pkt;
  1694. wifi_tx_report_t *ptr;
  1695. compat_wifi_tx_report_t *cptr;
  1696. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1697. dhd_dbg_pkt_mon_state_t tx_status_state;
  1698. uint16 pkt_count, count;
  1699. unsigned long flags;
  1700. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1701. BCM_REFERENCE(ptr);
  1702. BCM_REFERENCE(cptr);
  1703. if (!dhdp || !dhdp->dbg) {
  1704. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1705. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1706. return -EINVAL;
  1707. }
  1708. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1709. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1710. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1711. if (PKT_MON_NOT_OPERATIONAL(tx_pkt_state) ||
  1712. PKT_MON_NOT_OPERATIONAL(tx_status_state)) {
  1713. DHD_PKT_MON(("%s(): packet monitor is not yet enabled, "
  1714. "tx_pkt_state=%d, tx_status_state=%d\n", __FUNCTION__,
  1715. tx_pkt_state, tx_status_state));
  1716. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1717. return -EINVAL;
  1718. }
  1719. count = 0;
  1720. tx_report = dhdp->dbg->pkt_mon.tx_report;
  1721. tx_pkt = tx_report->tx_pkts;
  1722. pkt_count = MIN(req_count, tx_report->status_pos);
  1723. {
  1724. ptr = (wifi_tx_report_t *)user_buf;
  1725. while ((count < pkt_count) && tx_pkt && ptr) {
  1726. __dhd_dbg_dump_tx_pkt_info(dhdp, tx_pkt, count);
  1727. __COPY_TO_USER(&ptr->fate, &tx_pkt->fate, sizeof(tx_pkt->fate));
  1728. __COPY_TO_USER(&ptr->frame_inf.payload_type,
  1729. &tx_pkt->info.payload_type,
  1730. OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
  1731. __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
  1732. PKTDATA(dhdp->osh, tx_pkt->info.pkt), tx_pkt->info.pkt_len);
  1733. ptr++;
  1734. tx_pkt++;
  1735. count++;
  1736. }
  1737. }
  1738. *resp_count = pkt_count;
  1739. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1740. if (!pkt_count) {
  1741. DHD_ERROR(("%s(): no tx_status in tx completion messages, "
  1742. "make sure that 'd11status' is enabled in firmware, "
  1743. "status_pos=%u", __FUNCTION__, pkt_count));
  1744. }
  1745. return BCME_OK;
  1746. }
  1747. int
  1748. dhd_dbg_monitor_get_rx_pkts(dhd_pub_t *dhdp, void __user *user_buf,
  1749. uint16 req_count, uint16 *resp_count)
  1750. {
  1751. dhd_dbg_rx_report_t *rx_report;
  1752. dhd_dbg_rx_info_t *rx_pkt;
  1753. wifi_rx_report_t *ptr;
  1754. compat_wifi_rx_report_t *cptr;
  1755. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1756. uint16 pkt_count, count;
  1757. unsigned long flags;
  1758. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1759. BCM_REFERENCE(ptr);
  1760. BCM_REFERENCE(cptr);
  1761. if (!dhdp || !dhdp->dbg) {
  1762. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1763. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1764. return -EINVAL;
  1765. }
  1766. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1767. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1768. if (PKT_MON_NOT_OPERATIONAL(rx_pkt_state)) {
  1769. DHD_PKT_MON(("%s(): packet fetch is not allowed , "
  1770. "rx_pkt_state=%d\n", __FUNCTION__, rx_pkt_state));
  1771. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1772. return -EINVAL;
  1773. }
  1774. count = 0;
  1775. rx_report = dhdp->dbg->pkt_mon.rx_report;
  1776. rx_pkt = rx_report->rx_pkts;
  1777. pkt_count = MIN(req_count, rx_report->pkt_pos);
  1778. {
  1779. ptr = (wifi_rx_report_t *)user_buf;
  1780. while ((count < pkt_count) && rx_pkt && ptr) {
  1781. __dhd_dbg_dump_rx_pkt_info(dhdp, rx_pkt, count);
  1782. __COPY_TO_USER(&ptr->fate, &rx_pkt->fate, sizeof(rx_pkt->fate));
  1783. __COPY_TO_USER(&ptr->frame_inf.payload_type,
  1784. &rx_pkt->info.payload_type,
  1785. OFFSETOF(dhd_dbg_pkt_info_t, pkt_hash));
  1786. __COPY_TO_USER(ptr->frame_inf.frame_content.ethernet_ii,
  1787. PKTDATA(dhdp->osh, rx_pkt->info.pkt), rx_pkt->info.pkt_len);
  1788. ptr++;
  1789. rx_pkt++;
  1790. count++;
  1791. }
  1792. }
  1793. *resp_count = pkt_count;
  1794. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1795. return BCME_OK;
  1796. }
  1797. int
  1798. dhd_dbg_detach_pkt_monitor(dhd_pub_t *dhdp)
  1799. {
  1800. dhd_dbg_tx_report_t *tx_report;
  1801. dhd_dbg_rx_report_t *rx_report;
  1802. dhd_dbg_pkt_mon_state_t tx_pkt_state;
  1803. dhd_dbg_pkt_mon_state_t tx_status_state;
  1804. dhd_dbg_pkt_mon_state_t rx_pkt_state;
  1805. unsigned long flags;
  1806. DHD_PKT_INFO(("%s, %d\n", __FUNCTION__, __LINE__));
  1807. if (!dhdp || !dhdp->dbg) {
  1808. DHD_PKT_MON(("%s(): dhdp=%p, dhdp->dbg=%p\n", __FUNCTION__,
  1809. dhdp, (dhdp ? dhdp->dbg : NULL)));
  1810. return -EINVAL;
  1811. }
  1812. DHD_PKT_MON_LOCK(dhdp->dbg->pkt_mon_lock, flags);
  1813. tx_pkt_state = dhdp->dbg->pkt_mon.tx_pkt_state;
  1814. tx_status_state = dhdp->dbg->pkt_mon.tx_status_state;
  1815. rx_pkt_state = dhdp->dbg->pkt_mon.rx_pkt_state;
  1816. if (PKT_MON_DETACHED(tx_pkt_state) || PKT_MON_DETACHED(tx_status_state) ||
  1817. PKT_MON_DETACHED(rx_pkt_state)) {
  1818. DHD_PKT_MON(("%s(): packet monitor is already detached, "
  1819. "tx_pkt_state=%d, tx_status_state=%d, rx_pkt_state=%d\n",
  1820. __FUNCTION__, tx_pkt_state, tx_status_state, rx_pkt_state));
  1821. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1822. return -EINVAL;
  1823. }
  1824. tx_report = dhdp->dbg->pkt_mon.tx_report;
  1825. rx_report = dhdp->dbg->pkt_mon.rx_report;
  1826. /* free and de-initalize tx packet monitoring */
  1827. dhdp->dbg->pkt_mon.tx_pkt_state = PKT_MON_DETACHED;
  1828. dhdp->dbg->pkt_mon.tx_status_state = PKT_MON_DETACHED;
  1829. if (tx_report) {
  1830. if (tx_report->tx_pkts) {
  1831. __dhd_dbg_free_tx_pkts(dhdp, tx_report->tx_pkts,
  1832. tx_report->pkt_pos);
  1833. MFREE(dhdp->osh, tx_report->tx_pkts,
  1834. (sizeof(*tx_report->tx_pkts) * MAX_FATE_LOG_LEN));
  1835. dhdp->dbg->pkt_mon.tx_report->tx_pkts = NULL;
  1836. }
  1837. MFREE(dhdp->osh, tx_report, sizeof(*tx_report));
  1838. dhdp->dbg->pkt_mon.tx_report = NULL;
  1839. }
  1840. dhdp->dbg->pkt_mon.tx_pkt_mon = NULL;
  1841. dhdp->dbg->pkt_mon.tx_status_mon = NULL;
  1842. /* free and de-initalize rx packet monitoring */
  1843. dhdp->dbg->pkt_mon.rx_pkt_state = PKT_MON_DETACHED;
  1844. if (rx_report) {
  1845. if (rx_report->rx_pkts) {
  1846. __dhd_dbg_free_rx_pkts(dhdp, rx_report->rx_pkts,
  1847. rx_report->pkt_pos);
  1848. MFREE(dhdp->osh, rx_report->rx_pkts,
  1849. (sizeof(*rx_report->rx_pkts) * MAX_FATE_LOG_LEN));
  1850. dhdp->dbg->pkt_mon.rx_report->rx_pkts = NULL;
  1851. }
  1852. MFREE(dhdp->osh, rx_report, sizeof(*rx_report));
  1853. dhdp->dbg->pkt_mon.rx_report = NULL;
  1854. }
  1855. dhdp->dbg->pkt_mon.rx_pkt_mon = NULL;
  1856. DHD_PKT_MON_UNLOCK(dhdp->dbg->pkt_mon_lock, flags);
  1857. DHD_PKT_MON(("%s(): packet monitor detach succeeded\n", __FUNCTION__));
  1858. return BCME_OK;
  1859. }
  1860. #endif /* DBG_PKT_MON */
  1861. #if defined(DBG_PKT_MON) || defined(DHD_PKT_LOGGING)
  1862. bool
  1863. dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt, uint32 pktid,
  1864. uint16 status)
  1865. {
  1866. bool pkt_fate = TRUE;
  1867. if (dhdp->d11_tx_status) {
  1868. pkt_fate = (status == WLFC_CTL_PKTFLAG_DISCARD) ? TRUE : FALSE;
  1869. DHD_DBG_PKT_MON_TX_STATUS(dhdp, pkt, pktid, status);
  1870. }
  1871. return pkt_fate;
  1872. }
  1873. #else /* DBG_PKT_MON || DHD_PKT_LOGGING */
  1874. bool
  1875. dhd_dbg_process_tx_status(dhd_pub_t *dhdp, void *pkt,
  1876. uint32 pktid, uint16 status)
  1877. {
  1878. return TRUE;
  1879. }
  1880. #endif /* DBG_PKT_MON || DHD_PKT_LOGGING */
  1881. /*
  1882. * dhd_dbg_attach: initialziation of dhd dbugability module
  1883. *
  1884. * Return: An error code or 0 on success.
  1885. */
  1886. int
  1887. dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
  1888. dbg_urgent_noti_t os_urgent_notifier, void *os_priv)
  1889. {
  1890. dhd_dbg_t *dbg = NULL;
  1891. dhd_dbg_ring_t *ring = NULL;
  1892. int ret = BCME_ERROR, ring_id = 0;
  1893. void *buf = NULL;
  1894. dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t));
  1895. if (!dbg)
  1896. return BCME_NOMEM;
  1897. buf = MALLOCZ(dhdp->osh, FW_VERBOSE_RING_SIZE);
  1898. if (!buf)
  1899. goto error;
  1900. ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID,
  1901. (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, buf, FALSE);
  1902. if (ret)
  1903. goto error;
  1904. buf = MALLOCZ(dhdp->osh, DHD_EVENT_RING_SIZE);
  1905. if (!buf)
  1906. goto error;
  1907. ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID,
  1908. (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, buf, FALSE);
  1909. if (ret)
  1910. goto error;
  1911. dbg->private = os_priv;
  1912. dbg->pullreq = os_pullreq;
  1913. dbg->urgent_notifier = os_urgent_notifier;
  1914. dhdp->dbg = dbg;
  1915. return BCME_OK;
  1916. error:
  1917. for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
  1918. if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
  1919. ring = &dbg->dbg_rings[ring_id];
  1920. dhd_dbg_ring_deinit(dhdp, ring);
  1921. if (ring->ring_buf) {
  1922. MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
  1923. ring->ring_buf = NULL;
  1924. }
  1925. ring->ring_size = 0;
  1926. }
  1927. }
  1928. MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
  1929. return ret;
  1930. }
  1931. /*
  1932. * dhd_dbg_detach: clean up dhd dbugability module
  1933. */
  1934. void
  1935. dhd_dbg_detach(dhd_pub_t *dhdp)
  1936. {
  1937. int ring_id;
  1938. dhd_dbg_ring_t *ring = NULL;
  1939. dhd_dbg_t *dbg;
  1940. if (!dhdp->dbg)
  1941. return;
  1942. dbg = dhdp->dbg;
  1943. for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
  1944. if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
  1945. ring = &dbg->dbg_rings[ring_id];
  1946. dhd_dbg_ring_deinit(dhdp, ring);
  1947. if (ring->ring_buf) {
  1948. MFREE(dhdp->osh, ring->ring_buf, ring->ring_size);
  1949. ring->ring_buf = NULL;
  1950. }
  1951. ring->ring_size = 0;
  1952. }
  1953. }
  1954. MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
  1955. }