xref: /OK3568_Linux_fs/kernel/drivers/net/wireless/rockchip_wlan/rkwifi/bcmdhd/dhd_macdbg.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 				&reglist[i], reglist_sz));
490 			idx += _dhd_print_d11regs(macdbg_info, &reglist[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(&reglist, 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, &reglist,
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(&reglist, 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, &reglist,
741 		start_idx, b, verbose);
742 
743 	return ((pd11regs_buf->idx > 0) ? BCME_OK : BCME_ERROR);
744 }
745 
746 #endif /* BCMDBG */
747