]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - tools/tools/ath/athregs/dumpregs.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / tools / tools / ath / athregs / dumpregs.c
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] >> 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
243 static int
244 regcompar(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
251 void
252 register_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
306 void
307 register_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
335 void
336 register_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
357 static __inline int
358 match(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
367 static int
368 ath_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
381 static int
382 ath_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
434 static void
435 ath_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
464 static void
465 ath_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
509 static void
510 ath_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
533 static void
534 ath_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
559 static void
560 ath_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
576 static void
577 ath_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
606 static u_int
607 ath_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  */
632 static const char*
633 ether_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
648 static void
649 ath_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 }