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