xref: /dflybsd-src/sys/dev/netif/ath/ath_hal/ah_osdep.c (revision df052c2a9588fe12c7a2df4e61e2bfa3f3e16ce0)
1572ff6f6SMatthew Dillon /*-
2572ff6f6SMatthew Dillon  * Copyright (c) 2002-2008 Sam Leffler, Errno Consulting
3572ff6f6SMatthew Dillon  * All rights reserved.
4572ff6f6SMatthew Dillon  *
5572ff6f6SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6572ff6f6SMatthew Dillon  * modification, are permitted provided that the following conditions
7572ff6f6SMatthew Dillon  * are met:
8572ff6f6SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
9572ff6f6SMatthew Dillon  *    notice, this list of conditions and the following disclaimer,
10572ff6f6SMatthew Dillon  *    without modification.
11572ff6f6SMatthew Dillon  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
12572ff6f6SMatthew Dillon  *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
13572ff6f6SMatthew Dillon  *    redistribution must be conditioned upon including a substantially
14572ff6f6SMatthew Dillon  *    similar Disclaimer requirement for further binary redistribution.
15572ff6f6SMatthew Dillon  *
16572ff6f6SMatthew Dillon  * NO WARRANTY
17572ff6f6SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18572ff6f6SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*df052c2aSSascha Wildner  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTABILITY
20572ff6f6SMatthew Dillon  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
21572ff6f6SMatthew Dillon  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
22572ff6f6SMatthew Dillon  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23572ff6f6SMatthew Dillon  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24572ff6f6SMatthew Dillon  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25572ff6f6SMatthew Dillon  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26572ff6f6SMatthew Dillon  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
27572ff6f6SMatthew Dillon  * THE POSSIBILITY OF SUCH DAMAGES.
28572ff6f6SMatthew Dillon  *
29572ff6f6SMatthew Dillon  * $FreeBSD$
30572ff6f6SMatthew Dillon  */
31572ff6f6SMatthew Dillon #include "opt_ah.h"
32572ff6f6SMatthew Dillon 
33dc249793SMatthew Dillon #if defined(__DragonFly__)
34dc249793SMatthew Dillon #define CTLFLAG_RWTUN	CTLFLAG_RW
35dc249793SMatthew Dillon #endif
36dc249793SMatthew Dillon 
37572ff6f6SMatthew Dillon #include <sys/param.h>
38572ff6f6SMatthew Dillon #include <sys/systm.h>
39572ff6f6SMatthew Dillon #include <sys/kernel.h>
40572ff6f6SMatthew Dillon #include <sys/module.h>
41572ff6f6SMatthew Dillon #include <sys/sysctl.h>
42572ff6f6SMatthew Dillon #include <sys/bus.h>
43572ff6f6SMatthew Dillon #include <sys/malloc.h>
44572ff6f6SMatthew Dillon #include <sys/proc.h>
45dc249793SMatthew Dillon #if defined(__DragonFly__)
46dc249793SMatthew Dillon #else
47b14ca477SMatthew Dillon #include <sys/pcpu.h>
48dc249793SMatthew Dillon #endif
49572ff6f6SMatthew Dillon #include <sys/lock.h>
50572ff6f6SMatthew Dillon 
51572ff6f6SMatthew Dillon #include <machine/stdarg.h>
52572ff6f6SMatthew Dillon 
53848b370cSMatthew Dillon #include <net/ethernet.h>		/* XXX for ether_sprintf */
54dc249793SMatthew Dillon #if defined(__DragonFly__)
553133c5e3SMatthew Dillon 
56dc249793SMatthew Dillon #include <net/if.h>
57dc249793SMatthew Dillon #include <net/if_var.h>
58dc249793SMatthew Dillon #include <net/if_media.h>
59dc249793SMatthew Dillon #include <net/if_types.h>
60dc249793SMatthew Dillon #include <netproto/802_11/ieee80211_var.h>	/* ether_sprintf */
61dc249793SMatthew Dillon 
62dc249793SMatthew Dillon #endif
63dc249793SMatthew Dillon 
64dc249793SMatthew Dillon #include <dev/netif/ath/ath_hal/ah.h>
65dc249793SMatthew Dillon #include <dev/netif/ath/ath_hal/ah_debug.h>
66848b370cSMatthew Dillon 
67572ff6f6SMatthew Dillon /*
68572ff6f6SMatthew Dillon  * WiSoC boards overload the bus tag with information about the
69572ff6f6SMatthew Dillon  * board layout.  We must extract the bus space tag from that
70572ff6f6SMatthew Dillon  * indirect structure.  For everyone else the tag is passed in
71572ff6f6SMatthew Dillon  * directly.
72572ff6f6SMatthew Dillon  * XXX cache indirect ref privately
73572ff6f6SMatthew Dillon  */
74572ff6f6SMatthew Dillon #ifdef AH_SUPPORT_AR5312
75572ff6f6SMatthew Dillon #define	BUSTAG(ah) \
76572ff6f6SMatthew Dillon 	((bus_space_tag_t) ((struct ar531x_config *)((ah)->ah_st))->tag)
77572ff6f6SMatthew Dillon #else
78572ff6f6SMatthew Dillon #define	BUSTAG(ah)	((ah)->ah_st)
79572ff6f6SMatthew Dillon #endif
80572ff6f6SMatthew Dillon 
81572ff6f6SMatthew Dillon /*
82572ff6f6SMatthew Dillon  * This lock is used to seralise register access for chips which have
83572ff6f6SMatthew Dillon  * problems w/ SMP CPUs issuing concurrent PCI transactions.
84572ff6f6SMatthew Dillon  *
85572ff6f6SMatthew Dillon  * XXX This is a global lock for now; it should be pushed to
86572ff6f6SMatthew Dillon  * a per-device lock in some platform-independent fashion.
87572ff6f6SMatthew Dillon  */
88dc249793SMatthew Dillon struct lock ah_regser_mtx;
89dc249793SMatthew Dillon LOCK_SYSINIT(ah_regser, &ah_regser_mtx, "Atheros register access mutex", 0);
90572ff6f6SMatthew Dillon 
91572ff6f6SMatthew Dillon extern	void ath_hal_printf(struct ath_hal *, const char*, ...)
92572ff6f6SMatthew Dillon 		__printflike(2, 3);
93572ff6f6SMatthew Dillon extern	void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
94572ff6f6SMatthew Dillon 		__printflike(2, 0);
95572ff6f6SMatthew Dillon extern	const char* ath_hal_ether_sprintf(const u_int8_t *mac);
96572ff6f6SMatthew Dillon extern	void *ath_hal_malloc(size_t);
97572ff6f6SMatthew Dillon extern	void ath_hal_free(void *);
98572ff6f6SMatthew Dillon #ifdef AH_ASSERT
99572ff6f6SMatthew Dillon extern	void ath_hal_assert_failed(const char* filename,
100572ff6f6SMatthew Dillon 		int lineno, const char* msg);
101572ff6f6SMatthew Dillon #endif
102572ff6f6SMatthew Dillon #ifdef AH_DEBUG
10356d84e38SSascha Wildner extern	void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
10456d84e38SSascha Wildner 		__printflike(3, 4);
105572ff6f6SMatthew Dillon #endif /* AH_DEBUG */
106572ff6f6SMatthew Dillon 
107572ff6f6SMatthew Dillon /* NB: put this here instead of the driver to avoid circular references */
108572ff6f6SMatthew Dillon SYSCTL_NODE(_hw, OID_AUTO, ath, CTLFLAG_RD, 0, "Atheros driver parameters");
109572ff6f6SMatthew Dillon static SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0,
110572ff6f6SMatthew Dillon     "Atheros HAL parameters");
111572ff6f6SMatthew Dillon 
112572ff6f6SMatthew Dillon #ifdef AH_DEBUG
113572ff6f6SMatthew Dillon int ath_hal_debug = 0;
114848b370cSMatthew Dillon SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_hal_debug,
115572ff6f6SMatthew Dillon     0, "Atheros HAL debugging printfs");
116572ff6f6SMatthew Dillon #endif /* AH_DEBUG */
117572ff6f6SMatthew Dillon 
118572ff6f6SMatthew Dillon static MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data");
119572ff6f6SMatthew Dillon 
120572ff6f6SMatthew Dillon void*
ath_hal_malloc(size_t size)121572ff6f6SMatthew Dillon ath_hal_malloc(size_t size)
122572ff6f6SMatthew Dillon {
123dc249793SMatthew Dillon 	return kmalloc(size, M_ATH_HAL, M_INTWAIT | M_ZERO);
124572ff6f6SMatthew Dillon }
125572ff6f6SMatthew Dillon 
126572ff6f6SMatthew Dillon void
ath_hal_free(void * p)127572ff6f6SMatthew Dillon ath_hal_free(void* p)
128572ff6f6SMatthew Dillon {
129dc249793SMatthew Dillon 	kfree(p, M_ATH_HAL);
130572ff6f6SMatthew Dillon }
131572ff6f6SMatthew Dillon 
132572ff6f6SMatthew Dillon void
ath_hal_vprintf(struct ath_hal * ah,const char * fmt,__va_list ap)133dc249793SMatthew Dillon ath_hal_vprintf(struct ath_hal *ah, const char* fmt, __va_list ap)
134572ff6f6SMatthew Dillon {
135dc249793SMatthew Dillon 	kvprintf(fmt, ap);
136572ff6f6SMatthew Dillon }
137572ff6f6SMatthew Dillon 
138572ff6f6SMatthew Dillon void
ath_hal_printf(struct ath_hal * ah,const char * fmt,...)139572ff6f6SMatthew Dillon ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
140572ff6f6SMatthew Dillon {
141dc249793SMatthew Dillon 	__va_list ap;
142dc249793SMatthew Dillon 	__va_start(ap, fmt);
143572ff6f6SMatthew Dillon 	ath_hal_vprintf(ah, fmt, ap);
144dc249793SMatthew Dillon 	__va_end(ap);
145572ff6f6SMatthew Dillon }
146572ff6f6SMatthew Dillon 
147572ff6f6SMatthew Dillon const char*
ath_hal_ether_sprintf(const u_int8_t * mac)148572ff6f6SMatthew Dillon ath_hal_ether_sprintf(const u_int8_t *mac)
149572ff6f6SMatthew Dillon {
150848b370cSMatthew Dillon 	return ether_sprintf(mac);
151572ff6f6SMatthew Dillon }
152572ff6f6SMatthew Dillon 
153572ff6f6SMatthew Dillon #ifdef AH_DEBUG
154572ff6f6SMatthew Dillon 
155d98a0bcfSMatthew Dillon /*
156d98a0bcfSMatthew Dillon  * XXX This is highly relevant only for the AR5416 and later
157d98a0bcfSMatthew Dillon  * PCI/PCIe NICs.  It'll need adjustment for other hardware
158d98a0bcfSMatthew Dillon  * variations.
159d98a0bcfSMatthew Dillon  */
160d98a0bcfSMatthew Dillon static int
ath_hal_reg_whilst_asleep(struct ath_hal * ah,uint32_t reg)161d98a0bcfSMatthew Dillon ath_hal_reg_whilst_asleep(struct ath_hal *ah, uint32_t reg)
162d98a0bcfSMatthew Dillon {
163d98a0bcfSMatthew Dillon 
164d98a0bcfSMatthew Dillon 	if (reg >= 0x4000 && reg < 0x5000)
165d98a0bcfSMatthew Dillon 		return (1);
166d98a0bcfSMatthew Dillon 	if (reg >= 0x6000 && reg < 0x7000)
167d98a0bcfSMatthew Dillon 		return (1);
168d98a0bcfSMatthew Dillon 	if (reg >= 0x7000 && reg < 0x8000)
169d98a0bcfSMatthew Dillon 		return (1);
170d98a0bcfSMatthew Dillon 	return (0);
171d98a0bcfSMatthew Dillon }
172d98a0bcfSMatthew Dillon 
173572ff6f6SMatthew Dillon void
DO_HALDEBUG(struct ath_hal * ah,u_int mask,const char * fmt,...)174572ff6f6SMatthew Dillon DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
175572ff6f6SMatthew Dillon {
176572ff6f6SMatthew Dillon 	if ((mask == HAL_DEBUG_UNMASKABLE) ||
177572ff6f6SMatthew Dillon 	    (ah != NULL && ah->ah_config.ah_debug & mask) ||
178572ff6f6SMatthew Dillon 	    (ath_hal_debug & mask)) {
179572ff6f6SMatthew Dillon 		__va_list ap;
180dc249793SMatthew Dillon 		__va_start(ap, fmt);
181572ff6f6SMatthew Dillon 		ath_hal_vprintf(ah, fmt, ap);
182dc249793SMatthew Dillon 		__va_end(ap);
183572ff6f6SMatthew Dillon 	}
184572ff6f6SMatthew Dillon }
185572ff6f6SMatthew Dillon #undef	HAL_DEBUG_UNMASKABLE
186572ff6f6SMatthew Dillon #endif /* AH_DEBUG */
187572ff6f6SMatthew Dillon 
188572ff6f6SMatthew Dillon #ifdef AH_DEBUG_ALQ
189572ff6f6SMatthew Dillon /*
190572ff6f6SMatthew Dillon  * ALQ register tracing support.
191572ff6f6SMatthew Dillon  *
192572ff6f6SMatthew Dillon  * Setting hw.ath.hal.alq=1 enables tracing of all register reads and
193572ff6f6SMatthew Dillon  * writes to the file /tmp/ath_hal.log.  The file format is a simple
194572ff6f6SMatthew Dillon  * fixed-size array of records.  When done logging set hw.ath.hal.alq=0
195572ff6f6SMatthew Dillon  * and then decode the file with the arcode program (that is part of the
196572ff6f6SMatthew Dillon  * HAL).  If you start+stop tracing the data will be appended to an
197572ff6f6SMatthew Dillon  * existing file.
198572ff6f6SMatthew Dillon  *
199572ff6f6SMatthew Dillon  * NB: doesn't handle multiple devices properly; only one DEVICE record
200572ff6f6SMatthew Dillon  *     is emitted and the different devices are not identified.
201572ff6f6SMatthew Dillon  */
202dc249793SMatthew Dillon /*#include <sys/alq.h> FreeBSD */
203dc249793SMatthew Dillon /*#include <sys/pcpu.h> FreeBSD */
204dc249793SMatthew Dillon #include <dev/netif/ath/ath_hal/ah_decode.h>
205572ff6f6SMatthew Dillon 
206572ff6f6SMatthew Dillon static	struct alq *ath_hal_alq;
207572ff6f6SMatthew Dillon static	int ath_hal_alq_emitdev;	/* need to emit DEVICE record */
208572ff6f6SMatthew Dillon static	u_int ath_hal_alq_lost;		/* count of lost records */
209572ff6f6SMatthew Dillon static	char ath_hal_logfile[MAXPATHLEN] = "/tmp/ath_hal.log";
210572ff6f6SMatthew Dillon 
211572ff6f6SMatthew Dillon SYSCTL_STRING(_hw_ath_hal, OID_AUTO, alq_logfile, CTLFLAG_RW,
212572ff6f6SMatthew Dillon     &ath_hal_logfile, sizeof(kernelname), "Name of ALQ logfile");
213572ff6f6SMatthew Dillon 
214572ff6f6SMatthew Dillon static	u_int ath_hal_alq_qsize = 64*1024;
215572ff6f6SMatthew Dillon 
216572ff6f6SMatthew Dillon static int
ath_hal_setlogging(int enable)217572ff6f6SMatthew Dillon ath_hal_setlogging(int enable)
218572ff6f6SMatthew Dillon {
219572ff6f6SMatthew Dillon 	int error;
220572ff6f6SMatthew Dillon 
221572ff6f6SMatthew Dillon 	if (enable) {
222572ff6f6SMatthew Dillon 		error = alq_open(&ath_hal_alq, ath_hal_logfile,
223572ff6f6SMatthew Dillon 			curthread->td_ucred, ALQ_DEFAULT_CMODE,
224572ff6f6SMatthew Dillon 			sizeof (struct athregrec), ath_hal_alq_qsize);
225572ff6f6SMatthew Dillon 		ath_hal_alq_lost = 0;
226572ff6f6SMatthew Dillon 		ath_hal_alq_emitdev = 1;
227dc249793SMatthew Dillon 		kprintf("ath_hal: logging to %s enabled\n",
228572ff6f6SMatthew Dillon 			ath_hal_logfile);
229572ff6f6SMatthew Dillon 	} else {
230572ff6f6SMatthew Dillon 		if (ath_hal_alq)
231572ff6f6SMatthew Dillon 			alq_close(ath_hal_alq);
232572ff6f6SMatthew Dillon 		ath_hal_alq = NULL;
233dc249793SMatthew Dillon 		kprintf("ath_hal: logging disabled\n");
234572ff6f6SMatthew Dillon 		error = 0;
235572ff6f6SMatthew Dillon 	}
236572ff6f6SMatthew Dillon 	return (error);
237572ff6f6SMatthew Dillon }
238572ff6f6SMatthew Dillon 
239572ff6f6SMatthew Dillon static int
sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)240572ff6f6SMatthew Dillon sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)
241572ff6f6SMatthew Dillon {
242572ff6f6SMatthew Dillon 	int error, enable;
243572ff6f6SMatthew Dillon 
244572ff6f6SMatthew Dillon 	enable = (ath_hal_alq != NULL);
245572ff6f6SMatthew Dillon         error = sysctl_handle_int(oidp, &enable, 0, req);
246572ff6f6SMatthew Dillon         if (error || !req->newptr)
247572ff6f6SMatthew Dillon                 return (error);
248572ff6f6SMatthew Dillon 	else
249572ff6f6SMatthew Dillon 		return (ath_hal_setlogging(enable));
250572ff6f6SMatthew Dillon }
251572ff6f6SMatthew Dillon SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
252572ff6f6SMatthew Dillon 	0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging");
253572ff6f6SMatthew Dillon SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW,
254572ff6f6SMatthew Dillon 	&ath_hal_alq_qsize, 0, "In-memory log size (#records)");
255572ff6f6SMatthew Dillon SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW,
256572ff6f6SMatthew Dillon 	&ath_hal_alq_lost, 0, "Register operations not logged");
257572ff6f6SMatthew Dillon 
258572ff6f6SMatthew Dillon static struct ale *
ath_hal_alq_get(struct ath_hal * ah)259572ff6f6SMatthew Dillon ath_hal_alq_get(struct ath_hal *ah)
260572ff6f6SMatthew Dillon {
261572ff6f6SMatthew Dillon 	struct ale *ale;
262572ff6f6SMatthew Dillon 
263572ff6f6SMatthew Dillon 	if (ath_hal_alq_emitdev) {
264572ff6f6SMatthew Dillon 		ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
265572ff6f6SMatthew Dillon 		if (ale) {
266572ff6f6SMatthew Dillon 			struct athregrec *r =
267572ff6f6SMatthew Dillon 				(struct athregrec *) ale->ae_data;
268572ff6f6SMatthew Dillon 			r->op = OP_DEVICE;
269572ff6f6SMatthew Dillon 			r->reg = 0;
270572ff6f6SMatthew Dillon 			r->val = ah->ah_devid;
271572ff6f6SMatthew Dillon 			alq_post(ath_hal_alq, ale);
272572ff6f6SMatthew Dillon 			ath_hal_alq_emitdev = 0;
273572ff6f6SMatthew Dillon 		} else
274572ff6f6SMatthew Dillon 			ath_hal_alq_lost++;
275572ff6f6SMatthew Dillon 	}
276572ff6f6SMatthew Dillon 	ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
277572ff6f6SMatthew Dillon 	if (!ale)
278572ff6f6SMatthew Dillon 		ath_hal_alq_lost++;
279572ff6f6SMatthew Dillon 	return ale;
280572ff6f6SMatthew Dillon }
281572ff6f6SMatthew Dillon 
282572ff6f6SMatthew Dillon void
ath_hal_reg_write(struct ath_hal * ah,u_int32_t reg,u_int32_t val)283572ff6f6SMatthew Dillon ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
284572ff6f6SMatthew Dillon {
285572ff6f6SMatthew Dillon 	bus_space_tag_t tag = BUSTAG(ah);
286572ff6f6SMatthew Dillon 	bus_space_handle_t h = ah->ah_sh;
287572ff6f6SMatthew Dillon 
288b14ca477SMatthew Dillon #ifdef	AH_DEBUG
289d98a0bcfSMatthew Dillon 	/* Debug - complain if we haven't fully waken things up */
290d98a0bcfSMatthew Dillon 	if (! ath_hal_reg_whilst_asleep(ah, reg) &&
291d98a0bcfSMatthew Dillon 	    ah->ah_powerMode != HAL_PM_AWAKE) {
292d98a0bcfSMatthew Dillon 		ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
293d98a0bcfSMatthew Dillon 		    __func__, reg, val, ah->ah_powerMode);
294d98a0bcfSMatthew Dillon 	}
295b14ca477SMatthew Dillon #endif
296d98a0bcfSMatthew Dillon 
297572ff6f6SMatthew Dillon 	if (ath_hal_alq) {
298572ff6f6SMatthew Dillon 		struct ale *ale = ath_hal_alq_get(ah);
299572ff6f6SMatthew Dillon 		if (ale) {
300572ff6f6SMatthew Dillon 			struct athregrec *r = (struct athregrec *) ale->ae_data;
301572ff6f6SMatthew Dillon 			r->threadid = curthread->td_tid;
302572ff6f6SMatthew Dillon 			r->op = OP_WRITE;
303572ff6f6SMatthew Dillon 			r->reg = reg;
304572ff6f6SMatthew Dillon 			r->val = val;
305572ff6f6SMatthew Dillon 			alq_post(ath_hal_alq, ale);
306572ff6f6SMatthew Dillon 		}
307572ff6f6SMatthew Dillon 	}
308572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
309dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
310572ff6f6SMatthew Dillon 	bus_space_write_4(tag, h, reg, val);
311b14ca477SMatthew Dillon 	OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
312572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
313dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_RELEASE);
314572ff6f6SMatthew Dillon }
315572ff6f6SMatthew Dillon 
316572ff6f6SMatthew Dillon u_int32_t
ath_hal_reg_read(struct ath_hal * ah,u_int32_t reg)317572ff6f6SMatthew Dillon ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
318572ff6f6SMatthew Dillon {
319572ff6f6SMatthew Dillon 	bus_space_tag_t tag = BUSTAG(ah);
320572ff6f6SMatthew Dillon 	bus_space_handle_t h = ah->ah_sh;
321572ff6f6SMatthew Dillon 	u_int32_t val;
322572ff6f6SMatthew Dillon 
323d98a0bcfSMatthew Dillon 	/* Debug - complain if we haven't fully waken things up */
324d98a0bcfSMatthew Dillon 	if (! ath_hal_reg_whilst_asleep(ah, reg) &&
325d98a0bcfSMatthew Dillon 	    ah->ah_powerMode != HAL_PM_AWAKE) {
326d98a0bcfSMatthew Dillon 		ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
327d98a0bcfSMatthew Dillon 		    __func__, reg, ah->ah_powerMode);
328d98a0bcfSMatthew Dillon 	}
329d98a0bcfSMatthew Dillon 
330572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
331dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
332b14ca477SMatthew Dillon 	OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
333572ff6f6SMatthew Dillon 	val = bus_space_read_4(tag, h, reg);
334572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
335dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_RELEASE);
336572ff6f6SMatthew Dillon 	if (ath_hal_alq) {
337572ff6f6SMatthew Dillon 		struct ale *ale = ath_hal_alq_get(ah);
338572ff6f6SMatthew Dillon 		if (ale) {
339572ff6f6SMatthew Dillon 			struct athregrec *r = (struct athregrec *) ale->ae_data;
340572ff6f6SMatthew Dillon 			r->threadid = curthread->td_tid;
341572ff6f6SMatthew Dillon 			r->op = OP_READ;
342572ff6f6SMatthew Dillon 			r->reg = reg;
343572ff6f6SMatthew Dillon 			r->val = val;
344572ff6f6SMatthew Dillon 			alq_post(ath_hal_alq, ale);
345572ff6f6SMatthew Dillon 		}
346572ff6f6SMatthew Dillon 	}
347572ff6f6SMatthew Dillon 	return val;
348572ff6f6SMatthew Dillon }
349572ff6f6SMatthew Dillon 
350572ff6f6SMatthew Dillon void
OS_MARK(struct ath_hal * ah,u_int id,u_int32_t v)351572ff6f6SMatthew Dillon OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
352572ff6f6SMatthew Dillon {
353572ff6f6SMatthew Dillon 	if (ath_hal_alq) {
354572ff6f6SMatthew Dillon 		struct ale *ale = ath_hal_alq_get(ah);
355572ff6f6SMatthew Dillon 		if (ale) {
356572ff6f6SMatthew Dillon 			struct athregrec *r = (struct athregrec *) ale->ae_data;
357572ff6f6SMatthew Dillon 			r->threadid = curthread->td_tid;
358572ff6f6SMatthew Dillon 			r->op = OP_MARK;
359572ff6f6SMatthew Dillon 			r->reg = id;
360572ff6f6SMatthew Dillon 			r->val = v;
361572ff6f6SMatthew Dillon 			alq_post(ath_hal_alq, ale);
362572ff6f6SMatthew Dillon 		}
363572ff6f6SMatthew Dillon 	}
364572ff6f6SMatthew Dillon }
365b14ca477SMatthew Dillon #else /* AH_DEBUG_ALQ */
366b14ca477SMatthew Dillon 
367572ff6f6SMatthew Dillon /*
368572ff6f6SMatthew Dillon  * Memory-mapped device register read/write.  These are here
369572ff6f6SMatthew Dillon  * as routines when debugging support is enabled and/or when
370572ff6f6SMatthew Dillon  * explicitly configured to use function calls.  The latter is
371572ff6f6SMatthew Dillon  * for architectures that might need to do something before
372572ff6f6SMatthew Dillon  * referencing memory (e.g. remap an i/o window).
373572ff6f6SMatthew Dillon  *
374572ff6f6SMatthew Dillon  * NB: see the comments in ah_osdep.h about byte-swapping register
375572ff6f6SMatthew Dillon  *     reads and writes to understand what's going on below.
376572ff6f6SMatthew Dillon  */
377572ff6f6SMatthew Dillon 
378572ff6f6SMatthew Dillon void
ath_hal_reg_write(struct ath_hal * ah,u_int32_t reg,u_int32_t val)379572ff6f6SMatthew Dillon ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
380572ff6f6SMatthew Dillon {
381572ff6f6SMatthew Dillon 	bus_space_tag_t tag = BUSTAG(ah);
382572ff6f6SMatthew Dillon 	bus_space_handle_t h = ah->ah_sh;
383572ff6f6SMatthew Dillon 
384b14ca477SMatthew Dillon #ifdef AH_DEBUG
385d98a0bcfSMatthew Dillon 	/* Debug - complain if we haven't fully waken things up */
386d98a0bcfSMatthew Dillon 	if (! ath_hal_reg_whilst_asleep(ah, reg) &&
387d98a0bcfSMatthew Dillon 	    ah->ah_powerMode != HAL_PM_AWAKE) {
388d98a0bcfSMatthew Dillon 		ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
389d98a0bcfSMatthew Dillon 		    __func__, reg, val, ah->ah_powerMode);
390d98a0bcfSMatthew Dillon 	}
391b14ca477SMatthew Dillon #endif
392d98a0bcfSMatthew Dillon 
393572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
394dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
395572ff6f6SMatthew Dillon 	bus_space_write_4(tag, h, reg, val);
396b14ca477SMatthew Dillon 	OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
397572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
398dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_RELEASE);
399572ff6f6SMatthew Dillon }
400572ff6f6SMatthew Dillon 
401572ff6f6SMatthew Dillon u_int32_t
ath_hal_reg_read(struct ath_hal * ah,u_int32_t reg)402572ff6f6SMatthew Dillon ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
403572ff6f6SMatthew Dillon {
404572ff6f6SMatthew Dillon 	bus_space_tag_t tag = BUSTAG(ah);
405572ff6f6SMatthew Dillon 	bus_space_handle_t h = ah->ah_sh;
406572ff6f6SMatthew Dillon 	u_int32_t val;
407572ff6f6SMatthew Dillon 
408b14ca477SMatthew Dillon #ifdef AH_DEBUG
409848b370cSMatthew Dillon 	/* Debug - complain if we haven't fully waken things up */
410848b370cSMatthew Dillon 	if (! ath_hal_reg_whilst_asleep(ah, reg) &&
411848b370cSMatthew Dillon 	    ah->ah_powerMode != HAL_PM_AWAKE) {
412848b370cSMatthew Dillon 		ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
413848b370cSMatthew Dillon 		    __func__, reg, ah->ah_powerMode);
414848b370cSMatthew Dillon 	}
415b14ca477SMatthew Dillon #endif
416848b370cSMatthew Dillon 
417572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
418dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
419b14ca477SMatthew Dillon 	OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
420572ff6f6SMatthew Dillon 	val = bus_space_read_4(tag, h, reg);
421572ff6f6SMatthew Dillon 	if (ah->ah_config.ah_serialise_reg_war)
422dc249793SMatthew Dillon 		lockmgr(&ah_regser_mtx, LK_RELEASE);
423572ff6f6SMatthew Dillon 	return val;
424572ff6f6SMatthew Dillon }
425922a4bc3SSascha Wildner #endif /* AH_DEBUG_ALQ */
426572ff6f6SMatthew Dillon 
427572ff6f6SMatthew Dillon #ifdef AH_ASSERT
428572ff6f6SMatthew Dillon void
ath_hal_assert_failed(const char * filename,int lineno,const char * msg)429572ff6f6SMatthew Dillon ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
430572ff6f6SMatthew Dillon {
431dc249793SMatthew Dillon 	kprintf("Atheros HAL assertion failure: %s: line %u: %s\n",
432572ff6f6SMatthew Dillon 		filename, lineno, msg);
433572ff6f6SMatthew Dillon 	panic("ath_hal_assert");
434572ff6f6SMatthew Dillon }
435572ff6f6SMatthew Dillon #endif /* AH_ASSERT */
436dc249793SMatthew Dillon 
437dc249793SMatthew Dillon /*
438dc249793SMatthew Dillon  * Module glue.
439dc249793SMatthew Dillon  */
440dc249793SMatthew Dillon static int
ath_hal_modevent(module_t mod,int type,void * unused)441dc249793SMatthew Dillon ath_hal_modevent(module_t mod, int type, void *unused)
442dc249793SMatthew Dillon {
443dc249793SMatthew Dillon        int error;
444dc249793SMatthew Dillon 
445dc249793SMatthew Dillon        wlan_serialize_enter();
446dc249793SMatthew Dillon 
447dc249793SMatthew Dillon        switch (type) {
448dc249793SMatthew Dillon        case MOD_LOAD:
449dc249793SMatthew Dillon 	       error = 0;
450dc249793SMatthew Dillon 	       break;
451dc249793SMatthew Dillon        case MOD_UNLOAD:
452dc249793SMatthew Dillon 	       error = 0;
453dc249793SMatthew Dillon 	       break;
454dc249793SMatthew Dillon        default:
455dc249793SMatthew Dillon 	       error = EINVAL;
456dc249793SMatthew Dillon 	       break;
457dc249793SMatthew Dillon        }
458dc249793SMatthew Dillon        wlan_serialize_exit();
459dc249793SMatthew Dillon 
460dc249793SMatthew Dillon        return error;
461dc249793SMatthew Dillon }
462dc249793SMatthew Dillon 
463dc249793SMatthew Dillon static moduledata_t ath_hal_mod = {
464dc249793SMatthew Dillon        "ath_hal",
465dc249793SMatthew Dillon        ath_hal_modevent,
466dc249793SMatthew Dillon        0
467dc249793SMatthew Dillon };
468dc249793SMatthew Dillon 
469dc249793SMatthew Dillon DECLARE_MODULE(ath_hal, ath_hal_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
470dc249793SMatthew Dillon MODULE_VERSION(ath_hal, 1);
471