Commit | Line | Data |
---|---|---|
84813812 LJ |
1 | /* |
2 | * DHD debugability support | |
3 | * | |
4 | * <<Broadcom-WL-IPTag/Open:>> | |
5 | * | |
6 | * Copyright (C) 1999-2019, Broadcom. | |
7 | * | |
8 | * Unless you and Broadcom execute a separate written software license | |
9 | * agreement governing use of this software, this software is licensed to you | |
10 | * under the terms of the GNU General Public License version 2 (the "GPL"), | |
11 | * available at http://www.broadcom.com/licenses/GPLv2.php, with the | |
12 | * following added to such license: | |
13 | * | |
14 | * As a special exception, the copyright holders of this software give you | |
15 | * permission to link this software with independent modules, and to copy and | |
16 | * distribute the resulting executable under terms of your choice, provided that | |
17 | * you also meet, for each linked independent module, the terms and conditions 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_mschdbg.c 639872 2016-05-25 05:39:30Z $ | |
27 | */ | |
28 | #ifdef SHOW_LOGTRACE | |
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 | static const char *head_log = ""; | |
44 | #define MSCH_EVENT_HEAD(space) \ | |
45 | do { \ | |
46 | MSCH_EVENT(("%s_E: ", head_log)); \ | |
47 | if (space > 0) { \ | |
48 | int ii; \ | |
49 | for (ii = 0; ii < space; ii += 4) MSCH_EVENT((" ")); \ | |
50 | } \ | |
51 | } while (0) | |
52 | #define MSCH_EVENT(args) do {if (dhd_msg_level & DHD_EVENT_VAL) printf args;} while (0) | |
53 | ||
54 | static uint64 solt_start_time[4], req_start_time[4], profiler_start_time[4]; | |
55 | static uint32 solt_chanspec[4] = {0, }, req_start[4] = {0, }; | |
56 | static bool lastMessages = FALSE; | |
57 | ||
58 | #define US_PRE_SEC 1000000 | |
59 | #define DATA_UNIT_FOR_LOG_CNT 4 | |
60 | ||
61 | static void dhd_mschdbg_us_to_sec(uint32 time_h, uint32 time_l, uint32 *sec, uint32 *remain) | |
62 | { | |
63 | uint64 cur_time = ((uint64)(ntoh32(time_h)) << 32) | ntoh32(time_l); | |
64 | uint64 r, u = 0; | |
65 | ||
66 | r = cur_time; | |
67 | while (time_h != 0) { | |
68 | u += (uint64)((0xffffffff / US_PRE_SEC)) * time_h; | |
69 | r = cur_time - u * US_PRE_SEC; | |
70 | time_h = (uint32)(r >> 32); | |
71 | } | |
72 | ||
73 | *sec = (uint32)(u + ((uint32)(r) / US_PRE_SEC)); | |
74 | *remain = (uint32)(r) % US_PRE_SEC; | |
75 | } | |
76 | ||
77 | static char *dhd_mschdbg_display_time(uint32 time_h, uint32 time_l) | |
78 | { | |
79 | static char display_time[32]; | |
80 | uint32 s, ss; | |
81 | ||
82 | if (time_h == 0xffffffff && time_l == 0xffffffff) { | |
83 | snprintf(display_time, 31, "-1"); | |
84 | } else { | |
85 | dhd_mschdbg_us_to_sec(time_h, time_l, &s, &ss); | |
86 | snprintf(display_time, 31, "%d.%06d", s, ss); | |
87 | } | |
88 | return display_time; | |
89 | } | |
90 | ||
91 | static void | |
92 | dhd_mschdbg_chanspec_list(int sp, char *data, uint16 ptr, uint16 chanspec_cnt) | |
93 | { | |
94 | int i, cnt = (int)ntoh16(chanspec_cnt); | |
95 | uint16 *chanspec_list = (uint16 *)(data + ntoh16(ptr)); | |
96 | char buf[CHANSPEC_STR_LEN]; | |
97 | chanspec_t c; | |
98 | ||
99 | MSCH_EVENT_HEAD(sp); | |
100 | MSCH_EVENT(("<chanspec_list>:")); | |
101 | for (i = 0; i < cnt; i++) { | |
102 | c = (chanspec_t)ntoh16(chanspec_list[i]); | |
103 | MSCH_EVENT((" %s", wf_chspec_ntoa(c, buf))); | |
104 | } | |
105 | MSCH_EVENT(("\n")); | |
106 | } | |
107 | ||
108 | static void | |
109 | dhd_mschdbg_elem_list(int sp, char *title, char *data, uint16 ptr, uint16 list_cnt) | |
110 | { | |
111 | int i, cnt = (int)ntoh16(list_cnt); | |
112 | uint32 *list = (uint32 *)(data + ntoh16(ptr)); | |
113 | ||
114 | MSCH_EVENT_HEAD(sp); | |
115 | MSCH_EVENT(("%s_list: ", title)); | |
116 | for (i = 0; i < cnt; i++) { | |
117 | MSCH_EVENT(("0x%08x->", ntoh32(list[i]))); | |
118 | } | |
119 | MSCH_EVENT(("null\n")); | |
120 | } | |
121 | ||
122 | static void | |
123 | dhd_mschdbg_req_param_profiler_event_data(int sp, int ver, char *data, uint16 ptr) | |
124 | { | |
125 | int sn = sp + 4; | |
126 | msch_req_param_profiler_event_data_t *p = | |
127 | (msch_req_param_profiler_event_data_t *)(data + ntoh16(ptr)); | |
128 | uint32 type, flags; | |
129 | ||
130 | MSCH_EVENT_HEAD(sp); | |
131 | MSCH_EVENT(("<request parameters>\n")); | |
132 | MSCH_EVENT_HEAD(sn); | |
133 | MSCH_EVENT(("req_type: ")); | |
134 | ||
135 | type = p->req_type; | |
136 | if (type < 4) { | |
137 | char *req_type[] = {"fixed", "start-flexible", "duration-flexible", | |
138 | "both-flexible"}; | |
139 | MSCH_EVENT(("%s", req_type[type])); | |
140 | } | |
141 | else | |
142 | MSCH_EVENT(("unknown(%d)", type)); | |
143 | ||
144 | flags = ntoh16(p->flags); | |
145 | if (flags & WL_MSCH_REQ_FLAGS_CHAN_CONTIGUOUS) | |
146 | MSCH_EVENT((", CHAN_CONTIGUOUS")); | |
147 | if (flags & WL_MSCH_REQ_FLAGS_MERGE_CONT_SLOTS) | |
148 | MSCH_EVENT((", MERGE_CONT_SLOTS")); | |
149 | if (flags & WL_MSCH_REQ_FLAGS_PREMTABLE) | |
150 | MSCH_EVENT((", PREMTABLE")); | |
151 | if (flags & WL_MSCH_REQ_FLAGS_PREMT_CURTS) | |
152 | MSCH_EVENT((", PREMT_CURTS")); | |
153 | if (flags & WL_MSCH_REQ_FLAGS_PREMT_IMMEDIATE) | |
154 | MSCH_EVENT((", PREMT_IMMEDIATE")); | |
155 | MSCH_EVENT((", priority: %d\n", p->priority)); | |
156 | ||
157 | MSCH_EVENT_HEAD(sn); | |
158 | MSCH_EVENT(("start-time: %s, duration: %d(us), interval: %d(us)\n", | |
159 | dhd_mschdbg_display_time(p->start_time_h, p->start_time_l), | |
160 | ntoh32(p->duration), ntoh32(p->interval))); | |
161 | ||
162 | if (type == WL_MSCH_RT_DUR_FLEX) { | |
163 | MSCH_EVENT_HEAD(sn); | |
164 | MSCH_EVENT(("dur_flex: %d(us)\n", ntoh32(p->flex.dur_flex))); | |
165 | } else if (type == WL_MSCH_RT_BOTH_FLEX) { | |
166 | MSCH_EVENT_HEAD(sn); | |
167 | MSCH_EVENT(("min_dur: %d(us), max_away_dur: %d(us)\n", | |
168 | ntoh32(p->flex.bf.min_dur), ntoh32(p->flex.bf.max_away_dur))); | |
169 | ||
170 | MSCH_EVENT_HEAD(sn); | |
171 | MSCH_EVENT(("hi_prio_time: %s, hi_prio_interval: %d(us)\n", | |
172 | dhd_mschdbg_display_time(p->flex.bf.hi_prio_time_h, | |
173 | p->flex.bf.hi_prio_time_l), | |
174 | ntoh32(p->flex.bf.hi_prio_interval))); | |
175 | } | |
176 | } | |
177 | ||
178 | static void | |
179 | dhd_mschdbg_timeslot_profiler_event_data(int sp, int ver, char *title, char *data, | |
180 | uint16 ptr, bool empty) | |
181 | { | |
182 | int s, sn = sp + 4; | |
183 | msch_timeslot_profiler_event_data_t *p = | |
184 | (msch_timeslot_profiler_event_data_t *)(data + ntoh16(ptr)); | |
185 | char *state[] = {"NONE", "CHN_SW", "ONCHAN_FIRE", "OFF_CHN_PREP", | |
186 | "OFF_CHN_DONE", "TS_COMPLETE"}; | |
187 | ||
188 | MSCH_EVENT_HEAD(sp); | |
189 | MSCH_EVENT(("<%s timeslot>: ", title)); | |
190 | if (empty) { | |
191 | MSCH_EVENT((" null\n")); | |
192 | return; | |
193 | } | |
194 | else | |
195 | MSCH_EVENT(("0x%08x\n", ntoh32(p->p_timeslot))); | |
196 | ||
197 | s = (int)(ntoh32(p->state)); | |
198 | if (s > 5) s = 0; | |
199 | ||
200 | MSCH_EVENT_HEAD(sn); | |
201 | MSCH_EVENT(("id: %d, state[%d]: %s, chan_ctxt: [0x%08x]\n", | |
202 | ntoh32(p->timeslot_id), ntoh32(p->state), state[s], ntoh32(p->p_chan_ctxt))); | |
203 | ||
204 | MSCH_EVENT_HEAD(sn); | |
205 | MSCH_EVENT(("fire_time: %s", | |
206 | dhd_mschdbg_display_time(p->fire_time_h, p->fire_time_l))); | |
207 | ||
208 | MSCH_EVENT((", pre_start_time: %s", | |
209 | dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l))); | |
210 | ||
211 | MSCH_EVENT((", end_time: %s", | |
212 | dhd_mschdbg_display_time(p->end_time_h, p->end_time_l))); | |
213 | ||
214 | MSCH_EVENT((", sch_dur: %s\n", | |
215 | dhd_mschdbg_display_time(p->sch_dur_h, p->sch_dur_l))); | |
216 | } | |
217 | ||
218 | static void | |
219 | dhd_mschdbg_req_timing_profiler_event_data(int sp, int ver, char *title, char *data, | |
220 | uint16 ptr, bool empty) | |
221 | { | |
222 | int sn = sp + 4; | |
223 | msch_req_timing_profiler_event_data_t *p = | |
224 | (msch_req_timing_profiler_event_data_t *)(data + ntoh16(ptr)); | |
225 | uint32 type; | |
226 | ||
227 | MSCH_EVENT_HEAD(sp); | |
228 | MSCH_EVENT(("<%s req_timing>: ", title)); | |
229 | if (empty) { | |
230 | MSCH_EVENT((" null\n")); | |
231 | return; | |
232 | } | |
233 | else | |
234 | MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", | |
235 | ntoh32(p->p_req_timing), ntoh32(p->p_prev), ntoh32(p->p_next))); | |
236 | ||
237 | MSCH_EVENT_HEAD(sn); | |
238 | MSCH_EVENT(("flags:")); | |
239 | type = ntoh16(p->flags); | |
240 | if ((type & 0x7f) == 0) | |
241 | MSCH_EVENT((" NONE")); | |
242 | else { | |
243 | if (type & WL_MSCH_RC_FLAGS_ONCHAN_FIRE) | |
244 | MSCH_EVENT((" ONCHAN_FIRE")); | |
245 | if (type & WL_MSCH_RC_FLAGS_START_FIRE_DONE) | |
246 | MSCH_EVENT((" START_FIRE")); | |
247 | if (type & WL_MSCH_RC_FLAGS_END_FIRE_DONE) | |
248 | MSCH_EVENT((" END_FIRE")); | |
249 | if (type & WL_MSCH_RC_FLAGS_ONFIRE_DONE) | |
250 | MSCH_EVENT((" ONFIRE_DONE")); | |
251 | if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_START) | |
252 | MSCH_EVENT((" SPLIT_SLOT_START")); | |
253 | if (type & WL_MSCH_RC_FLAGS_SPLIT_SLOT_END) | |
254 | MSCH_EVENT((" SPLIT_SLOT_END")); | |
255 | if (type & WL_MSCH_RC_FLAGS_PRE_ONFIRE_DONE) | |
256 | MSCH_EVENT((" PRE_ONFIRE_DONE")); | |
257 | } | |
258 | MSCH_EVENT(("\n")); | |
259 | ||
260 | MSCH_EVENT_HEAD(sn); | |
261 | MSCH_EVENT(("pre_start_time: %s", | |
262 | dhd_mschdbg_display_time(p->pre_start_time_h, p->pre_start_time_l))); | |
263 | ||
264 | MSCH_EVENT((", start_time: %s", | |
265 | dhd_mschdbg_display_time(p->start_time_h, p->start_time_l))); | |
266 | ||
267 | MSCH_EVENT((", end_time: %s\n", | |
268 | dhd_mschdbg_display_time(p->end_time_h, p->end_time_l))); | |
269 | ||
270 | if (p->p_timeslot && (p->timeslot_ptr == 0)) { | |
271 | MSCH_EVENT_HEAD(sn); | |
272 | MSCH_EVENT(("<%s timeslot>: 0x%08x\n", title, ntoh32(p->p_timeslot))); | |
273 | } else | |
274 | dhd_mschdbg_timeslot_profiler_event_data(sn, ver, title, data, p->timeslot_ptr, | |
275 | (p->timeslot_ptr == 0)); | |
276 | } | |
277 | ||
278 | static void | |
279 | dhd_mschdbg_chan_ctxt_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) | |
280 | { | |
281 | int sn = sp + 4; | |
282 | msch_chan_ctxt_profiler_event_data_t *p = | |
283 | (msch_chan_ctxt_profiler_event_data_t *)(data + ntoh16(ptr)); | |
284 | chanspec_t c; | |
285 | char buf[CHANSPEC_STR_LEN]; | |
286 | ||
287 | MSCH_EVENT_HEAD(sp); | |
288 | MSCH_EVENT(("<chan_ctxt>: ")); | |
289 | if (empty) { | |
290 | MSCH_EVENT((" null\n")); | |
291 | return; | |
292 | } | |
293 | else | |
294 | MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", | |
295 | ntoh32(p->p_chan_ctxt), ntoh32(p->p_prev), ntoh32(p->p_next))); | |
296 | ||
297 | c = (chanspec_t)ntoh16(p->chanspec); | |
298 | ||
299 | MSCH_EVENT_HEAD(sn); | |
300 | MSCH_EVENT(("channel: %s, bf_sch_pending: %s, bf_skipped: %d\n", | |
301 | wf_chspec_ntoa(c, buf), p->bf_sch_pending? "TRUE" : "FALSE", | |
302 | ntoh32(p->bf_skipped_count))); | |
303 | ||
304 | MSCH_EVENT_HEAD(sn); | |
305 | MSCH_EVENT(("bf_link: prev 0x%08x, next 0x%08x\n", | |
306 | ntoh32(p->bf_link_prev), ntoh32(p->bf_link_next))); | |
307 | ||
308 | MSCH_EVENT_HEAD(sn); | |
309 | MSCH_EVENT(("onchan_time: %s", | |
310 | dhd_mschdbg_display_time(p->onchan_time_h, p->onchan_time_l))); | |
311 | MSCH_EVENT((", actual_onchan_dur: %s", | |
312 | dhd_mschdbg_display_time(p->actual_onchan_dur_h, p->actual_onchan_dur_l))); | |
313 | MSCH_EVENT((", pend_onchan_dur: %s\n", | |
314 | dhd_mschdbg_display_time(p->pend_onchan_dur_h, p->pend_onchan_dur_l))); | |
315 | ||
316 | dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, | |
317 | p->req_entity_list_cnt); | |
318 | dhd_mschdbg_elem_list(sn, "bf_entity", data, p->bf_entity_list_ptr, | |
319 | p->bf_entity_list_cnt); | |
320 | } | |
321 | ||
322 | static void | |
323 | dhd_mschdbg_req_entity_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) | |
324 | { | |
325 | int sn = sp + 4; | |
326 | msch_req_entity_profiler_event_data_t *p = | |
327 | (msch_req_entity_profiler_event_data_t *)(data + ntoh16(ptr)); | |
328 | char buf[CHANSPEC_STR_LEN]; | |
329 | chanspec_t c; | |
330 | uint32 flags; | |
331 | ||
332 | MSCH_EVENT_HEAD(sp); | |
333 | MSCH_EVENT(("<req_entity>: ")); | |
334 | if (empty) { | |
335 | MSCH_EVENT((" null\n")); | |
336 | return; | |
337 | } | |
338 | else | |
339 | MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", | |
340 | ntoh32(p->p_req_entity), ntoh32(p->req_hdl_link_prev), | |
341 | ntoh32(p->req_hdl_link_next))); | |
342 | ||
343 | MSCH_EVENT_HEAD(sn); | |
344 | MSCH_EVENT(("req_hdl: [0x%08x]\n", ntoh32(p->p_req_hdl))); | |
345 | ||
346 | MSCH_EVENT_HEAD(sn); | |
347 | MSCH_EVENT(("chan_ctxt_link: prev 0x%08x, next 0x%08x\n", | |
348 | ntoh32(p->chan_ctxt_link_prev), ntoh32(p->chan_ctxt_link_next))); | |
349 | MSCH_EVENT_HEAD(sn); | |
350 | MSCH_EVENT(("rt_specific_link: prev 0x%08x, next 0x%08x\n", | |
351 | ntoh32(p->rt_specific_link_prev), ntoh32(p->rt_specific_link_next))); | |
352 | MSCH_EVENT_HEAD(sn); | |
353 | MSCH_EVENT(("start_fixed_link: prev 0x%08x, next 0x%08x\n", | |
354 | ntoh32(p->start_fixed_link_prev), ntoh32(p->start_fixed_link_next))); | |
355 | MSCH_EVENT_HEAD(sn); | |
356 | MSCH_EVENT(("both_flex_list: prev 0x%08x, next 0x%08x\n", | |
357 | ntoh32(p->both_flex_list_prev), ntoh32(p->both_flex_list_next))); | |
358 | ||
359 | c = (chanspec_t)ntoh16(p->chanspec); | |
360 | MSCH_EVENT_HEAD(sn); | |
361 | if (ver >= 2) { | |
362 | MSCH_EVENT(("channel: %s, onchan Id %d, current chan Id %d, priority %d", | |
363 | wf_chspec_ntoa(c, buf), ntoh16(p->onchan_chn_idx), ntoh16(p->cur_chn_idx), | |
364 | ntoh16(p->priority))); | |
365 | flags = ntoh32(p->flags); | |
366 | if (flags & WL_MSCH_ENTITY_FLAG_MULTI_INSTANCE) | |
367 | MSCH_EVENT((" : MULTI_INSTANCE\n")); | |
368 | else | |
369 | MSCH_EVENT(("\n")); | |
370 | MSCH_EVENT_HEAD(sn); | |
371 | MSCH_EVENT(("actual_start_time: %s, ", | |
372 | dhd_mschdbg_display_time(p->actual_start_time_h, p->actual_start_time_l))); | |
373 | MSCH_EVENT(("curts_fire_time: %s, ", | |
374 | dhd_mschdbg_display_time(p->curts_fire_time_h, p->curts_fire_time_l))); | |
375 | } else { | |
376 | MSCH_EVENT(("channel: %s, priority %d, ", wf_chspec_ntoa(c, buf), | |
377 | ntoh16(p->priority))); | |
378 | } | |
379 | MSCH_EVENT(("bf_last_serv_time: %s\n", | |
380 | dhd_mschdbg_display_time(p->bf_last_serv_time_h, p->bf_last_serv_time_l))); | |
381 | ||
382 | dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "current", data, p->cur_slot_ptr, | |
383 | (p->cur_slot_ptr == 0)); | |
384 | dhd_mschdbg_req_timing_profiler_event_data(sn, ver, "pending", data, p->pend_slot_ptr, | |
385 | (p->pend_slot_ptr == 0)); | |
386 | ||
387 | if (p->p_chan_ctxt && (p->chan_ctxt_ptr == 0)) { | |
388 | MSCH_EVENT_HEAD(sn); | |
389 | MSCH_EVENT(("<chan_ctxt>: 0x%08x\n", ntoh32(p->p_chan_ctxt))); | |
390 | } | |
391 | else | |
392 | dhd_mschdbg_chan_ctxt_profiler_event_data(sn, ver, data, p->chan_ctxt_ptr, | |
393 | (p->chan_ctxt_ptr == 0)); | |
394 | } | |
395 | ||
396 | static void | |
397 | dhd_mschdbg_req_handle_profiler_event_data(int sp, int ver, char *data, uint16 ptr, bool empty) | |
398 | { | |
399 | int sn = sp + 4; | |
400 | msch_req_handle_profiler_event_data_t *p = | |
401 | (msch_req_handle_profiler_event_data_t *)(data + ntoh16(ptr)); | |
402 | uint32 flags; | |
403 | ||
404 | MSCH_EVENT_HEAD(sp); | |
405 | MSCH_EVENT(("<req_handle>: ")); | |
406 | if (empty) { | |
407 | MSCH_EVENT((" null\n")); | |
408 | return; | |
409 | } | |
410 | else | |
411 | MSCH_EVENT(("0x%08x (prev 0x%08x, next 0x%08x)\n", | |
412 | ntoh32(p->p_req_handle), ntoh32(p->p_prev), ntoh32(p->p_next))); | |
413 | ||
414 | dhd_mschdbg_elem_list(sn, "req_entity", data, p->req_entity_list_ptr, | |
415 | p->req_entity_list_cnt); | |
416 | MSCH_EVENT_HEAD(sn); | |
417 | MSCH_EVENT(("cb_func: [0x%08x], cb_func: [0x%08x]", | |
418 | ntoh32(p->cb_func), ntoh32(p->cb_ctxt))); | |
419 | if (ver < 2) { | |
420 | MSCH_EVENT((", chan_cnt: %d", ntoh16(p->chan_cnt))); | |
421 | } | |
422 | flags = ntoh32(p->flags); | |
423 | if (flags & WL_MSCH_REQ_HDL_FLAGS_NEW_REQ) | |
424 | MSCH_EVENT((", NEW_REQ")); | |
425 | MSCH_EVENT(("\n")); | |
426 | ||
427 | dhd_mschdbg_req_param_profiler_event_data(sn, ver, data, p->req_param_ptr); | |
428 | ||
429 | if (ver >= 2) { | |
430 | MSCH_EVENT_HEAD(sn); | |
431 | MSCH_EVENT(("req_time: %s\n", | |
432 | dhd_mschdbg_display_time(p->req_time_h, p->req_time_l))); | |
433 | MSCH_EVENT_HEAD(sn); | |
434 | MSCH_EVENT(("chan_cnt: %d, chan idx %d, last chan idx %d\n", | |
435 | ntoh16(p->chan_cnt), ntoh16(p->chan_idx), ntoh16(p->last_chan_idx))); | |
436 | if (p->chanspec_list && p->chanspec_cnt) { | |
437 | dhd_mschdbg_chanspec_list(sn, data, p->chanspec_list, p->chanspec_cnt); | |
438 | } | |
439 | } | |
440 | } | |
441 | ||
442 | static void | |
443 | dhd_mschdbg_profiler_profiler_event_data(int sp, int ver, char *data, uint16 ptr) | |
444 | { | |
445 | msch_profiler_profiler_event_data_t *p = | |
446 | (msch_profiler_profiler_event_data_t *)(data + ntoh16(ptr)); | |
447 | uint32 flags; | |
448 | ||
449 | MSCH_EVENT_HEAD(sp); | |
450 | MSCH_EVENT(("free list: req_hdl 0x%08x, req_entity 0x%08x," | |
451 | " chan_ctxt 0x%08x, chanspec 0x%08x\n", | |
452 | ntoh32(p->free_req_hdl_list), ntoh32(p->free_req_entity_list), | |
453 | ntoh32(p->free_chan_ctxt_list), ntoh32(p->free_chanspec_list))); | |
454 | ||
455 | MSCH_EVENT_HEAD(sp); | |
456 | MSCH_EVENT(("alloc count: chanspec %d, req_entity %d, req_hdl %d, " | |
457 | "chan_ctxt %d, timeslot %d\n", | |
458 | ntoh16(p->msch_chanspec_alloc_cnt), ntoh16(p->msch_req_entity_alloc_cnt), | |
459 | ntoh16(p->msch_req_hdl_alloc_cnt), ntoh16(p->msch_chan_ctxt_alloc_cnt), | |
460 | ntoh16(p->msch_timeslot_alloc_cnt))); | |
461 | ||
462 | dhd_mschdbg_elem_list(sp, "req_hdl", data, p->msch_req_hdl_list_ptr, | |
463 | p->msch_req_hdl_list_cnt); | |
464 | dhd_mschdbg_elem_list(sp, "chan_ctxt", data, p->msch_chan_ctxt_list_ptr, | |
465 | p->msch_chan_ctxt_list_cnt); | |
466 | dhd_mschdbg_elem_list(sp, "req_timing", data, p->msch_req_timing_list_ptr, | |
467 | p->msch_req_timing_list_cnt); | |
468 | dhd_mschdbg_elem_list(sp, "start_fixed", data, p->msch_start_fixed_list_ptr, | |
469 | p->msch_start_fixed_list_cnt); | |
470 | dhd_mschdbg_elem_list(sp, "both_flex_req_entity", data, | |
471 | p->msch_both_flex_req_entity_list_ptr, | |
472 | p->msch_both_flex_req_entity_list_cnt); | |
473 | dhd_mschdbg_elem_list(sp, "start_flex", data, p->msch_start_flex_list_ptr, | |
474 | p->msch_start_flex_list_cnt); | |
475 | dhd_mschdbg_elem_list(sp, "both_flex", data, p->msch_both_flex_list_ptr, | |
476 | p->msch_both_flex_list_cnt); | |
477 | ||
478 | if (p->p_cur_msch_timeslot && (p->cur_msch_timeslot_ptr == 0)) { | |
479 | MSCH_EVENT_HEAD(sp); | |
480 | MSCH_EVENT(("<cur_msch timeslot>: 0x%08x\n", | |
481 | ntoh32(p->p_cur_msch_timeslot))); | |
482 | } else | |
483 | dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "cur_msch", data, | |
484 | p->cur_msch_timeslot_ptr, (p->cur_msch_timeslot_ptr == 0)); | |
485 | ||
486 | if (p->p_next_timeslot && (p->next_timeslot_ptr == 0)) { | |
487 | MSCH_EVENT_HEAD(sp); | |
488 | MSCH_EVENT(("<next timeslot>: 0x%08x\n", | |
489 | ntoh32(p->p_next_timeslot))); | |
490 | } else | |
491 | dhd_mschdbg_timeslot_profiler_event_data(sp, ver, "next", data, | |
492 | p->next_timeslot_ptr, (p->next_timeslot_ptr == 0)); | |
493 | ||
494 | MSCH_EVENT_HEAD(sp); | |
495 | MSCH_EVENT(("ts_id: %d, ", ntoh32(p->ts_id))); | |
496 | flags = ntoh32(p->flags); | |
497 | if (flags & WL_MSCH_STATE_IN_TIEMR_CTXT) | |
498 | MSCH_EVENT(("IN_TIEMR_CTXT, ")); | |
499 | if (flags & WL_MSCH_STATE_SCHD_PENDING) | |
500 | MSCH_EVENT(("SCHD_PENDING, ")); | |
501 | MSCH_EVENT(("slotskip_flags: %d, cur_armed_timeslot: 0x%08x\n", | |
502 | (ver >= 2)? ntoh32(p->slotskip_flag) : 0, ntoh32(p->cur_armed_timeslot))); | |
503 | MSCH_EVENT_HEAD(sp); | |
504 | MSCH_EVENT(("flex_list_cnt: %d, service_interval: %d, " | |
505 | "max_lo_prio_interval: %d\n", | |
506 | ntoh16(p->flex_list_cnt), ntoh32(p->service_interval), | |
507 | ntoh32(p->max_lo_prio_interval))); | |
508 | } | |
509 | ||
510 | static void dhd_mschdbg_dump_data(dhd_pub_t *dhdp, void *raw_event_ptr, int type, | |
511 | char *data, int len) | |
512 | { | |
513 | uint64 t = 0, tt = 0; | |
514 | uint32 s = 0, ss = 0; | |
515 | int wlc_index, ver; | |
516 | ||
517 | ver = (type & WL_MSCH_PROFILER_VER_MASK) >> WL_MSCH_PROFILER_VER_SHIFT; | |
518 | wlc_index = (type & WL_MSCH_PROFILER_WLINDEX_MASK) >> WL_MSCH_PROFILER_WLINDEX_SHIFT; | |
519 | if (wlc_index >= 4) | |
520 | return; | |
521 | ||
522 | type &= WL_MSCH_PROFILER_TYPE_MASK; | |
523 | if (type <= WL_MSCH_PROFILER_PROFILE_END) { | |
524 | msch_profiler_event_data_t *pevent = (msch_profiler_event_data_t *)data; | |
525 | tt = ((uint64)(ntoh32(pevent->time_hi)) << 32) | ntoh32(pevent->time_lo); | |
526 | dhd_mschdbg_us_to_sec(pevent->time_hi, pevent->time_lo, &s, &ss); | |
527 | } | |
528 | ||
529 | if (lastMessages && (type != WL_MSCH_PROFILER_MESSAGE) && | |
530 | (type != WL_MSCH_PROFILER_EVENT_LOG)) { | |
531 | MSCH_EVENT_HEAD(0); | |
532 | MSCH_EVENT(("\n")); | |
533 | lastMessages = FALSE; | |
534 | } | |
535 | ||
536 | switch (type) { | |
537 | case WL_MSCH_PROFILER_START: | |
538 | MSCH_EVENT_HEAD(0); | |
539 | MSCH_EVENT(("%06d.%06d START\n", s, ss)); | |
540 | break; | |
541 | ||
542 | case WL_MSCH_PROFILER_EXIT: | |
543 | MSCH_EVENT_HEAD(0); | |
544 | MSCH_EVENT(("%06d.%06d EXIT\n", s, ss)); | |
545 | break; | |
546 | ||
547 | case WL_MSCH_PROFILER_REQ: | |
548 | { | |
549 | msch_req_profiler_event_data_t *p = (msch_req_profiler_event_data_t *)data; | |
550 | MSCH_EVENT_HEAD(0); | |
551 | MSCH_EVENT(("\n")); | |
552 | MSCH_EVENT_HEAD(0); | |
553 | MSCH_EVENT(("===============================\n")); | |
554 | MSCH_EVENT_HEAD(0); | |
555 | MSCH_EVENT(("%06d.%06d [wl%d] REGISTER:\n", s, ss, wlc_index)); | |
556 | dhd_mschdbg_req_param_profiler_event_data(4, ver, data, p->req_param_ptr); | |
557 | dhd_mschdbg_chanspec_list(4, data, p->chanspec_ptr, p->chanspec_cnt); | |
558 | MSCH_EVENT_HEAD(0); | |
559 | MSCH_EVENT(("===============================\n")); | |
560 | MSCH_EVENT_HEAD(0); | |
561 | MSCH_EVENT(("\n")); | |
562 | } | |
563 | break; | |
564 | ||
565 | case WL_MSCH_PROFILER_CALLBACK: | |
566 | { | |
567 | msch_callback_profiler_event_data_t *p = | |
568 | (msch_callback_profiler_event_data_t *)data; | |
569 | char buf[CHANSPEC_STR_LEN]; | |
570 | chanspec_t chanspec; | |
571 | uint16 cbtype; | |
572 | ||
573 | MSCH_EVENT_HEAD(0); | |
574 | MSCH_EVENT(("%06d.%06d [wl%d] CALLBACK: ", s, ss, wlc_index)); | |
575 | chanspec = (chanspec_t)ntoh16(p->chanspec); | |
576 | MSCH_EVENT(("req_hdl[0x%08x], channel %s --", | |
577 | ntoh32(p->p_req_hdl), wf_chspec_ntoa(chanspec, buf))); | |
578 | ||
579 | cbtype = ntoh16(p->type); | |
580 | if (cbtype & WL_MSCH_CT_ON_CHAN) | |
581 | MSCH_EVENT((" ON_CHAN")); | |
582 | if (cbtype & WL_MSCH_CT_OFF_CHAN) | |
583 | MSCH_EVENT((" OFF_CHAN")); | |
584 | if (cbtype & WL_MSCH_CT_REQ_START) | |
585 | MSCH_EVENT((" REQ_START")); | |
586 | if (cbtype & WL_MSCH_CT_REQ_END) | |
587 | MSCH_EVENT((" REQ_END")); | |
588 | if (cbtype & WL_MSCH_CT_SLOT_START) | |
589 | MSCH_EVENT((" SLOT_START")); | |
590 | if (cbtype & WL_MSCH_CT_SLOT_SKIP) | |
591 | MSCH_EVENT((" SLOT_SKIP")); | |
592 | if (cbtype & WL_MSCH_CT_SLOT_END) | |
593 | MSCH_EVENT((" SLOT_END")); | |
594 | if (cbtype & WL_MSCH_CT_OFF_CHAN_DONE) | |
595 | MSCH_EVENT((" OFF_CHAN_DONE")); | |
596 | if (cbtype & WL_MSCH_CT_PARTIAL) | |
597 | MSCH_EVENT((" PARTIAL")); | |
598 | if (cbtype & WL_MSCH_CT_PRE_ONCHAN) | |
599 | MSCH_EVENT((" PRE_ONCHAN")); | |
600 | if (cbtype & WL_MSCH_CT_PRE_REQ_START) | |
601 | MSCH_EVENT((" PRE_REQ_START")); | |
602 | ||
603 | if (cbtype & WL_MSCH_CT_REQ_START) { | |
604 | req_start[wlc_index] = 1; | |
605 | req_start_time[wlc_index] = tt; | |
606 | } else if (cbtype & WL_MSCH_CT_REQ_END) { | |
607 | if (req_start[wlc_index]) { | |
608 | MSCH_EVENT((" : REQ duration %d", | |
609 | (uint32)(tt - req_start_time[wlc_index]))); | |
610 | req_start[wlc_index] = 0; | |
611 | } | |
612 | } | |
613 | ||
614 | if (cbtype & WL_MSCH_CT_SLOT_START) { | |
615 | solt_chanspec[wlc_index] = p->chanspec; | |
616 | solt_start_time[wlc_index] = tt; | |
617 | } else if (cbtype & WL_MSCH_CT_SLOT_END) { | |
618 | if (p->chanspec == solt_chanspec[wlc_index]) { | |
619 | MSCH_EVENT((" : SLOT duration %d", | |
620 | (uint32)(tt - solt_start_time[wlc_index]))); | |
621 | solt_chanspec[wlc_index] = 0; | |
622 | } | |
623 | } | |
624 | MSCH_EVENT(("\n")); | |
625 | ||
626 | if (cbtype & (WL_MSCH_CT_ON_CHAN | WL_MSCH_CT_SLOT_SKIP)) { | |
627 | MSCH_EVENT_HEAD(4); | |
628 | if (cbtype & WL_MSCH_CT_ON_CHAN) { | |
629 | MSCH_EVENT(("ID %d onchan idx %d cur_chan_seq_start %s ", | |
630 | ntoh32(p->timeslot_id), ntoh32(p->onchan_idx), | |
631 | dhd_mschdbg_display_time(p->cur_chan_seq_start_time_h, | |
632 | p->cur_chan_seq_start_time_l))); | |
633 | } | |
634 | t = ((uint64)(ntoh32(p->start_time_h)) << 32) | | |
635 | ntoh32(p->start_time_l); | |
636 | MSCH_EVENT(("start %s ", | |
637 | dhd_mschdbg_display_time(p->start_time_h, | |
638 | p->start_time_l))); | |
639 | tt = ((uint64)(ntoh32(p->end_time_h)) << 32) | ntoh32(p->end_time_l); | |
640 | MSCH_EVENT(("end %s duration %d\n", | |
641 | dhd_mschdbg_display_time(p->end_time_h, p->end_time_l), | |
642 | (p->end_time_h == 0xffffffff && p->end_time_l == 0xffffffff)? | |
643 | -1 : (int)(tt - t))); | |
644 | } | |
645 | ||
646 | } | |
647 | break; | |
648 | ||
649 | case WL_MSCH_PROFILER_EVENT_LOG: | |
650 | { | |
651 | while (len >= (int)WL_MSCH_EVENT_LOG_HEAD_SIZE) { | |
652 | msch_event_log_profiler_event_data_t *p = | |
653 | (msch_event_log_profiler_event_data_t *)data; | |
654 | /* TODO: How to parse MSCH if extended event tag is present ??? */ | |
655 | prcd_event_log_hdr_t hdr; | |
656 | int size = WL_MSCH_EVENT_LOG_HEAD_SIZE + p->hdr.count * sizeof(uint32); | |
657 | if (len < size || size > sizeof(msch_event_log_profiler_event_data_t)) { | |
658 | break; | |
659 | } | |
660 | data += size; | |
661 | len -= size; | |
662 | dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); | |
663 | MSCH_EVENT_HEAD(0); | |
664 | MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); | |
665 | bzero(&hdr, sizeof(hdr)); | |
666 | hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; | |
667 | hdr.count = p->hdr.count + 1; | |
668 | /* exclude LSB 2 bits which indicate binary/non-binary data */ | |
669 | hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2; | |
670 | hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num); | |
671 | if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) { | |
672 | hdr.binary_payload = TRUE; | |
673 | } | |
674 | dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0); | |
675 | } | |
676 | lastMessages = TRUE; | |
677 | break; | |
678 | } | |
679 | ||
680 | case WL_MSCH_PROFILER_MESSAGE: | |
681 | { | |
682 | msch_message_profiler_event_data_t *p = (msch_message_profiler_event_data_t *)data; | |
683 | MSCH_EVENT_HEAD(0); | |
684 | MSCH_EVENT(("%06d.%06d [wl%d]: %s", s, ss, wlc_index, p->message)); | |
685 | lastMessages = TRUE; | |
686 | break; | |
687 | } | |
688 | ||
689 | case WL_MSCH_PROFILER_PROFILE_START: | |
690 | profiler_start_time[wlc_index] = tt; | |
691 | MSCH_EVENT_HEAD(0); | |
692 | MSCH_EVENT(("-------------------------------\n")); | |
693 | MSCH_EVENT_HEAD(0); | |
694 | MSCH_EVENT(("%06d.%06d [wl%d] PROFILE DATA:\n", s, ss, wlc_index)); | |
695 | dhd_mschdbg_profiler_profiler_event_data(4, ver, data, 0); | |
696 | break; | |
697 | ||
698 | case WL_MSCH_PROFILER_PROFILE_END: | |
699 | MSCH_EVENT_HEAD(0); | |
700 | MSCH_EVENT(("%06d.%06d [wl%d] PROFILE END: take time %d\n", s, ss, | |
701 | wlc_index, (uint32)(tt - profiler_start_time[wlc_index]))); | |
702 | MSCH_EVENT_HEAD(0); | |
703 | MSCH_EVENT(("-------------------------------\n")); | |
704 | MSCH_EVENT_HEAD(0); | |
705 | MSCH_EVENT(("\n")); | |
706 | break; | |
707 | ||
708 | case WL_MSCH_PROFILER_REQ_HANDLE: | |
709 | dhd_mschdbg_req_handle_profiler_event_data(4, ver, data, 0, FALSE); | |
710 | break; | |
711 | ||
712 | case WL_MSCH_PROFILER_REQ_ENTITY: | |
713 | dhd_mschdbg_req_entity_profiler_event_data(4, ver, data, 0, FALSE); | |
714 | break; | |
715 | ||
716 | case WL_MSCH_PROFILER_CHAN_CTXT: | |
717 | dhd_mschdbg_chan_ctxt_profiler_event_data(4, ver, data, 0, FALSE); | |
718 | break; | |
719 | ||
720 | case WL_MSCH_PROFILER_REQ_TIMING: | |
721 | dhd_mschdbg_req_timing_profiler_event_data(4, ver, "msch", data, 0, FALSE); | |
722 | break; | |
723 | ||
724 | default: | |
725 | MSCH_EVENT_HEAD(0); | |
726 | MSCH_EVENT(("[wl%d] ERROR: unsupported EVENT reason code:%d; ", | |
727 | wlc_index, type)); | |
728 | break; | |
729 | } | |
730 | } | |
731 | ||
732 | void | |
733 | wl_mschdbg_event_handler(dhd_pub_t *dhdp, void *raw_event_ptr, int type, void *data, int len) | |
734 | { | |
735 | head_log = "MSCH"; | |
736 | dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, (char *)data, len); | |
737 | } | |
738 | ||
739 | void | |
740 | wl_mschdbg_verboselog_handler(dhd_pub_t *dhdp, void *raw_event_ptr, prcd_event_log_hdr_t *plog_hdr, | |
741 | uint32 *log_ptr) | |
742 | { | |
743 | uint32 log_pyld_len; | |
744 | head_log = "CONSOLE"; | |
745 | ||
746 | if (plog_hdr->count == 0) { | |
747 | return; | |
748 | } | |
749 | log_pyld_len = (plog_hdr->count - 1) * DATA_UNIT_FOR_LOG_CNT; | |
750 | ||
751 | if (plog_hdr->tag == EVENT_LOG_TAG_MSCHPROFILE) { | |
752 | msch_event_log_profiler_event_data_t *p = | |
753 | (msch_event_log_profiler_event_data_t *)log_ptr; | |
754 | /* TODO: How to parse MSCH if extended event tag is present ??? */ | |
755 | prcd_event_log_hdr_t hdr; | |
756 | uint32 s, ss; | |
757 | ||
758 | if (log_pyld_len < OFFSETOF(msch_event_log_profiler_event_data_t, data) || | |
759 | log_pyld_len > sizeof(msch_event_log_profiler_event_data_t)) { | |
760 | return; | |
761 | } | |
762 | ||
763 | dhd_mschdbg_us_to_sec(p->time_hi, p->time_lo, &s, &ss); | |
764 | MSCH_EVENT_HEAD(0); | |
765 | MSCH_EVENT(("%06d.%06d [wl%d]: ", s, ss, p->hdr.tag)); | |
766 | bzero(&hdr, sizeof(hdr)); | |
767 | hdr.tag = EVENT_LOG_TAG_MSCHPROFILE; | |
768 | hdr.count = p->hdr.count + 1; | |
769 | /* exclude LSB 2 bits which indicate binary/non-binary data */ | |
770 | hdr.fmt_num = ntoh16(p->hdr.fmt_num) >> 2; | |
771 | hdr.fmt_num_raw = ntoh16(p->hdr.fmt_num); | |
772 | if (ntoh16(p->hdr.fmt_num) == DHD_OW_BI_RAW_EVENT_LOG_FMT) { | |
773 | hdr.binary_payload = TRUE; | |
774 | } | |
775 | dhd_dbg_verboselog_printf(dhdp, &hdr, raw_event_ptr, p->data, 0, 0); | |
776 | } else { | |
777 | msch_collect_tlv_t *p = (msch_collect_tlv_t *)log_ptr; | |
778 | int type = ntoh16(p->type); | |
779 | int len = ntoh16(p->size); | |
780 | ||
781 | if (log_pyld_len < OFFSETOF(msch_collect_tlv_t, value) + len) { | |
782 | return; | |
783 | } | |
784 | ||
785 | dhd_mschdbg_dump_data(dhdp, raw_event_ptr, type, p->value, len); | |
786 | } | |
787 | } | |
788 | #endif /* SHOW_LOGTRACE */ |