1189702Ssam/*-
2189702Ssam * Copyright (c) 2002-2009 Sam Leffler, Errno Consulting
3189702Ssam * All rights reserved.
4189702Ssam *
5189702Ssam * Redistribution and use in source and binary forms, with or without
6189702Ssam * modification, are permitted provided that the following conditions
7189702Ssam * are met:
8189702Ssam * 1. Redistributions of source code must retain the above copyright
9189702Ssam *    notice, this list of conditions and the following disclaimer,
10189702Ssam *    without modification.
11189702Ssam * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12189702Ssam *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13189702Ssam *    redistribution must be conditioned upon including a substantially
14189702Ssam *    similar Disclaimer requirement for further binary redistribution.
15189702Ssam *
16189702Ssam * NO WARRANTY
17189702Ssam * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18189702Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19189702Ssam * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
20189702Ssam * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21189702Ssam * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22189702Ssam * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23189702Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24189702Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25189702Ssam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26189702Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27189702Ssam * THE POSSIBILITY OF SUCH DAMAGES.
28189702Ssam *
29189702Ssam * $FreeBSD$
30189702Ssam */
31189702Ssam#include "diag.h"
32189702Ssam
33189702Ssam#include "ah.h"
34189702Ssam#include "ah_internal.h"
35189702Ssam#include "ah_decode.h"
36189702Ssam
37189702Ssam#include "dumpregs.h"
38189702Ssam
39189702Ssam#include <stdlib.h>
40217680Sadrian#include <string.h>
41217680Sadrian#include <err.h>
42189702Ssam#include <sys/file.h>
43189702Ssam#include <sys/stat.h>
44189702Ssam#include <sys/mman.h>
45189702Ssam
46189702Ssamtypedef struct {
47189702Ssam	HAL_REVS revs;
48189702Ssam	int chipnum;
49189702Ssam#define	MAXREGS	5*1024
50189702Ssam	struct dumpreg *regs[MAXREGS];
51189702Ssam	u_int nregs;
52189702Ssam} dumpregs_t;
53189702Ssamstatic	dumpregs_t state;
54189702Ssam
55189702Ssamstatic void opdevice(const struct athregrec *r);
56189702Ssamstatic const char* opmark(FILE *, int, const struct athregrec *);
57189702Ssamstatic void oprw(FILE *fd, int recnum, struct athregrec *r);
58189702Ssam
59189702Ssamint
60189702Ssammain(int argc, char *argv[])
61189702Ssam{
62189702Ssam	int fd, i, nrecs, same;
63189702Ssam	struct stat sb;
64189702Ssam	void *addr;
65189702Ssam	const char *filename = "/tmp/ath_hal.log";
66189702Ssam	struct athregrec *rprev;
67189702Ssam
68189702Ssam	if (argc > 1)
69189702Ssam		filename = argv[1];
70189702Ssam	fd = open(filename, O_RDONLY);
71189702Ssam	if (fd < 0)
72244962Sadrian		err(1, "open: %s", filename);
73189702Ssam	if (fstat(fd, &sb) < 0)
74189702Ssam		err(1, "fstat");
75189702Ssam	addr = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE|MAP_NOCORE, fd, 0);
76189702Ssam	if (addr == MAP_FAILED)
77189702Ssam		err(1, "mmap");
78189702Ssam	nrecs = sb.st_size / sizeof (struct athregrec);
79189702Ssam	printf("%u records", nrecs);
80189702Ssam	rprev = NULL;
81189702Ssam	same = 0;
82189702Ssam	state.chipnum = 5210;
83189702Ssam	for (i = 0; i < nrecs; i++) {
84189702Ssam		struct athregrec *r = &((struct athregrec *) addr)[i];
85189702Ssam		if (rprev && bcmp(r, rprev, sizeof (*r)) == 0) {
86189702Ssam			same++;
87189702Ssam			continue;
88189702Ssam		}
89189702Ssam		if (same)
90189702Ssam			printf("\t\t+%u time%s", same, same == 1 ? "" : "s");
91189702Ssam		switch (r->op) {
92189702Ssam		case OP_DEVICE:
93189702Ssam			opdevice(r);
94189702Ssam			break;
95189702Ssam		case OP_READ:
96189702Ssam		case OP_WRITE:
97189702Ssam			oprw(stdout, i, r);
98189702Ssam			break;
99189702Ssam		case OP_MARK:
100189702Ssam			opmark(stdout, i, r);
101189702Ssam			break;
102189702Ssam		}
103189702Ssam		rprev = r;
104189702Ssam		same = 0;
105189702Ssam	}
106189702Ssam	putchar('\n');
107189702Ssam	return 0;
108189702Ssam}
109189702Ssam
110189702Ssamstatic const char*
111189702Ssamopmark(FILE *fd, int i, const struct athregrec *r)
112189702Ssam{
113189702Ssam	fprintf(fd, "\n%05d: ", i);
114189702Ssam	switch (r->reg) {
115189702Ssam	case AH_MARK_RESET:
116189702Ssam		fprintf(fd, "ar%uReset %s", state.chipnum,
117189702Ssam			r->val ? "change channel" : "no channel change");
118189702Ssam		break;
119189702Ssam	case AH_MARK_RESET_LINE:
120189702Ssam		fprintf(fd, "ar%u_reset.c; line %u", state.chipnum, r->val);
121189702Ssam		break;
122189702Ssam	case AH_MARK_RESET_DONE:
123189702Ssam		if (r->val)
124189702Ssam			fprintf(fd, "ar%uReset (done), FAIL, error %u",
125189702Ssam				state.chipnum, r->val);
126189702Ssam		else
127189702Ssam			fprintf(fd, "ar%uReset (done), OK", state.chipnum);
128189702Ssam		break;
129189702Ssam	case AH_MARK_CHIPRESET:
130202161Sgavin		fprintf(fd, "ar%uChipReset, channel %u MHz", state.chipnum, r->val);
131189702Ssam		break;
132189702Ssam	case AH_MARK_PERCAL:
133202161Sgavin		fprintf(fd, "ar%uPerCalibration, channel %u MHz", state.chipnum, r->val);
134189702Ssam		break;
135189702Ssam	case AH_MARK_SETCHANNEL:
136202161Sgavin		fprintf(fd, "ar%uSetChannel, channel %u MHz", state.chipnum, r->val);
137189702Ssam		break;
138189702Ssam	case AH_MARK_ANI_RESET:
139189702Ssam		switch (r->val) {
140189702Ssam		case HAL_M_STA:
141189702Ssam			fprintf(fd, "ar%uAniReset, HAL_M_STA", state.chipnum);
142189702Ssam			break;
143189702Ssam		case HAL_M_IBSS:
144189702Ssam			fprintf(fd, "ar%uAniReset, HAL_M_IBSS", state.chipnum);
145189702Ssam			break;
146189702Ssam		case HAL_M_HOSTAP:
147189702Ssam			fprintf(fd, "ar%uAniReset, HAL_M_HOSTAP", state.chipnum);
148189702Ssam			break;
149189702Ssam		case HAL_M_MONITOR:
150189702Ssam			fprintf(fd, "ar%uAniReset, HAL_M_MONITOR", state.chipnum);
151189702Ssam			break;
152189702Ssam		default:
153189702Ssam			fprintf(fd, "ar%uAniReset, opmode %u", state.chipnum, r->val);
154189702Ssam			break;
155189702Ssam		}
156189702Ssam		break;
157189702Ssam	case AH_MARK_ANI_POLL:
158189702Ssam		fprintf(fd, "ar%uAniPoll, listenTime %u", state.chipnum, r->val);
159189702Ssam		break;
160189702Ssam	case AH_MARK_ANI_CONTROL:
161189702Ssam		switch (r->val) {
162189702Ssam		case HAL_ANI_PRESENT:
163189702Ssam			fprintf(fd, "ar%uAniControl, PRESENT", state.chipnum);
164189702Ssam			break;
165189702Ssam		case HAL_ANI_NOISE_IMMUNITY_LEVEL:
166189702Ssam			fprintf(fd, "ar%uAniControl, NOISE_IMMUNITY", state.chipnum);
167189702Ssam			break;
168189702Ssam		case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
169189702Ssam			fprintf(fd, "ar%uAniControl, OFDM_WEAK_SIGNAL", state.chipnum);
170189702Ssam			break;
171189702Ssam		case HAL_ANI_CCK_WEAK_SIGNAL_THR:
172189702Ssam			fprintf(fd, "ar%uAniControl, CCK_WEAK_SIGNAL", state.chipnum);
173189702Ssam			break;
174189702Ssam		case HAL_ANI_FIRSTEP_LEVEL:
175189702Ssam			fprintf(fd, "ar%uAniControl, FIRSTEP_LEVEL", state.chipnum);
176189702Ssam			break;
177189702Ssam		case HAL_ANI_SPUR_IMMUNITY_LEVEL:
178189702Ssam			fprintf(fd, "ar%uAniControl, SPUR_IMMUNITY", state.chipnum);
179189702Ssam			break;
180189702Ssam		case HAL_ANI_MODE:
181189702Ssam			fprintf(fd, "ar%uAniControl, MODE", state.chipnum);
182189702Ssam			break;
183189702Ssam		case HAL_ANI_PHYERR_RESET:
184189702Ssam			fprintf(fd, "ar%uAniControl, PHYERR_RESET", state.chipnum);
185189702Ssam			break;
186189702Ssam		default:
187189702Ssam			fprintf(fd, "ar%uAniControl, cmd %u", state.chipnum, r->val);
188189702Ssam			break;
189189702Ssam		}
190189702Ssam		break;
191189702Ssam	default:
192189702Ssam		fprintf(fd, "mark #%u value %u/0x%x", r->reg, r->val, r->val);
193189702Ssam		break;
194189702Ssam	}
195269638Sadrian	return (NULL);
196189702Ssam}
197189702Ssam
198189702Ssam#include "ah_devid.h"
199189702Ssam
200189702Ssamstatic void
201189702Ssamopdevice(const struct athregrec *r)
202189702Ssam{
203189702Ssam	switch (r->val) {
204189702Ssam	case AR5210_PROD:
205189702Ssam	case AR5210_DEFAULT:
206189702Ssam		state.chipnum = 5210;
207189702Ssam		state.revs.ah_macVersion = 1;
208189702Ssam		state.revs.ah_macRev = 0;
209189702Ssam		break;
210189702Ssam	case AR5211_DEVID:
211189702Ssam	case AR5311_DEVID:
212189702Ssam	case AR5211_DEFAULT:
213189702Ssam	case AR5211_FPGA11B:
214189702Ssam		state.chipnum = 5211;
215189702Ssam		state.revs.ah_macVersion = 2;
216189702Ssam		state.revs.ah_macRev = 0;
217189702Ssam		break;
218189702Ssam	/* AR5212 */
219189702Ssam	case AR5212_DEFAULT:
220189702Ssam	case AR5212_DEVID:
221189702Ssam	case AR5212_FPGA:
222189702Ssam	case AR5212_DEVID_IBM:
223189702Ssam	case AR5212_AR5312_REV2:
224189702Ssam	case AR5212_AR5312_REV7:
225189702Ssam	case AR5212_AR2313_REV8:
226189702Ssam	case AR5212_AR2315_REV6:
227189702Ssam	case AR5212_AR2315_REV7:
228189702Ssam	case AR5212_AR2317_REV1:
229189702Ssam	case AR5212_AR2317_REV2:
230189702Ssam
231189702Ssam	/* AR5212 compatible devid's also attach to 5212 */
232189702Ssam	case AR5212_DEVID_0014:
233189702Ssam	case AR5212_DEVID_0015:
234189702Ssam	case AR5212_DEVID_0016:
235189702Ssam	case AR5212_DEVID_0017:
236189702Ssam	case AR5212_DEVID_0018:
237189702Ssam	case AR5212_DEVID_0019:
238189702Ssam	case AR5212_AR2413:
239189702Ssam	case AR5212_AR5413:
240189702Ssam	case AR5212_AR5424:
241189702Ssam	case AR5212_AR2417:
242189702Ssam	case AR5212_DEVID_FF19:
243189702Ssam		state.chipnum = 5212;
244189702Ssam		state.revs.ah_macVersion = 4;
245189702Ssam		state.revs.ah_macRev = 5;
246189702Ssam		break;
247189702Ssam
248189702Ssam	/* AR5213 */
249189702Ssam	case AR5213_SREV_1_0:
250189702Ssam	case AR5213_SREV_REG:
251189702Ssam		state.chipnum = 5213;
252189702Ssam		state.revs.ah_macVersion = 5;
253189702Ssam		state.revs.ah_macRev = 9;
254189702Ssam		break;
255189702Ssam
256189702Ssam	/* AR5416 compatible devid's  */
257189702Ssam	case AR5416_DEVID_PCI:
258189702Ssam	case AR5416_DEVID_PCIE:
259189702Ssam	case AR9160_DEVID_PCI:
260189702Ssam	case AR9280_DEVID_PCI:
261189702Ssam	case AR9280_DEVID_PCIE:
262189702Ssam	case AR9285_DEVID_PCIE:
263269638Sadrian	case AR9287_DEVID_PCI:
264269638Sadrian	case AR9287_DEVID_PCIE:
265269638Sadrian	case AR9300_DEVID_AR9330:
266189702Ssam		state.chipnum = 5416;
267189702Ssam		state.revs.ah_macVersion = 13;
268189702Ssam		state.revs.ah_macRev = 8;
269189702Ssam		break;
270189702Ssam	default:
271189702Ssam		printf("Unknown device id 0x%x\n", r->val);
272189702Ssam		exit(-1);
273189702Ssam	}
274189702Ssam}
275189702Ssam
276189702Ssamstatic int
277189702Ssamregcompar(const void *a, const void *b)
278189702Ssam{
279189702Ssam	const struct dumpreg *ra = *(const struct dumpreg **)a;
280189702Ssam	const struct dumpreg *rb = *(const struct dumpreg **)b;
281189702Ssam	return ra->addr - rb->addr;
282189702Ssam}
283189702Ssam
284189702Ssamvoid
285189702Ssamregister_regs(struct dumpreg *chipregs, u_int nchipregs,
286189702Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
287189702Ssam{
288189702Ssam	const int existing_regs = state.nregs;
289189702Ssam	int i, j;
290189702Ssam
291189702Ssam	for (i = 0; i < nchipregs; i++) {
292189702Ssam		struct dumpreg *nr = &chipregs[i];
293189702Ssam		if (nr->srevMin == 0)
294189702Ssam			nr->srevMin = def_srev_min;
295189702Ssam		if (nr->srevMax == 0)
296189702Ssam			nr->srevMax = def_srev_max;
297189702Ssam		if (nr->phyMin == 0)
298189702Ssam			nr->phyMin = def_phy_min;
299189702Ssam		if (nr->phyMax == 0)
300189702Ssam			nr->phyMax = def_phy_max;
301189702Ssam		for (j = 0; j < existing_regs; j++) {
302189702Ssam			struct dumpreg *r = state.regs[j];
303189702Ssam			/*
304189702Ssam			 * Check if we can just expand the mac+phy
305189702Ssam			 * coverage for the existing entry.
306189702Ssam			 */
307189702Ssam			if (nr->addr == r->addr &&
308189702Ssam			    (nr->name == r->name ||
309244962Sadrian			     (nr->name != NULL && r->name != NULL &&
310244962Sadrian			     strcmp(nr->name, r->name) == 0))) {
311189702Ssam				if (nr->srevMin < r->srevMin &&
312189702Ssam				    (r->srevMin <= nr->srevMax &&
313189702Ssam				     nr->srevMax+1 <= r->srevMax)) {
314189702Ssam					r->srevMin = nr->srevMin;
315189702Ssam					goto skip;
316189702Ssam				}
317189702Ssam				if (nr->srevMax > r->srevMax &&
318189702Ssam				    (r->srevMin <= nr->srevMin &&
319189702Ssam				     nr->srevMin <= r->srevMax)) {
320189702Ssam					r->srevMax = nr->srevMax;
321189702Ssam					goto skip;
322189702Ssam				}
323189702Ssam			}
324189702Ssam			if (r->addr > nr->addr)
325189702Ssam				break;
326189702Ssam		}
327189702Ssam		/*
328189702Ssam		 * New item, add to the end, it'll be sorted below.
329189702Ssam		 */
330189702Ssam		if (state.nregs == MAXREGS)
331189702Ssam			errx(-1, "too many registers; bump MAXREGS");
332189702Ssam		state.regs[state.nregs++] = nr;
333189702Ssam	skip:
334189702Ssam		;
335189702Ssam	}
336189702Ssam	qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar);
337189702Ssam}
338189702Ssam
339189702Ssamvoid
340189702Ssamregister_keycache(u_int nslots,
341189702Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
342189702Ssam{
343189702Ssam	/* discard, no use */
344189702Ssam}
345189702Ssam
346189702Ssamvoid
347189702Ssamregister_range(u_int brange, u_int erange, int type,
348189702Ssam	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
349189702Ssam{
350189702Ssam	/* discard, no use */
351189702Ssam}
352189702Ssam
353189702Ssamstatic const struct dumpreg *
354189702Ssamfindreg(int reg)
355189702Ssam{
356189702Ssam	const HAL_REVS *revs = &state.revs;
357189702Ssam	int i;
358189702Ssam
359189702Ssam	for (i = 0; i < state.nregs; i++) {
360189702Ssam		const struct dumpreg *dr = state.regs[i];
361189702Ssam		if (dr->addr == reg &&
362189702Ssam		    MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev))
363189702Ssam			return dr;
364189702Ssam	}
365189702Ssam	return NULL;
366189702Ssam}
367189702Ssam
368189702Ssam/* XXX cheat, 5212 has a superset of the key table defs */
369189702Ssam#include "ar5212/ar5212reg.h"
370189702Ssam#include "ar5212/ar5212phy.h"
371189702Ssam
372189702Ssam#define PWR_TABLE_SIZE	64
373189702Ssam
374189702Ssamstatic void
375189702Ssamoprw(FILE *fd, int recnum, struct athregrec *r)
376189702Ssam{
377189702Ssam	const struct dumpreg *dr;
378189702Ssam	char buf[64];
379189702Ssam	const char* bits;
380189702Ssam	int i;
381189702Ssam
382233887Sadrian	fprintf(fd, "\n%05d: [%d] ", recnum, r->threadid);
383189702Ssam	dr = findreg(r->reg);
384189702Ssam	if (dr != NULL && dr->name != NULL) {
385189702Ssam		snprintf(buf, sizeof (buf), "AR_%s (0x%x)", dr->name, r->reg);
386189702Ssam		bits = dr->bits;
387189702Ssam	} else if (AR_KEYTABLE(0) <= r->reg && r->reg < AR_KEYTABLE(128)) {
388189702Ssam		snprintf(buf, sizeof (buf), "AR_KEYTABLE%u(%u) (0x%x)",
389189702Ssam			((r->reg - AR_KEYTABLE_0) >> 2) & 7,
390189702Ssam			(r->reg - AR_KEYTABLE_0) >> 5, r->reg);
391189702Ssam		bits = NULL;
392189702Ssam#if 0
393189702Ssam	} else if (AR_PHY_PCDAC_TX_POWER(0) <= r->reg && r->reg < AR_PHY_PCDAC_TX_POWER(PWR_TABLE_SIZE/2)) {
394189702Ssam		snprintf(buf, sizeof (buf), "AR_PHY_PCDAC_TX_POWER(%u) (0x%x)",
395189702Ssam			(r->reg - AR_PHY_PCDAC_TX_POWER_0) >> 2, r->reg);
396189702Ssam		bits = NULL;
397189702Ssam#endif
398189702Ssam	} else if (AR_RATE_DURATION(0) <= r->reg && r->reg < AR_RATE_DURATION(32)) {
399189702Ssam		snprintf(buf, sizeof (buf), "AR_RATE_DURATION(0x%x) (0x%x)",
400189702Ssam			(r->reg - AR_RATE_DURATION_0) >> 2, r->reg);
401189702Ssam		bits = NULL;
402189702Ssam	} else if (AR_PHY_BASE <= r->reg) {
403189702Ssam		snprintf(buf, sizeof (buf), "AR_PHY(%u) (0x%x)",
404189702Ssam			(r->reg - AR_PHY_BASE) >> 2, r->reg);
405189702Ssam		bits = NULL;
406189702Ssam	} else {
407189702Ssam		snprintf(buf, sizeof (buf), "0x%x", r->reg);
408189702Ssam		bits = NULL;
409189702Ssam	}
410189702Ssam	fprintf(fd, "%-30s %s 0x%x", buf, r->op ? "<=" : "=>", r->val);
411189702Ssam	if (bits) {
412189702Ssam		const char *p = bits;
413189702Ssam		int tmp, n;
414189702Ssam
415189702Ssam		for (tmp = 0, p++; *p;) {
416189702Ssam			n = *p++;
417189702Ssam			if (r->val & (1 << (n - 1))) {
418189702Ssam				putc(tmp ? ',' : '<', fd);
419189702Ssam				for (; (n = *p) > ' '; ++p)
420189702Ssam					putc(n, fd);
421189702Ssam				tmp = 1;
422189702Ssam			} else
423189702Ssam				for (; *p > ' '; ++p)
424189702Ssam					continue;
425189702Ssam		}
426189702Ssam		if (tmp)
427189702Ssam			putc('>', fd);
428189702Ssam	}
429189702Ssam}
430