1185743Ssam/*-
2185743Ssam * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3185743Ssam * All rights reserved.
4185743Ssam *
5185743Ssam * Redistribution and use in source and binary forms, with or without
6185743Ssam * modification, are permitted provided that the following conditions
7185743Ssam * are met:
8185743Ssam * 1. Redistributions of source code must retain the above copyright
9185743Ssam *    notice, this list of conditions and the following disclaimer,
10185743Ssam *    without modification.
11185743Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12185743Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13185743Ssam *    redistribution must be conditioned upon including a substantially
14185743Ssam *    similar Disclaimer requirement for further binary redistribution.
15185743Ssam *
16185743Ssam * NO WARRANTY
17185743Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18185743Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19185743Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20185743Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21185743Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22185743Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23185743Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24185743Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25185743Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26185743Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27185743Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28185743Ssam *
29185743Ssam * $FreeBSD$
30185743Ssam */
31185743Ssam#include "diag.h"
32185743Ssam
33185743Ssam#include "ah.h"
34185743Ssam#include "ah_internal.h"
35185743Ssam/* XXX cheat, 5212 has a superset of the key table defs */
36185743Ssam#include "ar5212/ar5212reg.h"
37185743Ssam
38185743Ssam#include "dumpregs.h"
39185743Ssam
40185743Ssam#include <getopt.h>
41185743Ssam#include <stdlib.h>
42185743Ssam#include <string.h>
43185743Ssam#include <ctype.h>
44217680Sadrian#include <err.h>
45185743Ssam
46185743Ssamtypedef struct {
47185743Ssam	HAL_REVS revs;
48185743Ssam	u_int32_t regdata[0xffff / sizeof(u_int32_t)];
49185743Ssam#define	MAXREGS	5*1024
50185743Ssam	struct dumpreg *regs[MAXREGS];
51185743Ssam	u_int nregs;
52185743Ssam	u_int	show_names	: 1,
53185743Ssam		show_addrs	: 1;
54185743Ssam} dumpregs_t;
55185743Ssamstatic	dumpregs_t state;
56185743Ssam
57185743Ssam#undef OS_REG_READ
58185743Ssam#define	OS_REG_READ(ah, off)	state.regdata[(off) >> 2]
59185743Ssam
60185743Ssamstatic	int ath_hal_anyregs(int what);
61185743Ssamstatic	int ath_hal_setupregs(struct ath_diag *atd, int what);
62185743Ssamstatic	u_int ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr);
63185743Ssamstatic	void ath_hal_dumpregs(FILE *fd, int what);
64185743Ssamstatic	void ath_hal_dumprange(FILE *fd, u_int a, u_int b);
65185743Ssamstatic	void ath_hal_dumpkeycache(FILE *fd, int nkeys);
66185743Ssamstatic	void ath_hal_dumpint(FILE *fd, int what);
67185743Ssamstatic	void ath_hal_dumpqcu(FILE *fd, int what);
68185743Ssamstatic	void ath_hal_dumpdcu(FILE *fd, int what);
69185743Ssamstatic	void ath_hal_dumpbb(FILE *fd, int what);
70185743Ssam
71185743Ssamstatic void
72185743Ssamusage(void)
73185743Ssam{
74185743Ssam	fprintf(stderr, "usage: athregs [-i interface] [-abdkmqxz]\n");
75185743Ssam	fprintf(stderr, "-a	display all registers\n");
76185743Ssam	fprintf(stderr, "-b	display baseband registers\n");
77185743Ssam	fprintf(stderr, "-d	display DCU registers\n");
78185743Ssam	fprintf(stderr, "-k	display key cache registers\n");
79185743Ssam	fprintf(stderr, "-m	display \"MAC\" registers (default)\n");
80185743Ssam	fprintf(stderr, "-q	display QCU registers\n");
81185743Ssam	fprintf(stderr, "-x	display XR registers\n");
82185743Ssam	fprintf(stderr, "-z	display interrupt registers\n");
83185743Ssam	fprintf(stderr, "\n");
84185743Ssam	fprintf(stderr, "-A	display register address\n");
85185743Ssam	fprintf(stderr, "-N	suppress display of register name\n");
86185743Ssam	exit(-1);
87185743Ssam}
88185743Ssam
89185743Ssamint
90185743Ssammain(int argc, char *argv[])
91185743Ssam{
92185743Ssam	struct ath_diag atd;
93185743Ssam	const char *ifname;
94185743Ssam	u_int32_t *data;
95185743Ssam	u_int32_t *dp, *ep;
96185743Ssam	int what, c, s, i;
97185743Ssam
98185743Ssam	s = socket(AF_INET, SOCK_DGRAM, 0);
99185743Ssam	if (s < 0)
100185743Ssam		err(1, "socket");
101185743Ssam	ifname = getenv("ATH");
102185743Ssam	if (!ifname)
103185743Ssam		ifname = ATH_DEFAULT;
104185743Ssam
105185743Ssam	what = 0;
106185743Ssam	state.show_addrs = 0;
107185743Ssam	state.show_names = 1;
108185743Ssam	while ((c = getopt(argc, argv, "i:aAbdkmNqxz")) != -1)
109185743Ssam		switch (c) {
110185743Ssam		case 'a':
111185743Ssam			what |= DUMP_ALL;
112185743Ssam			break;
113185743Ssam		case 'A':
114185743Ssam			state.show_addrs = 1;
115185743Ssam			break;
116185743Ssam		case 'b':
117185743Ssam			what |= DUMP_BASEBAND;
118185743Ssam			break;
119185743Ssam		case 'd':
120185743Ssam			what |= DUMP_DCU;
121185743Ssam			break;
122185743Ssam		case 'k':
123185743Ssam			what |= DUMP_KEYCACHE;
124185743Ssam			break;
125185743Ssam		case 'i':
126185743Ssam			ifname = optarg;
127185743Ssam			break;
128185743Ssam		case 'm':
129185743Ssam			what |= DUMP_BASIC;
130185743Ssam			break;
131185743Ssam		case 'N':
132185743Ssam			state.show_names = 0;
133185743Ssam			break;
134185743Ssam		case 'q':
135185743Ssam			what |= DUMP_QCU;
136185743Ssam			break;
137185743Ssam		case 'x':
138185743Ssam			what |= DUMP_XR;
139185743Ssam			break;
140185743Ssam		case 'z':
141185743Ssam			what |= DUMP_INTERRUPT;
142185743Ssam			break;
143185743Ssam		default:
144185743Ssam			usage();
145185743Ssam			/*NOTREACHED*/
146185743Ssam		}
147185743Ssam	strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
148185743Ssam
149185743Ssam	argc -= optind;
150185743Ssam	argv += optind;
151185743Ssam	if (what == 0)
152185743Ssam		what = DUMP_BASIC;
153185743Ssam
154185743Ssam	atd.ad_id = HAL_DIAG_REVS;
155185743Ssam	atd.ad_out_data = (caddr_t) &state.revs;
156185743Ssam	atd.ad_out_size = sizeof(state.revs);
157185743Ssam	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
158185743Ssam		err(1, atd.ad_name);
159185743Ssam
160185743Ssam	if (ath_hal_setupregs(&atd, what) == 0)
161185743Ssam		errx(-1, "no registers are known for this part "
162185743Ssam		    "(devid 0x%x mac %d.%d phy %d)", state.revs.ah_devid,
163185743Ssam		    state.revs.ah_macVersion, state.revs.ah_macRev,
164185743Ssam		    state.revs.ah_phyRev);
165185743Ssam
166185743Ssam	atd.ad_out_size = ath_hal_setupdiagregs((HAL_REGRANGE *) atd.ad_in_data,
167185743Ssam		atd.ad_in_size / sizeof(HAL_REGRANGE));
168185743Ssam	atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
169185743Ssam	if (atd.ad_out_data == NULL) {
170185743Ssam		fprintf(stderr, "Cannot malloc output buffer, size %u\n",
171185743Ssam			atd.ad_out_size);
172185743Ssam		exit(-1);
173185743Ssam	}
174185743Ssam	atd.ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN;
175185743Ssam	if (ioctl(s, SIOCGATHDIAG, &atd) < 0)
176185743Ssam		err(1, atd.ad_name);
177185743Ssam
178185743Ssam	/*
179185743Ssam	 * Expand register data into global space that can be
180185743Ssam	 * indexed directly by register offset.
181185743Ssam	 */
182185743Ssam	dp = (u_int32_t *)atd.ad_out_data;
183185743Ssam	ep = (u_int32_t *)(atd.ad_out_data + atd.ad_out_size);
184185743Ssam	while (dp < ep) {
185185743Ssam		u_int r = dp[0] >> 16;		/* start of range */
186185743Ssam		u_int e = dp[0] & 0xffff;	/* end of range */
187185743Ssam		dp++;
188185743Ssam		/* convert offsets to indices */
189185743Ssam		r >>= 2; e >>= 2;
190185743Ssam		do {
191185743Ssam			if (dp >= ep) {
192185743Ssam				fprintf(stderr, "Warning, botched return data;"
193185743Ssam					"register at offset 0x%x not present\n",
194185743Ssam					r << 2);
195185743Ssam				break;
196185743Ssam			}
197185743Ssam			state.regdata[r++] = *dp++;
198185743Ssam		} while (r <= e);
199185743Ssam	}
200185743Ssam
201185743Ssam	if (what & DUMP_BASIC)
202185743Ssam		ath_hal_dumpregs(stdout, DUMP_BASIC);
203185743Ssam	if ((what & DUMP_INTERRUPT) && ath_hal_anyregs(DUMP_INTERRUPT)) {
204185743Ssam		if (what & DUMP_BASIC)
205185743Ssam			putchar('\n');
206185743Ssam		if (state.show_addrs)
207185743Ssam			ath_hal_dumpregs(stdout, DUMP_INTERRUPT);
208185743Ssam		else
209185743Ssam			ath_hal_dumpint(stdout, what);
210185743Ssam	}
211185743Ssam	if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) {
212185743Ssam		if (what & (DUMP_BASIC|DUMP_INTERRUPT))
213185743Ssam			putchar('\n');
214185743Ssam		if (state.show_addrs)
215185743Ssam			ath_hal_dumpregs(stdout, DUMP_QCU);
216185743Ssam		else
217185743Ssam			ath_hal_dumpqcu(stdout, what);
218185743Ssam	}
219185743Ssam	if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) {
220185743Ssam		if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU))
221185743Ssam			putchar('\n');
222185743Ssam		if (state.show_addrs)
223185743Ssam			ath_hal_dumpregs(stdout, DUMP_DCU);
224185743Ssam		else
225185743Ssam			ath_hal_dumpdcu(stdout, what);
226185743Ssam	}
227185743Ssam	if (what & DUMP_KEYCACHE) {
228185743Ssam		if (state.show_addrs) {
229185743Ssam			if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU))
230185743Ssam				putchar('\n');
231185743Ssam			ath_hal_dumpregs(stdout, DUMP_KEYCACHE);
232185743Ssam		} else
233185743Ssam			ath_hal_dumpkeycache(stdout, 128);
234185743Ssam	}
235185743Ssam	if (what & DUMP_BASEBAND) {
236185743Ssam		if (what &~ DUMP_BASEBAND)
237185743Ssam			fprintf(stdout, "\n");
238185743Ssam		ath_hal_dumpbb(stdout, what);
239185743Ssam	}
240185743Ssam	return 0;
241185743Ssam}
242185743Ssam
243185743Ssamstatic int
244185743Ssamregcompar(const void *a, const void *b)
245185743Ssam{
246185743Ssam	const struct dumpreg *ra = *(const struct dumpreg **)a;
247185743Ssam	const struct dumpreg *rb = *(const struct dumpreg **)b;
248185743Ssam	return ra->addr - rb->addr;
249185743Ssam}
250185743Ssam
251185743Ssamvoid
252185743Ssamregister_regs(struct dumpreg *chipregs, u_int nchipregs,
253185743Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
254185743Ssam{
255185743Ssam	const int existing_regs = state.nregs;
256185743Ssam	int i, j;
257185743Ssam
258185743Ssam	for (i = 0; i < nchipregs; i++) {
259185743Ssam		struct dumpreg *nr = &chipregs[i];
260185743Ssam		if (nr->srevMin == 0)
261185743Ssam			nr->srevMin = def_srev_min;
262185743Ssam		if (nr->srevMax == 0)
263185743Ssam			nr->srevMax = def_srev_max;
264185743Ssam		if (nr->phyMin == 0)
265185743Ssam			nr->phyMin = def_phy_min;
266185743Ssam		if (nr->phyMax == 0)
267185743Ssam			nr->phyMax = def_phy_max;
268185743Ssam		for (j = 0; j < existing_regs; j++) {
269185743Ssam			struct dumpreg *r = state.regs[j];
270185743Ssam			/*
271185743Ssam			 * Check if we can just expand the mac+phy
272185743Ssam			 * coverage for the existing entry.
273185743Ssam			 */
274185743Ssam			if (nr->addr == r->addr &&
275185743Ssam			    (nr->name == r->name ||
276185743Ssam			     nr->name != NULL && r->name != NULL &&
277185743Ssam			     strcmp(nr->name, r->name) == 0)) {
278185743Ssam				if (nr->srevMin < r->srevMin &&
279185743Ssam				    (r->srevMin <= nr->srevMax &&
280185743Ssam				     nr->srevMax+1 <= r->srevMax)) {
281185743Ssam					r->srevMin = nr->srevMin;
282185743Ssam					goto skip;
283185743Ssam				}
284185743Ssam				if (nr->srevMax > r->srevMax &&
285185743Ssam				    (r->srevMin <= nr->srevMin &&
286185743Ssam				     nr->srevMin <= r->srevMax)) {
287185743Ssam					r->srevMax = nr->srevMax;
288185743Ssam					goto skip;
289185743Ssam				}
290185743Ssam			}
291185743Ssam			if (r->addr > nr->addr)
292185743Ssam				break;
293185743Ssam		}
294185743Ssam		/*
295185743Ssam		 * New item, add to the end, it'll be sorted below.
296185743Ssam		 */
297185743Ssam		if (state.nregs == MAXREGS)
298185743Ssam			errx(-1, "too many registers; bump MAXREGS");
299185743Ssam		state.regs[state.nregs++] = nr;
300185743Ssam	skip:
301185743Ssam		;
302185743Ssam	}
303185743Ssam	qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar);
304185743Ssam}
305185743Ssam
306185743Ssamvoid
307185743Ssamregister_keycache(u_int nslots,
308185743Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
309185743Ssam{
310185743Ssam#define	SET(r, a) do { \
311185743Ssam	r->addr = a; r->type = DUMP_KEYCACHE; r++; \
312185743Ssam} while(0)
313185743Ssam	struct dumpreg *keyregs, *r;
314185743Ssam	int i;
315185743Ssam
316185743Ssam	keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg));
317185743Ssam	if (keyregs == NULL)
318185743Ssam		errx(-1, "no space to %d keycache slots\n", nslots);
319185743Ssam	r = keyregs;
320185743Ssam	for (i = 0; i < nslots; i++) {
321185743Ssam		SET(r, AR_KEYTABLE_KEY0(i));
322185743Ssam		SET(r, AR_KEYTABLE_KEY1(i));
323185743Ssam		SET(r, AR_KEYTABLE_KEY2(i));
324185743Ssam		SET(r, AR_KEYTABLE_KEY3(i));
325185743Ssam		SET(r, AR_KEYTABLE_KEY4(i));
326185743Ssam		SET(r, AR_KEYTABLE_TYPE(i));
327185743Ssam		SET(r, AR_KEYTABLE_MAC0(i));
328185743Ssam		SET(r, AR_KEYTABLE_MAC1(i));
329185743Ssam	}
330185743Ssam	register_regs(keyregs, 8*nslots,
331185743Ssam	    def_srev_min, def_srev_max, def_phy_min, def_phy_max);
332185743Ssam#undef SET
333185743Ssam}
334185743Ssam
335185743Ssamvoid
336185743Ssamregister_range(u_int brange, u_int erange, int type,
337185743Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
338185743Ssam{
339185743Ssam	struct dumpreg *bbregs, *r;
340185743Ssam	int i, nregs;
341185743Ssam
342185743Ssam	nregs = (erange - brange) / sizeof(uint32_t);
343185743Ssam	bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg));
344185743Ssam	if (bbregs == NULL)
345185743Ssam		errx(-1, "no space for %d register slots (type %d)\n",
346185743Ssam		    nregs, type);
347185743Ssam	r = bbregs;
348185743Ssam	for (i = 0; i < nregs; i++) {
349185743Ssam		r->addr = brange + (i<<2);
350185743Ssam		r->type = type;
351185743Ssam		r++;
352185743Ssam	}
353185743Ssam	register_regs(bbregs, nregs,
354185743Ssam	    def_srev_min, def_srev_max, def_phy_min, def_phy_max);
355185743Ssam}
356185743Ssam
357217680Sadrianstatic __inline int
358185743Ssammatch(const struct dumpreg *dr, const HAL_REVS *revs)
359185743Ssam{
360185743Ssam	if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev))
361185743Ssam		return 0;
362185743Ssam	if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev))
363185743Ssam		return 0;
364185743Ssam	return 1;
365185743Ssam}
366185743Ssam
367185743Ssamstatic int
368185743Ssamath_hal_anyregs(int what)
369185743Ssam{
370185743Ssam	const HAL_REVS *revs = &state.revs;
371185743Ssam	int i;
372185743Ssam
373185743Ssam	for (i = 0; i < state.nregs; i++) {
374185743Ssam		const struct dumpreg *dr = state.regs[i];
375185743Ssam		if ((what & dr->type) && match(dr, revs))
376185743Ssam			return 1;
377185743Ssam	}
378185743Ssam	return 0;
379185743Ssam}
380185743Ssam
381185743Ssamstatic int
382185743Ssamath_hal_setupregs(struct ath_diag *atd, int what)
383185743Ssam{
384185743Ssam	const HAL_REVS *revs = &state.revs;
385185743Ssam	HAL_REGRANGE r;
386185743Ssam	size_t space = 0;
387185743Ssam	u_int8_t *cp;
388185743Ssam	int i, brun, erun;
389185743Ssam
390185743Ssam	brun = erun = -1;
391185743Ssam	for (i = 0; i < state.nregs; i++) {
392185743Ssam		const struct dumpreg *dr = state.regs[i];
393185743Ssam		if ((what & dr->type) && match(dr, revs)) {
394185743Ssam			if (erun + 4 != dr->addr) {
395185743Ssam				if (brun != -1)
396185743Ssam					space += sizeof(HAL_REGRANGE);
397185743Ssam				brun = erun = dr->addr;
398185743Ssam			} else
399185743Ssam				erun = dr->addr;
400185743Ssam		}
401185743Ssam	}
402185743Ssam	space += sizeof(HAL_REGRANGE);
403185743Ssam
404185743Ssam	atd->ad_in_data = (caddr_t) malloc(space);
405185743Ssam	if (atd->ad_in_data == NULL) {
406185743Ssam		fprintf(stderr, "Cannot malloc memory for registers!\n");
407185743Ssam		exit(-1);
408185743Ssam	}
409185743Ssam	atd->ad_in_size = space;
410185743Ssam	cp = (u_int8_t *) atd->ad_in_data;
411185743Ssam	brun = erun = -1;
412185743Ssam	for (i = 0; i < state.nregs; i++) {
413185743Ssam		const struct dumpreg *dr = state.regs[i];
414185743Ssam		if ((what & dr->type) && match(dr, revs)) {
415185743Ssam			if (erun + 4 != dr->addr) {
416185743Ssam				if (brun != -1) {
417185743Ssam					r.start = brun, r.end = erun;
418185743Ssam					memcpy(cp, &r, sizeof(r));
419185743Ssam					cp += sizeof(r);
420185743Ssam				}
421185743Ssam				brun = erun = dr->addr;
422185743Ssam			} else
423185743Ssam				erun = dr->addr;
424185743Ssam		}
425185743Ssam	}
426185743Ssam	if (brun != -1) {
427185743Ssam		r.start = brun, r.end = erun;
428185743Ssam		memcpy(cp, &r, sizeof(r));
429185743Ssam		cp += sizeof(r);
430185743Ssam	}
431185743Ssam	return space / sizeof(uint32_t);
432185743Ssam}
433185743Ssam
434185743Ssamstatic void
435185743Ssamath_hal_dumpregs(FILE *fd, int what)
436185743Ssam{
437185743Ssam	const HAL_REVS *revs = &state.revs;
438185743Ssam	const char *sep = "";
439185743Ssam	int i, count, itemsperline;
440185743Ssam
441185743Ssam	count = 0;
442185743Ssam	itemsperline = 4;
443185743Ssam	if (state.show_names && state.show_addrs)
444185743Ssam		itemsperline--;
445185743Ssam	for (i = 0; i < state.nregs; i++) {
446185743Ssam		const struct dumpreg *dr = state.regs[i];
447185743Ssam		if ((what & dr->type) && match(dr, revs)) {
448185743Ssam			if (state.show_names && dr->name != NULL) {
449185743Ssam				fprintf(fd, "%s%-8s", sep, dr->name);
450185743Ssam				if (state.show_addrs)
451185743Ssam					fprintf(fd, " [%04x]", dr->addr);
452185743Ssam			} else
453185743Ssam				fprintf(fd, "%s%04x", sep, dr->addr);
454185743Ssam			fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr));
455185743Ssam			sep = " ";
456185743Ssam			if ((++count % itemsperline) == 0)
457185743Ssam				sep = "\n";
458185743Ssam		}
459185743Ssam	}
460185743Ssam	if (count)
461185743Ssam		fprintf(fd, "\n");
462185743Ssam}
463185743Ssam
464185743Ssamstatic void
465185743Ssamath_hal_dumprange(FILE *fd, u_int a, u_int b)
466185743Ssam{
467185743Ssam	u_int r;
468185743Ssam
469185743Ssam	for (r = a; r+16 <= b; r += 5*4)
470185743Ssam		fprintf(fd,
471185743Ssam			"%04x %08x  %04x %08x  %04x %08x  %04x %08x  %04x %08x\n"
472185743Ssam			, r, OS_REG_READ(ah, r)
473185743Ssam			, r+4, OS_REG_READ(ah, r+4)
474185743Ssam			, r+8, OS_REG_READ(ah, r+8)
475185743Ssam			, r+12, OS_REG_READ(ah, r+12)
476185743Ssam			, r+16, OS_REG_READ(ah, r+16)
477185743Ssam		);
478185743Ssam	switch (b-r) {
479185743Ssam	case 16:
480185743Ssam		fprintf(fd
481185743Ssam			, "%04x %08x  %04x %08x  %04x %08x  %04x %08x\n"
482185743Ssam			, r, OS_REG_READ(ah, r)
483185743Ssam			, r+4, OS_REG_READ(ah, r+4)
484185743Ssam			, r+8, OS_REG_READ(ah, r+8)
485185743Ssam			, r+12, OS_REG_READ(ah, r+12)
486185743Ssam		);
487185743Ssam		break;
488185743Ssam	case 12:
489185743Ssam		fprintf(fd, "%04x %08x  %04x %08x  %04x %08x\n"
490185743Ssam			, r, OS_REG_READ(ah, r)
491185743Ssam			, r+4, OS_REG_READ(ah, r+4)
492185743Ssam			, r+8, OS_REG_READ(ah, r+8)
493185743Ssam		);
494185743Ssam		break;
495185743Ssam	case 8:
496185743Ssam		fprintf(fd, "%04x %08x  %04x %08x\n"
497185743Ssam			, r, OS_REG_READ(ah, r)
498185743Ssam			, r+4, OS_REG_READ(ah, r+4)
499185743Ssam		);
500185743Ssam		break;
501185743Ssam	case 4:
502185743Ssam		fprintf(fd, "%04x %08x\n"
503185743Ssam			, r, OS_REG_READ(ah, r)
504185743Ssam		);
505185743Ssam		break;
506185743Ssam	}
507185743Ssam}
508185743Ssam
509185743Ssamstatic void
510185743Ssamath_hal_dumpint(FILE *fd, int what)
511185743Ssam{
512185743Ssam	int i;
513185743Ssam
514185743Ssam	/* Interrupt registers */
515185743Ssam	fprintf(fd, "IMR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
516185743Ssam		, OS_REG_READ(ah, AR_IMR)
517185743Ssam		, OS_REG_READ(ah, AR_IMR_S0)
518185743Ssam		, OS_REG_READ(ah, AR_IMR_S1)
519185743Ssam		, OS_REG_READ(ah, AR_IMR_S2)
520185743Ssam		, OS_REG_READ(ah, AR_IMR_S3)
521185743Ssam		, OS_REG_READ(ah, AR_IMR_S4)
522185743Ssam	);
523185743Ssam	fprintf(fd, "ISR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
524185743Ssam		, OS_REG_READ(ah, AR_ISR)
525185743Ssam		, OS_REG_READ(ah, AR_ISR_S0)
526185743Ssam		, OS_REG_READ(ah, AR_ISR_S1)
527185743Ssam		, OS_REG_READ(ah, AR_ISR_S2)
528185743Ssam		, OS_REG_READ(ah, AR_ISR_S3)
529185743Ssam		, OS_REG_READ(ah, AR_ISR_S4)
530185743Ssam	);
531185743Ssam}
532185743Ssam
533185743Ssamstatic void
534185743Ssamath_hal_dumpqcu(FILE *fd, int what)
535185743Ssam{
536185743Ssam	int i;
537185743Ssam
538185743Ssam	/* QCU registers */
539185743Ssam	fprintf(fd, "%-8s %08x  %-8s %08x  %-8s %08x\n"
540185743Ssam		, "Q_TXE", OS_REG_READ(ah, AR_Q_TXE)
541185743Ssam		, "Q_TXD", OS_REG_READ(ah, AR_Q_TXD)
542185743Ssam		, "Q_RDYTIMSHD", OS_REG_READ(ah, AR_Q_RDYTIMESHDN)
543185743Ssam	);
544185743Ssam	fprintf(fd, "Q_ONESHOTARM_SC %08x  Q_ONESHOTARM_CC %08x\n"
545185743Ssam		, OS_REG_READ(ah, AR_Q_ONESHOTARM_SC)
546185743Ssam		, OS_REG_READ(ah, AR_Q_ONESHOTARM_CC)
547185743Ssam	);
548185743Ssam	for (i = 0; i < 10; i++)
549185743Ssam		fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n"
550185743Ssam			, i
551185743Ssam			, OS_REG_READ(ah, AR_QTXDP(i))
552185743Ssam			, OS_REG_READ(ah, AR_QCBRCFG(i))
553185743Ssam			, OS_REG_READ(ah, AR_QRDYTIMECFG(i))
554185743Ssam			, OS_REG_READ(ah, AR_QMISC(i))
555185743Ssam			, OS_REG_READ(ah, AR_QSTS(i))
556185743Ssam		);
557185743Ssam}
558185743Ssam
559185743Ssamstatic void
560185743Ssamath_hal_dumpdcu(FILE *fd, int what)
561185743Ssam{
562185743Ssam	int i;
563185743Ssam
564185743Ssam	/* DCU registers */
565185743Ssam	for (i = 0; i < 10; i++)
566185743Ssam		fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n"
567185743Ssam			, i
568185743Ssam			, OS_REG_READ(ah, AR_DQCUMASK(i))
569185743Ssam			, OS_REG_READ(ah, AR_DLCL_IFS(i))
570185743Ssam			, OS_REG_READ(ah, AR_DRETRY_LIMIT(i))
571185743Ssam			, OS_REG_READ(ah, AR_DCHNTIME(i))
572185743Ssam			, OS_REG_READ(ah, AR_DMISC(i))
573185743Ssam		);
574185743Ssam}
575185743Ssam
576185743Ssamstatic void
577185743Ssamath_hal_dumpbb(FILE *fd, int what)
578185743Ssam{
579185743Ssam	const HAL_REVS *revs = &state.revs;
580185743Ssam	int i, brun, erun;
581185743Ssam
582185743Ssam	brun = erun = 0;
583185743Ssam	for (i = 0; i < state.nregs; i++) {
584185743Ssam		const struct dumpreg *dr = state.regs[i];
585185743Ssam		if (!match(dr, revs))
586185743Ssam			continue;
587185743Ssam		if (dr->type & DUMP_BASEBAND) {
588185743Ssam			if (brun == 0) {
589185743Ssam				brun = erun = dr->addr;
590185743Ssam			} else if (dr->addr == erun + sizeof(uint32_t)) {
591185743Ssam				erun = dr->addr;
592185743Ssam			} else {
593185743Ssam				ath_hal_dumprange(fd, brun, erun);
594185743Ssam				brun = erun = dr->addr;
595185743Ssam			}
596185743Ssam		} else {
597185743Ssam			if (brun != 0)
598185743Ssam				ath_hal_dumprange(fd, brun, erun);
599185743Ssam			brun = erun = 0;
600185743Ssam		}
601185743Ssam	}
602185743Ssam	if (brun != 0)
603185743Ssam		ath_hal_dumprange(fd, brun, erun);
604185743Ssam}
605185743Ssam
606185743Ssamstatic u_int
607185743Ssamath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr)
608185743Ssam{
609185743Ssam	u_int space;
610185743Ssam	int i;
611185743Ssam
612185743Ssam	space = 0;
613185743Ssam	for (i = 0; i < nr; i++) {
614185743Ssam		u_int n = 2 * sizeof(u_int32_t);	/* reg range + first */
615185743Ssam		if (regs[i].end) {
616185743Ssam			if (regs[i].end < regs[i].start) {
617185743Ssam				fprintf(stderr, "%s: bad register range, "
618185743Ssam					"end 0x%x < start 0x%x\n",
619185743Ssam					__func__, regs[i].end, regs[i].end);
620185743Ssam				exit(-1);
621185743Ssam			}
622185743Ssam			n += regs[i].end - regs[i].start;
623185743Ssam		}
624185743Ssam		space += n;
625185743Ssam	}
626185743Ssam	return space;
627185743Ssam}
628185743Ssam
629185743Ssam/*
630185743Ssam * Format an Ethernet MAC for printing.
631185743Ssam */
632185743Ssamstatic const char*
633185743Ssamether_sprintf(const u_int8_t *mac)
634185743Ssam{
635185743Ssam	static char etherbuf[18];
636185743Ssam	snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
637185743Ssam		mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
638185743Ssam	return etherbuf;
639185743Ssam}
640185743Ssam
641185743Ssam#ifndef isclr
642185743Ssam#define	setbit(a,i)	((a)[(i)/NBBY] |= 1<<((i)%NBBY))
643185743Ssam#define	clrbit(a,i)	((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
644185743Ssam#define	isset(a,i)	((a)[(i)/NBBY] & (1<<((i)%NBBY)))
645185743Ssam#define	isclr(a,i)	(((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
646185743Ssam#endif
647185743Ssam
648185743Ssamstatic void
649185743Ssamath_hal_dumpkeycache(FILE *fd, int nkeys)
650185743Ssam{
651185743Ssam	static const char *keytypenames[] = {
652185743Ssam		"WEP-40", 	/* AR_KEYTABLE_TYPE_40 */
653185743Ssam		"WEP-104",	/* AR_KEYTABLE_TYPE_104 */
654185743Ssam		"#2",
655185743Ssam		"WEP-128",	/* AR_KEYTABLE_TYPE_128 */
656185743Ssam		"TKIP",		/* AR_KEYTABLE_TYPE_TKIP */
657185743Ssam		"AES-OCB",	/* AR_KEYTABLE_TYPE_AES */
658185743Ssam		"AES-CCM",	/* AR_KEYTABLE_TYPE_CCM */
659185743Ssam		"CLR",		/* AR_KEYTABLE_TYPE_CLR */
660185743Ssam	};
661185743Ssam	int micEnabled = SREV(state.revs.ah_macVersion, state.revs.ah_macRev) < SREV(4,8) ? 0 :
662185743Ssam	       OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_CRPT_MIC_ENABLE;
663185743Ssam	u_int8_t mac[IEEE80211_ADDR_LEN];
664185743Ssam	u_int8_t ismic[128/NBBY];
665185743Ssam	int entry;
666185743Ssam	int first = 1;
667185743Ssam
668185743Ssam	memset(ismic, 0, sizeof(ismic));
669185743Ssam	for (entry = 0; entry < nkeys; entry++) {
670185743Ssam		u_int32_t macLo, macHi, type;
671185743Ssam		u_int32_t key0, key1, key2, key3, key4;
672185743Ssam
673185743Ssam		macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
674185743Ssam		if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry))
675185743Ssam			continue;
676185743Ssam		macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry));
677185743Ssam		macHi <<= 1;
678185743Ssam		if (macLo & (1<<31))
679185743Ssam			macHi |= 1;
680185743Ssam		macLo <<= 1;
681185743Ssam		mac[4] = macHi & 0xff;
682185743Ssam		mac[5] = macHi >> 8;
683185743Ssam		mac[0] = macLo & 0xff;
684185743Ssam		mac[1] = macLo >> 8;
685185743Ssam		mac[2] = macLo >> 16;
686185743Ssam		mac[3] = macLo >> 24;
687185743Ssam		type = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));
688185743Ssam		if ((type & 7) == AR_KEYTABLE_TYPE_TKIP && micEnabled)
689185743Ssam			setbit(ismic, entry+64);
690185743Ssam		key0 = OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry));
691185743Ssam		key1 = OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry));
692185743Ssam		key2 = OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry));
693185743Ssam		key3 = OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry));
694185743Ssam		key4 = OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry));
695185743Ssam		if (first) {
696185743Ssam			fprintf(fd, "\n");
697185743Ssam			first = 0;
698185743Ssam		}
699185743Ssam		fprintf(fd, "KEY[%03u] MAC %s %-7s %02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x\n"
700185743Ssam			, entry
701185743Ssam			, ether_sprintf(mac)
702185743Ssam			, isset(ismic, entry) ? "MIC" : keytypenames[type & 7]
703185743Ssam			, (key0 >>  0) & 0xff
704185743Ssam			, (key0 >>  8) & 0xff
705185743Ssam			, (key0 >> 16) & 0xff
706185743Ssam			, (key0 >> 24) & 0xff
707185743Ssam			, (key1 >>  0) & 0xff
708185743Ssam			, (key1 >>  8) & 0xff
709185743Ssam			, (key2 >>  0) & 0xff
710185743Ssam			, (key2 >>  8) & 0xff
711185743Ssam			, (key2 >> 16) & 0xff
712185743Ssam			, (key2 >> 24) & 0xff
713185743Ssam			, (key3 >>  0) & 0xff
714185743Ssam			, (key3 >>  8) & 0xff
715185743Ssam			, (key4 >>  0) & 0xff
716185743Ssam			, (key4 >>  8) & 0xff
717185743Ssam			, (key4 >> 16) & 0xff
718185743Ssam			, (key4 >> 24) & 0xff
719185743Ssam		);
720185743Ssam	}
721185743Ssam}
722