/*- * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any * redistribution must be conditioned upon including a substantially * similar Disclaimer requirement for further binary redistribution. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. * * $FreeBSD$ */ #include "diag.h" #include "ah.h" #include "ah_internal.h" #include "ah_decode.h" #include "dumpregs.h" #include #include #include #include #include #include typedef struct { HAL_REVS revs; int chipnum; #define MAXREGS 5*1024 struct dumpreg *regs[MAXREGS]; u_int nregs; } dumpregs_t; static dumpregs_t state; static void opdevice(const struct athregrec *r); static const char* opmark(FILE *, int, const struct athregrec *); static void oprw(FILE *fd, int recnum, struct athregrec *r); int main(int argc, char *argv[]) { int fd, i, nrecs, same; struct stat sb; void *addr; const char *filename = "/tmp/ath_hal.log"; struct athregrec *rprev; if (argc > 1) filename = argv[1]; fd = open(filename, O_RDONLY); if (fd < 0) err(1, "open: %s", filename); if (fstat(fd, &sb) < 0) err(1, "fstat"); addr = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE|MAP_NOCORE, fd, 0); if (addr == MAP_FAILED) err(1, "mmap"); nrecs = sb.st_size / sizeof (struct athregrec); printf("%u records", nrecs); rprev = NULL; same = 0; state.chipnum = 5210; for (i = 0; i < nrecs; i++) { struct athregrec *r = &((struct athregrec *) addr)[i]; if (rprev && bcmp(r, rprev, sizeof (*r)) == 0) { same++; continue; } if (same) printf("\t\t+%u time%s", same, same == 1 ? "" : "s"); switch (r->op) { case OP_DEVICE: opdevice(r); break; case OP_READ: case OP_WRITE: oprw(stdout, i, r); break; case OP_MARK: opmark(stdout, i, r); break; } rprev = r; same = 0; } putchar('\n'); return 0; } static const char* opmark(FILE *fd, int i, const struct athregrec *r) { fprintf(fd, "\n%05d: ", i); switch (r->reg) { case AH_MARK_RESET: fprintf(fd, "ar%uReset %s", state.chipnum, r->val ? "change channel" : "no channel change"); break; case AH_MARK_RESET_LINE: fprintf(fd, "ar%u_reset.c; line %u", state.chipnum, r->val); break; case AH_MARK_RESET_DONE: if (r->val) fprintf(fd, "ar%uReset (done), FAIL, error %u", state.chipnum, r->val); else fprintf(fd, "ar%uReset (done), OK", state.chipnum); break; case AH_MARK_CHIPRESET: fprintf(fd, "ar%uChipReset, channel %u MHz", state.chipnum, r->val); break; case AH_MARK_PERCAL: fprintf(fd, "ar%uPerCalibration, channel %u MHz", state.chipnum, r->val); break; case AH_MARK_SETCHANNEL: fprintf(fd, "ar%uSetChannel, channel %u MHz", state.chipnum, r->val); break; case AH_MARK_ANI_RESET: switch (r->val) { case HAL_M_STA: fprintf(fd, "ar%uAniReset, HAL_M_STA", state.chipnum); break; case HAL_M_IBSS: fprintf(fd, "ar%uAniReset, HAL_M_IBSS", state.chipnum); break; case HAL_M_HOSTAP: fprintf(fd, "ar%uAniReset, HAL_M_HOSTAP", state.chipnum); break; case HAL_M_MONITOR: fprintf(fd, "ar%uAniReset, HAL_M_MONITOR", state.chipnum); break; default: fprintf(fd, "ar%uAniReset, opmode %u", state.chipnum, r->val); break; } break; case AH_MARK_ANI_POLL: fprintf(fd, "ar%uAniPoll, listenTime %u", state.chipnum, r->val); break; case AH_MARK_ANI_CONTROL: switch (r->val) { case HAL_ANI_PRESENT: fprintf(fd, "ar%uAniControl, PRESENT", state.chipnum); break; case HAL_ANI_NOISE_IMMUNITY_LEVEL: fprintf(fd, "ar%uAniControl, NOISE_IMMUNITY", state.chipnum); break; case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION: fprintf(fd, "ar%uAniControl, OFDM_WEAK_SIGNAL", state.chipnum); break; case HAL_ANI_CCK_WEAK_SIGNAL_THR: fprintf(fd, "ar%uAniControl, CCK_WEAK_SIGNAL", state.chipnum); break; case HAL_ANI_FIRSTEP_LEVEL: fprintf(fd, "ar%uAniControl, FIRSTEP_LEVEL", state.chipnum); break; case HAL_ANI_SPUR_IMMUNITY_LEVEL: fprintf(fd, "ar%uAniControl, SPUR_IMMUNITY", state.chipnum); break; case HAL_ANI_MODE: fprintf(fd, "ar%uAniControl, MODE", state.chipnum); break; case HAL_ANI_PHYERR_RESET: fprintf(fd, "ar%uAniControl, PHYERR_RESET", state.chipnum); break; default: fprintf(fd, "ar%uAniControl, cmd %u", state.chipnum, r->val); break; } break; default: fprintf(fd, "mark #%u value %u/0x%x", r->reg, r->val, r->val); break; } exit(0); } #include "ah_devid.h" static void opdevice(const struct athregrec *r) { switch (r->val) { case AR5210_PROD: case AR5210_DEFAULT: state.chipnum = 5210; state.revs.ah_macVersion = 1; state.revs.ah_macRev = 0; break; case AR5211_DEVID: case AR5311_DEVID: case AR5211_DEFAULT: case AR5211_FPGA11B: state.chipnum = 5211; state.revs.ah_macVersion = 2; state.revs.ah_macRev = 0; break; /* AR5212 */ case AR5212_DEFAULT: case AR5212_DEVID: case AR5212_FPGA: case AR5212_DEVID_IBM: case AR5212_AR5312_REV2: case AR5212_AR5312_REV7: case AR5212_AR2313_REV8: case AR5212_AR2315_REV6: case AR5212_AR2315_REV7: case AR5212_AR2317_REV1: case AR5212_AR2317_REV2: /* AR5212 compatible devid's also attach to 5212 */ case AR5212_DEVID_0014: case AR5212_DEVID_0015: case AR5212_DEVID_0016: case AR5212_DEVID_0017: case AR5212_DEVID_0018: case AR5212_DEVID_0019: case AR5212_AR2413: case AR5212_AR5413: case AR5212_AR5424: case AR5212_AR2417: case AR5212_DEVID_FF19: state.chipnum = 5212; state.revs.ah_macVersion = 4; state.revs.ah_macRev = 5; break; /* AR5213 */ case AR5213_SREV_1_0: case AR5213_SREV_REG: state.chipnum = 5213; state.revs.ah_macVersion = 5; state.revs.ah_macRev = 9; break; /* AR5416 compatible devid's */ case AR5416_DEVID_PCI: case AR5416_DEVID_PCIE: case AR9160_DEVID_PCI: case AR9280_DEVID_PCI: case AR9280_DEVID_PCIE: case AR9285_DEVID_PCIE: state.chipnum = 5416; state.revs.ah_macVersion = 13; state.revs.ah_macRev = 8; break; default: printf("Unknown device id 0x%x\n", r->val); exit(-1); } } static int regcompar(const void *a, const void *b) { const struct dumpreg *ra = *(const struct dumpreg **)a; const struct dumpreg *rb = *(const struct dumpreg **)b; return ra->addr - rb->addr; } 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) { const int existing_regs = state.nregs; int i, j; for (i = 0; i < nchipregs; i++) { struct dumpreg *nr = &chipregs[i]; if (nr->srevMin == 0) nr->srevMin = def_srev_min; if (nr->srevMax == 0) nr->srevMax = def_srev_max; if (nr->phyMin == 0) nr->phyMin = def_phy_min; if (nr->phyMax == 0) nr->phyMax = def_phy_max; for (j = 0; j < existing_regs; j++) { struct dumpreg *r = state.regs[j]; /* * Check if we can just expand the mac+phy * coverage for the existing entry. */ if (nr->addr == r->addr && (nr->name == r->name || (nr->name != NULL && r->name != NULL && strcmp(nr->name, r->name) == 0))) { if (nr->srevMin < r->srevMin && (r->srevMin <= nr->srevMax && nr->srevMax+1 <= r->srevMax)) { r->srevMin = nr->srevMin; goto skip; } if (nr->srevMax > r->srevMax && (r->srevMin <= nr->srevMin && nr->srevMin <= r->srevMax)) { r->srevMax = nr->srevMax; goto skip; } } if (r->addr > nr->addr) break; } /* * New item, add to the end, it'll be sorted below. */ if (state.nregs == MAXREGS) errx(-1, "too many registers; bump MAXREGS"); state.regs[state.nregs++] = nr; skip: ; } qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); } void register_keycache(u_int nslots, int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) { /* discard, no use */ } 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) { /* discard, no use */ } static const struct dumpreg * findreg(int reg) { const HAL_REVS *revs = &state.revs; int i; for (i = 0; i < state.nregs; i++) { const struct dumpreg *dr = state.regs[i]; if (dr->addr == reg && MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev)) return dr; } return NULL; } /* XXX cheat, 5212 has a superset of the key table defs */ #include "ar5212/ar5212reg.h" #include "ar5212/ar5212phy.h" #define PWR_TABLE_SIZE 64 static void oprw(FILE *fd, int recnum, struct athregrec *r) { const struct dumpreg *dr; char buf[64]; const char* bits; int i; fprintf(fd, "\n%05d: [%d] ", recnum, r->threadid); dr = findreg(r->reg); if (dr != NULL && dr->name != NULL) { snprintf(buf, sizeof (buf), "AR_%s (0x%x)", dr->name, r->reg); bits = dr->bits; } else if (AR_KEYTABLE(0) <= r->reg && r->reg < AR_KEYTABLE(128)) { snprintf(buf, sizeof (buf), "AR_KEYTABLE%u(%u) (0x%x)", ((r->reg - AR_KEYTABLE_0) >> 2) & 7, (r->reg - AR_KEYTABLE_0) >> 5, r->reg); bits = NULL; #if 0 } else if (AR_PHY_PCDAC_TX_POWER(0) <= r->reg && r->reg < AR_PHY_PCDAC_TX_POWER(PWR_TABLE_SIZE/2)) { snprintf(buf, sizeof (buf), "AR_PHY_PCDAC_TX_POWER(%u) (0x%x)", (r->reg - AR_PHY_PCDAC_TX_POWER_0) >> 2, r->reg); bits = NULL; #endif } else if (AR_RATE_DURATION(0) <= r->reg && r->reg < AR_RATE_DURATION(32)) { snprintf(buf, sizeof (buf), "AR_RATE_DURATION(0x%x) (0x%x)", (r->reg - AR_RATE_DURATION_0) >> 2, r->reg); bits = NULL; } else if (AR_PHY_BASE <= r->reg) { snprintf(buf, sizeof (buf), "AR_PHY(%u) (0x%x)", (r->reg - AR_PHY_BASE) >> 2, r->reg); bits = NULL; } else { snprintf(buf, sizeof (buf), "0x%x", r->reg); bits = NULL; } fprintf(fd, "%-30s %s 0x%x", buf, r->op ? "<=" : "=>", r->val); if (bits) { const char *p = bits; int tmp, n; for (tmp = 0, p++; *p;) { n = *p++; if (r->val & (1 << (n - 1))) { putc(tmp ? ',' : '<', fd); for (; (n = *p) > ' '; ++p) putc(n, fd); tmp = 1; } else for (; *p > ' '; ++p) continue; } if (tmp) putc('>', fd); } }