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