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