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