xref: /dragonfly/tools/tools/ath/athregs/dumpregs.c (revision 7d3e9a5b)
1 /*-
2  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer,
10  *    without modification.
11  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13  *    redistribution must be conditioned upon including a substantially
14  *    similar Disclaimer requirement for further binary redistribution.
15  *
16  * NO WARRANTY
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY
20  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27  * THE POSSIBILITY OF SUCH DAMAGES.
28  *
29  * $FreeBSD: src/tools/tools/ath/athregs/dumpregs.c,v 1.1 2008/12/07 19:17:33 sam Exp $
30  */
31 #include "diag.h"
32 
33 #include "ah.h"
34 #include "ah_internal.h"
35 /* XXX cheat, 5212 has a superset of the key table defs */
36 #include "ar5212/ar5212reg.h"
37 
38 #include "dumpregs.h"
39 
40 #include <getopt.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <ctype.h>
44 
45 typedef struct {
46 	HAL_REVS revs;
47 	u_int32_t regdata[0xffff / sizeof(u_int32_t)];
48 #define	MAXREGS	5*1024
49 	struct dumpreg *regs[MAXREGS];
50 	u_int nregs;
51 	u_int	show_names	: 1,
52 		show_addrs	: 1;
53 } dumpregs_t;
54 static	dumpregs_t state;
55 
56 #undef OS_REG_READ
57 #define	OS_REG_READ(ah, off)	state.regdata[(off) >> 2]
58 
59 static	int ath_hal_anyregs(int what);
60 static	int ath_hal_setupregs(struct ath_diag *atd, int what);
61 static	u_int ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr);
62 static	void ath_hal_dumpregs(FILE *fd, int what);
63 static	void ath_hal_dumprange(FILE *fd, u_int a, u_int b);
64 static	void ath_hal_dumpkeycache(FILE *fd, int nkeys);
65 static	void ath_hal_dumpint(FILE *fd, int what);
66 static	void ath_hal_dumpqcu(FILE *fd, int what);
67 static	void ath_hal_dumpdcu(FILE *fd, int what);
68 static	void ath_hal_dumpbb(FILE *fd, int what);
69 
70 static void
71 usage(void)
72 {
73 	fprintf(stderr, "usage: athregs [-i interface] [-abdkmqxz]\n");
74 	fprintf(stderr, "-a	display all registers\n");
75 	fprintf(stderr, "-b	display baseband registers\n");
76 	fprintf(stderr, "-d	display DCU registers\n");
77 	fprintf(stderr, "-k	display key cache registers\n");
78 	fprintf(stderr, "-m	display \"MAC\" registers (default)\n");
79 	fprintf(stderr, "-q	display QCU registers\n");
80 	fprintf(stderr, "-x	display XR registers\n");
81 	fprintf(stderr, "-z	display interrupt registers\n");
82 	fprintf(stderr, "\n");
83 	fprintf(stderr, "-A	display register address\n");
84 	fprintf(stderr, "-N	suppress display of register name\n");
85 	exit(-1);
86 }
87 
88 int
89 main(int argc, char *argv[])
90 {
91 	struct ath_diag atd;
92 	const char *ifname;
93 	u_int32_t *data;
94 	u_int32_t *dp, *ep;
95 	int what, c, s, i;
96 
97 	s = socket(AF_INET, SOCK_DGRAM, 0);
98 	if (s < 0)
99 		err(1, "socket");
100 	ifname = getenv("ATH");
101 	if (!ifname)
102 		ifname = ATH_DEFAULT;
103 
104 	what = 0;
105 	state.show_addrs = 0;
106 	state.show_names = 1;
107 	while ((c = getopt(argc, argv, "i:aAbdkmNqxz")) != -1)
108 		switch (c) {
109 		case 'a':
110 			what |= DUMP_ALL;
111 			break;
112 		case 'A':
113 			state.show_addrs = 1;
114 			break;
115 		case 'b':
116 			what |= DUMP_BASEBAND;
117 			break;
118 		case 'd':
119 			what |= DUMP_DCU;
120 			break;
121 		case 'k':
122 			what |= DUMP_KEYCACHE;
123 			break;
124 		case 'i':
125 			ifname = optarg;
126 			break;
127 		case 'm':
128 			what |= DUMP_BASIC;
129 			break;
130 		case 'N':
131 			state.show_names = 0;
132 			break;
133 		case 'q':
134 			what |= DUMP_QCU;
135 			break;
136 		case 'x':
137 			what |= DUMP_XR;
138 			break;
139 		case 'z':
140 			what |= DUMP_INTERRUPT;
141 			break;
142 		default:
143 			usage();
144 			/*NOTREACHED*/
145 		}
146 	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
147 
148 	argc -= optind;
149 	argv += optind;
150 	if (what == 0)
151 		what = DUMP_BASIC;
152 
153 	atd.ad_id = HAL_DIAG_REVS;
154 	atd.ad_out_data = (caddr_t) &state.revs;
155 	atd.ad_out_size = sizeof(state.revs);
156 	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
157 		err(1, atd.ad_name);
158 
159 	if (ath_hal_setupregs(&atd, what) == 0)
160 		errx(-1, "no registers are known for this part "
161 		    "(devid 0x%x mac %d.%d phy %d)", state.revs.ah_devid,
162 		    state.revs.ah_macVersion, state.revs.ah_macRev,
163 		    state.revs.ah_phyRev);
164 
165 	atd.ad_out_size = ath_hal_setupdiagregs((HAL_REGRANGE *) atd.ad_in_data,
166 		atd.ad_in_size / sizeof(HAL_REGRANGE));
167 	atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
168 	if (atd.ad_out_data == NULL) {
169 		fprintf(stderr, "Cannot malloc output buffer, size %u\n",
170 			atd.ad_out_size);
171 		exit(-1);
172 	}
173 	atd.ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN;
174 	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
175 		err(1, atd.ad_name);
176 
177 	/*
178 	 * Expand register data into global space that can be
179 	 * indexed directly by register offset.
180 	 */
181 	dp = (u_int32_t *)atd.ad_out_data;
182 	ep = (u_int32_t *)(atd.ad_out_data + atd.ad_out_size);
183 	while (dp < ep) {
184 		u_int r = dp[0] >> 16;		/* start of range */
185 		u_int e = dp[0] & 0xffff;	/* end of range */
186 		dp++;
187 		/* convert offsets to indices */
188 		r >>= 2; e >>= 2;
189 		do {
190 			if (dp >= ep) {
191 				fprintf(stderr, "Warning, botched return data;"
192 					"register at offset 0x%x not present\n",
193 					r << 2);
194 				break;
195 			}
196 			state.regdata[r++] = *dp++;
197 		} while (r <= e);
198 	}
199 
200 	if (what & DUMP_BASIC)
201 		ath_hal_dumpregs(stdout, DUMP_BASIC);
202 	if ((what & DUMP_INTERRUPT) && ath_hal_anyregs(DUMP_INTERRUPT)) {
203 		if (what & DUMP_BASIC)
204 			putchar('\n');
205 		if (state.show_addrs)
206 			ath_hal_dumpregs(stdout, DUMP_INTERRUPT);
207 		else
208 			ath_hal_dumpint(stdout, what);
209 	}
210 	if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) {
211 		if (what & (DUMP_BASIC|DUMP_INTERRUPT))
212 			putchar('\n');
213 		if (state.show_addrs)
214 			ath_hal_dumpregs(stdout, DUMP_QCU);
215 		else
216 			ath_hal_dumpqcu(stdout, what);
217 	}
218 	if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) {
219 		if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU))
220 			putchar('\n');
221 		if (state.show_addrs)
222 			ath_hal_dumpregs(stdout, DUMP_DCU);
223 		else
224 			ath_hal_dumpdcu(stdout, what);
225 	}
226 	if (what & DUMP_KEYCACHE) {
227 		if (state.show_addrs) {
228 			if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU))
229 				putchar('\n');
230 			ath_hal_dumpregs(stdout, DUMP_KEYCACHE);
231 		} else
232 			ath_hal_dumpkeycache(stdout, 128);
233 	}
234 	if (what & DUMP_BASEBAND) {
235 		if (what &~ DUMP_BASEBAND)
236 			fprintf(stdout, "\n");
237 		ath_hal_dumpbb(stdout, what);
238 	}
239 	return 0;
240 }
241 
242 static int
243 regcompar(const void *a, const void *b)
244 {
245 	const struct dumpreg *ra = *(const struct dumpreg **)a;
246 	const struct dumpreg *rb = *(const struct dumpreg **)b;
247 	return ra->addr - rb->addr;
248 }
249 
250 void
251 register_regs(struct dumpreg *chipregs, u_int nchipregs,
252 	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
253 {
254 	const int existing_regs = state.nregs;
255 	int i, j;
256 
257 	for (i = 0; i < nchipregs; i++) {
258 		struct dumpreg *nr = &chipregs[i];
259 		if (nr->srevMin == 0)
260 			nr->srevMin = def_srev_min;
261 		if (nr->srevMax == 0)
262 			nr->srevMax = def_srev_max;
263 		if (nr->phyMin == 0)
264 			nr->phyMin = def_phy_min;
265 		if (nr->phyMax == 0)
266 			nr->phyMax = def_phy_max;
267 		for (j = 0; j < existing_regs; j++) {
268 			struct dumpreg *r = state.regs[j];
269 			/*
270 			 * Check if we can just expand the mac+phy
271 			 * coverage for the existing entry.
272 			 */
273 			if (nr->addr == r->addr &&
274 			    (nr->name == r->name ||
275 			     nr->name != NULL && r->name != NULL &&
276 			     strcmp(nr->name, r->name) == 0)) {
277 				if (nr->srevMin < r->srevMin &&
278 				    (r->srevMin <= nr->srevMax &&
279 				     nr->srevMax+1 <= r->srevMax)) {
280 					r->srevMin = nr->srevMin;
281 					goto skip;
282 				}
283 				if (nr->srevMax > r->srevMax &&
284 				    (r->srevMin <= nr->srevMin &&
285 				     nr->srevMin <= r->srevMax)) {
286 					r->srevMax = nr->srevMax;
287 					goto skip;
288 				}
289 			}
290 			if (r->addr > nr->addr)
291 				break;
292 		}
293 		/*
294 		 * New item, add to the end, it'll be sorted below.
295 		 */
296 		if (state.nregs == MAXREGS)
297 			errx(-1, "too many registers; bump MAXREGS");
298 		state.regs[state.nregs++] = nr;
299 	skip:
300 		;
301 	}
302 	qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar);
303 }
304 
305 void
306 register_keycache(u_int nslots,
307 	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
308 {
309 #define	SET(r, a) do { \
310 	r->addr = a; r->type = DUMP_KEYCACHE; r++; \
311 } while(0)
312 	struct dumpreg *keyregs, *r;
313 	int i;
314 
315 	keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg));
316 	if (keyregs == NULL)
317 		errx(-1, "no space to %d keycache slots\n", nslots);
318 	r = keyregs;
319 	for (i = 0; i < nslots; i++) {
320 		SET(r, AR_KEYTABLE_KEY0(i));
321 		SET(r, AR_KEYTABLE_KEY1(i));
322 		SET(r, AR_KEYTABLE_KEY2(i));
323 		SET(r, AR_KEYTABLE_KEY3(i));
324 		SET(r, AR_KEYTABLE_KEY4(i));
325 		SET(r, AR_KEYTABLE_TYPE(i));
326 		SET(r, AR_KEYTABLE_MAC0(i));
327 		SET(r, AR_KEYTABLE_MAC1(i));
328 	}
329 	register_regs(keyregs, 8*nslots,
330 	    def_srev_min, def_srev_max, def_phy_min, def_phy_max);
331 #undef SET
332 }
333 
334 void
335 register_range(u_int brange, u_int erange, int type,
336 	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
337 {
338 	struct dumpreg *bbregs, *r;
339 	int i, nregs;
340 
341 	nregs = (erange - brange) / sizeof(uint32_t);
342 	bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg));
343 	if (bbregs == NULL)
344 		errx(-1, "no space for %d register slots (type %d)\n",
345 		    nregs, type);
346 	r = bbregs;
347 	for (i = 0; i < nregs; i++) {
348 		r->addr = brange + (i<<2);
349 		r->type = type;
350 		r++;
351 	}
352 	register_regs(bbregs, nregs,
353 	    def_srev_min, def_srev_max, def_phy_min, def_phy_max);
354 }
355 
356 static __inline
357 match(const struct dumpreg *dr, const HAL_REVS *revs)
358 {
359 	if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev))
360 		return 0;
361 	if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev))
362 		return 0;
363 	return 1;
364 }
365 
366 static int
367 ath_hal_anyregs(int what)
368 {
369 	const HAL_REVS *revs = &state.revs;
370 	int i;
371 
372 	for (i = 0; i < state.nregs; i++) {
373 		const struct dumpreg *dr = state.regs[i];
374 		if ((what & dr->type) && match(dr, revs))
375 			return 1;
376 	}
377 	return 0;
378 }
379 
380 static int
381 ath_hal_setupregs(struct ath_diag *atd, int what)
382 {
383 	const HAL_REVS *revs = &state.revs;
384 	HAL_REGRANGE r;
385 	size_t space = 0;
386 	u_int8_t *cp;
387 	int i, brun, erun;
388 
389 	brun = erun = -1;
390 	for (i = 0; i < state.nregs; i++) {
391 		const struct dumpreg *dr = state.regs[i];
392 		if ((what & dr->type) && match(dr, revs)) {
393 			if (erun + 4 != dr->addr) {
394 				if (brun != -1)
395 					space += sizeof(HAL_REGRANGE);
396 				brun = erun = dr->addr;
397 			} else
398 				erun = dr->addr;
399 		}
400 	}
401 	space += sizeof(HAL_REGRANGE);
402 
403 	atd->ad_in_data = (caddr_t) malloc(space);
404 	if (atd->ad_in_data == NULL) {
405 		fprintf(stderr, "Cannot malloc memory for registers!\n");
406 		exit(-1);
407 	}
408 	atd->ad_in_size = space;
409 	cp = (u_int8_t *) atd->ad_in_data;
410 	brun = erun = -1;
411 	for (i = 0; i < state.nregs; i++) {
412 		const struct dumpreg *dr = state.regs[i];
413 		if ((what & dr->type) && match(dr, revs)) {
414 			if (erun + 4 != dr->addr) {
415 				if (brun != -1) {
416 					r.start = brun, r.end = erun;
417 					memcpy(cp, &r, sizeof(r));
418 					cp += sizeof(r);
419 				}
420 				brun = erun = dr->addr;
421 			} else
422 				erun = dr->addr;
423 		}
424 	}
425 	if (brun != -1) {
426 		r.start = brun, r.end = erun;
427 		memcpy(cp, &r, sizeof(r));
428 		cp += sizeof(r);
429 	}
430 	return space / sizeof(uint32_t);
431 }
432 
433 static void
434 ath_hal_dumpregs(FILE *fd, int what)
435 {
436 	const HAL_REVS *revs = &state.revs;
437 	const char *sep = "";
438 	int i, count, itemsperline;
439 
440 	count = 0;
441 	itemsperline = 4;
442 	if (state.show_names && state.show_addrs)
443 		itemsperline--;
444 	for (i = 0; i < state.nregs; i++) {
445 		const struct dumpreg *dr = state.regs[i];
446 		if ((what & dr->type) && match(dr, revs)) {
447 			if (state.show_names && dr->name != NULL) {
448 				fprintf(fd, "%s%-8s", sep, dr->name);
449 				if (state.show_addrs)
450 					fprintf(fd, " [%04x]", dr->addr);
451 			} else
452 				fprintf(fd, "%s%04x", sep, dr->addr);
453 			fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr));
454 			sep = " ";
455 			if ((++count % itemsperline) == 0)
456 				sep = "\n";
457 		}
458 	}
459 	if (count)
460 		fprintf(fd, "\n");
461 }
462 
463 static void
464 ath_hal_dumprange(FILE *fd, u_int a, u_int b)
465 {
466 	u_int r;
467 
468 	for (r = a; r+16 <= b; r += 5*4)
469 		fprintf(fd,
470 			"%04x %08x  %04x %08x  %04x %08x  %04x %08x  %04x %08x\n"
471 			, r, OS_REG_READ(ah, r)
472 			, r+4, OS_REG_READ(ah, r+4)
473 			, r+8, OS_REG_READ(ah, r+8)
474 			, r+12, OS_REG_READ(ah, r+12)
475 			, r+16, OS_REG_READ(ah, r+16)
476 		);
477 	switch (b-r) {
478 	case 16:
479 		fprintf(fd
480 			, "%04x %08x  %04x %08x  %04x %08x  %04x %08x\n"
481 			, r, OS_REG_READ(ah, r)
482 			, r+4, OS_REG_READ(ah, r+4)
483 			, r+8, OS_REG_READ(ah, r+8)
484 			, r+12, OS_REG_READ(ah, r+12)
485 		);
486 		break;
487 	case 12:
488 		fprintf(fd, "%04x %08x  %04x %08x  %04x %08x\n"
489 			, r, OS_REG_READ(ah, r)
490 			, r+4, OS_REG_READ(ah, r+4)
491 			, r+8, OS_REG_READ(ah, r+8)
492 		);
493 		break;
494 	case 8:
495 		fprintf(fd, "%04x %08x  %04x %08x\n"
496 			, r, OS_REG_READ(ah, r)
497 			, r+4, OS_REG_READ(ah, r+4)
498 		);
499 		break;
500 	case 4:
501 		fprintf(fd, "%04x %08x\n"
502 			, r, OS_REG_READ(ah, r)
503 		);
504 		break;
505 	}
506 }
507 
508 static void
509 ath_hal_dumpint(FILE *fd, int what)
510 {
511 	int i;
512 
513 	/* Interrupt registers */
514 	fprintf(fd, "IMR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
515 		, OS_REG_READ(ah, AR_IMR)
516 		, OS_REG_READ(ah, AR_IMR_S0)
517 		, OS_REG_READ(ah, AR_IMR_S1)
518 		, OS_REG_READ(ah, AR_IMR_S2)
519 		, OS_REG_READ(ah, AR_IMR_S3)
520 		, OS_REG_READ(ah, AR_IMR_S4)
521 	);
522 	fprintf(fd, "ISR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
523 		, OS_REG_READ(ah, AR_ISR)
524 		, OS_REG_READ(ah, AR_ISR_S0)
525 		, OS_REG_READ(ah, AR_ISR_S1)
526 		, OS_REG_READ(ah, AR_ISR_S2)
527 		, OS_REG_READ(ah, AR_ISR_S3)
528 		, OS_REG_READ(ah, AR_ISR_S4)
529 	);
530 }
531 
532 static void
533 ath_hal_dumpqcu(FILE *fd, int what)
534 {
535 	int i;
536 
537 	/* QCU registers */
538 	fprintf(fd, "%-8s %08x  %-8s %08x  %-8s %08x\n"
539 		, "Q_TXE", OS_REG_READ(ah, AR_Q_TXE)
540 		, "Q_TXD", OS_REG_READ(ah, AR_Q_TXD)
541 		, "Q_RDYTIMSHD", OS_REG_READ(ah, AR_Q_RDYTIMESHDN)
542 	);
543 	fprintf(fd, "Q_ONESHOTARM_SC %08x  Q_ONESHOTARM_CC %08x\n"
544 		, OS_REG_READ(ah, AR_Q_ONESHOTARM_SC)
545 		, OS_REG_READ(ah, AR_Q_ONESHOTARM_CC)
546 	);
547 	for (i = 0; i < 10; i++)
548 		fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n"
549 			, i
550 			, OS_REG_READ(ah, AR_QTXDP(i))
551 			, OS_REG_READ(ah, AR_QCBRCFG(i))
552 			, OS_REG_READ(ah, AR_QRDYTIMECFG(i))
553 			, OS_REG_READ(ah, AR_QMISC(i))
554 			, OS_REG_READ(ah, AR_QSTS(i))
555 		);
556 }
557 
558 static void
559 ath_hal_dumpdcu(FILE *fd, int what)
560 {
561 	int i;
562 
563 	/* DCU registers */
564 	for (i = 0; i < 10; i++)
565 		fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n"
566 			, i
567 			, OS_REG_READ(ah, AR_DQCUMASK(i))
568 			, OS_REG_READ(ah, AR_DLCL_IFS(i))
569 			, OS_REG_READ(ah, AR_DRETRY_LIMIT(i))
570 			, OS_REG_READ(ah, AR_DCHNTIME(i))
571 			, OS_REG_READ(ah, AR_DMISC(i))
572 		);
573 }
574 
575 static void
576 ath_hal_dumpbb(FILE *fd, int what)
577 {
578 	const HAL_REVS *revs = &state.revs;
579 	int i, brun, erun;
580 
581 	brun = erun = 0;
582 	for (i = 0; i < state.nregs; i++) {
583 		const struct dumpreg *dr = state.regs[i];
584 		if (!match(dr, revs))
585 			continue;
586 		if (dr->type & DUMP_BASEBAND) {
587 			if (brun == 0) {
588 				brun = erun = dr->addr;
589 			} else if (dr->addr == erun + sizeof(uint32_t)) {
590 				erun = dr->addr;
591 			} else {
592 				ath_hal_dumprange(fd, brun, erun);
593 				brun = erun = dr->addr;
594 			}
595 		} else {
596 			if (brun != 0)
597 				ath_hal_dumprange(fd, brun, erun);
598 			brun = erun = 0;
599 		}
600 	}
601 	if (brun != 0)
602 		ath_hal_dumprange(fd, brun, erun);
603 }
604 
605 static u_int
606 ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr)
607 {
608 	u_int space;
609 	int i;
610 
611 	space = 0;
612 	for (i = 0; i < nr; i++) {
613 		u_int n = 2 * sizeof(u_int32_t);	/* reg range + first */
614 		if (regs[i].end) {
615 			if (regs[i].end < regs[i].start) {
616 				fprintf(stderr, "%s: bad register range, "
617 					"end 0x%x < start 0x%x\n",
618 					__func__, regs[i].end, regs[i].end);
619 				exit(-1);
620 			}
621 			n += regs[i].end - regs[i].start;
622 		}
623 		space += n;
624 	}
625 	return space;
626 }
627 
628 /*
629  * Format an Ethernet MAC for printing.
630  */
631 static const char*
632 ether_sprintf(const u_int8_t *mac)
633 {
634 	static char etherbuf[18];
635 	snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
636 		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
637 	return etherbuf;
638 }
639 
640 #ifndef isclr
641 #define	setbit(a,i)	((a)[(i)/NBBY] |= 1<<((i)%NBBY))
642 #define	clrbit(a,i)	((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
643 #define	isset(a,i)	((a)[(i)/NBBY] & (1<<((i)%NBBY)))
644 #define	isclr(a,i)	(((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
645 #endif
646 
647 static void
648 ath_hal_dumpkeycache(FILE *fd, int nkeys)
649 {
650 	static const char *keytypenames[] = {
651 		"WEP-40", 	/* AR_KEYTABLE_TYPE_40 */
652 		"WEP-104",	/* AR_KEYTABLE_TYPE_104 */
653 		"#2",
654 		"WEP-128",	/* AR_KEYTABLE_TYPE_128 */
655 		"TKIP",		/* AR_KEYTABLE_TYPE_TKIP */
656 		"AES-OCB",	/* AR_KEYTABLE_TYPE_AES */
657 		"AES-CCM",	/* AR_KEYTABLE_TYPE_CCM */
658 		"CLR",		/* AR_KEYTABLE_TYPE_CLR */
659 	};
660 	int micEnabled = SREV(state.revs.ah_macVersion, state.revs.ah_macRev) < SREV(4,8) ? 0 :
661 	       OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_CRPT_MIC_ENABLE;
662 	u_int8_t mac[IEEE80211_ADDR_LEN];
663 	u_int8_t ismic[128/NBBY];
664 	int entry;
665 	int first = 1;
666 
667 	memset(ismic, 0, sizeof(ismic));
668 	for (entry = 0; entry < nkeys; entry++) {
669 		u_int32_t macLo, macHi, type;
670 		u_int32_t key0, key1, key2, key3, key4;
671 
672 		macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
673 		if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry))
674 			continue;
675 		macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry));
676 		macHi <<= 1;
677 		if (macLo & (1<<31))
678 			macHi |= 1;
679 		macLo <<= 1;
680 		mac[4] = macHi & 0xff;
681 		mac[5] = macHi >> 8;
682 		mac[0] = macLo & 0xff;
683 		mac[1] = macLo >> 8;
684 		mac[2] = macLo >> 16;
685 		mac[3] = macLo >> 24;
686 		type = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));
687 		if ((type & 7) == AR_KEYTABLE_TYPE_TKIP && micEnabled)
688 			setbit(ismic, entry+64);
689 		key0 = OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry));
690 		key1 = OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry));
691 		key2 = OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry));
692 		key3 = OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry));
693 		key4 = OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry));
694 		if (first) {
695 			fprintf(fd, "\n");
696 			first = 0;
697 		}
698 		fprintf(fd, "KEY[%03u] MAC %s %-7s %02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x\n"
699 			, entry
700 			, ether_sprintf(mac)
701 			, isset(ismic, entry) ? "MIC" : keytypenames[type & 7]
702 			, (key0 >>  0) & 0xff
703 			, (key0 >>  8) & 0xff
704 			, (key0 >> 16) & 0xff
705 			, (key0 >> 24) & 0xff
706 			, (key1 >>  0) & 0xff
707 			, (key1 >>  8) & 0xff
708 			, (key2 >>  0) & 0xff
709 			, (key2 >>  8) & 0xff
710 			, (key2 >> 16) & 0xff
711 			, (key2 >> 24) & 0xff
712 			, (key3 >>  0) & 0xff
713 			, (key3 >>  8) & 0xff
714 			, (key4 >>  0) & 0xff
715 			, (key4 >>  8) & 0xff
716 			, (key4 >> 16) & 0xff
717 			, (key4 >> 24) & 0xff
718 		);
719 	}
720 }
721