xref: /freebsd/sys/dev/ath/ah_osdep.c (revision 94942af266ac119ede0ca836f9aa5a5ac0582938)
1 /*-
2  * Copyright (c) 2002-2006 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  * 3. Neither the names of the above-listed copyright holders nor the names
16  *    of any contributors may be used to endorse or promote products derived
17  *    from this software without specific prior written permission.
18  *
19  * Alternatively, this software may be distributed under the terms of the
20  * GNU General Public License ("GPL") version 2 as published by the Free
21  * Software Foundation.
22  *
23  * NO WARRANTY
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
27  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
28  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
29  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
32  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
34  * THE POSSIBILITY OF SUCH DAMAGES.
35  *
36  * $FreeBSD$
37  */
38 #include "opt_ah.h"
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/module.h>
44 #include <sys/sysctl.h>
45 #include <sys/bus.h>
46 #include <sys/malloc.h>
47 #include <sys/proc.h>
48 
49 #include <machine/stdarg.h>
50 
51 #include <net/ethernet.h>		/* XXX for ether_sprintf */
52 
53 #include <contrib/dev/ath/ah.h>
54 
55 /*
56  * WiSoC boards overload the bus tag with information about the
57  * board layout.  We must extract the bus space tag from that
58  * indirect structure.  For everyone else the tag is passed in
59  * directly.
60  * XXX cache indirect ref privately
61  */
62 #ifdef AH_SUPPORT_AR5312
63 #define	BUSTAG(ah) \
64 	((bus_space_tag_t) ((struct ar531x_config *)((ah)->ah_st))->tag)
65 #else
66 #define	BUSTAG(ah)	((bus_space_tag_t) (ah)->ah_st)
67 #endif
68 
69 extern	void ath_hal_printf(struct ath_hal *, const char*, ...)
70 		__printflike(2,3);
71 extern	void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
72 		__printflike(2, 0);
73 extern	const char* ath_hal_ether_sprintf(const u_int8_t *mac);
74 extern	void *ath_hal_malloc(size_t);
75 extern	void ath_hal_free(void *);
76 #ifdef AH_ASSERT
77 extern	void ath_hal_assert_failed(const char* filename,
78 		int lineno, const char* msg);
79 #endif
80 #ifdef AH_DEBUG
81 extern	void HALDEBUG(struct ath_hal *ah, const char* fmt, ...);
82 extern	void HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...);
83 #endif /* AH_DEBUG */
84 
85 /* NB: put this here instead of the driver to avoid circular references */
86 SYSCTL_NODE(_hw, OID_AUTO, ath, CTLFLAG_RD, 0, "Atheros driver parameters");
87 SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0, "Atheros HAL parameters");
88 
89 #ifdef AH_DEBUG
90 static	int ath_hal_debug = 0;
91 SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RW, &ath_hal_debug,
92 	    0, "Atheros HAL debugging printfs");
93 TUNABLE_INT("hw.ath.hal.debug", &ath_hal_debug);
94 #endif /* AH_DEBUG */
95 
96 SYSCTL_STRING(_hw_ath_hal, OID_AUTO, version, CTLFLAG_RD, ath_hal_version, 0,
97 	"Atheros HAL version");
98 
99 /* NB: these are deprecated; they exist for now for compatibility */
100 int	ath_hal_dma_beacon_response_time = 2;	/* in TU's */
101 SYSCTL_INT(_hw_ath_hal, OID_AUTO, dma_brt, CTLFLAG_RW,
102 	   &ath_hal_dma_beacon_response_time, 0,
103 	   "Atheros HAL DMA beacon response time");
104 int	ath_hal_sw_beacon_response_time = 10;	/* in TU's */
105 SYSCTL_INT(_hw_ath_hal, OID_AUTO, sw_brt, CTLFLAG_RW,
106 	   &ath_hal_sw_beacon_response_time, 0,
107 	   "Atheros HAL software beacon response time");
108 int	ath_hal_additional_swba_backoff = 0;	/* in TU's */
109 SYSCTL_INT(_hw_ath_hal, OID_AUTO, swba_backoff, CTLFLAG_RW,
110 	   &ath_hal_additional_swba_backoff, 0,
111 	   "Atheros HAL additional SWBA backoff time");
112 
113 MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data");
114 
115 void*
116 ath_hal_malloc(size_t size)
117 {
118 	return malloc(size, M_ATH_HAL, M_NOWAIT | M_ZERO);
119 }
120 
121 void
122 ath_hal_free(void* p)
123 {
124 	return free(p, M_ATH_HAL);
125 }
126 
127 void
128 ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
129 {
130 	vprintf(fmt, ap);
131 }
132 
133 void
134 ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
135 {
136 	va_list ap;
137 	va_start(ap, fmt);
138 	ath_hal_vprintf(ah, fmt, ap);
139 	va_end(ap);
140 }
141 
142 const char*
143 ath_hal_ether_sprintf(const u_int8_t *mac)
144 {
145 	return ether_sprintf(mac);
146 }
147 
148 #ifdef AH_DEBUG
149 void
150 HALDEBUG(struct ath_hal *ah, const char* fmt, ...)
151 {
152 	if (ath_hal_debug) {
153 		__va_list ap;
154 		va_start(ap, fmt);
155 		ath_hal_vprintf(ah, fmt, ap);
156 		va_end(ap);
157 	}
158 }
159 
160 void
161 HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...)
162 {
163 	if (ath_hal_debug >= level) {
164 		__va_list ap;
165 		va_start(ap, fmt);
166 		ath_hal_vprintf(ah, fmt, ap);
167 		va_end(ap);
168 	}
169 }
170 #endif /* AH_DEBUG */
171 
172 #ifdef AH_DEBUG_ALQ
173 /*
174  * ALQ register tracing support.
175  *
176  * Setting hw.ath.hal.alq=1 enables tracing of all register reads and
177  * writes to the file /tmp/ath_hal.log.  The file format is a simple
178  * fixed-size array of records.  When done logging set hw.ath.hal.alq=0
179  * and then decode the file with the arcode program (that is part of the
180  * HAL).  If you start+stop tracing the data will be appended to an
181  * existing file.
182  *
183  * NB: doesn't handle multiple devices properly; only one DEVICE record
184  *     is emitted and the different devices are not identified.
185  */
186 #include <sys/alq.h>
187 #include <sys/pcpu.h>
188 #include <contrib/dev/ath/ah_decode.h>
189 
190 static	struct alq *ath_hal_alq;
191 static	int ath_hal_alq_emitdev;	/* need to emit DEVICE record */
192 static	u_int ath_hal_alq_lost;		/* count of lost records */
193 static	const char *ath_hal_logfile = "/tmp/ath_hal.log";
194 static	u_int ath_hal_alq_qsize = 64*1024;
195 
196 static int
197 ath_hal_setlogging(int enable)
198 {
199 	int error;
200 
201 	if (enable) {
202 		error = alq_open(&ath_hal_alq, ath_hal_logfile,
203 			curthread->td_ucred, ALQ_DEFAULT_CMODE,
204 			sizeof (struct athregrec), ath_hal_alq_qsize);
205 		ath_hal_alq_lost = 0;
206 		ath_hal_alq_emitdev = 1;
207 		printf("ath_hal: logging to %s enabled\n",
208 			ath_hal_logfile);
209 	} else {
210 		if (ath_hal_alq)
211 			alq_close(ath_hal_alq);
212 		ath_hal_alq = NULL;
213 		printf("ath_hal: logging disabled\n");
214 		error = 0;
215 	}
216 	return (error);
217 }
218 
219 static int
220 sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)
221 {
222 	int error, enable;
223 
224 	enable = (ath_hal_alq != NULL);
225         error = sysctl_handle_int(oidp, &enable, 0, req);
226         if (error || !req->newptr)
227                 return (error);
228 	else
229 		return (ath_hal_setlogging(enable));
230 }
231 SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
232 	0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging");
233 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW,
234 	&ath_hal_alq_qsize, 0, "In-memory log size (#records)");
235 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW,
236 	&ath_hal_alq_lost, 0, "Register operations not logged");
237 
238 static struct ale *
239 ath_hal_alq_get(struct ath_hal *ah)
240 {
241 	struct ale *ale;
242 
243 	if (ath_hal_alq_emitdev) {
244 		ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
245 		if (ale) {
246 			struct athregrec *r =
247 				(struct athregrec *) ale->ae_data;
248 			r->op = OP_DEVICE;
249 			r->reg = 0;
250 			r->val = ah->ah_devid;
251 			alq_post(ath_hal_alq, ale);
252 			ath_hal_alq_emitdev = 0;
253 		} else
254 			ath_hal_alq_lost++;
255 	}
256 	ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
257 	if (!ale)
258 		ath_hal_alq_lost++;
259 	return ale;
260 }
261 
262 void
263 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
264 {
265 	bus_space_tag_t tag = BUSTAG(ah);
266 	bus_space_handle_t h = (bus_space_handle_t) ah->ah_sh;
267 
268 	if (ath_hal_alq) {
269 		struct ale *ale = ath_hal_alq_get(ah);
270 		if (ale) {
271 			struct athregrec *r = (struct athregrec *) ale->ae_data;
272 			r->op = OP_WRITE;
273 			r->reg = reg;
274 			r->val = val;
275 			alq_post(ath_hal_alq, ale);
276 		}
277 	}
278 #if _BYTE_ORDER == _BIG_ENDIAN
279 	if (reg >= 0x4000 && reg < 0x5000)
280 		bus_space_write_4(tag, h, reg, val);
281 	else
282 #endif
283 		bus_space_write_stream_4(tag, h, reg, val);
284 }
285 
286 u_int32_t
287 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
288 {
289 	bus_space_tag_t tag = BUSTAG(ah);
290 	bus_space_handle_t h = (bus_space_handle_t) ah->ah_sh;
291 	u_int32_t val;
292 
293 #if _BYTE_ORDER == _BIG_ENDIAN
294 	if (reg >= 0x4000 && reg < 0x5000)
295 		val = bus_space_read_4(tag, h, reg);
296 	else
297 #endif
298 		val = bus_space_read_stream_4(tag, h, reg);
299 	if (ath_hal_alq) {
300 		struct ale *ale = ath_hal_alq_get(ah);
301 		if (ale) {
302 			struct athregrec *r = (struct athregrec *) ale->ae_data;
303 			r->op = OP_READ;
304 			r->reg = reg;
305 			r->val = val;
306 			alq_post(ath_hal_alq, ale);
307 		}
308 	}
309 	return val;
310 }
311 
312 void
313 OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
314 {
315 	if (ath_hal_alq) {
316 		struct ale *ale = ath_hal_alq_get(ah);
317 		if (ale) {
318 			struct athregrec *r = (struct athregrec *) ale->ae_data;
319 			r->op = OP_MARK;
320 			r->reg = id;
321 			r->val = v;
322 			alq_post(ath_hal_alq, ale);
323 		}
324 	}
325 }
326 #elif defined(AH_DEBUG) || defined(AH_REGOPS_FUNC)
327 /*
328  * Memory-mapped device register read/write.  These are here
329  * as routines when debugging support is enabled and/or when
330  * explicitly configured to use function calls.  The latter is
331  * for architectures that might need to do something before
332  * referencing memory (e.g. remap an i/o window).
333  *
334  * NB: see the comments in ah_osdep.h about byte-swapping register
335  *     reads and writes to understand what's going on below.
336  */
337 
338 void
339 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
340 {
341 	bus_space_tag_t tag = BUSTAG(ah);
342 	bus_space_handle_t h = (bus_space_handle_t) ah->ah_sh;
343 
344 #if _BYTE_ORDER == _BIG_ENDIAN
345 	if (reg >= 0x4000 && reg < 0x5000)
346 		bus_space_write_4(tag, h, reg, val);
347 	else
348 #endif
349 		bus_space_write_stream_4(tag, h, reg, val);
350 }
351 
352 u_int32_t
353 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
354 {
355 	bus_space_tag_t tag = BUSTAG(ah);
356 	bus_space_handle_t h = (bus_space_handle_t) ah->ah_sh;
357 	u_int32_t val;
358 
359 #if _BYTE_ORDER == _BIG_ENDIAN
360 	if (reg >= 0x4000 && reg < 0x5000)
361 		val = bus_space_read_4(tag, h, reg);
362 	else
363 #endif
364 		val = bus_space_read_stream_4(tag, h, reg);
365 	return val;
366 }
367 #endif /* AH_DEBUG || AH_REGOPS_FUNC */
368 
369 #ifdef AH_ASSERT
370 void
371 ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
372 {
373 	printf("Atheros HAL assertion failure: %s: line %u: %s\n",
374 		filename, lineno, msg);
375 	panic("ath_hal_assert");
376 }
377 #endif /* AH_ASSERT */
378 
379 /*
380  * Delay n microseconds.
381  */
382 void
383 ath_hal_delay(int n)
384 {
385 	DELAY(n);
386 }
387 
388 u_int32_t
389 ath_hal_getuptime(struct ath_hal *ah)
390 {
391 	struct bintime bt;
392 	getbinuptime(&bt);
393 	return (bt.sec * 1000) +
394 		(((uint64_t)1000 * (uint32_t)(bt.frac >> 32)) >> 32);
395 }
396 
397 void
398 ath_hal_memzero(void *dst, size_t n)
399 {
400 	bzero(dst, n);
401 }
402 
403 void *
404 ath_hal_memcpy(void *dst, const void *src, size_t n)
405 {
406 	return memcpy(dst, src, n);
407 }
408 
409 /*
410  * Module glue.
411  */
412 
413 static int
414 ath_hal_modevent(module_t mod, int type, void *unused)
415 {
416 	const char *sep;
417 	int i;
418 
419 	switch (type) {
420 	case MOD_LOAD:
421 		printf("ath_hal: %s (", ath_hal_version);
422 		sep = "";
423 		for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
424 			printf("%s%s", sep, ath_hal_buildopts[i]);
425 			sep = ", ";
426 		}
427 		printf(")\n");
428 		return 0;
429 	case MOD_UNLOAD:
430 		return 0;
431 	}
432 	return EINVAL;
433 }
434 
435 static moduledata_t ath_hal_mod = {
436 	"ath_hal",
437 	ath_hal_modevent,
438 	0
439 };
440 DECLARE_MODULE(ath_hal, ath_hal_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
441 MODULE_VERSION(ath_hal, 1);
442