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 46typedef 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; 55static dumpregs_t state; 56 57#undef OS_REG_READ 58#define OS_REG_READ(ah, off) state.regdata[(off) >> 2] 59 60static int ath_hal_anyregs(int what); 61static int ath_hal_setupregs(struct ath_diag *atd, int what); 62static u_int ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr); 63static void ath_hal_dumpregs(FILE *fd, int what); 64static void ath_hal_dumprange(FILE *fd, u_int a, u_int b); 65static void ath_hal_dumpkeycache(FILE *fd, int nkeys); 66static void ath_hal_dumpint(FILE *fd, int what); 67static void ath_hal_dumpqcu(FILE *fd, int what); 68static void ath_hal_dumpdcu(FILE *fd, int what); 69static void ath_hal_dumpbb(FILE *fd, int what); 70 71static void 72usage(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 89int 90main(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] >> 16; /* start of range */ 186 u_int e = dp[0] & 0xffff; /* end of range */ 187 dp++; 188 /* convert offsets to indices */ 189 r >>= 2; e >>= 2; 190 do { 191 if (dp >= ep) { 192 fprintf(stderr, "Warning, botched return data;" 193 "register at offset 0x%x not present\n", 194 r << 2); 195 break; 196 } 197 state.regdata[r++] = *dp++; 198 } while (r <= e); 199 } 200 201 if (what & DUMP_BASIC) 202 ath_hal_dumpregs(stdout, DUMP_BASIC); 203 if ((what & DUMP_INTERRUPT) && ath_hal_anyregs(DUMP_INTERRUPT)) { 204 if (what & DUMP_BASIC) 205 putchar('\n'); 206 if (state.show_addrs) 207 ath_hal_dumpregs(stdout, DUMP_INTERRUPT); 208 else 209 ath_hal_dumpint(stdout, what); 210 } 211 if ((what & DUMP_QCU) && ath_hal_anyregs(DUMP_QCU)) { 212 if (what & (DUMP_BASIC|DUMP_INTERRUPT)) 213 putchar('\n'); 214 if (state.show_addrs) 215 ath_hal_dumpregs(stdout, DUMP_QCU); 216 else 217 ath_hal_dumpqcu(stdout, what); 218 } 219 if ((what & DUMP_DCU) && ath_hal_anyregs(DUMP_DCU)) { 220 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU)) 221 putchar('\n'); 222 if (state.show_addrs) 223 ath_hal_dumpregs(stdout, DUMP_DCU); 224 else 225 ath_hal_dumpdcu(stdout, what); 226 } 227 if (what & DUMP_KEYCACHE) { 228 if (state.show_addrs) { 229 if (what & (DUMP_BASIC|DUMP_INTERRUPT|DUMP_QCU|DUMP_DCU)) 230 putchar('\n'); 231 ath_hal_dumpregs(stdout, DUMP_KEYCACHE); 232 } else 233 ath_hal_dumpkeycache(stdout, 128); 234 } 235 if (what & DUMP_BASEBAND) { 236 if (what &~ DUMP_BASEBAND) 237 fprintf(stdout, "\n"); 238 ath_hal_dumpbb(stdout, what); 239 } 240 return 0; 241} 242 243static int 244regcompar(const void *a, const void *b) 245{ 246 const struct dumpreg *ra = *(const struct dumpreg **)a; 247 const struct dumpreg *rb = *(const struct dumpreg **)b; 248 return ra->addr - rb->addr; 249} 250 251void 252register_regs(struct dumpreg *chipregs, u_int nchipregs, 253 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 254{ 255 const int existing_regs = state.nregs; 256 int i, j; 257 258 for (i = 0; i < nchipregs; i++) { 259 struct dumpreg *nr = &chipregs[i]; 260 if (nr->srevMin == 0) 261 nr->srevMin = def_srev_min; 262 if (nr->srevMax == 0) 263 nr->srevMax = def_srev_max; 264 if (nr->phyMin == 0) 265 nr->phyMin = def_phy_min; 266 if (nr->phyMax == 0) 267 nr->phyMax = def_phy_max; 268 for (j = 0; j < existing_regs; j++) { 269 struct dumpreg *r = state.regs[j]; 270 /* 271 * Check if we can just expand the mac+phy 272 * coverage for the existing entry. 273 */ 274 if (nr->addr == r->addr && 275 (nr->name == r->name || 276 nr->name != NULL && r->name != NULL && 277 strcmp(nr->name, r->name) == 0)) { 278 if (nr->srevMin < r->srevMin && 279 (r->srevMin <= nr->srevMax && 280 nr->srevMax+1 <= r->srevMax)) { 281 r->srevMin = nr->srevMin; 282 goto skip; 283 } 284 if (nr->srevMax > r->srevMax && 285 (r->srevMin <= nr->srevMin && 286 nr->srevMin <= r->srevMax)) { 287 r->srevMax = nr->srevMax; 288 goto skip; 289 } 290 } 291 if (r->addr > nr->addr) 292 break; 293 } 294 /* 295 * New item, add to the end, it'll be sorted below. 296 */ 297 if (state.nregs == MAXREGS) 298 errx(-1, "too many registers; bump MAXREGS"); 299 state.regs[state.nregs++] = nr; 300 skip: 301 ; 302 } 303 qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); 304} 305 306void 307register_keycache(u_int nslots, 308 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 309{ 310#define SET(r, a) do { \ 311 r->addr = a; r->type = DUMP_KEYCACHE; r++; \ 312} while(0) 313 struct dumpreg *keyregs, *r; 314 int i; 315 316 keyregs = (struct dumpreg *) calloc(nslots, 8*sizeof(struct dumpreg)); 317 if (keyregs == NULL) 318 errx(-1, "no space to %d keycache slots\n", nslots); 319 r = keyregs; 320 for (i = 0; i < nslots; i++) { 321 SET(r, AR_KEYTABLE_KEY0(i)); 322 SET(r, AR_KEYTABLE_KEY1(i)); 323 SET(r, AR_KEYTABLE_KEY2(i)); 324 SET(r, AR_KEYTABLE_KEY3(i)); 325 SET(r, AR_KEYTABLE_KEY4(i)); 326 SET(r, AR_KEYTABLE_TYPE(i)); 327 SET(r, AR_KEYTABLE_MAC0(i)); 328 SET(r, AR_KEYTABLE_MAC1(i)); 329 } 330 register_regs(keyregs, 8*nslots, 331 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 332#undef SET 333} 334 335void 336register_range(u_int brange, u_int erange, int type, 337 int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 338{ 339 struct dumpreg *bbregs, *r; 340 int i, nregs; 341 342 nregs = (erange - brange) / sizeof(uint32_t); 343 bbregs = (struct dumpreg *) calloc(nregs, sizeof(struct dumpreg)); 344 if (bbregs == NULL) 345 errx(-1, "no space for %d register slots (type %d)\n", 346 nregs, type); 347 r = bbregs; 348 for (i = 0; i < nregs; i++) { 349 r->addr = brange + (i<<2); 350 r->type = type; 351 r++; 352 } 353 register_regs(bbregs, nregs, 354 def_srev_min, def_srev_max, def_phy_min, def_phy_max); 355} 356 357static __inline int 358match(const struct dumpreg *dr, const HAL_REVS *revs) 359{ 360 if (!MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev)) 361 return 0; 362 if ((dr->type & DUMP_BASEBAND) && !PHY_MATCH(dr, revs->ah_phyRev)) 363 return 0; 364 return 1; 365} 366 367static int 368ath_hal_anyregs(int what) 369{ 370 const HAL_REVS *revs = &state.revs; 371 int i; 372 373 for (i = 0; i < state.nregs; i++) { 374 const struct dumpreg *dr = state.regs[i]; 375 if ((what & dr->type) && match(dr, revs)) 376 return 1; 377 } 378 return 0; 379} 380 381static int 382ath_hal_setupregs(struct ath_diag *atd, int what) 383{ 384 const HAL_REVS *revs = &state.revs; 385 HAL_REGRANGE r; 386 size_t space = 0; 387 u_int8_t *cp; 388 int i, brun, erun; 389 390 brun = erun = -1; 391 for (i = 0; i < state.nregs; i++) { 392 const struct dumpreg *dr = state.regs[i]; 393 if ((what & dr->type) && match(dr, revs)) { 394 if (erun + 4 != dr->addr) { 395 if (brun != -1) 396 space += sizeof(HAL_REGRANGE); 397 brun = erun = dr->addr; 398 } else 399 erun = dr->addr; 400 } 401 } 402 space += sizeof(HAL_REGRANGE); 403 404 atd->ad_in_data = (caddr_t) malloc(space); 405 if (atd->ad_in_data == NULL) { 406 fprintf(stderr, "Cannot malloc memory for registers!\n"); 407 exit(-1); 408 } 409 atd->ad_in_size = space; 410 cp = (u_int8_t *) atd->ad_in_data; 411 brun = erun = -1; 412 for (i = 0; i < state.nregs; i++) { 413 const struct dumpreg *dr = state.regs[i]; 414 if ((what & dr->type) && match(dr, revs)) { 415 if (erun + 4 != dr->addr) { 416 if (brun != -1) { 417 r.start = brun, r.end = erun; 418 memcpy(cp, &r, sizeof(r)); 419 cp += sizeof(r); 420 } 421 brun = erun = dr->addr; 422 } else 423 erun = dr->addr; 424 } 425 } 426 if (brun != -1) { 427 r.start = brun, r.end = erun; 428 memcpy(cp, &r, sizeof(r)); 429 cp += sizeof(r); 430 } 431 return space / sizeof(uint32_t); 432} 433 434static void 435ath_hal_dumpregs(FILE *fd, int what) 436{ 437 const HAL_REVS *revs = &state.revs; 438 const char *sep = ""; 439 int i, count, itemsperline; 440 441 count = 0; 442 itemsperline = 4; 443 if (state.show_names && state.show_addrs) 444 itemsperline--; 445 for (i = 0; i < state.nregs; i++) { 446 const struct dumpreg *dr = state.regs[i]; 447 if ((what & dr->type) && match(dr, revs)) { 448 if (state.show_names && dr->name != NULL) { 449 fprintf(fd, "%s%-8s", sep, dr->name); 450 if (state.show_addrs) 451 fprintf(fd, " [%04x]", dr->addr); 452 } else 453 fprintf(fd, "%s%04x", sep, dr->addr); 454 fprintf(fd, " %08x", OS_REG_READ(ah, dr->addr)); 455 sep = " "; 456 if ((++count % itemsperline) == 0) 457 sep = "\n"; 458 } 459 } 460 if (count) 461 fprintf(fd, "\n"); 462} 463 464static void 465ath_hal_dumprange(FILE *fd, u_int a, u_int b) 466{ 467 u_int r; 468 469 for (r = a; r+16 <= b; r += 5*4) 470 fprintf(fd, 471 "%04x %08x %04x %08x %04x %08x %04x %08x %04x %08x\n" 472 , r, OS_REG_READ(ah, r) 473 , r+4, OS_REG_READ(ah, r+4) 474 , r+8, OS_REG_READ(ah, r+8) 475 , r+12, OS_REG_READ(ah, r+12) 476 , r+16, OS_REG_READ(ah, r+16) 477 ); 478 switch (b-r) { 479 case 16: 480 fprintf(fd 481 , "%04x %08x %04x %08x %04x %08x %04x %08x\n" 482 , r, OS_REG_READ(ah, r) 483 , r+4, OS_REG_READ(ah, r+4) 484 , r+8, OS_REG_READ(ah, r+8) 485 , r+12, OS_REG_READ(ah, r+12) 486 ); 487 break; 488 case 12: 489 fprintf(fd, "%04x %08x %04x %08x %04x %08x\n" 490 , r, OS_REG_READ(ah, r) 491 , r+4, OS_REG_READ(ah, r+4) 492 , r+8, OS_REG_READ(ah, r+8) 493 ); 494 break; 495 case 8: 496 fprintf(fd, "%04x %08x %04x %08x\n" 497 , r, OS_REG_READ(ah, r) 498 , r+4, OS_REG_READ(ah, r+4) 499 ); 500 break; 501 case 4: 502 fprintf(fd, "%04x %08x\n" 503 , r, OS_REG_READ(ah, r) 504 ); 505 break; 506 } 507} 508 509static void 510ath_hal_dumpint(FILE *fd, int what) 511{ 512 int i; 513 514 /* Interrupt registers */ 515 fprintf(fd, "IMR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n" 516 , OS_REG_READ(ah, AR_IMR) 517 , OS_REG_READ(ah, AR_IMR_S0) 518 , OS_REG_READ(ah, AR_IMR_S1) 519 , OS_REG_READ(ah, AR_IMR_S2) 520 , OS_REG_READ(ah, AR_IMR_S3) 521 , OS_REG_READ(ah, AR_IMR_S4) 522 ); 523 fprintf(fd, "ISR: %08x S0 %08x S1 %08x S2 %08x S3 %08x S4 %08x\n" 524 , OS_REG_READ(ah, AR_ISR) 525 , OS_REG_READ(ah, AR_ISR_S0) 526 , OS_REG_READ(ah, AR_ISR_S1) 527 , OS_REG_READ(ah, AR_ISR_S2) 528 , OS_REG_READ(ah, AR_ISR_S3) 529 , OS_REG_READ(ah, AR_ISR_S4) 530 ); 531} 532 533static void 534ath_hal_dumpqcu(FILE *fd, int what) 535{ 536 int i; 537 538 /* QCU registers */ 539 fprintf(fd, "%-8s %08x %-8s %08x %-8s %08x\n" 540 , "Q_TXE", OS_REG_READ(ah, AR_Q_TXE) 541 , "Q_TXD", OS_REG_READ(ah, AR_Q_TXD) 542 , "Q_RDYTIMSHD", OS_REG_READ(ah, AR_Q_RDYTIMESHDN) 543 ); 544 fprintf(fd, "Q_ONESHOTARM_SC %08x Q_ONESHOTARM_CC %08x\n" 545 , OS_REG_READ(ah, AR_Q_ONESHOTARM_SC) 546 , OS_REG_READ(ah, AR_Q_ONESHOTARM_CC) 547 ); 548 for (i = 0; i < 10; i++) 549 fprintf(fd, "Q[%u] TXDP %08x CBR %08x RDYT %08x MISC %08x STS %08x\n" 550 , i 551 , OS_REG_READ(ah, AR_QTXDP(i)) 552 , OS_REG_READ(ah, AR_QCBRCFG(i)) 553 , OS_REG_READ(ah, AR_QRDYTIMECFG(i)) 554 , OS_REG_READ(ah, AR_QMISC(i)) 555 , OS_REG_READ(ah, AR_QSTS(i)) 556 ); 557} 558 559static void 560ath_hal_dumpdcu(FILE *fd, int what) 561{ 562 int i; 563 564 /* DCU registers */ 565 for (i = 0; i < 10; i++) 566 fprintf(fd, "D[%u] MASK %08x IFS %08x RTRY %08x CHNT %08x MISC %06x\n" 567 , i 568 , OS_REG_READ(ah, AR_DQCUMASK(i)) 569 , OS_REG_READ(ah, AR_DLCL_IFS(i)) 570 , OS_REG_READ(ah, AR_DRETRY_LIMIT(i)) 571 , OS_REG_READ(ah, AR_DCHNTIME(i)) 572 , OS_REG_READ(ah, AR_DMISC(i)) 573 ); 574} 575 576static void 577ath_hal_dumpbb(FILE *fd, int what) 578{ 579 const HAL_REVS *revs = &state.revs; 580 int i, brun, erun; 581 582 brun = erun = 0; 583 for (i = 0; i < state.nregs; i++) { 584 const struct dumpreg *dr = state.regs[i]; 585 if (!match(dr, revs)) 586 continue; 587 if (dr->type & DUMP_BASEBAND) { 588 if (brun == 0) { 589 brun = erun = dr->addr; 590 } else if (dr->addr == erun + sizeof(uint32_t)) { 591 erun = dr->addr; 592 } else { 593 ath_hal_dumprange(fd, brun, erun); 594 brun = erun = dr->addr; 595 } 596 } else { 597 if (brun != 0) 598 ath_hal_dumprange(fd, brun, erun); 599 brun = erun = 0; 600 } 601 } 602 if (brun != 0) 603 ath_hal_dumprange(fd, brun, erun); 604} 605 606static u_int 607ath_hal_setupdiagregs(const HAL_REGRANGE regs[], u_int nr) 608{ 609 u_int space; 610 int i; 611 612 space = 0; 613 for (i = 0; i < nr; i++) { 614 u_int n = 2 * sizeof(u_int32_t); /* reg range + first */ 615 if (regs[i].end) { 616 if (regs[i].end < regs[i].start) { 617 fprintf(stderr, "%s: bad register range, " 618 "end 0x%x < start 0x%x\n", 619 __func__, regs[i].end, regs[i].end); 620 exit(-1); 621 } 622 n += regs[i].end - regs[i].start; 623 } 624 space += n; 625 } 626 return space; 627} 628 629/* 630 * Format an Ethernet MAC for printing. 631 */ 632static const char* 633ether_sprintf(const u_int8_t *mac) 634{ 635 static char etherbuf[18]; 636 snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x", 637 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 638 return etherbuf; 639} 640 641#ifndef isclr 642#define setbit(a,i) ((a)[(i)/NBBY] |= 1<<((i)%NBBY)) 643#define clrbit(a,i) ((a)[(i)/NBBY] &= ~(1<<((i)%NBBY))) 644#define isset(a,i) ((a)[(i)/NBBY] & (1<<((i)%NBBY))) 645#define isclr(a,i) (((a)[(i)/NBBY] & (1<<((i)%NBBY))) == 0) 646#endif 647 648static void 649ath_hal_dumpkeycache(FILE *fd, int nkeys) 650{ 651 static const char *keytypenames[] = { 652 "WEP-40", /* AR_KEYTABLE_TYPE_40 */ 653 "WEP-104", /* AR_KEYTABLE_TYPE_104 */ 654 "#2", 655 "WEP-128", /* AR_KEYTABLE_TYPE_128 */ 656 "TKIP", /* AR_KEYTABLE_TYPE_TKIP */ 657 "AES-OCB", /* AR_KEYTABLE_TYPE_AES */ 658 "AES-CCM", /* AR_KEYTABLE_TYPE_CCM */ 659 "CLR", /* AR_KEYTABLE_TYPE_CLR */ 660 }; 661 int micEnabled = SREV(state.revs.ah_macVersion, state.revs.ah_macRev) < SREV(4,8) ? 0 : 662 OS_REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_CRPT_MIC_ENABLE; 663 u_int8_t mac[IEEE80211_ADDR_LEN]; 664 u_int8_t ismic[128/NBBY]; 665 int entry; 666 int first = 1; 667 668 memset(ismic, 0, sizeof(ismic)); 669 for (entry = 0; entry < nkeys; entry++) { 670 u_int32_t macLo, macHi, type; 671 u_int32_t key0, key1, key2, key3, key4; 672 673 macHi = OS_REG_READ(ah, AR_KEYTABLE_MAC1(entry)); 674 if ((macHi & AR_KEYTABLE_VALID) == 0 && isclr(ismic, entry)) 675 continue; 676 macLo = OS_REG_READ(ah, AR_KEYTABLE_MAC0(entry)); 677 macHi <<= 1; 678 if (macLo & (1<<31)) 679 macHi |= 1; 680 macLo <<= 1; 681 mac[4] = macHi & 0xff; 682 mac[5] = macHi >> 8; 683 mac[0] = macLo & 0xff; 684 mac[1] = macLo >> 8; 685 mac[2] = macLo >> 16; 686 mac[3] = macLo >> 24; 687 type = OS_REG_READ(ah, AR_KEYTABLE_TYPE(entry)); 688 if ((type & 7) == AR_KEYTABLE_TYPE_TKIP && micEnabled) 689 setbit(ismic, entry+64); 690 key0 = OS_REG_READ(ah, AR_KEYTABLE_KEY0(entry)); 691 key1 = OS_REG_READ(ah, AR_KEYTABLE_KEY1(entry)); 692 key2 = OS_REG_READ(ah, AR_KEYTABLE_KEY2(entry)); 693 key3 = OS_REG_READ(ah, AR_KEYTABLE_KEY3(entry)); 694 key4 = OS_REG_READ(ah, AR_KEYTABLE_KEY4(entry)); 695 if (first) { 696 fprintf(fd, "\n"); 697 first = 0; 698 } 699 fprintf(fd, "KEY[%03u] MAC %s %-7s %02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x\n" 700 , entry 701 , ether_sprintf(mac) 702 , isset(ismic, entry) ? "MIC" : keytypenames[type & 7] 703 , (key0 >> 0) & 0xff 704 , (key0 >> 8) & 0xff 705 , (key0 >> 16) & 0xff 706 , (key0 >> 24) & 0xff 707 , (key1 >> 0) & 0xff 708 , (key1 >> 8) & 0xff 709 , (key2 >> 0) & 0xff 710 , (key2 >> 8) & 0xff 711 , (key2 >> 16) & 0xff 712 , (key2 >> 24) & 0xff 713 , (key3 >> 0) & 0xff 714 , (key3 >> 8) & 0xff 715 , (key4 >> 0) & 0xff 716 , (key4 >> 8) & 0xff 717 , (key4 >> 16) & 0xff 718 , (key4 >> 24) & 0xff 719 ); 720 } 721} 722