1 /* D11 macdbg functions for Broadcom 802.11abgn
2 * Networking Adapter Device Drivers.
3 *
4 * Broadcom Proprietary and Confidential. Copyright (C) 2020,
5 * All Rights Reserved.
6 *
7 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Broadcom;
8 * the contents of this file may not be disclosed to third parties,
9 * copied or duplicated in any form, in whole or in part, without
10 * the prior written permission of Broadcom.
11 *
12 *
13 * <<Broadcom-WL-IPTag/Proprietary:>>
14 *
15 * $Id: dhd_macdbg.c 670412 2016-11-15 20:01:18Z shinuk $
16 */
17
18 #ifdef BCMDBG
19 #include <typedefs.h>
20 #include <osl.h>
21
22 #include <bcmutils.h>
23 #include <dhd_dbg.h>
24 #include <dhd_macdbg.h>
25 #include "d11reglist_proto.h"
26 #include "dhdioctl.h"
27 #include <sdiovar.h>
28
29 #ifdef BCMDBUS
30 #include <dbus.h>
31 #define BUS_IOVAR_OP(a, b, c, d, e, f, g) dbus_iovar_op(a->dbus, b, c, d, e, f, g)
32 #else
33 #include <dhd_bus.h>
34 #define BUS_IOVAR_OP dhd_bus_iovar_op
35 #endif
36
37 typedef struct _macdbg_info_t {
38 dhd_pub_t *dhdp;
39 d11regs_list_t *pd11regs;
40 uint16 d11regs_sz;
41 d11regs_list_t *pd11regs_x;
42 uint16 d11regsx_sz;
43 svmp_list_t *psvmpmems;
44 uint16 svmpmems_sz;
45 } macdbg_info_t;
46
47 #define SVMPLIST_HARDCODE
48
49 int
dhd_macdbg_attach(dhd_pub_t * dhdp)50 dhd_macdbg_attach(dhd_pub_t *dhdp)
51 {
52 macdbg_info_t *macdbg_info = MALLOCZ(dhdp->osh, sizeof(*macdbg_info));
53 #ifdef SVMPLIST_HARDCODE
54 svmp_list_t svmpmems[] = {
55 {0x20000, 256},
56 {0x21e10, 16},
57 {0x20300, 16},
58 {0x20700, 16},
59 {0x20b00, 16},
60 {0x20be0, 16},
61 {0x20bff, 16},
62 {0xc000, 32},
63 {0xe000, 32},
64 {0x10000, 0x8000},
65 {0x18000, 0x8000}
66 };
67 #endif /* SVMPLIST_HARDCODE */
68
69 if (macdbg_info == NULL) {
70 return BCME_NOMEM;
71 }
72 dhdp->macdbg_info = macdbg_info;
73 macdbg_info->dhdp = dhdp;
74
75 #ifdef SVMPLIST_HARDCODE
76 macdbg_info->psvmpmems = MALLOCZ(dhdp->osh, sizeof(svmpmems));
77 if (macdbg_info->psvmpmems == NULL) {
78 return BCME_NOMEM;
79 }
80
81 macdbg_info->svmpmems_sz = ARRAYSIZE(svmpmems);
82 memcpy(macdbg_info->psvmpmems, svmpmems, sizeof(svmpmems));
83
84 DHD_ERROR(("%s: psvmpmems %p svmpmems_sz %d\n",
85 __FUNCTION__, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz));
86 #endif
87 return BCME_OK;
88 }
89
90 void
dhd_macdbg_detach(dhd_pub_t * dhdp)91 dhd_macdbg_detach(dhd_pub_t *dhdp)
92 {
93 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
94 ASSERT(macdbg_info);
95
96 if (macdbg_info->pd11regs) {
97 ASSERT(macdbg_info->d11regs_sz > 0);
98 MFREE(dhdp->osh, macdbg_info->pd11regs,
99 (macdbg_info->d11regs_sz * sizeof(macdbg_info->pd11regs[0])));
100 macdbg_info->d11regs_sz = 0;
101 }
102 if (macdbg_info->pd11regs_x) {
103 ASSERT(macdbg_info->d11regsx_sz > 0);
104 MFREE(dhdp->osh, macdbg_info->pd11regs_x,
105 (macdbg_info->d11regsx_sz * sizeof(macdbg_info->pd11regs_x[0])));
106 macdbg_info->d11regsx_sz = 0;
107 }
108 if (macdbg_info->psvmpmems) {
109 ASSERT(macdbg_info->svmpmems_sz > 0);
110 MFREE(dhdp->osh, macdbg_info->psvmpmems,
111 (macdbg_info->svmpmems_sz * sizeof(macdbg_info->psvmpmems[0])));
112 macdbg_info->svmpmems_sz = 0;
113 }
114 MFREE(dhdp->osh, macdbg_info, sizeof(*macdbg_info));
115 }
116
117 void
dhd_macdbg_event_handler(dhd_pub_t * dhdp,uint32 reason,uint8 * event_data,uint32 datalen)118 dhd_macdbg_event_handler(dhd_pub_t *dhdp, uint32 reason,
119 uint8 *event_data, uint32 datalen)
120 {
121 d11regs_list_t *pd11regs;
122 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
123 uint d11regs_sz;
124
125 DHD_TRACE(("%s: reason %d datalen %d\n", __FUNCTION__, reason, datalen));
126 switch (reason) {
127 case WLC_E_MACDBG_LIST_PSMX:
128 /* Fall through */
129 case WLC_E_MACDBG_LIST_PSM:
130 pd11regs = MALLOCZ(dhdp->osh, datalen);
131 if (pd11regs == NULL) {
132 DHD_ERROR(("%s: NOMEM for len %d\n", __FUNCTION__, datalen));
133 return;
134 }
135 memcpy(pd11regs, event_data, datalen);
136 d11regs_sz = datalen / sizeof(pd11regs[0]);
137 DHD_ERROR(("%s: d11regs %p d11regs_sz %d\n",
138 __FUNCTION__, pd11regs, d11regs_sz));
139 if (reason == WLC_E_MACDBG_LIST_PSM) {
140 macdbg_info->pd11regs = pd11regs;
141 macdbg_info->d11regs_sz = (uint16)d11regs_sz;
142 } else {
143 macdbg_info->pd11regs_x = pd11regs;
144 macdbg_info->d11regsx_sz = (uint16)d11regs_sz;
145 }
146 break;
147 case WLC_E_MACDBG_REGALL:
148 #ifdef LINUX
149 /* Schedule to work queue as this context could be ISR */
150 dhd_schedule_macdbg_dump(dhdp);
151 #else
152 /* Dump PSMr */
153 (void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, FALSE);
154 /* Dump PSMx */
155 (void) dhd_macdbg_dumpmac(dhdp, NULL, 0, NULL, TRUE);
156 /* Dump SVMP mems */
157 (void) dhd_macdbg_dumpsvmp(dhdp, NULL, 0, NULL);
158 #endif
159 break;
160 default:
161 DHD_ERROR(("%s: Unknown reason %d\n",
162 __FUNCTION__, reason));
163 }
164 return;
165 }
166
167 static uint16
_dhd_get_ihr16(macdbg_info_t * macdbg_info,uint16 addr,struct bcmstrbuf * b,bool verbose)168 _dhd_get_ihr16(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose)
169 {
170 sdreg_t sdreg;
171 uint16 val;
172
173 sdreg.func = 2;
174 sdreg.offset = (0x1000 | addr);
175 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
176 &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
177 if (verbose) {
178 if (b) {
179 bcm_bprintf(b, "DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n",
180 (addr + 0x18001000), val);
181 } else {
182 printf("DEBUG: IHR16: read 0x%08x, size 2, value 0x%04x\n",
183 (addr + 0x18001000), val);
184 }
185 }
186 return val;
187 }
188
189 static uint32
_dhd_get_ihr32(macdbg_info_t * macdbg_info,uint16 addr,struct bcmstrbuf * b,bool verbose)190 _dhd_get_ihr32(macdbg_info_t *macdbg_info, uint16 addr, struct bcmstrbuf *b, bool verbose)
191 {
192 sdreg_t sdreg;
193 uint32 val;
194
195 sdreg.func = 4;
196 sdreg.offset = (0x1000 | addr);
197 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
198 &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
199 if (verbose) {
200 if (b) {
201 bcm_bprintf(b, "DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n",
202 (addr + 0x18001000), val);
203 } else {
204 printf("DEBUG: IHR32: read 0x%08x, size 4, value 0x%08x\n",
205 (addr + 0x18001000), val);
206 }
207 }
208 return val;
209 }
210
211 static void
_dhd_set_ihr16(macdbg_info_t * macdbg_info,uint16 addr,uint16 val,struct bcmstrbuf * b,bool verbose)212 _dhd_set_ihr16(macdbg_info_t *macdbg_info, uint16 addr, uint16 val,
213 struct bcmstrbuf *b, bool verbose)
214 {
215 sdreg_t sdreg;
216
217 sdreg.func = 2;
218 sdreg.offset = (0x1000 | addr);
219 sdreg.value = val;
220
221 if (verbose) {
222 if (b) {
223 bcm_bprintf(b, "DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n",
224 (addr + 0x18001000), val);
225 } else {
226 printf("DEBUG: IHR16: write 0x%08x, size 2, value 0x%04x\n",
227 (addr + 0x18001000), val);
228 }
229 }
230 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
231 NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
232 }
233
234 static void
_dhd_set_ihr32(macdbg_info_t * macdbg_info,uint16 addr,uint32 val,struct bcmstrbuf * b,bool verbose)235 _dhd_set_ihr32(macdbg_info_t *macdbg_info, uint16 addr, uint32 val,
236 struct bcmstrbuf *b, bool verbose)
237 {
238 sdreg_t sdreg;
239
240 sdreg.func = 4;
241 sdreg.offset = (0x1000 | addr);
242 sdreg.value = val;
243
244 if (verbose) {
245 if (b) {
246 bcm_bprintf(b, "DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n",
247 (addr + 0x18001000), val);
248 } else {
249 printf("DEBUG: IHR32: write 0x%08x, size 4, value 0x%08x\n",
250 (addr + 0x18001000), val);
251 }
252 }
253 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
254 NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
255 }
256
257 static uint32
_dhd_get_d11obj32(macdbg_info_t * macdbg_info,uint16 objaddr,uint32 sel,struct bcmstrbuf * b,bool verbose)258 _dhd_get_d11obj32(macdbg_info_t *macdbg_info, uint16 objaddr, uint32 sel,
259 struct bcmstrbuf *b, bool verbose)
260 {
261 uint32 val;
262 sdreg_t sdreg;
263 sdreg.func = 4; // 4bytes by default.
264 sdreg.offset = 0x1160;
265
266 if (objaddr == 0xffff) {
267 if (verbose) {
268 goto objaddr_read;
269 } else {
270 goto objdata_read;
271 }
272 }
273
274 if (objaddr & 0x3) {
275 printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, objaddr);
276 }
277
278 sdreg.value = (sel | (objaddr >> 2));
279
280 if (verbose) {
281 if (b) {
282 bcm_bprintf(b, "DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n",
283 (sel & 0x00020000) ? "SCR":"SHM",
284 (sdreg.offset + 0x18000000), sdreg.func, sdreg.value);
285 } else {
286 printf("DEBUG: %s: Indirect: write 0x%08x, size %d, value 0x%08x\n",
287 (sel & 0x00020000) ? "SCR":"SHM",
288 (sdreg.offset + 0x18000000), sdreg.func, sdreg.value);
289 }
290 }
291 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
292 NULL, 0, &sdreg, sizeof(sdreg), IOV_SET);
293
294 objaddr_read:
295 /* Give some time to obj addr register */
296 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
297 &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
298 if (verbose) {
299 if (b) {
300 bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n",
301 (sel & 0x00020000) ? "SCR":"SHM",
302 (sdreg.offset + 0x18000000), sdreg.func, val);
303 } else {
304 printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%08x\n",
305 (sel & 0x00020000) ? "SCR":"SHM",
306 (sdreg.offset + 0x18000000), sdreg.func, val);
307 }
308 }
309
310 objdata_read:
311 sdreg.offset = 0x1164;
312 BUS_IOVAR_OP(macdbg_info->dhdp, "sbreg",
313 &sdreg, sizeof(sdreg), &val, sizeof(val), IOV_GET);
314 if (verbose) {
315 if (b) {
316 bcm_bprintf(b, "DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n",
317 (sel & 0x00020000) ? "SCR":"SHM",
318 (sdreg.offset + 0x18000000), sdreg.func, val);
319 } else {
320 printf("DEBUG: %s: Indirect: Read 0x%08x, size %d, value 0x%04x\n",
321 (sel & 0x00020000) ? "SCR":"SHM",
322 (sdreg.offset + 0x18000000), sdreg.func, val);
323 }
324 }
325 return val;
326 }
327
328 static uint16
_dhd_get_d11obj16(macdbg_info_t * macdbg_info,uint16 objaddr,uint32 sel,d11obj_cache_t * obj_cache,struct bcmstrbuf * b,bool verbose)329 _dhd_get_d11obj16(macdbg_info_t *macdbg_info, uint16 objaddr,
330 uint32 sel, d11obj_cache_t *obj_cache, struct bcmstrbuf *b, bool verbose)
331 {
332 uint32 val;
333 if (obj_cache && obj_cache->cache_valid && ((obj_cache->sel ^ sel) & (0xffffff)) == 0) {
334 if (obj_cache->addr32 == (objaddr & ~0x3)) {
335 /* XXX: Same objaddr read as the previous one */
336 if (verbose) {
337 if (b) {
338 bcm_bprintf(b, "DEBUG: %s: Read cache value: "
339 "addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
340 (sel & 0x00020000) ? "SCR":"SHM",
341 obj_cache->addr32, obj_cache->sel, obj_cache->val);
342 } else {
343 printf("DEBUG: %s: Read cache value: "
344 "addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
345 (sel & 0x00020000) ? "SCR":"SHM",
346 obj_cache->addr32, obj_cache->sel, obj_cache->val);
347 }
348 }
349 val = obj_cache->val;
350 goto exit;
351 } else if ((obj_cache->sel & 0x02000000) &&
352 (obj_cache->addr32 + 4 == (objaddr & ~0x3))) {
353 /* XXX: objaddr is auto incrementing, so just read objdata */
354 if (verbose) {
355 if (b) {
356 bcm_bprintf(b, "DEBUG: %s: Read objdata only: "
357 "addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
358 (sel & 0x00020000) ? "SCR":"SHM",
359 obj_cache->addr32, obj_cache->sel, obj_cache->val);
360 } else {
361 printf("DEBUG: %s: Read objdata only: "
362 "addr32 0x%04x, sel 0x%08x, value 0x%08x\n",
363 (sel & 0x00020000) ? "SCR":"SHM",
364 obj_cache->addr32, obj_cache->sel, obj_cache->val);
365 }
366 }
367 val = _dhd_get_d11obj32(macdbg_info, 0xffff, sel, b, verbose);
368 goto exit;
369 }
370 }
371 val = _dhd_get_d11obj32(macdbg_info, (objaddr & ~0x2), sel, b, verbose);
372 exit:
373 if (obj_cache) {
374 obj_cache->addr32 = (objaddr & ~0x3);
375 obj_cache->sel = sel;
376 obj_cache->val = val;
377 obj_cache->cache_valid = TRUE;
378 }
379 return (uint16)((objaddr & 0x2) ? (val >> 16) : val);
380 }
381
382 static int
_dhd_print_d11reg(macdbg_info_t * macdbg_info,int idx,int type,uint16 addr,struct bcmstrbuf * b,d11obj_cache_t * obj_cache,bool verbose)383 _dhd_print_d11reg(macdbg_info_t *macdbg_info, int idx, int type, uint16 addr, struct bcmstrbuf *b,
384 d11obj_cache_t *obj_cache, bool verbose)
385 {
386 const char *regname[D11REG_TYPE_MAX] = D11REGTYPENAME;
387 uint32 val;
388
389 if (type == D11REG_TYPE_IHR32) {
390 if ((addr & 0x3)) {
391 printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr);
392 addr &= ~0x3;
393 }
394 val = _dhd_get_ihr32(macdbg_info, addr, b, verbose);
395 if (b) {
396 bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-8x\n",
397 idx, regname[type], addr, val);
398 } else {
399 printf("%-3d %s 0x%-4x = 0x%-8x\n",
400 idx, regname[type], addr, val);
401 }
402 } else {
403 switch (type) {
404 case D11REG_TYPE_IHR16: {
405 if ((addr & 0x1)) {
406 printf("%s: ERROR! Invalid addr 0x%x\n", __FUNCTION__, addr);
407 addr &= ~0x1;
408 }
409 val = _dhd_get_ihr16(macdbg_info, addr, b, verbose);
410 break;
411 }
412 case D11REG_TYPE_IHRX16:
413 val = _dhd_get_d11obj16(macdbg_info, (addr - 0x400) << 1, 0x020b0000,
414 obj_cache, b, verbose);
415 break;
416 case D11REG_TYPE_SCR:
417 val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x02020000,
418 obj_cache, b, verbose);
419 break;
420 case D11REG_TYPE_SCRX:
421 val = _dhd_get_d11obj16(macdbg_info, addr << 2, 0x020a0000,
422 obj_cache, b, verbose);
423 break;
424 case D11REG_TYPE_SHM:
425 val = _dhd_get_d11obj16(macdbg_info, addr, 0x02010000,
426 obj_cache, b, verbose);
427 break;
428 case D11REG_TYPE_SHMX:
429 val = _dhd_get_d11obj16(macdbg_info, addr, 0x02090000,
430 obj_cache, b, verbose);
431 break;
432 default:
433 printf("Unrecognized type %d!\n", type);
434 return 0;
435 }
436 if (b) {
437 bcm_bprintf(b, "%-3d %s 0x%-4x = 0x%-4x\n",
438 idx, regname[type], addr, val);
439 } else {
440 printf("%-3d %s 0x%-4x = 0x%-4x\n",
441 idx, regname[type], addr, val);
442 }
443 }
444 return 1;
445 }
446
447 static int
_dhd_print_d11regs(macdbg_info_t * macdbg_info,d11regs_list_t * pregs,int start_idx,struct bcmstrbuf * b,bool verbose)448 _dhd_print_d11regs(macdbg_info_t *macdbg_info, d11regs_list_t *pregs,
449 int start_idx, struct bcmstrbuf *b, bool verbose)
450 {
451 uint16 addr;
452 int idx = 0;
453 d11obj_cache_t obj_cache = {0, 0, 0, FALSE};
454
455 addr = pregs->addr;
456 if (pregs->type >= D11REG_TYPE_MAX) {
457 printf("%s: wrong type %d\n", __FUNCTION__, pregs->type);
458 return 0;
459 }
460 if (pregs->bitmap) {
461 while (pregs->bitmap) {
462 if (pregs->bitmap && (pregs->bitmap & 0x1)) {
463 _dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type,
464 addr, b, &obj_cache, verbose);
465 idx++;
466 }
467 pregs->bitmap = pregs->bitmap >> 1;
468 addr += pregs->step;
469 }
470 } else {
471 for (; idx < pregs->cnt; idx++) {
472 _dhd_print_d11reg(macdbg_info, (idx + start_idx), pregs->type,
473 addr, b, &obj_cache, verbose);
474 addr += pregs->step;
475 }
476 }
477 return idx;
478 }
479
480 static int
_dhd_pd11regs_bylist(macdbg_info_t * macdbg_info,d11regs_list_t * reglist,uint16 reglist_sz,struct bcmstrbuf * b)481 _dhd_pd11regs_bylist(macdbg_info_t *macdbg_info, d11regs_list_t *reglist,
482 uint16 reglist_sz, struct bcmstrbuf *b)
483 {
484 uint i, idx = 0;
485
486 if (reglist != NULL && reglist_sz > 0) {
487 for (i = 0; i < reglist_sz; i++) {
488 DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__,
489 ®list[i], reglist_sz));
490 idx += _dhd_print_d11regs(macdbg_info, ®list[i], idx, b, FALSE);
491 }
492 }
493 return idx;
494 }
495
496 int
dhd_macdbg_dumpmac(dhd_pub_t * dhdp,char * buf,int buflen,int * outbuflen,bool dump_x)497 dhd_macdbg_dumpmac(dhd_pub_t *dhdp, char *buf, int buflen,
498 int *outbuflen, bool dump_x)
499 {
500 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
501 struct bcmstrbuf *b = NULL;
502 struct bcmstrbuf bcmstrbuf;
503 uint cnt = 0;
504
505 DHD_TRACE(("%s %d %p %d %p %d %p %d\n", __FUNCTION__, __LINE__,
506 buf, buflen, macdbg_info->pd11regs, macdbg_info->d11regs_sz,
507 macdbg_info->pd11regs_x, macdbg_info->d11regsx_sz));
508
509 if (buf && buflen > 0) {
510 bcm_binit(&bcmstrbuf, buf, buflen);
511 b = &bcmstrbuf;
512 }
513 if (!dump_x) {
514 /* Dump PSMr */
515 cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs,
516 macdbg_info->d11regs_sz, b);
517 } else {
518 /* Dump PSMx */
519 cnt += _dhd_pd11regs_bylist(macdbg_info, macdbg_info->pd11regs_x,
520 macdbg_info->d11regsx_sz, b);
521 }
522
523 if (b && outbuflen) {
524 if ((uint)buflen > BCMSTRBUF_LEN(b)) {
525 *outbuflen = buflen - BCMSTRBUF_LEN(b);
526 } else {
527 DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__));
528 *outbuflen = buflen;
529 /* Do not return buftooshort to allow printing macregs we have got */
530 }
531 }
532
533 return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED);
534 }
535
536 int
dhd_macdbg_pd11regs(dhd_pub_t * dhdp,char * params,int plen,char * buf,int buflen)537 dhd_macdbg_pd11regs(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen)
538 {
539 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
540 dhd_pd11regs_param *pd11regs = (void *)params;
541 dhd_pd11regs_buf *pd11regs_buf = (void *)buf;
542 uint16 start_idx;
543 bool verbose;
544 d11regs_list_t reglist;
545 struct bcmstrbuf *b = NULL;
546 struct bcmstrbuf bcmstrbuf;
547
548 start_idx = pd11regs->start_idx;
549 verbose = pd11regs->verbose;
550 memcpy(®list, pd11regs->plist, sizeof(reglist));
551 memset(buf, '\0', buflen);
552 bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf),
553 (buflen - OFFSETOF(dhd_pd11regs_buf, pbuf)));
554 b = &bcmstrbuf;
555 pd11regs_buf->idx = (uint16)_dhd_print_d11regs(macdbg_info, ®list,
556 start_idx, b, verbose);
557
558 return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR);
559 }
560
561 int
dhd_macdbg_reglist(dhd_pub_t * dhdp,char * buf,int buflen)562 dhd_macdbg_reglist(dhd_pub_t *dhdp, char *buf, int buflen)
563 {
564 int err, desc_idx = 0;
565 dhd_maclist_t *maclist = (dhd_maclist_t *)buf;
566 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
567 void *xtlvbuf_p = maclist->plist;
568 uint16 xtlvbuflen = (uint16)buflen;
569 xtlv_desc_t xtlv_desc[] = {
570 {0, 0, NULL},
571 {0, 0, NULL},
572 {0, 0, NULL},
573 {0, 0, NULL}
574 };
575
576 if (!macdbg_info->pd11regs) {
577 err = BCME_NOTFOUND;
578 goto exit;
579 }
580 ASSERT(macdbg_info->d11regs_sz > 0);
581 xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_R;
582 xtlv_desc[desc_idx].len =
583 macdbg_info->d11regs_sz * (uint16)sizeof(*(macdbg_info->pd11regs));
584 xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs;
585 desc_idx++;
586
587 if (macdbg_info->pd11regs_x) {
588 ASSERT(macdbg_info->d11regsx_sz);
589 xtlv_desc[desc_idx].type = DHD_MACLIST_XTLV_X;
590 xtlv_desc[desc_idx].len = macdbg_info->d11regsx_sz *
591 (uint16)sizeof(*(macdbg_info->pd11regs_x));
592 xtlv_desc[desc_idx].ptr = macdbg_info->pd11regs_x;
593 desc_idx++;
594 }
595
596 if (macdbg_info->psvmpmems) {
597 ASSERT(macdbg_info->svmpmems_sz);
598 xtlv_desc[desc_idx].type = DHD_SVMPLIST_XTLV;
599 xtlv_desc[desc_idx].len = macdbg_info->svmpmems_sz *
600 (uint16)sizeof(*(macdbg_info->psvmpmems));
601 xtlv_desc[desc_idx].ptr = macdbg_info->psvmpmems;
602 desc_idx++;
603 }
604
605 err = bcm_pack_xtlv_buf_from_mem((uint8 **)&xtlvbuf_p, &xtlvbuflen,
606 xtlv_desc, BCM_XTLV_OPTION_ALIGN32);
607
608 maclist->version = 0; /* No version control for now anyway */
609 maclist->bytes_len = (buflen - xtlvbuflen);
610
611 exit:
612 return err;
613 }
614
615 static int
_dhd_print_svmps(macdbg_info_t * macdbg_info,svmp_list_t * psvmp,int start_idx,struct bcmstrbuf * b,bool verbose)616 _dhd_print_svmps(macdbg_info_t *macdbg_info, svmp_list_t *psvmp,
617 int start_idx, struct bcmstrbuf *b, bool verbose)
618 {
619 int idx;
620 uint32 addr, mem_id, offset, prev_mem_id, prev_offset;
621 uint16 cnt, val;
622
623 BCM_REFERENCE(start_idx);
624
625 /* Set tbl ID and tbl offset. */
626 _dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose);
627 _dhd_set_ihr32(macdbg_info, 0x3fc, 0x8000000e, b, verbose);
628
629 addr = psvmp->addr;
630 cnt = psvmp->cnt;
631
632 /* In validate previous mem_id and offset */
633 prev_mem_id = (uint32)(-1);
634 prev_offset = (uint32)(-1);
635
636 for (idx = 0; idx < cnt; idx++, addr++) {
637 mem_id = (addr >> 15);
638 offset = (addr & 0x7fff) >> 1;
639
640 if (mem_id != prev_mem_id) {
641 /* Set mem_id */
642 _dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id & 0xffff0000) | 0x10),
643 b, verbose);
644 _dhd_set_ihr32(macdbg_info, 0x3fc, ((mem_id << 16) | 0xf),
645 b, verbose);
646 }
647
648 if (offset != prev_offset) {
649 /* XXX: Is this needed?
650 * _dhd_set_ihr32(macdbg_info, 0x3fc, 0x30000d, b, verbose);
651 */
652 /* svmp offset */
653 _dhd_set_ihr32(macdbg_info, 0x3fc, ((offset << 16) | 0xe),
654 b, verbose);
655 }
656 /* Read hi or lo */
657 _dhd_set_ihr16(macdbg_info, 0x3fc, ((addr & 0x1) ? 0x10 : 0xf), b, verbose);
658 val = _dhd_get_ihr16(macdbg_info, 0x3fe, b, verbose);
659 if (b) {
660 bcm_bprintf(b, "0x%-4x 0x%-4x\n",
661 addr, val);
662
663 } else {
664 printf("0x%-4x 0x%-4x\n",
665 addr, val);
666 }
667 prev_mem_id = mem_id;
668 prev_offset = offset;
669 }
670 return idx;
671 }
672
673 static int
_dhd_psvmps_bylist(macdbg_info_t * macdbg_info,svmp_list_t * svmplist,uint16 svmplist_sz,struct bcmstrbuf * b)674 _dhd_psvmps_bylist(macdbg_info_t *macdbg_info, svmp_list_t *svmplist,
675 uint16 svmplist_sz, struct bcmstrbuf *b)
676 {
677 uint i, idx = 0;
678
679 if (svmplist != NULL && svmplist_sz > 0) {
680 for (i = 0; i < svmplist_sz; i++) {
681 DHD_TRACE(("%s %d %p %d\n", __FUNCTION__, __LINE__,
682 &svmplist[i], svmplist_sz));
683 idx += _dhd_print_svmps(macdbg_info, &svmplist[i], idx, b, FALSE);
684 }
685 }
686 return idx;
687 }
688
689 int
dhd_macdbg_dumpsvmp(dhd_pub_t * dhdp,char * buf,int buflen,int * outbuflen)690 dhd_macdbg_dumpsvmp(dhd_pub_t *dhdp, char *buf, int buflen,
691 int *outbuflen)
692 {
693 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
694 struct bcmstrbuf *b = NULL;
695 struct bcmstrbuf bcmstrbuf;
696 uint cnt = 0;
697
698 DHD_TRACE(("%s %d %p %d %p %d\n", __FUNCTION__, __LINE__,
699 buf, buflen, macdbg_info->psvmpmems, macdbg_info->svmpmems_sz));
700
701 if (buf && buflen > 0) {
702 bcm_binit(&bcmstrbuf, buf, buflen);
703 b = &bcmstrbuf;
704 }
705 cnt = _dhd_psvmps_bylist(macdbg_info, macdbg_info->psvmpmems,
706 macdbg_info->svmpmems_sz, b);
707
708 if (b && outbuflen) {
709 if ((uint)buflen > BCMSTRBUF_LEN(b)) {
710 *outbuflen = buflen - BCMSTRBUF_LEN(b);
711 } else {
712 DHD_ERROR(("%s: buflen insufficient!\n", __FUNCTION__));
713 *outbuflen = buflen;
714 /* Do not return buftooshort to allow printing macregs we have got */
715 }
716 }
717
718 return ((cnt > 0) ? BCME_OK : BCME_UNSUPPORTED);
719 }
720
721 int
dhd_macdbg_psvmpmems(dhd_pub_t * dhdp,char * params,int plen,char * buf,int buflen)722 dhd_macdbg_psvmpmems(dhd_pub_t *dhdp, char *params, int plen, char *buf, int buflen)
723 {
724 macdbg_info_t *macdbg_info = dhdp->macdbg_info;
725 dhd_pd11regs_param *pd11regs = (void *)params;
726 dhd_pd11regs_buf *pd11regs_buf = (void *)buf;
727 uint16 start_idx;
728 bool verbose;
729 svmp_list_t reglist;
730 struct bcmstrbuf *b = NULL;
731 struct bcmstrbuf bcmstrbuf;
732
733 start_idx = pd11regs->start_idx;
734 verbose = pd11regs->verbose;
735 memcpy(®list, pd11regs->plist, sizeof(reglist));
736 memset(buf, '\0', buflen);
737 bcm_binit(&bcmstrbuf, (char *)(pd11regs_buf->pbuf),
738 (buflen - OFFSETOF(dhd_pd11regs_buf, pbuf)));
739 b = &bcmstrbuf;
740 pd11regs_buf->idx = (uint16)_dhd_print_svmps(macdbg_info, ®list,
741 start_idx, b, verbose);
742
743 return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR);
744 }
745
746 #endif /* BCMDBG */
747