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