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