1189704Ssam/*- 2189704Ssam * Copyright (c) 2009 Sam Leffler, Errno Consulting 3189704Ssam * All rights reserved. 4189704Ssam * 5189704Ssam * Redistribution and use in source and binary forms, with or without 6189704Ssam * modification, are permitted provided that the following conditions 7189704Ssam * are met: 8189704Ssam * 1. Redistributions of source code must retain the above copyright 9189704Ssam * notice, this list of conditions and the following disclaimer, 10189704Ssam * without modification. 11189704Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12189704Ssam * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13189704Ssam * redistribution must be conditioned upon including a substantially 14189704Ssam * similar Disclaimer requirement for further binary redistribution. 15189704Ssam * 16189704Ssam * NO WARRANTY 17189704Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18189704Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19189704Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 20189704Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 21189704Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 22189704Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23189704Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24189704Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 25189704Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26189704Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 27189704Ssam * THE POSSIBILITY OF SUCH DAMAGES. 28189704Ssam * 29189704Ssam * $FreeBSD$ 30189704Ssam */ 31189704Ssam#include "diag.h" 32189704Ssam 33189704Ssam#include "ah.h" 34189704Ssam#include "ah_internal.h" 35189704Ssam 36189704Ssam#include "dumpregs.h" 37189704Ssam 38189704Ssam#include <getopt.h> 39189704Ssam#include <stdlib.h> 40189704Ssam#include <string.h> 41189704Ssam#include <ctype.h> 42196599Ssam#include <err.h> 43196599Ssam#include <errno.h> 44189704Ssam 45189704Ssamtypedef struct { 46189704Ssam HAL_REVS revs; 47189704Ssam#define MAXREGS 5*1024 48189704Ssam struct dumpreg *regs[MAXREGS]; 49189704Ssam u_int nregs; 50189704Ssam} dumpregs_t; 51189704Ssamstatic dumpregs_t state; 52189704Ssam 53189704Ssamstatic uint32_t regread(int s, struct ath_diag *atd, uint32_t r); 54189704Ssamstatic void regwrite(int s, struct ath_diag *atd, uint32_t r, uint32_t v); 55189704Ssamstatic const struct dumpreg *reglookup(const char *v); 56189704Ssam 57189704Ssamstatic void 58189704Ssamusage(void) 59189704Ssam{ 60189704Ssam fprintf(stderr, "usage: athpoke [-i interface] [reg[=value]] ...\n"); 61189704Ssam exit(-1); 62189704Ssam} 63189704Ssam 64189704Ssamint 65189704Ssammain(int argc, char *argv[]) 66189704Ssam{ 67189704Ssam struct ath_diag atd; 68189704Ssam const char *ifname; 69196599Ssam char *eptr; 70189704Ssam int c, s; 71189704Ssam 72189704Ssam s = socket(AF_INET, SOCK_DGRAM, 0); 73189704Ssam if (s < 0) 74189704Ssam err(1, "socket"); 75189704Ssam ifname = getenv("ATH"); 76189704Ssam if (!ifname) 77189704Ssam ifname = ATH_DEFAULT; 78189704Ssam 79189704Ssam while ((c = getopt(argc, argv, "i:")) != -1) 80189704Ssam switch (c) { 81189704Ssam case 'i': 82189704Ssam ifname = optarg; 83189704Ssam break; 84189704Ssam default: 85189704Ssam usage(); 86189704Ssam /*NOTREACHED*/ 87189704Ssam } 88189704Ssam strncpy(atd.ad_name, ifname, sizeof (atd.ad_name)); 89189704Ssam 90189704Ssam atd.ad_id = HAL_DIAG_REVS; 91189704Ssam atd.ad_out_data = (caddr_t) &state.revs; 92189704Ssam atd.ad_out_size = sizeof(state.revs); 93189704Ssam if (ioctl(s, SIOCGATHDIAG, &atd) < 0) 94189704Ssam err(1, atd.ad_name); 95189704Ssam 96189704Ssam argc -= optind; 97189704Ssam argv += optind; 98189704Ssam 99189704Ssam for (; argc > 0; argc--, argv++) { 100189704Ssam char *cp; 101189704Ssam const struct dumpreg *dr; 102189704Ssam uint32_t reg; 103189704Ssam 104189704Ssam cp = strchr(argv[0], '='); 105189704Ssam if (cp != NULL) 106189704Ssam *cp++ = '\0'; 107189704Ssam dr = reglookup(argv[0]); 108196599Ssam if (dr == NULL) { 109196599Ssam errno = 0; 110196599Ssam reg = (uint32_t) strtoul(argv[0], &eptr, 0); 111196599Ssam if (argv[0] == eptr || eptr[0] != '\0') 112196599Ssam errx(1, "invalid register \"%s\"", argv[0]); 113196599Ssam } else 114196599Ssam reg = dr->addr; 115189704Ssam if (cp != NULL) 116189704Ssam regwrite(s, &atd, reg, (uint32_t) strtoul(cp, NULL, 0)); 117194872Ssam printf("%s = %08x\n", argv[0], regread(s, &atd, reg)); 118189704Ssam } 119189704Ssam return 0; 120189704Ssam} 121189704Ssam 122189704Ssamstatic uint32_t 123189704Ssamregread(int s, struct ath_diag *atd, uint32_t r) 124189704Ssam{ 125189704Ssam HAL_REGRANGE ra; 126189704Ssam uint32_t v[2]; 127189704Ssam 128189704Ssam ra.start = r; 129189704Ssam ra.end = 0; 130189704Ssam 131189704Ssam atd->ad_in_data = (caddr_t) &ra; 132189704Ssam atd->ad_in_size = sizeof(ra); 133189704Ssam atd->ad_out_data = (caddr_t) v; 134189704Ssam atd->ad_out_size = sizeof(v); 135189704Ssam atd->ad_id = HAL_DIAG_REGS | ATH_DIAG_IN | ATH_DIAG_DYN; 136189704Ssam if (ioctl(s, SIOCGATHDIAG, atd) < 0) 137189704Ssam err(1, atd->ad_name); 138189704Ssam return v[1]; 139189704Ssam} 140189704Ssam 141189704Ssamstatic void 142189704Ssamregwrite(int s, struct ath_diag *atd, uint32_t r, uint32_t v) 143189704Ssam{ 144189704Ssam HAL_REGWRITE rw; 145189704Ssam 146189704Ssam rw.addr = r; 147189704Ssam rw.value = v; 148189704Ssam atd->ad_in_data = (caddr_t) &rw; 149189704Ssam atd->ad_in_size = sizeof(rw); 150189704Ssam atd->ad_id = HAL_DIAG_SETREGS | ATH_DIAG_IN; 151189704Ssam if (ioctl(s, SIOCGATHDIAG, atd) < 0) 152189704Ssam err(1, atd->ad_name); 153189704Ssam} 154189704Ssam 155189704Ssamstatic int 156189704Ssamregcompar(const void *a, const void *b) 157189704Ssam{ 158189704Ssam const struct dumpreg *ra = *(const struct dumpreg **)a; 159189704Ssam const struct dumpreg *rb = *(const struct dumpreg **)b; 160189704Ssam return ra->addr - rb->addr; 161189704Ssam} 162189704Ssam 163189704Ssamvoid 164189704Ssamregister_regs(struct dumpreg *chipregs, u_int nchipregs, 165189704Ssam int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 166189704Ssam{ 167189704Ssam const int existing_regs = state.nregs; 168189704Ssam int i, j; 169189704Ssam 170189704Ssam for (i = 0; i < nchipregs; i++) { 171189704Ssam struct dumpreg *nr = &chipregs[i]; 172189704Ssam if (nr->srevMin == 0) 173189704Ssam nr->srevMin = def_srev_min; 174189704Ssam if (nr->srevMax == 0) 175189704Ssam nr->srevMax = def_srev_max; 176189704Ssam if (nr->phyMin == 0) 177189704Ssam nr->phyMin = def_phy_min; 178189704Ssam if (nr->phyMax == 0) 179189704Ssam nr->phyMax = def_phy_max; 180189704Ssam for (j = 0; j < existing_regs; j++) { 181189704Ssam struct dumpreg *r = state.regs[j]; 182189704Ssam /* 183189704Ssam * Check if we can just expand the mac+phy 184189704Ssam * coverage for the existing entry. 185189704Ssam */ 186189704Ssam if (nr->addr == r->addr && 187189704Ssam (nr->name == r->name || 188189704Ssam nr->name != NULL && r->name != NULL && 189189704Ssam strcmp(nr->name, r->name) == 0)) { 190189704Ssam if (nr->srevMin < r->srevMin && 191189704Ssam (r->srevMin <= nr->srevMax && 192189704Ssam nr->srevMax+1 <= r->srevMax)) { 193189704Ssam r->srevMin = nr->srevMin; 194189704Ssam goto skip; 195189704Ssam } 196189704Ssam if (nr->srevMax > r->srevMax && 197189704Ssam (r->srevMin <= nr->srevMin && 198189704Ssam nr->srevMin <= r->srevMax)) { 199189704Ssam r->srevMax = nr->srevMax; 200189704Ssam goto skip; 201189704Ssam } 202189704Ssam } 203189704Ssam if (r->addr > nr->addr) 204189704Ssam break; 205189704Ssam } 206189704Ssam /* 207189704Ssam * New item, add to the end, it'll be sorted below. 208189704Ssam */ 209189704Ssam if (state.nregs == MAXREGS) 210189704Ssam errx(-1, "too many registers; bump MAXREGS"); 211189704Ssam state.regs[state.nregs++] = nr; 212189704Ssam skip: 213189704Ssam ; 214189704Ssam } 215189704Ssam qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar); 216189704Ssam} 217189704Ssam 218189704Ssamvoid 219189704Ssamregister_keycache(u_int nslots, 220189704Ssam int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 221189704Ssam{ 222189704Ssam /* discard, no use */ 223189704Ssam} 224189704Ssam 225189704Ssamvoid 226189704Ssamregister_range(u_int brange, u_int erange, int type, 227189704Ssam int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max) 228189704Ssam{ 229189704Ssam /* discard, no use */ 230189704Ssam} 231189704Ssam 232189704Ssamstatic const struct dumpreg * 233189704Ssamreglookup(const char *v) 234189704Ssam{ 235189704Ssam const HAL_REVS *revs = &state.revs; 236189704Ssam int i; 237189704Ssam 238189704Ssam if (strncasecmp(v, "AR_", 3) == 0) 239189704Ssam v += 3; 240189704Ssam for (i = 0; i < state.nregs; i++) { 241189704Ssam const struct dumpreg *dr = state.regs[i]; 242189704Ssam if (MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev) && 243189704Ssam strcasecmp(v, dr->name) == 0) 244189704Ssam return dr; 245189704Ssam } 246189704Ssam return NULL; 247189704Ssam} 248