1/*-
2 * Copyright (c) 2002-2009 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#include "diag.h"
30
31#include "ah.h"
32#include "ah_internal.h"
33#include "ah_decode.h"
34
35#include "dumpregs.h"
36
37#include <stdlib.h>
38#include <string.h>
39#include <err.h>
40#include <sys/file.h>
41#include <sys/stat.h>
42#include <sys/mman.h>
43
44typedef struct {
45	HAL_REVS revs;
46	int chipnum;
47#define	MAXREGS	5*1024
48	struct dumpreg *regs[MAXREGS];
49	u_int nregs;
50} dumpregs_t;
51static	dumpregs_t state;
52
53static void opdevice(const struct athregrec *r);
54static const char* opmark(FILE *, int, const struct athregrec *);
55static void oprw(FILE *fd, int recnum, struct athregrec *r);
56
57int
58main(int argc, char *argv[])
59{
60	int fd, i, nrecs, same;
61	struct stat sb;
62	void *addr;
63	const char *filename = "/tmp/ath_hal.log";
64	struct athregrec *rprev;
65
66	if (argc > 1)
67		filename = argv[1];
68	fd = open(filename, O_RDONLY);
69	if (fd < 0)
70		err(1, "open: %s", filename);
71	if (fstat(fd, &sb) < 0)
72		err(1, "fstat");
73	addr = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE|MAP_NOCORE, fd, 0);
74	if (addr == MAP_FAILED)
75		err(1, "mmap");
76	nrecs = sb.st_size / sizeof (struct athregrec);
77	printf("%u records", nrecs);
78	rprev = NULL;
79	same = 0;
80	state.chipnum = 5210;
81	for (i = 0; i < nrecs; i++) {
82		struct athregrec *r = &((struct athregrec *) addr)[i];
83		if (rprev && bcmp(r, rprev, sizeof (*r)) == 0) {
84			same++;
85			continue;
86		}
87		if (same)
88			printf("\t\t+%u time%s", same, same == 1 ? "" : "s");
89		switch (r->op) {
90		case OP_DEVICE:
91			opdevice(r);
92			break;
93		case OP_READ:
94		case OP_WRITE:
95			oprw(stdout, i, r);
96			break;
97		case OP_MARK:
98			opmark(stdout, i, r);
99			break;
100		}
101		rprev = r;
102		same = 0;
103	}
104	putchar('\n');
105	return 0;
106}
107
108static const char*
109opmark(FILE *fd, int i, const struct athregrec *r)
110{
111	fprintf(fd, "\n%05d: ", i);
112	switch (r->reg) {
113	case AH_MARK_RESET:
114		fprintf(fd, "ar%uReset %s", state.chipnum,
115			r->val ? "change channel" : "no channel change");
116		break;
117	case AH_MARK_RESET_LINE:
118		fprintf(fd, "ar%u_reset.c; line %u", state.chipnum, r->val);
119		break;
120	case AH_MARK_RESET_DONE:
121		if (r->val)
122			fprintf(fd, "ar%uReset (done), FAIL, error %u",
123				state.chipnum, r->val);
124		else
125			fprintf(fd, "ar%uReset (done), OK", state.chipnum);
126		break;
127	case AH_MARK_CHIPRESET:
128		fprintf(fd, "ar%uChipReset, channel %u MHz", state.chipnum, r->val);
129		break;
130	case AH_MARK_PERCAL:
131		fprintf(fd, "ar%uPerCalibration, channel %u MHz", state.chipnum, r->val);
132		break;
133	case AH_MARK_SETCHANNEL:
134		fprintf(fd, "ar%uSetChannel, channel %u MHz", state.chipnum, r->val);
135		break;
136	case AH_MARK_ANI_RESET:
137		switch (r->val) {
138		case HAL_M_STA:
139			fprintf(fd, "ar%uAniReset, HAL_M_STA", state.chipnum);
140			break;
141		case HAL_M_IBSS:
142			fprintf(fd, "ar%uAniReset, HAL_M_IBSS", state.chipnum);
143			break;
144		case HAL_M_HOSTAP:
145			fprintf(fd, "ar%uAniReset, HAL_M_HOSTAP", state.chipnum);
146			break;
147		case HAL_M_MONITOR:
148			fprintf(fd, "ar%uAniReset, HAL_M_MONITOR", state.chipnum);
149			break;
150		default:
151			fprintf(fd, "ar%uAniReset, opmode %u", state.chipnum, r->val);
152			break;
153		}
154		break;
155	case AH_MARK_ANI_POLL:
156		fprintf(fd, "ar%uAniPoll, listenTime %u", state.chipnum, r->val);
157		break;
158	case AH_MARK_ANI_CONTROL:
159		switch (r->val) {
160		case HAL_ANI_PRESENT:
161			fprintf(fd, "ar%uAniControl, PRESENT", state.chipnum);
162			break;
163		case HAL_ANI_NOISE_IMMUNITY_LEVEL:
164			fprintf(fd, "ar%uAniControl, NOISE_IMMUNITY", state.chipnum);
165			break;
166		case HAL_ANI_OFDM_WEAK_SIGNAL_DETECTION:
167			fprintf(fd, "ar%uAniControl, OFDM_WEAK_SIGNAL", state.chipnum);
168			break;
169		case HAL_ANI_CCK_WEAK_SIGNAL_THR:
170			fprintf(fd, "ar%uAniControl, CCK_WEAK_SIGNAL", state.chipnum);
171			break;
172		case HAL_ANI_FIRSTEP_LEVEL:
173			fprintf(fd, "ar%uAniControl, FIRSTEP_LEVEL", state.chipnum);
174			break;
175		case HAL_ANI_SPUR_IMMUNITY_LEVEL:
176			fprintf(fd, "ar%uAniControl, SPUR_IMMUNITY", state.chipnum);
177			break;
178		case HAL_ANI_MODE:
179			fprintf(fd, "ar%uAniControl, MODE", state.chipnum);
180			break;
181		case HAL_ANI_PHYERR_RESET:
182			fprintf(fd, "ar%uAniControl, PHYERR_RESET", state.chipnum);
183			break;
184		default:
185			fprintf(fd, "ar%uAniControl, cmd %u", state.chipnum, r->val);
186			break;
187		}
188		break;
189	default:
190		fprintf(fd, "mark #%u value %u/0x%x", r->reg, r->val, r->val);
191		break;
192	}
193	return (NULL);
194}
195
196#include "ah_devid.h"
197
198static void
199opdevice(const struct athregrec *r)
200{
201	switch (r->val) {
202	case AR5210_PROD:
203	case AR5210_DEFAULT:
204		state.chipnum = 5210;
205		state.revs.ah_macVersion = 1;
206		state.revs.ah_macRev = 0;
207		break;
208	case AR5211_DEVID:
209	case AR5311_DEVID:
210	case AR5211_DEFAULT:
211	case AR5211_FPGA11B:
212		state.chipnum = 5211;
213		state.revs.ah_macVersion = 2;
214		state.revs.ah_macRev = 0;
215		break;
216	/* AR5212 */
217	case AR5212_DEFAULT:
218	case AR5212_DEVID:
219	case AR5212_FPGA:
220	case AR5212_DEVID_IBM:
221	case AR5212_AR5312_REV2:
222	case AR5212_AR5312_REV7:
223	case AR5212_AR2313_REV8:
224	case AR5212_AR2315_REV6:
225	case AR5212_AR2315_REV7:
226	case AR5212_AR2317_REV1:
227	case AR5212_AR2317_REV2:
228
229	/* AR5212 compatible devid's also attach to 5212 */
230	case AR5212_DEVID_0014:
231	case AR5212_DEVID_0015:
232	case AR5212_DEVID_0016:
233	case AR5212_DEVID_0017:
234	case AR5212_DEVID_0018:
235	case AR5212_DEVID_0019:
236	case AR5212_AR2413:
237	case AR5212_AR5413:
238	case AR5212_AR5424:
239	case AR5212_AR2417:
240	case AR5212_DEVID_FF19:
241		state.chipnum = 5212;
242		state.revs.ah_macVersion = 4;
243		state.revs.ah_macRev = 5;
244		break;
245
246	/* AR5213 */
247	case AR5213_SREV_1_0:
248	case AR5213_SREV_REG:
249		state.chipnum = 5213;
250		state.revs.ah_macVersion = 5;
251		state.revs.ah_macRev = 9;
252		break;
253
254	/* AR5416 compatible devid's  */
255	case AR5416_DEVID_PCI:
256	case AR5416_DEVID_PCIE:
257	case AR9160_DEVID_PCI:
258	case AR9280_DEVID_PCI:
259	case AR9280_DEVID_PCIE:
260	case AR9285_DEVID_PCIE:
261	case AR9287_DEVID_PCI:
262	case AR9287_DEVID_PCIE:
263	case AR9300_DEVID_AR9330:
264		state.chipnum = 5416;
265		state.revs.ah_macVersion = 13;
266		state.revs.ah_macRev = 8;
267		break;
268	default:
269		printf("Unknown device id 0x%x\n", r->val);
270		exit(-1);
271	}
272}
273
274static int
275regcompar(const void *a, const void *b)
276{
277	const struct dumpreg *ra = *(const struct dumpreg **)a;
278	const struct dumpreg *rb = *(const struct dumpreg **)b;
279	return ra->addr - rb->addr;
280}
281
282void
283register_regs(struct dumpreg *chipregs, u_int nchipregs,
284	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
285{
286	const int existing_regs = state.nregs;
287	int i, j;
288
289	for (i = 0; i < nchipregs; i++) {
290		struct dumpreg *nr = &chipregs[i];
291		if (nr->srevMin == 0)
292			nr->srevMin = def_srev_min;
293		if (nr->srevMax == 0)
294			nr->srevMax = def_srev_max;
295		if (nr->phyMin == 0)
296			nr->phyMin = def_phy_min;
297		if (nr->phyMax == 0)
298			nr->phyMax = def_phy_max;
299		for (j = 0; j < existing_regs; j++) {
300			struct dumpreg *r = state.regs[j];
301			/*
302			 * Check if we can just expand the mac+phy
303			 * coverage for the existing entry.
304			 */
305			if (nr->addr == r->addr &&
306			    (nr->name == r->name ||
307			     (nr->name != NULL && r->name != NULL &&
308			     strcmp(nr->name, r->name) == 0))) {
309				if (nr->srevMin < r->srevMin &&
310				    (r->srevMin <= nr->srevMax &&
311				     nr->srevMax+1 <= r->srevMax)) {
312					r->srevMin = nr->srevMin;
313					goto skip;
314				}
315				if (nr->srevMax > r->srevMax &&
316				    (r->srevMin <= nr->srevMin &&
317				     nr->srevMin <= r->srevMax)) {
318					r->srevMax = nr->srevMax;
319					goto skip;
320				}
321			}
322			if (r->addr > nr->addr)
323				break;
324		}
325		/*
326		 * New item, add to the end, it'll be sorted below.
327		 */
328		if (state.nregs == MAXREGS)
329			errx(-1, "too many registers; bump MAXREGS");
330		state.regs[state.nregs++] = nr;
331	skip:
332		;
333	}
334	qsort(state.regs, state.nregs, sizeof(struct dumpreg *), regcompar);
335}
336
337void
338register_keycache(u_int nslots,
339	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
340{
341	/* discard, no use */
342}
343
344void
345register_range(u_int brange, u_int erange, int type,
346	int def_srev_min, int def_srev_max, int def_phy_min, int def_phy_max)
347{
348	/* discard, no use */
349}
350
351static const struct dumpreg *
352findreg(int reg)
353{
354	const HAL_REVS *revs = &state.revs;
355	int i;
356
357	for (i = 0; i < state.nregs; i++) {
358		const struct dumpreg *dr = state.regs[i];
359		if (dr->addr == reg &&
360		    MAC_MATCH(dr, revs->ah_macVersion, revs->ah_macRev))
361			return dr;
362	}
363	return NULL;
364}
365
366/* XXX cheat, 5212 has a superset of the key table defs */
367#include "ar5212/ar5212reg.h"
368#include "ar5212/ar5212phy.h"
369
370#define PWR_TABLE_SIZE	64
371
372static void
373oprw(FILE *fd, int recnum, struct athregrec *r)
374{
375	const struct dumpreg *dr;
376	char buf[64];
377	const char* bits;
378	int i;
379
380	fprintf(fd, "\n%05d: [%d] ", recnum, r->threadid);
381	dr = findreg(r->reg);
382	if (dr != NULL && dr->name != NULL) {
383		snprintf(buf, sizeof (buf), "AR_%s (0x%x)", dr->name, r->reg);
384		bits = dr->bits;
385	} else if (AR_KEYTABLE(0) <= r->reg && r->reg < AR_KEYTABLE(128)) {
386		snprintf(buf, sizeof (buf), "AR_KEYTABLE%u(%u) (0x%x)",
387			((r->reg - AR_KEYTABLE_0) >> 2) & 7,
388			(r->reg - AR_KEYTABLE_0) >> 5, r->reg);
389		bits = NULL;
390#if 0
391	} else if (AR_PHY_PCDAC_TX_POWER(0) <= r->reg && r->reg < AR_PHY_PCDAC_TX_POWER(PWR_TABLE_SIZE/2)) {
392		snprintf(buf, sizeof (buf), "AR_PHY_PCDAC_TX_POWER(%u) (0x%x)",
393			(r->reg - AR_PHY_PCDAC_TX_POWER_0) >> 2, r->reg);
394		bits = NULL;
395#endif
396	} else if (AR_RATE_DURATION(0) <= r->reg && r->reg < AR_RATE_DURATION(32)) {
397		snprintf(buf, sizeof (buf), "AR_RATE_DURATION(0x%x) (0x%x)",
398			(r->reg - AR_RATE_DURATION_0) >> 2, r->reg);
399		bits = NULL;
400	} else if (AR_PHY_BASE <= r->reg) {
401		snprintf(buf, sizeof (buf), "AR_PHY(%u) (0x%x)",
402			(r->reg - AR_PHY_BASE) >> 2, r->reg);
403		bits = NULL;
404	} else {
405		snprintf(buf, sizeof (buf), "0x%x", r->reg);
406		bits = NULL;
407	}
408	fprintf(fd, "%-30s %s 0x%x", buf, r->op ? "<=" : "=>", r->val);
409	if (bits) {
410		const char *p = bits;
411		int tmp, n;
412
413		for (tmp = 0, p++; *p;) {
414			n = *p++;
415			if (r->val & (1 << (n - 1))) {
416				putc(tmp ? ',' : '<', fd);
417				for (; (n = *p) > ' '; ++p)
418					putc(n, fd);
419				tmp = 1;
420			} else
421				for (; *p > ' '; ++p)
422					continue;
423		}
424		if (tmp)
425			putc('>', fd);
426	}
427}
428