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