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 #include "ctrl.h" 47 48 typedef struct { 49 HAL_REVS revs; 50 u_int32_t regdata[0xffff / sizeof(u_int32_t)]; 51 #define MAXREGS 5*1024 52 struct dumpreg *regs[MAXREGS]; 53 u_int nregs; 54 u_int show_names : 1, 55 show_addrs : 1; 56 } dumpregs_t; 57 static dumpregs_t state; 58 59 #undef OS_REG_READ 60 #define OS_REG_READ(ah, off) state.regdata[(off) >> 2] 61 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); 72 73 static void 74 usage(void) 75 { 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"); 88 exit(-1); 89 } 90 91 int 92 main(int argc, char *argv[]) 93 { 94 struct ath_diag atd; 95 const char *ifname; 96 u_int32_t *data; 97 u_int32_t *dp, *ep; 98 int what, c, i; 99 struct ath_driver_req req; 100 101 ath_driver_req_init(&req); 102 103 ifname = getenv("ATH"); 104 if (!ifname) 105 ifname = ATH_DEFAULT; 106 107 what = 0; 108 state.show_addrs = 0; 109 state.show_names = 1; 110 while ((c = getopt(argc, argv, "i:aAbdkmNqxz")) != -1) 111 switch (c) { 112 case 'a': 113 what |= DUMP_ALL; 114 break; 115 case 'A': 116 state.show_addrs = 1; 117 break; 118 case 'b': 119 what |= DUMP_BASEBAND; 120 break; 121 case 'd': 122 what |= DUMP_DCU; 123 break; 124 case 'k': 125 what |= DUMP_KEYCACHE; 126 break; 127 case 'i': 128 ifname = optarg; 129 break; 130 case 'm': 131 what |= DUMP_BASIC; 132 break; 133 case 'N': 134 state.show_names = 0; 135 break; 136 case 'q': 137 what |= DUMP_QCU; 138 break; 139 case 'x': 140 what |= DUMP_XR; 141 break; 142 case 'z': 143 what |= DUMP_INTERRUPT; 144 break; 145 default: 146 usage(); 147 /*NOTREACHED*/ 148 } 149 150 /* Initialise the driver interface */ 151 if (ath_driver_req_open(&req, ifname) < 0) { 152 exit(127); 153 } 154 155 /* 156 * Whilst we're doing the ath_diag pieces, we have to set this 157 * ourselves. 158 */ 159 strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 160 161 argc -= optind; 162 argv += optind; 163 if (what == 0) 164 what = DUMP_BASIC; 165 166 atd.ad_id = HAL_DIAG_REVS; 167 atd.ad_out_data = (caddr_t) &state.revs; 168 atd.ad_out_size = sizeof(state.revs); 169 170 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0) 171 err(1, "%s", atd.ad_name); 172 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); 178 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", 184 atd.ad_out_size); 185 exit(-1); 186 } 187 atd.ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN; 188 189 if (ath_driver_req_fetch_diag(&req, SIOCGATHDIAG, &atd) < 0) 190 err(1, "%s", atd.ad_name); 191 192 /* 193 * Expand register data into global space that can be 194 * indexed directly by register offset. 195 */ 196 dp = (u_int32_t *)atd.ad_out_data; 197 ep = (u_int32_t *)(atd.ad_out_data + atd.ad_out_size); 198 while (dp < ep) { 199 u_int r = dp[0]; /* start of range */ 200 u_int e = dp[1]; /* end of range */ 201 dp++; 202 dp++; 203 /* convert offsets to indices */ 204 r >>= 2; e >>= 2; 205 do { 206 if (dp >= ep) { 207 fprintf(stderr, "Warning, botched return data;" 208 "register at offset 0x%x not present\n", 209 r << 2); 210 break; 211 } 212 state.regdata[r++] = *dp++; 213 } while (r <= e); 214 } 215 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) 220 putchar('\n'); 221 if (state.show_addrs) 222 ath_hal_dumpregs(stdout, DUMP_INTERRUPT); 223 else 224 ath_hal_dumpint(stdout, what); 225 } 226 if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) { 227 if (what & (DUMP_BASIC|DUMP_INTERRUPT)) 228 putchar('\n'); 229 if (state.show_addrs) 230 ath_hal_dumpregs(stdout, DUMP_QCU); 231 else 232 ath_hal_dumpqcu(stdout, what); 233 } 234 if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) { 235 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU)) 236 putchar('\n'); 237 if (state.show_addrs) 238 ath_hal_dumpregs(stdout, DUMP_DCU); 239 else 240 ath_hal_dumpdcu(stdout, what); 241 } 242 if (what & DUMP_KEYCACHE) { 243 if (state.show_addrs) { 244 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU)) 245 putchar('\n'); 246 ath_hal_dumpregs(stdout, DUMP_KEYCACHE); 247 } else 248 ath_hal_dumpkeycache(stdout, 128); 249 } 250 if (what & DUMP_BASEBAND) { 251 if (what &~ DUMP_BASEBAND) 252 fprintf(stdout, "\n"); 253 ath_hal_dumpbb(stdout, what); 254 } 255 ath_driver_req_close(&req); 256 return 0; 257 } 258 259 static int 260 regcompar(const void *a, const void *b) 261 { 262 const struct dumpreg *ra = *(const struct dumpreg **)a; 263 const struct dumpreg *rb = *(const struct dumpreg **)b; 264 return ra->addr - rb->addr; 265 } 266 267 void 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) 270 { 271 const int existing_regs = state.nregs; 272 int i, j; 273 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; 280 if (nr->phyMin == 0) 281 nr->phyMin = def_phy_min; 282 if (nr->phyMax == 0) 283 nr->phyMax = def_phy_max; 284 for (j = 0; j < existing_regs; j++) { 285 struct dumpreg *r = state.regs[j]; 286 /* 287 * Check if we can just expand the mac+phy 288 * coverage for the existing entry. 289 */ 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; 298 goto skip; 299 } 300 if (nr->srevMax > r->srevMax && 301 (r->srevMin <= nr->srevMin && 302 nr->srevMin <= r->srevMax)) { 303 r->srevMax = nr->srevMax; 304 goto skip; 305 } 306 } 307 if (r->addr > nr->addr) 308 break; 309 } 310 /* 311 * New item, add to the end, it'll be sorted below. 312 */ 313 if (state.nregs == MAXREGS) 314 errx(-1, "too many registers; bump MAXREGS"); 315 state.regs[state.nregs++] = nr; 316 skip: 317 ; 318 } 319 qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); 320 } 321 322 void 323 register_keycache(u_int nslots, 324 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 325 { 326 #define SET(r, a) do { \ 327 r->addr = a; r->type = DUMP_KEYCACHE; r++; \ 328 } while(0) 329 struct dumpreg *keyregs, *r; 330 int i; 331 332 keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg)); 333 if (keyregs == NULL) 334 errx(-1, "no space to %d keycache slots\n", nslots); 335 r = keyregs; 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)); 345 } 346 register_regs(keyregs, 8*nslots, 347 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 348 #undef SET 349 } 350 351 void 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) 354 { 355 struct dumpreg *bbregs, *r; 356 int i, nregs; 357 358 nregs = (erange - brange) / sizeof(uint32_t); 359 bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg)); 360 if (bbregs == NULL) 361 errx(-1, "no space for %d register slots (type %d)\n", 362 nregs, type); 363 r = bbregs; 364 for (i = 0; i < nregs; i++) { 365 r->addr = brange + (i<<2); 366 r->type = type; 367 r++; 368 } 369 register_regs(bbregs, nregs, 370 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 371 } 372 373 static __inline int 374 match(const struct dumpreg *dr, const HAL_REVS *revs) 375 { 376 if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev)) 377 return 0; 378 if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev)) 379 return 0; 380 return 1; 381 } 382 383 static int 384 ath_hal_anyregs(int what) 385 { 386 const HAL_REVS *revs = &state.revs; 387 int i; 388 389 for (i = 0; i < state.nregs; i++) { 390 const struct dumpreg *dr = state.regs[i]; 391 if ((what & dr->type) && match(dr, revs)) 392 return 1; 393 } 394 return 0; 395 } 396 397 static int 398 ath_hal_setupregs(struct ath_diag *atd, int what) 399 { 400 const HAL_REVS *revs = &state.revs; 401 HAL_REGRANGE r; 402 size_t space = 0; 403 u_int8_t *cp; 404 int i, brun, erun; 405 406 brun = erun = -1; 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) { 411 if (brun != -1) 412 space += sizeof(HAL_REGRANGE); 413 brun = erun = dr->addr; 414 } else 415 erun = dr->addr; 416 } 417 } 418 space += sizeof(HAL_REGRANGE); 419 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"); 423 exit(-1); 424 } 425 atd->ad_in_size = space; 426 cp = (u_int8_t *) atd->ad_in_data; 427 brun = erun = -1; 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) { 432 if (brun != -1) { 433 r.start = brun, r.end = erun; 434 memcpy(cp, &r, sizeof(r)); 435 cp += sizeof(r); 436 } 437 brun = erun = dr->addr; 438 } else 439 erun = dr->addr; 440 } 441 } 442 if (brun != -1) { 443 r.start = brun, r.end = erun; 444 memcpy(cp, &r, sizeof(r)); 445 cp += sizeof(r); 446 } 447 return space / sizeof(uint32_t); 448 } 449 450 static void 451 ath_hal_dumpregs(FILE *fd, int what) 452 { 453 const HAL_REVS *revs = &state.revs; 454 const char *sep = ""; 455 int i, count, itemsperline; 456 457 count = 0; 458 itemsperline = 4; 459 if (state.show_names && state.show_addrs) 460 itemsperline--; 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); 468 } else 469 fprintf(fd, "%s%04x", sep, dr->addr); 470 fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr)); 471 sep = " "; 472 if ((++count % itemsperline) == 0) 473 sep = "\n"; 474 } 475 } 476 if (count) 477 fprintf(fd, "\n"); 478 } 479 480 static void 481 ath_hal_dumprange(FILE *fd, u_int a, u_int b) 482 { 483 u_int r; 484 485 for (r = a; r+16 <= b; r += 5*4) 486 fprintf(fd, 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) 493 ); 494 switch (b-r) { 495 case 16: 496 fprintf(fd 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) 502 ); 503 break; 504 case 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) 509 ); 510 break; 511 case 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) 515 ); 516 break; 517 case 4: 518 fprintf(fd, "%04x %08x\n" 519 , r, OS_REG_READ(ah, r) 520 ); 521 break; 522 } 523 } 524 525 static void 526 ath_hal_dumpint(FILE *fd, int what) 527 { 528 int i; 529 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) 538 ); 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) 546 ); 547 } 548 549 static void 550 ath_hal_dumpqcu(FILE *fd, int what) 551 { 552 int i; 553 554 /* QCU registers */ 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) 559 ); 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) 563 ); 564 for (i = 0; i < 10; i++) 565 fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n" 566 , i 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)) 572 ); 573 } 574 575 static void 576 ath_hal_dumpdcu(FILE *fd, int what) 577 { 578 int i; 579 580 /* DCU registers */ 581 for (i = 0; i < 10; i++) 582 fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n" 583 , i 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)) 589 ); 590 } 591 592 static void 593 ath_hal_dumpbb(FILE *fd, int what) 594 { 595 const HAL_REVS *revs = &state.revs; 596 int i, brun, erun; 597 598 brun = erun = 0; 599 for (i = 0; i < state.nregs; i++) { 600 const struct dumpreg *dr = state.regs[i]; 601 if (!match(dr, revs)) 602 continue; 603 if (dr->type & DUMP_BASEBAND) { 604 if (brun == 0) { 605 brun = erun = dr->addr; 606 } else if (dr->addr == erun + sizeof(uint32_t)) { 607 erun = dr->addr; 608 } else { 609 ath_hal_dumprange(fd, brun, erun); 610 brun = erun = dr->addr; 611 } 612 } else { 613 if (brun != 0) 614 ath_hal_dumprange(fd, brun, erun); 615 brun = erun = 0; 616 } 617 } 618 if (brun != 0) 619 ath_hal_dumprange(fd, brun, erun); 620 } 621 622 static u_int 623 ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr) 624 { 625 u_int space; 626 int i; 627 628 space = 0; 629 for (i = 0; i < nr; i++) { 630 u_int n = sizeof(HAL_REGRANGE) + sizeof(u_int32_t); /* reg range + first */ 631 if (regs[i].end) { 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); 636 exit(-1); 637 } 638 n += regs[i].end - regs[i].start; 639 } 640 space += n; 641 } 642 return space; 643 } 644 645 /* 646 * Format an Ethernet MAC for printing. 647 */ 648 static const char* 649 ether_sprintf(const u_int8_t *mac) 650 { 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]); 654 return etherbuf; 655 } 656 657 #ifndef isclr 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) 662 #endif 663 664 static void 665 ath_hal_dumpkeycache(FILE *fd, int nkeys) 666 { 667 static const char *keytypenames[] = { 668 "WEP-40", /* AR_KEYTABLE_TYPE_40 */ 669 "WEP-104", /* AR_KEYTABLE_TYPE_104 */ 670 "#2", 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 */ 676 }; 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]; 681 int entry; 682 int first = 1; 683 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; 688 689 macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); 690 if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry)) 691 continue; 692 macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry)); 693 macHi <<= 1; 694 if (macLo & (1<<31)) 695 macHi |= 1; 696 macLo <<= 1; 697 mac[4] = macHi & 0xff; 698 mac[5] = macHi >> 8; 699 mac[0] = macLo & 0xff; 700 mac[1] = macLo >> 8; 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)); 711 if (first) { 712 fprintf(fd, "\n"); 713 first = 0; 714 } 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" 716 , entry 717 , ether_sprintf(mac) 718 , isset(ismic, entry) ? "MIC" : keytypenames[type & 7] 719 , (key0 >> 0) & 0xff 720 , (key0 >> 8) & 0xff 721 , (key0 >> 16) & 0xff 722 , (key0 >> 24) & 0xff 723 , (key1 >> 0) & 0xff 724 , (key1 >> 8) & 0xff 725 , (key2 >> 0) & 0xff 726 , (key2 >> 8) & 0xff 727 , (key2 >> 16) & 0xff 728 , (key2 >> 24) & 0xff 729 , (key3 >> 0) & 0xff 730 , (key3 >> 8) & 0xff 731 , (key4 >> 0) & 0xff 732 , (key4 >> 8) & 0xff 733 , (key4 >> 16) & 0xff 734 , (key4 >> 24) & 0xff 735 ); 736 } 737 } 738