2 * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
34 #include "ah_internal.h"
35 /* XXX cheat, 5212 has a superset of the key table defs */
36 #include "ar5212/ar5212reg.h"
50 u_int32_t regdata[0xffff / sizeof(u_int32_t)];
51 #define MAXREGS 5*1024
52 struct dumpreg *regs[MAXREGS];
57 static dumpregs_t state;
60 #define OS_REG_READ(ah, off) state.regdata[(off) >> 2]
62 static int ath_hal_anyregs(int what);
63 static int ath_hal_setupregs(struct ath_diag *atd, int what);
64 static u_int ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr);
65 static void ath_hal_dumpregs(FILE *fd, int what);
66 static void ath_hal_dumprange(FILE *fd, u_int a, u_int b);
67 static void ath_hal_dumpkeycache(FILE *fd, int nkeys);
68 static void ath_hal_dumpint(FILE *fd, int what);
69 static void ath_hal_dumpqcu(FILE *fd, int what);
70 static void ath_hal_dumpdcu(FILE *fd, int what);
71 static void ath_hal_dumpbb(FILE *fd, int what);
76 fprintf(stderr, "usage: athregs [-i interface] [-abdkmqxz]\n");
77 fprintf(stderr, "-a display all registers\n");
78 fprintf(stderr, "-b display baseband registers\n");
79 fprintf(stderr, "-d display DCU registers\n");
80 fprintf(stderr, "-k display key cache registers\n");
81 fprintf(stderr, "-m display \"MAC\" registers (default)\n");
82 fprintf(stderr, "-q display QCU registers\n");
83 fprintf(stderr, "-x display XR registers\n");
84 fprintf(stderr, "-z display interrupt registers\n");
85 fprintf(stderr, "\n");
86 fprintf(stderr, "-A display register address\n");
87 fprintf(stderr, "-N suppress display of register name\n");
92 main(int argc, char *argv[])
99 struct ath_driver_req req;
101 ath_driver_req_init(&req);
103 ifname = getenv("ATH");
105 ifname = ATH_DEFAULT;
108 state.show_addrs = 0;
109 state.show_names = 1;
110 while ((c = getopt(argc, argv, "i:aAbdkmNqxz")) != -1)
116 state.show_addrs = 1;
119 what |= DUMP_BASEBAND;
125 what |= DUMP_KEYCACHE;
134 state.show_names = 0;
143 what |= DUMP_INTERRUPT;
150 /* Initialise the driver interface */
151 if (ath_driver_req_open(&req, ifname) < 0) {
156 * Whilst we're doing the ath_diag pieces, we have to set this
159 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name));
166 atd.ad_id = HAL_DIAG_REVS;
167 atd.ad_out_data = (caddr_t) &state.revs;
168 atd.ad_out_size = sizeof(state.revs);
170 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0)
171 err(1, "%s", atd.ad_name);
173 if (ath_hal_setupregs(&atd, what) == 0)
174 errx(-1, "no registers are known for this part "
175 "(devid 0x%x mac %d.%d phy %d)", state.revs.ah_devid,
176 state.revs.ah_macVersion, state.revs.ah_macRev,
177 state.revs.ah_phyRev);
179 atd.ad_out_size = ath_hal_setupdiagregs((HAL_REGRANGE *) atd.ad_in_data,
180 atd.ad_in_size / sizeof(HAL_REGRANGE));
181 atd.ad_out_data = (caddr_t) malloc(atd.ad_out_size);
182 if (atd.ad_out_data == NULL) {
183 fprintf(stderr, "Cannot malloc output buffer, size %u\n",
187 atd.ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN;
189 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0)
190 err(1, "%s", atd.ad_name);
193 * Expand register data into global space that can be
194 * indexed directly by register offset.
196 dp = (u_int32_t *)atd.ad_out_data;
197 ep = (u_int32_t *)(atd.ad_out_data + atd.ad_out_size);
199 u_int r = dp[0]; /* start of range */
200 u_int e = dp[1]; /* end of range */
203 /* convert offsets to indices */
207 fprintf(stderr, "Warning, botched return data;"
208 "register at offset 0x%x not present\n",
212 state.regdata[r++] = *dp++;
216 if (what & DUMP_BASIC)
217 ath_hal_dumpregs(stdout, DUMP_BASIC);
218 if ((what & DUMP_INTERRUPT) && ath_hal_anyregs(DUMP_INTERRUPT)) {
219 if (what & DUMP_BASIC)
221 if (state.show_addrs)
222 ath_hal_dumpregs(stdout, DUMP_INTERRUPT);
224 ath_hal_dumpint(stdout, what);
226 if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) {
227 if (what & (DUMP_BASIC|DUMP_INTERRUPT))
229 if (state.show_addrs)
230 ath_hal_dumpregs(stdout, DUMP_QCU);
232 ath_hal_dumpqcu(stdout, what);
234 if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) {
235 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU))
237 if (state.show_addrs)
238 ath_hal_dumpregs(stdout, DUMP_DCU);
240 ath_hal_dumpdcu(stdout, what);
242 if (what & DUMP_KEYCACHE) {
243 if (state.show_addrs) {
244 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU))
246 ath_hal_dumpregs(stdout, DUMP_KEYCACHE);
248 ath_hal_dumpkeycache(stdout, 128);
250 if (what & DUMP_BASEBAND) {
251 if (what &~ DUMP_BASEBAND)
252 fprintf(stdout, "\n");
253 ath_hal_dumpbb(stdout, what);
255 ath_driver_req_close(&req);
260 regcompar(const void *a, const void *b)
262 const struct dumpreg *ra = *(const struct dumpreg **)a;
263 const struct dumpreg *rb = *(const struct dumpreg **)b;
264 return ra->addr - rb->addr;
268 register_regs(struct dumpreg *chipregs, u_int nchipregs,
269 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
271 const int existing_regs = state.nregs;
274 for (i = 0; i < nchipregs; i++) {
275 struct dumpreg *nr = &chipregs[i];
276 if (nr->srevMin == 0)
277 nr->srevMin = def_srev_min;
278 if (nr->srevMax == 0)
279 nr->srevMax = def_srev_max;
281 nr->phyMin = def_phy_min;
283 nr->phyMax = def_phy_max;
284 for (j = 0; j < existing_regs; j++) {
285 struct dumpreg *r = state.regs[j];
287 * Check if we can just expand the mac+phy
288 * coverage for the existing entry.
290 if (nr->addr == r->addr &&
291 (nr->name == r->name ||
292 nr->name != NULL && r->name != NULL &&
293 strcmp(nr->name, r->name) == 0)) {
294 if (nr->srevMin < r->srevMin &&
295 (r->srevMin <= nr->srevMax &&
296 nr->srevMax+1 <= r->srevMax)) {
297 r->srevMin = nr->srevMin;
300 if (nr->srevMax > r->srevMax &&
301 (r->srevMin <= nr->srevMin &&
302 nr->srevMin <= r->srevMax)) {
303 r->srevMax = nr->srevMax;
307 if (r->addr > nr->addr)
311 * New item, add to the end, it'll be sorted below.
313 if (state.nregs == MAXREGS)
314 errx(-1, "too many registers; bump MAXREGS");
315 state.regs[state.nregs++] = nr;
319 qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar);
323 register_keycache(u_int nslots,
324 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
326 #define SET(r, a) do { \
327 r->addr = a; r->type = DUMP_KEYCACHE; r++; \
329 struct dumpreg *keyregs, *r;
332 keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg));
334 errx(-1, "no space to %d keycache slots\n", nslots);
336 for (i = 0; i < nslots; i++) {
337 SET(r, AR_KEYTABLE_KEY0(i));
338 SET(r, AR_KEYTABLE_KEY1(i));
339 SET(r, AR_KEYTABLE_KEY2(i));
340 SET(r, AR_KEYTABLE_KEY3(i));
341 SET(r, AR_KEYTABLE_KEY4(i));
342 SET(r, AR_KEYTABLE_TYPE(i));
343 SET(r, AR_KEYTABLE_MAC0(i));
344 SET(r, AR_KEYTABLE_MAC1(i));
346 register_regs(keyregs, 8*nslots,
347 def_srev_min, def_srev_max, def_phy_min, def_phy_max);
352 register_range(u_int brange, u_int erange, int type,
353 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
355 struct dumpreg *bbregs, *r;
358 nregs = (erange - brange) / sizeof(uint32_t);
359 bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg));
361 errx(-1, "no space for %d register slots (type %d)\n",
364 for (i = 0; i < nregs; i++) {
365 r->addr = brange + (i<<2);
369 register_regs(bbregs, nregs,
370 def_srev_min, def_srev_max, def_phy_min, def_phy_max);
374 match(const struct dumpreg *dr, const HAL_REVS *revs)
376 if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev))
378 if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev))
384 ath_hal_anyregs(int what)
386 const HAL_REVS *revs = &state.revs;
389 for (i = 0; i < state.nregs; i++) {
390 const struct dumpreg *dr = state.regs[i];
391 if ((what & dr->type) && match(dr, revs))
398 ath_hal_setupregs(struct ath_diag *atd, int what)
400 const HAL_REVS *revs = &state.revs;
407 for (i = 0; i < state.nregs; i++) {
408 const struct dumpreg *dr = state.regs[i];
409 if ((what & dr->type) && match(dr, revs)) {
410 if (erun + 4 != dr->addr) {
412 space += sizeof(HAL_REGRANGE);
413 brun = erun = dr->addr;
418 space += sizeof(HAL_REGRANGE);
420 atd->ad_in_data = (caddr_t) malloc(space);
421 if (atd->ad_in_data == NULL) {
422 fprintf(stderr, "Cannot malloc memory for registers!\n");
425 atd->ad_in_size = space;
426 cp = (u_int8_t *) atd->ad_in_data;
428 for (i = 0; i < state.nregs; i++) {
429 const struct dumpreg *dr = state.regs[i];
430 if ((what & dr->type) && match(dr, revs)) {
431 if (erun + 4 != dr->addr) {
433 r.start = brun, r.end = erun;
434 memcpy(cp, &r, sizeof(r));
437 brun = erun = dr->addr;
443 r.start = brun, r.end = erun;
444 memcpy(cp, &r, sizeof(r));
447 return space / sizeof(uint32_t);
451 ath_hal_dumpregs(FILE *fd, int what)
453 const HAL_REVS *revs = &state.revs;
454 const char *sep = "";
455 int i, count, itemsperline;
459 if (state.show_names && state.show_addrs)
461 for (i = 0; i < state.nregs; i++) {
462 const struct dumpreg *dr = state.regs[i];
463 if ((what & dr->type) && match(dr, revs)) {
464 if (state.show_names && dr->name != NULL) {
465 fprintf(fd, "%s%-8s", sep, dr->name);
466 if (state.show_addrs)
467 fprintf(fd, " [%04x]", dr->addr);
469 fprintf(fd, "%s%04x", sep, dr->addr);
470 fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr));
472 if ((++count % itemsperline) == 0)
481 ath_hal_dumprange(FILE *fd, u_int a, u_int b)
485 for (r = a; r+16 <= b; r += 5*4)
487 "%04x %08x %04x %08x %04x %08x %04x %08x %04x %08x\n"
488 , r, OS_REG_READ(ah, r)
489 , r+4, OS_REG_READ(ah, r+4)
490 , r+8, OS_REG_READ(ah, r+8)
491 , r+12, OS_REG_READ(ah, r+12)
492 , r+16, OS_REG_READ(ah, r+16)
497 , "%04x %08x %04x %08x %04x %08x %04x %08x\n"
498 , r, OS_REG_READ(ah, r)
499 , r+4, OS_REG_READ(ah, r+4)
500 , r+8, OS_REG_READ(ah, r+8)
501 , r+12, OS_REG_READ(ah, r+12)
505 fprintf(fd, "%04x %08x %04x %08x %04x %08x\n"
506 , r, OS_REG_READ(ah, r)
507 , r+4, OS_REG_READ(ah, r+4)
508 , r+8, OS_REG_READ(ah, r+8)
512 fprintf(fd, "%04x %08x %04x %08x\n"
513 , r, OS_REG_READ(ah, r)
514 , r+4, OS_REG_READ(ah, r+4)
518 fprintf(fd, "%04x %08x\n"
519 , r, OS_REG_READ(ah, r)
526 ath_hal_dumpint(FILE *fd, int what)
530 /* Interrupt registers */
531 fprintf(fd, "IMR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
532 , OS_REG_READ(ah, AR_IMR)
533 , OS_REG_READ(ah, AR_IMR_S0)
534 , OS_REG_READ(ah, AR_IMR_S1)
535 , OS_REG_READ(ah, AR_IMR_S2)
536 , OS_REG_READ(ah, AR_IMR_S3)
537 , OS_REG_READ(ah, AR_IMR_S4)
539 fprintf(fd, "ISR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n"
540 , OS_REG_READ(ah, AR_ISR)
541 , OS_REG_READ(ah, AR_ISR_S0)
542 , OS_REG_READ(ah, AR_ISR_S1)
543 , OS_REG_READ(ah, AR_ISR_S2)
544 , OS_REG_READ(ah, AR_ISR_S3)
545 , OS_REG_READ(ah, AR_ISR_S4)
550 ath_hal_dumpqcu(FILE *fd, int what)
555 fprintf(fd, "%-8s %08x %-8s %08x %-8s %08x\n"
556 , "Q_TXE", OS_REG_READ(ah, AR_Q_TXE)
557 , "Q_TXD", OS_REG_READ(ah, AR_Q_TXD)
558 , "Q_RDYTIMSHD", OS_REG_READ(ah, AR_Q_RDYTIMESHDN)
560 fprintf(fd, "Q_ONESHOTARM_SC %08x Q_ONESHOTARM_CC %08x\n"
561 , OS_REG_READ(ah, AR_Q_ONESHOTARM_SC)
562 , OS_REG_READ(ah, AR_Q_ONESHOTARM_CC)
564 for (i = 0; i < 10; i++)
565 fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n"
567 , OS_REG_READ(ah, AR_QTXDP(i))
568 , OS_REG_READ(ah, AR_QCBRCFG(i))
569 , OS_REG_READ(ah, AR_QRDYTIMECFG(i))
570 , OS_REG_READ(ah, AR_QMISC(i))
571 , OS_REG_READ(ah, AR_QSTS(i))
576 ath_hal_dumpdcu(FILE *fd, int what)
581 for (i = 0; i < 10; i++)
582 fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n"
584 , OS_REG_READ(ah, AR_DQCUMASK(i))
585 , OS_REG_READ(ah, AR_DLCL_IFS(i))
586 , OS_REG_READ(ah, AR_DRETRY_LIMIT(i))
587 , OS_REG_READ(ah, AR_DCHNTIME(i))
588 , OS_REG_READ(ah, AR_DMISC(i))
593 ath_hal_dumpbb(FILE *fd, int what)
595 const HAL_REVS *revs = &state.revs;
599 for (i = 0; i < state.nregs; i++) {
600 const struct dumpreg *dr = state.regs[i];
601 if (!match(dr, revs))
603 if (dr->type & DUMP_BASEBAND) {
605 brun = erun = dr->addr;
606 } else if (dr->addr == erun + sizeof(uint32_t)) {
609 ath_hal_dumprange(fd, brun, erun);
610 brun = erun = dr->addr;
614 ath_hal_dumprange(fd, brun, erun);
619 ath_hal_dumprange(fd, brun, erun);
623 ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr)
629 for (i = 0; i < nr; i++) {
630 u_int n = sizeof(HAL_REGRANGE) + sizeof(u_int32_t); /* reg range + first */
632 if (regs[i].end < regs[i].start) {
633 fprintf(stderr, "%s: bad register range, "
634 "end 0x%x < start 0x%x\n",
635 __func__, regs[i].end, regs[i].end);
638 n += regs[i].end - regs[i].start;
646 * Format an Ethernet MAC for printing.
649 ether_sprintf(const u_int8_t *mac)
651 static char etherbuf[18];
652 snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
653 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
658 #define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY))
659 #define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY)))
660 #define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY)))
661 #define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0)
665 ath_hal_dumpkeycache(FILE *fd, int nkeys)
667 static const char *keytypenames[] = {
668 "WEP-40", /* AR_KEYTABLE_TYPE_40 */
669 "WEP-104", /* AR_KEYTABLE_TYPE_104 */
671 "WEP-128", /* AR_KEYTABLE_TYPE_128 */
672 "TKIP", /* AR_KEYTABLE_TYPE_TKIP */
673 "AES-OCB", /* AR_KEYTABLE_TYPE_AES */
674 "AES-CCM", /* AR_KEYTABLE_TYPE_CCM */
675 "CLR", /* AR_KEYTABLE_TYPE_CLR */
677 int micEnabled = SREV(state.revs.ah_macVersion, state.revs.ah_macRev) < SREV(4,8) ? 0 :
678 OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_CRPT_MIC_ENABLE;
679 u_int8_t mac[IEEE80211_ADDR_LEN];
680 u_int8_t ismic[128/NBBY];
684 memset(ismic, 0, sizeof(ismic));
685 for (entry = 0; entry < nkeys; entry++) {
686 u_int32_t macLo, macHi, type;
687 u_int32_t key0, key1, key2, key3, key4;
689 macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry));
690 if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry))
692 macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry));
697 mac[4] = macHi & 0xff;
699 mac[0] = macLo & 0xff;
701 mac[2] = macLo >> 16;
702 mac[3] = macLo >> 24;
703 type = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry));
704 if ((type & 7) == AR_KEYTABLE_TYPE_TKIP && micEnabled)
705 setbit(ismic, entry+64);
706 key0 = OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry));
707 key1 = OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry));
708 key2 = OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry));
709 key3 = OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry));
710 key4 = OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry));
715 fprintf(fd, "KEY[%03u] MAC %s %-7s %02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x\n"
718 , isset(ismic, entry) ? "MIC" : keytypenames[type & 7]
721 , (key0 >> 16) & 0xff
722 , (key0 >> 24) & 0xff
727 , (key2 >> 16) & 0xff
728 , (key2 >> 24) & 0xff
733 , (key4 >> 16) & 0xff
734 , (key4 >> 24) & 0xff