e7071448d08cfa26cced5fc5c22d699f04448fa5
[GitHub/LineageOS/G12/android_hardware_amlogic_kernel-modules_dhd-driver.git] / bcmdhd-usb.1.363.110.17.x / dhd_debug.c
1 /*
2 * DHD debugability support
3 *
4 * Copyright (C) 1999-2016, Broadcom Corporation
5 *
6 * Unless you and Broadcom execute a separate written software license
7 * agreement governing use of this software, this software is licensed to you
8 * under the terms of the GNU General Public License version 2 (the "GPL"),
9 * available at http://www.broadcom.com/licenses/GPLv2.php, with the
10 * following added to such license:
11 *
12 * As a special exception, the copyright holders of this software give you
13 * permission to link this software with independent modules, and to copy and
14 * distribute the resulting executable under terms of your choice, provided that
15 * you also meet, for each linked independent module, the terms and conditions of
16 * the license of that module. An independent module is a module which is not
17 * derived from this software. The special exception does not apply to any
18 * modifications of the software.
19 *
20 * Notwithstanding the above, under no circumstances may you combine this
21 * software in any way with any other Broadcom software provided under a license
22 * other than the GPL, without Broadcom's express prior written consent.
23 *
24 *
25 * <<Broadcom-WL-IPTag/Open:>>
26 *
27 * $Id: dhd_debug.c 560028 2015-05-29 10:50:33Z $
28 */
29
30 #include <typedefs.h>
31 #include <osl.h>
32 #include <bcmutils.h>
33 #include <bcmendian.h>
34 #include <dngl_stats.h>
35 #include <dhd.h>
36 #include <dhd_dbg.h>
37 #include <dhd_debug.h>
38
39 #include <event_log.h>
40 #include <event_trace.h>
41 #include <msgtrace.h>
42
43 #define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3)
44 #define RING_STAT_TO_STATUS(ring, status) \
45 do { \
46 strncpy(status.name, ring->name, \
47 sizeof(status.name) - 1); \
48 status.ring_id = ring->id; \
49 status.ring_buffer_byte_size = ring->ring_size; \
50 status.written_bytes = ring->stat.written_bytes; \
51 status.written_records = ring->stat.written_records; \
52 status.read_bytes = ring->stat.read_bytes; \
53 status.verbose_level = ring->log_level; \
54 } while (0)
55
56 #define READ_AVAIL_SPACE(w, r, d) ((w >= r) ? (w - r) : (d - r))
57
58 struct map_table {
59 uint16 fw_id;
60 uint16 host_id;
61 char *desc;
62 };
63
64 struct map_table event_map[] = {
65 {WLC_E_AUTH, WIFI_EVENT_AUTH_COMPLETE, "AUTH_COMPLETE"},
66 {WLC_E_ASSOC, WIFI_EVENT_ASSOC_COMPLETE, "ASSOC_COMPLETE"},
67 {TRACE_FW_AUTH_STARTED, WIFI_EVENT_FW_AUTH_STARTED, "AUTH STARTED"},
68 {TRACE_FW_ASSOC_STARTED, WIFI_EVENT_FW_ASSOC_STARTED, "ASSOC STARTED"},
69 {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_FW_RE_ASSOC_STARTED, "REASSOC STARTED"},
70 {TRACE_G_SCAN_STARTED, WIFI_EVENT_G_SCAN_STARTED, "GSCAN STARTED"},
71 {WLC_E_PFN_SCAN_COMPLETE, WIFI_EVENT_G_SCAN_COMPLETE, "GSCAN COMPLETE"},
72 {WLC_E_DISASSOC, WIFI_EVENT_DISASSOCIATION_REQUESTED, "DIASSOC REQUESTED"},
73 {WLC_E_REASSOC, WIFI_EVENT_RE_ASSOCIATION_REQUESTED, "REASSOC REQUESTED"},
74 {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_REQUESTED, "ROAM REQUESTED"},
75 {WLC_E_BEACON_FRAME_RX, WIFI_EVENT_BEACON_RECEIVED, "BEACON Received"},
76 {TRACE_ROAM_SCAN_STARTED, WIFI_EVENT_ROAM_SCAN_STARTED, "ROAM SCAN STARTED"},
77 {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"},
78 {TRACE_ROAM_AUTH_STARTED, WIFI_EVENT_ROAM_AUTH_STARTED, "ROAM AUTH STARTED"},
79 {WLC_E_AUTH, WIFI_EVENT_ROAM_AUTH_COMPLETE, "ROAM AUTH COMPLETED"},
80 {TRACE_FW_RE_ASSOC_STARTED, WIFI_EVENT_ROAM_ASSOC_STARTED, "ROAM ASSOC STARTED"},
81 {WLC_E_ASSOC, WIFI_EVENT_ROAM_ASSOC_COMPLETE, "ROAM ASSOC COMPLETED"},
82 {TRACE_ROAM_SCAN_COMPLETE, WIFI_EVENT_ROAM_SCAN_COMPLETE, "ROAM SCAN COMPLETED"},
83 {TRACE_BT_COEX_BT_SCO_START, WIFI_EVENT_BT_COEX_BT_SCO_START, "BT SCO START"},
84 {TRACE_BT_COEX_BT_SCO_STOP, WIFI_EVENT_BT_COEX_BT_SCO_STOP, "BT SCO STOP"},
85 {TRACE_BT_COEX_BT_SCAN_START, WIFI_EVENT_BT_COEX_BT_SCAN_START, "BT COEX SCAN START"},
86 {TRACE_BT_COEX_BT_SCAN_STOP, WIFI_EVENT_BT_COEX_BT_SCAN_STOP, "BT COEX SCAN STOP"},
87 {TRACE_BT_COEX_BT_HID_START, WIFI_EVENT_BT_COEX_BT_HID_START, "BT HID START"},
88 {TRACE_BT_COEX_BT_HID_STOP, WIFI_EVENT_BT_COEX_BT_HID_STOP, "BT HID STOP"},
89 {WLC_E_EAPOL_MSG, WIFI_EVENT_FW_EAPOL_FRAME_RECEIVED, "FW EAPOL PKT RECEIVED"},
90 {TRACE_FW_EAPOL_FRAME_TRANSMIT_START, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_START,
91 "FW EAPOL PKT TRANSMITED"},
92 {TRACE_FW_EAPOL_FRAME_TRANSMIT_STOP, WIFI_EVENT_FW_EAPOL_FRAME_TRANSMIT_STOP,
93 "FW EAPOL PKT TX STOPPED"},
94 {TRACE_BLOCK_ACK_NEGOTIATION_COMPLETE, WIFI_EVENT_BLOCK_ACK_NEGOTIATION_COMPLETE,
95 "BLOCK ACK NEGO COMPLETED"},
96 };
97
98 struct map_table event_tag_map[] = {
99 {TRACE_TAG_VENDOR_SPECIFIC, WIFI_TAG_VENDOR_SPECIFIC, "VENDOR SPECIFIC DATA"},
100 {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"},
101 {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"},
102 {TRACE_TAG_SSID, WIFI_TAG_SSID, "SSID"},
103 {TRACE_TAG_STATUS, WIFI_TAG_STATUS, "STATUS"},
104 {TRACE_TAG_CHANNEL_SPEC, WIFI_TAG_CHANNEL_SPEC, "CHANSPEC"},
105 {TRACE_TAG_WAKE_LOCK_EVENT, WIFI_TAG_WAKE_LOCK_EVENT, "WAKELOCK EVENT"},
106 {TRACE_TAG_ADDR1, WIFI_TAG_ADDR1, "ADDR_1"},
107 {TRACE_TAG_ADDR2, WIFI_TAG_ADDR2, "ADDR_2"},
108 {TRACE_TAG_ADDR3, WIFI_TAG_ADDR3, "ADDR_3"},
109 {TRACE_TAG_ADDR4, WIFI_TAG_ADDR4, "ADDR_4"},
110 {TRACE_TAG_TSF, WIFI_TAG_TSF, "TSF"},
111 {TRACE_TAG_IE, WIFI_TAG_IE, "802.11 IE"},
112 {TRACE_TAG_INTERFACE, WIFI_TAG_INTERFACE, "INTERFACE"},
113 {TRACE_TAG_REASON_CODE, WIFI_TAG_REASON_CODE, "REASON CODE"},
114 {TRACE_TAG_RATE_MBPS, WIFI_TAG_RATE_MBPS, "RATE"},
115 };
116
117 /* define log level per ring type */
118 struct log_level_table fw_verbose_level_map[] = {
119 {1, EVENT_LOG_TAG_PCI_ERROR, "PCI_ERROR"},
120 {1, EVENT_LOG_TAG_PCI_WARN, "PCI_WARN"},
121 {2, EVENT_LOG_TAG_PCI_INFO, "PCI_INFO"},
122 {3, EVENT_LOG_TAG_PCI_DBG, "PCI_DEBUG"},
123 {3, EVENT_LOG_TAG_BEACON_LOG, "BEACON_LOG"},
124 {2, EVENT_LOG_TAG_WL_ASSOC_LOG, "ASSOC_LOG"},
125 {2, EVENT_LOG_TAG_WL_ROAM_LOG, "ROAM_LOG"},
126 {1, EVENT_LOG_TAG_TRACE_WL_INFO, "WL INFO"},
127 {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, "BTCOEX INFO"},
128 {1, EVENT_LOG_TAG_SCAN_WARN, "SCAN_WARN"},
129 {1, EVENT_LOG_TAG_SCAN_ERROR, "SCAN_ERROR"},
130 {2, EVENT_LOG_TAG_SCAN_TRACE_LOW, "SCAN_TRACE_LOW"},
131 {2, EVENT_LOG_TAG_SCAN_TRACE_HIGH, "SCAN_TRACE_HIGH"}
132 };
133
134 struct log_level_table fw_event_level_map[] = {
135 {1, EVENT_LOG_TAG_TRACE_WL_INFO, "WL_INFO"},
136 {1, EVENT_LOG_TAG_TRACE_BTCOEX_INFO, "BTCOEX_INFO"},
137 {2, EVENT_LOG_TAG_BEACON_LOG, "BEACON LOG"},
138 };
139
140 struct map_table nan_event_map[] = {
141 {TRACE_NAN_CLUSTER_STARTED, NAN_EVENT_CLUSTER_STARTED, "NAN_CLUSTER_STARTED"},
142 {TRACE_NAN_CLUSTER_JOINED, NAN_EVENT_CLUSTER_JOINED, "NAN_CLUSTER_JOINED"},
143 {TRACE_NAN_CLUSTER_MERGED, NAN_EVENT_CLUSTER_MERGED, "NAN_CLUSTER_MERGED"},
144 {TRACE_NAN_ROLE_CHANGED, NAN_EVENT_ROLE_CHANGED, "NAN_ROLE_CHANGED"},
145 {TRACE_NAN_SCAN_COMPLETE, NAN_EVENT_SCAN_COMPLETE, "NAN_SCAN_COMPLETE"},
146 {TRACE_NAN_STATUS_CHNG, NAN_EVENT_STATUS_CHNG, "NAN_STATUS_CHNG"},
147 };
148
149 struct log_level_table nan_event_level_map[] = {
150 {1, EVENT_LOG_TAG_NAN_ERROR, "NAN_ERROR"},
151 {2, EVENT_LOG_TAG_NAN_INFO, "NAN_INFO"},
152 {3, EVENT_LOG_TAG_NAN_DBG, "NAN_DEBUG"},
153 };
154
155 struct map_table nan_evt_tag_map[] = {
156 {TRACE_TAG_BSSID, WIFI_TAG_BSSID, "BSSID"},
157 {TRACE_TAG_ADDR, WIFI_TAG_ADDR, "ADDR_0"},
158 };
159
160 /* reference tab table */
161 uint ref_tag_tbl[EVENT_LOG_TAG_MAX + 1] = {0};
162
163 enum dbg_ring_state {
164 RING_STOP = 0, /* ring is not initialized */
165 RING_ACTIVE, /* ring is live and logging */
166 RING_SUSPEND /* ring is initialized but not logging */
167 };
168
169 struct ring_statistics {
170 /* number of bytes that was written to the buffer by driver */
171 uint32 written_bytes;
172 /* number of bytes that was read from the buffer by user land */
173 uint32 read_bytes;
174 /* number of records that was written to the buffer by driver */
175 uint32 written_records;
176 };
177
178 typedef struct dhd_dbg_ring {
179 int id; /* ring id */
180 uint8 name[DBGRING_NAME_MAX]; /* name string */
181 uint32 ring_size; /* numbers of item in ring */
182 uint32 wp; /* write pointer */
183 uint32 rp; /* read pointer */
184 uint32 log_level; /* log_level */
185 uint32 threshold; /* threshold bytes */
186 void * ring_buf; /* pointer of actually ring buffer */
187 void * lock; /* spin lock for ring access */
188 struct ring_statistics stat; /* statistics */
189 enum dbg_ring_state state; /* ring state enum */
190 } dhd_dbg_ring_t;
191
192 typedef struct dhd_dbg {
193 dhd_dbg_ring_t dbg_rings[DEBUG_RING_ID_MAX];
194 void *private; /* os private_data */
195 dbg_pullreq_t pullreq;
196 dbg_urgent_noti_t urgent_notifier;
197 } dhd_dbg_t;
198
199 typedef struct dhddbg_loglist_item {
200 dll_t list;
201 event_log_hdr_t *hdr;
202 } loglist_item_t;
203
204 typedef struct dhbdbg_pending_item {
205 dll_t list;
206 dhd_dbg_ring_status_t ring_status;
207 dhd_dbg_ring_entry_t *ring_entry;
208 } pending_item_t;
209
210 /* get next entry; offset must point to valid entry */
211 static uint32
212 next_entry(dhd_dbg_ring_t *ring, int32 offset)
213 {
214 dhd_dbg_ring_entry_t *entry =
215 (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + offset);
216
217 /*
218 * A length == 0 record is the end of buffer marker. Wrap around and
219 * read the message at the start of the buffer as *this* one, and
220 * return the one after that.
221 */
222 if (!entry->len) {
223 entry = (dhd_dbg_ring_entry_t *)ring->ring_buf;
224 return ENTRY_LENGTH(entry);
225 }
226 return offset + ENTRY_LENGTH(entry);
227 }
228
229 /* get record by offset; idx must point to valid entry */
230 static dhd_dbg_ring_entry_t *
231 get_entry(dhd_dbg_ring_t *ring, int32 offset)
232 {
233 dhd_dbg_ring_entry_t *entry =
234 (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + offset);
235
236 /*
237 * A length == 0 record is the end of buffer marker. Wrap around and
238 * read the message at the start of the buffer.
239 */
240 if (!entry->len)
241 return (dhd_dbg_ring_entry_t *)ring->ring_buf;
242 return entry;
243 }
244
245 int
246 dhd_dbg_ring_pull(dhd_pub_t *dhdp, int ring_id, void *data, uint32 buf_len)
247 {
248 uint32 avail_len, r_len = 0;
249 unsigned long flags;
250 dhd_dbg_ring_t *ring;
251 dhd_dbg_ring_entry_t *hdr;
252
253 if (!dhdp || !dhdp->dbg)
254 return r_len;
255 ring = &dhdp->dbg->dbg_rings[ring_id];
256 if (ring->state != RING_ACTIVE)
257 return r_len;
258
259 flags = dhd_os_spin_lock(ring->lock);
260
261 /* get a fresh pending length */
262 avail_len = READ_AVAIL_SPACE(ring->wp, ring->rp, ring->ring_size);
263 while (avail_len > 0 && buf_len > 0) {
264 hdr = get_entry(ring, ring->rp);
265 memcpy(data, hdr, ENTRY_LENGTH(hdr));
266 r_len += ENTRY_LENGTH(hdr);
267 /* update read pointer */
268 ring->rp = next_entry(ring, ring->rp);
269 data = (uint8 *)data + ENTRY_LENGTH(hdr);
270 avail_len -= ENTRY_LENGTH(hdr);
271 buf_len -= ENTRY_LENGTH(hdr);
272 ring->stat.read_bytes += ENTRY_LENGTH(hdr);
273 DHD_DBGIF(("%s read_bytes %d\n", __FUNCTION__,
274 ring->stat.read_bytes));
275 }
276 dhd_os_spin_unlock(ring->lock, flags);
277
278 return r_len;
279 }
280
281 int
282 dhd_dbg_ring_push(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_entry_t *hdr, void *data)
283 {
284 unsigned long flags;
285 uint32 w_len;
286 dhd_dbg_ring_t *ring;
287 dhd_dbg_ring_entry_t *w_entry;
288 if (!dhdp || !dhdp->dbg)
289 return BCME_BADADDR;
290
291 ring = &dhdp->dbg->dbg_rings[ring_id];
292
293 if (ring->state != RING_ACTIVE)
294 return BCME_OK;
295
296 flags = dhd_os_spin_lock(ring->lock);
297
298 w_len = ENTRY_LENGTH(hdr);
299 /* prep the space */
300 do {
301 if (ring->rp == ring->wp)
302 break;
303 if (ring->rp < ring->wp) {
304 if (ring->ring_size - ring->wp == w_len) {
305 if (ring->rp == 0)
306 ring->rp = next_entry(ring, ring->rp);
307 break;
308 } else if (ring->ring_size - ring->wp < w_len) {
309 if (ring->rp == 0)
310 ring->rp = next_entry(ring, ring->rp);
311 /* 0 pad insufficient tail space */
312 memset((uint8 *)ring->ring_buf + ring->wp, 0,
313 DBG_RING_ENTRY_SIZE);
314 ring->wp = 0;
315 continue;
316 } else {
317 break;
318 }
319 }
320 if (ring->rp > ring->wp) {
321 if (ring->rp - ring->wp <= w_len) {
322 ring->rp = next_entry(ring, ring->rp);
323 continue;
324 } else {
325 break;
326 }
327 }
328 } while (1);
329
330 w_entry = (dhd_dbg_ring_entry_t *)((uint8 *)ring->ring_buf + ring->wp);
331 /* header */
332 memcpy(w_entry, hdr, DBG_RING_ENTRY_SIZE);
333 w_entry->len = hdr->len;
334 /* payload */
335 memcpy((char *)w_entry + DBG_RING_ENTRY_SIZE, data, w_entry->len);
336 /* update write pointer */
337 ring->wp += w_len;
338 /* update statistics */
339 ring->stat.written_records++;
340 ring->stat.written_bytes += w_len;
341 dhd_os_spin_unlock(ring->lock, flags);
342 DHD_DBGIF(("%s : written_records %d, written_bytes %d\n", __FUNCTION__,
343 ring->stat.written_records, ring->stat.written_bytes));
344
345 /* if the current pending size is bigger than threshold */
346 if (ring->threshold > 0 &&
347 (READ_AVAIL_SPACE(ring->wp, ring->rp, ring->ring_size) >=
348 ring->threshold))
349 dhdp->dbg->pullreq(dhdp->dbg->private, ring->id);
350 return BCME_OK;
351 }
352
353 static int
354 dhd_dbg_msgtrace_seqchk(uint32 *prev, uint32 cur)
355 {
356 /* normal case including wrap around */
357 if ((cur == 0 && *prev == 0xFFFFFFFF) || ((cur - *prev) == 1)) {
358 goto done;
359 } else if (cur == *prev) {
360 DHD_EVENT(("%s duplicate trace\n", __FUNCTION__));
361 return -1;
362 } else if (cur > *prev) {
363 DHD_EVENT(("%s lost %d packets\n", __FUNCTION__, cur - *prev));
364 } else {
365 DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n",
366 __FUNCTION__, *prev, cur));
367 }
368 done:
369 *prev = cur;
370 return 0;
371 }
372
373 static void
374 dhd_dbg_msgtrace_msg_parser(void *event_data)
375 {
376 msgtrace_hdr_t *hdr;
377 char *data, *s;
378 static uint32 seqnum_prev = 0;
379
380 hdr = (msgtrace_hdr_t *)event_data;
381 data = (char *)event_data + MSGTRACE_HDRLEN;
382
383 /* There are 2 bytes available at the end of data */
384 data[ntoh16(hdr->len)] = '\0';
385
386 if (ntoh32(hdr->discarded_bytes) || ntoh32(hdr->discarded_printf)) {
387 DHD_DBGIF(("WLC_E_TRACE: [Discarded traces in dongle -->"
388 "discarded_bytes %d discarded_printf %d]\n",
389 ntoh32(hdr->discarded_bytes),
390 ntoh32(hdr->discarded_printf)));
391 }
392
393 if (dhd_dbg_msgtrace_seqchk(&seqnum_prev, ntoh32(hdr->seqnum)))
394 return;
395
396 /* Display the trace buffer. Advance from
397 * \n to \n to avoid display big
398 * printf (issue with Linux printk )
399 */
400 while (*data != '\0' && (s = strstr(data, "\n")) != NULL) {
401 *s = '\0';
402 DHD_FWLOG(("[FWLOG] %s\n", data));
403 data = s+1;
404 }
405 if (*data)
406 DHD_FWLOG(("[FWLOG] %s", data));
407 }
408
409 static INLINE void dhd_dbg_verboselog_handler(dhd_pub_t *dhdp,
410 event_log_hdr_t *hdr, void *raw_event_ptr) {};
411 static INLINE void dhd_dbg_msgtrace_log_parser(dhd_pub_t *dhdp,
412 void *event_data, void *raw_event_ptr, uint datalen) {};
413
414 void
415 dhd_dbg_trace_evnt_handler(dhd_pub_t *dhdp, void *event_data,
416 void *raw_event_ptr, uint datalen)
417 {
418 msgtrace_hdr_t *hdr;
419
420 hdr = (msgtrace_hdr_t *)event_data;
421
422 if (hdr->version != MSGTRACE_VERSION) {
423 DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n",
424 __FUNCTION__, MSGTRACE_VERSION, hdr->version));
425 return;
426 }
427
428 if (hdr->trace_type == MSGTRACE_HDR_TYPE_MSG)
429 dhd_dbg_msgtrace_msg_parser(event_data);
430 else if (hdr->trace_type == MSGTRACE_HDR_TYPE_LOG)
431 dhd_dbg_msgtrace_log_parser(dhdp, event_data, raw_event_ptr, datalen);
432 }
433
434 static int
435 dhd_dbg_ring_init(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring, uint16 id, uint8 *name,
436 uint32 ring_sz, int section)
437 {
438 void *buf;
439 unsigned long flags;
440 #ifdef CONFIG_DHD_USE_STATIC_BUF
441 buf = dhd_wlan_mem_prealloc(section, ring_sz);
442 #else
443 buf = MALLOCZ(dhdp->osh, ring_sz);
444 #endif
445 if (!buf)
446 return BCME_NOMEM;
447
448 ring->lock = dhd_os_spin_lock_init(dhdp->osh);
449
450 flags = dhd_os_spin_lock(ring->lock);
451 ring->id = id;
452 strncpy(ring->name, name, DBGRING_NAME_MAX);
453 ring->name[DBGRING_NAME_MAX - 1] = 0;
454 ring->ring_size = ring_sz;
455 ring->wp = ring->rp = 0;
456 ring->ring_buf = buf;
457 ring->threshold = DBGRING_FLUSH_THRESHOLD(ring);
458 ring->state = RING_SUSPEND;
459 dhd_os_spin_unlock(ring->lock, flags);
460
461 return BCME_OK;
462 }
463
464 static void
465 dhd_dbg_ring_deinit(dhd_pub_t *dhdp, dhd_dbg_ring_t *ring)
466 {
467 void *buf;
468 uint32 ring_sz;
469 unsigned long flags;
470
471 if (!ring->ring_buf)
472 return;
473
474 flags = dhd_os_spin_lock(ring->lock);
475 ring->id = 0;
476 ring->name[0] = 0;
477 ring_sz = ring->ring_size;
478 ring->ring_size = 0;
479 ring->wp = ring->rp = 0;
480 buf = ring->ring_buf;
481 ring->ring_buf = NULL;
482 memset(&ring->stat, 0, sizeof(ring->stat));
483 ring->threshold = 0;
484 ring->state = RING_STOP;
485 dhd_os_spin_unlock(ring->lock, flags);
486
487 dhd_os_spin_lock_deinit(dhdp->osh, ring->lock);
488 #ifndef CONFIG_DHD_USE_STATIC_BUF
489 MFREE(dhdp->osh, buf, ring_sz);
490 #endif
491 }
492
493 /*
494 * dhd_dbg_set_event_log_tag : modify the state of an event log tag
495 */
496 void
497 dhd_dbg_set_event_log_tag(dhd_pub_t *dhdp, uint16 tag, uint8 set)
498 {
499 wl_el_tag_params_t pars;
500 char *cmd = "event_log_tag_control";
501 char iovbuf[WLC_IOCTL_SMLEN] = { 0 };
502 int ret;
503
504 memset(&pars, 0, sizeof(pars));
505 pars.tag = tag;
506 pars.set = set;
507 pars.flags = EVENT_LOG_TAG_FLAG_LOG;
508
509 if (!bcm_mkiovar(cmd, (char *)&pars, sizeof(pars), iovbuf, sizeof(iovbuf))) {
510 DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__));
511 return;
512 }
513
514 ret = dhd_wl_ioctl_cmd(dhdp, WLC_SET_VAR, iovbuf, sizeof(iovbuf), TRUE, 0);
515 if (ret) {
516 DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__, ret));
517 }
518 }
519
520 int
521 dhd_dbg_set_configuration(dhd_pub_t *dhdp, int ring_id, int log_level, int flags, uint32 threshold)
522 {
523 dhd_dbg_ring_t *ring;
524 uint8 set = 1;
525 unsigned long lock_flags;
526 int i, array_len = 0;
527 struct log_level_table *log_level_tbl = NULL;
528 if (!dhdp || !dhdp->dbg)
529 return BCME_BADADDR;
530
531 ring = &dhdp->dbg->dbg_rings[ring_id];
532
533 if (ring->state == RING_STOP)
534 return BCME_UNSUPPORTED;
535
536 lock_flags = dhd_os_spin_lock(ring->lock);
537 if (log_level == 0)
538 ring->state = RING_SUSPEND;
539 else
540 ring->state = RING_ACTIVE;
541 ring->log_level = log_level;
542
543 ring->threshold = (threshold > ring->threshold) ? ring->ring_size : threshold;
544 dhd_os_spin_unlock(ring->lock, lock_flags);
545 if (log_level > 0)
546 set = TRUE;
547
548 if (ring->id == FW_EVENT_RING_ID) {
549 log_level_tbl = fw_event_level_map;
550 array_len = ARRAYSIZE(fw_event_level_map);
551 } else if (ring->id == FW_VERBOSE_RING_ID) {
552 log_level_tbl = fw_verbose_level_map;
553 array_len = ARRAYSIZE(fw_verbose_level_map);
554 } else if (ring->id == NAN_EVENT_RING_ID) {
555 log_level_tbl = nan_event_level_map;
556 array_len = ARRAYSIZE(nan_event_level_map);
557 }
558
559 for (i = 0; i < array_len; i++) {
560 if (log_level == 0 || (log_level_tbl[i].log_level > log_level)) {
561 /* clear the reference per ring */
562 ref_tag_tbl[log_level_tbl[i].tag] &= ~(1 << ring_id);
563 } else {
564 /* set the reference per ring */
565 ref_tag_tbl[log_level_tbl[i].tag] |= (1 << ring_id);
566 }
567 set = (ref_tag_tbl[log_level_tbl[i].tag])? 1 : 0;
568 DHD_DBGIF(("%s TAG(%s) is %s for the ring(%s)\n", __FUNCTION__,
569 log_level_tbl[i].desc, (set)? "SET" : "CLEAR", ring->name));
570 dhd_dbg_set_event_log_tag(dhdp, log_level_tbl[i].tag, set);
571 }
572 return BCME_OK;
573 }
574
575 /*
576 * dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer
577 * Return: An error code or 0 on success.
578 */
579
580 int
581 dhd_dbg_get_ring_status(dhd_pub_t *dhdp, int ring_id, dhd_dbg_ring_status_t *dbg_ring_status)
582 {
583 int ret = BCME_OK;
584 int id = 0;
585 dhd_dbg_t *dbg;
586 dhd_dbg_ring_t *dbg_ring;
587 dhd_dbg_ring_status_t ring_status;
588 if (!dhdp || !dhdp->dbg)
589 return BCME_BADADDR;
590 dbg = dhdp->dbg;
591
592 memset(&ring_status, 0, sizeof(dhd_dbg_ring_status_t));
593 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
594 dbg_ring = &dbg->dbg_rings[id];
595 if (VALID_RING(dbg_ring->id) && (dbg_ring->id == ring_id)) {
596 RING_STAT_TO_STATUS(dbg_ring, ring_status);
597 *dbg_ring_status = ring_status;
598 break;
599 }
600 }
601 if (!VALID_RING(id)) {
602 DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__, ring_id));
603 ret = BCME_NOTFOUND;
604 }
605 return ret;
606 }
607
608 /*
609 * dhd_dbg_find_ring_id : return ring_id based on ring_name
610 * Return: An invalid ring id for failure or valid ring id on success.
611 */
612
613 int
614 dhd_dbg_find_ring_id(dhd_pub_t *dhdp, char *ring_name)
615 {
616 int id;
617 dhd_dbg_t *dbg;
618 dhd_dbg_ring_t *ring;
619
620 if (!dhdp || !dhdp->dbg)
621 return BCME_BADADDR;
622
623 dbg = dhdp->dbg;
624 for (id = DEBUG_RING_ID_INVALID + 1; id < DEBUG_RING_ID_MAX; id++) {
625 ring = &dbg->dbg_rings[id];
626 if (!strncmp(ring->name, ring_name, sizeof(ring->name) - 1))
627 break;
628 }
629 return id;
630 }
631
632 /*
633 * dhd_dbg_get_priv : get the private data of dhd dbugability module
634 * Return : An NULL on failure or valid data address
635 */
636 void *
637 dhd_dbg_get_priv(dhd_pub_t *dhdp)
638 {
639 if (!dhdp || !dhdp->dbg)
640 return NULL;
641 return dhdp->dbg->private;
642 }
643
644 /*
645 * dhd_dbg_start : start and stop All of Ring buffers
646 * Return: An error code or 0 on success.
647 */
648 int
649 dhd_dbg_start(dhd_pub_t *dhdp, bool start)
650 {
651 int ret = BCME_OK;
652 int ring_id;
653 dhd_dbg_t *dbg;
654 dhd_dbg_ring_t *dbg_ring;
655 if (!dhdp || !dhdp->dbg)
656 return BCME_BADARG;
657 dbg = dhdp->dbg;
658
659 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
660 dbg_ring = &dbg->dbg_rings[ring_id];
661 if (!start) {
662 if (VALID_RING(dbg_ring->id)) {
663 /* Initialize the information for the ring */
664 dbg_ring->state = RING_SUSPEND;
665 dbg_ring->log_level = 0;
666 dbg_ring->rp = dbg_ring->wp = 0;
667 dbg_ring->threshold = 0;
668 memset(&dbg_ring->stat, 0, sizeof(struct ring_statistics));
669 memset(dbg_ring->ring_buf, 0, dbg_ring->ring_size);
670 }
671 }
672 }
673 return ret;
674 }
675
676 /*
677 * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer
678 *
679 * Return: An error code or 0 on success.
680 */
681
682 int
683 dhd_dbg_send_urgent_evt(dhd_pub_t *dhdp, const void *data, const uint32 len)
684 {
685 dhd_dbg_t *dbg;
686 int ret = BCME_OK;
687 if (!dhdp || !dhdp->dbg)
688 return BCME_BADADDR;
689
690 dbg = dhdp->dbg;
691 if (dbg->urgent_notifier) {
692 dbg->urgent_notifier(dhdp, data, len);
693 }
694 return ret;
695 }
696 /*
697 * dhd_dbg_attach: initialziation of dhd dbugability module
698 *
699 * Return: An error code or 0 on success.
700 */
701 int
702 dhd_dbg_attach(dhd_pub_t *dhdp, dbg_pullreq_t os_pullreq,
703 dbg_urgent_noti_t os_urgent_notifier, void *os_priv)
704 {
705 dhd_dbg_t *dbg;
706 int ret, ring_id;
707
708 dbg = MALLOCZ(dhdp->osh, sizeof(dhd_dbg_t));
709 if (!dbg)
710 return BCME_NOMEM;
711
712 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_VERBOSE_RING_ID], FW_VERBOSE_RING_ID,
713 (uint8 *)FW_VERBOSE_RING_NAME, FW_VERBOSE_RING_SIZE, DHD_PREALLOC_FW_VERBOSE_RING);
714 if (ret)
715 goto error;
716
717 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[FW_EVENT_RING_ID], FW_EVENT_RING_ID,
718 (uint8 *)FW_EVENT_RING_NAME, FW_EVENT_RING_SIZE, DHD_PREALLOC_FW_EVENT_RING);
719 if (ret)
720 goto error;
721
722 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[DHD_EVENT_RING_ID], DHD_EVENT_RING_ID,
723 (uint8 *)DHD_EVENT_RING_NAME, DHD_EVENT_RING_SIZE, DHD_PREALLOC_DHD_EVENT_RING);
724 if (ret)
725 goto error;
726
727 ret = dhd_dbg_ring_init(dhdp, &dbg->dbg_rings[NAN_EVENT_RING_ID], NAN_EVENT_RING_ID,
728 (uint8 *)NAN_EVENT_RING_NAME, NAN_EVENT_RING_SIZE, DHD_PREALLOC_NAN_EVENT_RING);
729 if (ret)
730 goto error;
731
732 dbg->private = os_priv;
733 dbg->pullreq = os_pullreq;
734 dbg->urgent_notifier = os_urgent_notifier;
735 dhdp->dbg = dbg;
736
737 return BCME_OK;
738
739 error:
740 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
741 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
742 dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]);
743 }
744 }
745 MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
746
747 return ret;
748 }
749
750 /*
751 * dhd_dbg_detach: clean up dhd dbugability module
752 */
753 void
754 dhd_dbg_detach(dhd_pub_t *dhdp)
755 {
756 int ring_id;
757 dhd_dbg_t *dbg;
758 if (!dhdp->dbg)
759 return;
760 dbg = dhdp->dbg;
761 for (ring_id = DEBUG_RING_ID_INVALID + 1; ring_id < DEBUG_RING_ID_MAX; ring_id++) {
762 if (VALID_RING(dbg->dbg_rings[ring_id].id)) {
763 dhd_dbg_ring_deinit(dhdp, &dbg->dbg_rings[ring_id]);
764 }
765 }
766 MFREE(dhdp->osh, dhdp->dbg, sizeof(dhd_dbg_t));
767 }