2 * DHD debugability support
4 * Copyright (C) 1999-2016, Broadcom Corporation
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:
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.
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.
25 * <<Broadcom-WL-IPTag/Open:>>
27 * $Id: dhd_debug.c 560028 2015-05-29 10:50:33Z $
33 #include <bcmendian.h>
34 #include <dngl_stats.h>
37 #include <dhd_debug.h>
39 #include <event_log.h>
40 #include <event_trace.h>
43 #define DBGRING_FLUSH_THRESHOLD(ring) (ring->ring_size / 3)
44 #define RING_STAT_TO_STATUS(ring, status) \
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; \
56 #define READ_AVAIL_SPACE(w, r, d) ((w >= r) ? (w - r) : (d - r))
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"},
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"},
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"}
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"},
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"},
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"},
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"},
160 /* reference tab table */
161 uint ref_tag_tbl
[EVENT_LOG_TAG_MAX
+ 1] = {0};
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 */
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 */
174 /* number of records that was written to the buffer by driver */
175 uint32 written_records
;
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 */
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
;
199 typedef struct dhddbg_loglist_item
{
201 event_log_hdr_t
*hdr
;
204 typedef struct dhbdbg_pending_item
{
206 dhd_dbg_ring_status_t ring_status
;
207 dhd_dbg_ring_entry_t
*ring_entry
;
210 /* get next entry; offset must point to valid entry */
212 next_entry(dhd_dbg_ring_t
*ring
, int32 offset
)
214 dhd_dbg_ring_entry_t
*entry
=
215 (dhd_dbg_ring_entry_t
*)((uint8
*)ring
->ring_buf
+ offset
);
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.
223 entry
= (dhd_dbg_ring_entry_t
*)ring
->ring_buf
;
224 return ENTRY_LENGTH(entry
);
226 return offset
+ ENTRY_LENGTH(entry
);
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
)
233 dhd_dbg_ring_entry_t
*entry
=
234 (dhd_dbg_ring_entry_t
*)((uint8
*)ring
->ring_buf
+ offset
);
237 * A length == 0 record is the end of buffer marker. Wrap around and
238 * read the message at the start of the buffer.
241 return (dhd_dbg_ring_entry_t
*)ring
->ring_buf
;
246 dhd_dbg_ring_pull(dhd_pub_t
*dhdp
, int ring_id
, void *data
, uint32 buf_len
)
248 uint32 avail_len
, r_len
= 0;
250 dhd_dbg_ring_t
*ring
;
251 dhd_dbg_ring_entry_t
*hdr
;
253 if (!dhdp
|| !dhdp
->dbg
)
255 ring
= &dhdp
->dbg
->dbg_rings
[ring_id
];
256 if (ring
->state
!= RING_ACTIVE
)
259 flags
= dhd_os_spin_lock(ring
->lock
);
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
));
276 dhd_os_spin_unlock(ring
->lock
, flags
);
282 dhd_dbg_ring_push(dhd_pub_t
*dhdp
, int ring_id
, dhd_dbg_ring_entry_t
*hdr
, void *data
)
286 dhd_dbg_ring_t
*ring
;
287 dhd_dbg_ring_entry_t
*w_entry
;
288 if (!dhdp
|| !dhdp
->dbg
)
291 ring
= &dhdp
->dbg
->dbg_rings
[ring_id
];
293 if (ring
->state
!= RING_ACTIVE
)
296 flags
= dhd_os_spin_lock(ring
->lock
);
298 w_len
= ENTRY_LENGTH(hdr
);
301 if (ring
->rp
== ring
->wp
)
303 if (ring
->rp
< ring
->wp
) {
304 if (ring
->ring_size
- ring
->wp
== w_len
) {
306 ring
->rp
= next_entry(ring
, ring
->rp
);
308 } else if (ring
->ring_size
- ring
->wp
< w_len
) {
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
);
320 if (ring
->rp
> ring
->wp
) {
321 if (ring
->rp
- ring
->wp
<= w_len
) {
322 ring
->rp
= next_entry(ring
, ring
->rp
);
330 w_entry
= (dhd_dbg_ring_entry_t
*)((uint8
*)ring
->ring_buf
+ ring
->wp
);
332 memcpy(w_entry
, hdr
, DBG_RING_ENTRY_SIZE
);
333 w_entry
->len
= hdr
->len
;
335 memcpy((char *)w_entry
+ DBG_RING_ENTRY_SIZE
, data
, w_entry
->len
);
336 /* update write pointer */
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
));
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
) >=
349 dhdp
->dbg
->pullreq(dhdp
->dbg
->private, ring
->id
);
354 dhd_dbg_msgtrace_seqchk(uint32
*prev
, uint32 cur
)
356 /* normal case including wrap around */
357 if ((cur
== 0 && *prev
== 0xFFFFFFFF) || ((cur
- *prev
) == 1)) {
359 } else if (cur
== *prev
) {
360 DHD_EVENT(("%s duplicate trace\n", __FUNCTION__
));
362 } else if (cur
> *prev
) {
363 DHD_EVENT(("%s lost %d packets\n", __FUNCTION__
, cur
- *prev
));
365 DHD_EVENT(("%s seq out of order, dhd %d, dongle %d\n",
366 __FUNCTION__
, *prev
, cur
));
374 dhd_dbg_msgtrace_msg_parser(void *event_data
)
378 static uint32 seqnum_prev
= 0;
380 hdr
= (msgtrace_hdr_t
*)event_data
;
381 data
= (char *)event_data
+ MSGTRACE_HDRLEN
;
383 /* There are 2 bytes available at the end of data */
384 data
[ntoh16(hdr
->len
)] = '\0';
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
)));
393 if (dhd_dbg_msgtrace_seqchk(&seqnum_prev
, ntoh32(hdr
->seqnum
)))
396 /* Display the trace buffer. Advance from
397 * \n to \n to avoid display big
398 * printf (issue with Linux printk )
400 while (*data
!= '\0' && (s
= strstr(data
, "\n")) != NULL
) {
402 DHD_FWLOG(("[FWLOG] %s\n", data
));
406 DHD_FWLOG(("[FWLOG] %s", data
));
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
) {};
415 dhd_dbg_trace_evnt_handler(dhd_pub_t
*dhdp
, void *event_data
,
416 void *raw_event_ptr
, uint datalen
)
420 hdr
= (msgtrace_hdr_t
*)event_data
;
422 if (hdr
->version
!= MSGTRACE_VERSION
) {
423 DHD_DBGIF(("%s unsupported MSGTRACE version, dhd %d, dongle %d\n",
424 __FUNCTION__
, MSGTRACE_VERSION
, hdr
->version
));
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
);
435 dhd_dbg_ring_init(dhd_pub_t
*dhdp
, dhd_dbg_ring_t
*ring
, uint16 id
, uint8
*name
,
436 uint32 ring_sz
, int section
)
440 #ifdef CONFIG_DHD_USE_STATIC_BUF
441 buf
= dhd_wlan_mem_prealloc(section
, ring_sz
);
443 buf
= MALLOCZ(dhdp
->osh
, ring_sz
);
448 ring
->lock
= dhd_os_spin_lock_init(dhdp
->osh
);
450 flags
= dhd_os_spin_lock(ring
->lock
);
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
);
465 dhd_dbg_ring_deinit(dhd_pub_t
*dhdp
, dhd_dbg_ring_t
*ring
)
474 flags
= dhd_os_spin_lock(ring
->lock
);
477 ring_sz
= ring
->ring_size
;
479 ring
->wp
= ring
->rp
= 0;
480 buf
= ring
->ring_buf
;
481 ring
->ring_buf
= NULL
;
482 memset(&ring
->stat
, 0, sizeof(ring
->stat
));
484 ring
->state
= RING_STOP
;
485 dhd_os_spin_unlock(ring
->lock
, flags
);
487 dhd_os_spin_lock_deinit(dhdp
->osh
, ring
->lock
);
488 #ifndef CONFIG_DHD_USE_STATIC_BUF
489 MFREE(dhdp
->osh
, buf
, ring_sz
);
494 * dhd_dbg_set_event_log_tag : modify the state of an event log tag
497 dhd_dbg_set_event_log_tag(dhd_pub_t
*dhdp
, uint16 tag
, uint8 set
)
499 wl_el_tag_params_t pars
;
500 char *cmd
= "event_log_tag_control";
501 char iovbuf
[WLC_IOCTL_SMLEN
] = { 0 };
504 memset(&pars
, 0, sizeof(pars
));
507 pars
.flags
= EVENT_LOG_TAG_FLAG_LOG
;
509 if (!bcm_mkiovar(cmd
, (char *)&pars
, sizeof(pars
), iovbuf
, sizeof(iovbuf
))) {
510 DHD_ERROR(("%s mkiovar failed\n", __FUNCTION__
));
514 ret
= dhd_wl_ioctl_cmd(dhdp
, WLC_SET_VAR
, iovbuf
, sizeof(iovbuf
), TRUE
, 0);
516 DHD_ERROR(("%s set log tag iovar failed %d\n", __FUNCTION__
, ret
));
521 dhd_dbg_set_configuration(dhd_pub_t
*dhdp
, int ring_id
, int log_level
, int flags
, uint32 threshold
)
523 dhd_dbg_ring_t
*ring
;
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
)
531 ring
= &dhdp
->dbg
->dbg_rings
[ring_id
];
533 if (ring
->state
== RING_STOP
)
534 return BCME_UNSUPPORTED
;
536 lock_flags
= dhd_os_spin_lock(ring
->lock
);
538 ring
->state
= RING_SUSPEND
;
540 ring
->state
= RING_ACTIVE
;
541 ring
->log_level
= log_level
;
543 ring
->threshold
= (threshold
> ring
->threshold
) ? ring
->ring_size
: threshold
;
544 dhd_os_spin_unlock(ring
->lock
, lock_flags
);
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
);
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
);
564 /* set the reference per ring */
565 ref_tag_tbl
[log_level_tbl
[i
].tag
] |= (1 << ring_id
);
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
);
576 * dhd_dbg_get_ring_status : get the ring status from the coresponding ring buffer
577 * Return: An error code or 0 on success.
581 dhd_dbg_get_ring_status(dhd_pub_t
*dhdp
, int ring_id
, dhd_dbg_ring_status_t
*dbg_ring_status
)
586 dhd_dbg_ring_t
*dbg_ring
;
587 dhd_dbg_ring_status_t ring_status
;
588 if (!dhdp
|| !dhdp
->dbg
)
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
;
601 if (!VALID_RING(id
)) {
602 DHD_ERROR(("%s : cannot find the ring_id : %d\n", __FUNCTION__
, ring_id
));
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.
614 dhd_dbg_find_ring_id(dhd_pub_t
*dhdp
, char *ring_name
)
618 dhd_dbg_ring_t
*ring
;
620 if (!dhdp
|| !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))
633 * dhd_dbg_get_priv : get the private data of dhd dbugability module
634 * Return : An NULL on failure or valid data address
637 dhd_dbg_get_priv(dhd_pub_t
*dhdp
)
639 if (!dhdp
|| !dhdp
->dbg
)
641 return dhdp
->dbg
->private;
645 * dhd_dbg_start : start and stop All of Ring buffers
646 * Return: An error code or 0 on success.
649 dhd_dbg_start(dhd_pub_t
*dhdp
, bool start
)
654 dhd_dbg_ring_t
*dbg_ring
;
655 if (!dhdp
|| !dhdp
->dbg
)
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
];
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
);
677 * dhd_dbg_send_urgent_evt: send the health check evt to Upper layer
679 * Return: An error code or 0 on success.
683 dhd_dbg_send_urgent_evt(dhd_pub_t
*dhdp
, const void *data
, const uint32 len
)
687 if (!dhdp
|| !dhdp
->dbg
)
691 if (dbg
->urgent_notifier
) {
692 dbg
->urgent_notifier(dhdp
, data
, len
);
697 * dhd_dbg_attach: initialziation of dhd dbugability module
699 * Return: An error code or 0 on success.
702 dhd_dbg_attach(dhd_pub_t
*dhdp
, dbg_pullreq_t os_pullreq
,
703 dbg_urgent_noti_t os_urgent_notifier
, void *os_priv
)
708 dbg
= MALLOCZ(dhdp
->osh
, sizeof(dhd_dbg_t
));
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
);
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
);
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
);
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
);
732 dbg
->private = os_priv
;
733 dbg
->pullreq
= os_pullreq
;
734 dbg
->urgent_notifier
= os_urgent_notifier
;
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
]);
745 MFREE(dhdp
->osh
, dhdp
->dbg
, sizeof(dhd_dbg_t
));
751 * dhd_dbg_detach: clean up dhd dbugability module
754 dhd_dbg_detach(dhd_pub_t
*dhdp
)
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
]);
766 MFREE(dhdp
->osh
, dhdp
->dbg
, sizeof(dhd_dbg_t
));