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
usage(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
main(int argc,char * argv[])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
regcompar(const void * a,const void * b)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
register_regs(struct dumpreg * chipregs,u_int nchipregs,int def_srev_min,int def_srev_max,int def_phy_min,int def_phy_max)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
register_keycache(u_int nslots,int def_srev_min,int def_srev_max,int def_phy_min,int def_phy_max)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
register_range(u_int brange,u_int erange,int type,int def_srev_min,int def_srev_max,int def_phy_min,int def_phy_max)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
match(const struct dumpreg * dr,const HAL_REVS * revs)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
ath_hal_anyregs(int what)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
ath_hal_setupregs(struct ath_diag * atd,int what)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
ath_hal_dumpregs(FILE * fd,int what)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
ath_hal_dumprange(FILE * fd,u_int a,u_int b)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
ath_hal_dumpint(FILE * fd,int what)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
ath_hal_dumpqcu(FILE * fd,int what)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
ath_hal_dumpdcu(FILE * fd,int what)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
ath_hal_dumpbb(FILE * fd,int what)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
ath_hal_setupdiagregs(const HAL_REGRANGE regs[],u_int nr)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*
ether_sprintf(const u_int8_t * mac)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
ath_hal_dumpkeycache(FILE * fd,int nkeys)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