1 /*-
2 * Copyright (c) 2002-2008 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, MERCHANTABILITY
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 * $FreeBSD$
30 */
31 #include "opt_ah.h"
32
33 #if defined(__DragonFly__)
34 #define CTLFLAG_RWTUN CTLFLAG_RW
35 #endif
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/module.h>
41 #include <sys/sysctl.h>
42 #include <sys/bus.h>
43 #include <sys/malloc.h>
44 #include <sys/proc.h>
45 #if defined(__DragonFly__)
46 #else
47 #include <sys/pcpu.h>
48 #endif
49 #include <sys/lock.h>
50
51 #include <machine/stdarg.h>
52
53 #include <net/ethernet.h> /* XXX for ether_sprintf */
54 #if defined(__DragonFly__)
55
56 #include <net/if.h>
57 #include <net/if_var.h>
58 #include <net/if_media.h>
59 #include <net/if_types.h>
60 #include <netproto/802_11/ieee80211_var.h> /* ether_sprintf */
61
62 #endif
63
64 #include <dev/netif/ath/ath_hal/ah.h>
65 #include <dev/netif/ath/ath_hal/ah_debug.h>
66
67 /*
68 * WiSoC boards overload the bus tag with information about the
69 * board layout. We must extract the bus space tag from that
70 * indirect structure. For everyone else the tag is passed in
71 * directly.
72 * XXX cache indirect ref privately
73 */
74 #ifdef AH_SUPPORT_AR5312
75 #define BUSTAG(ah) \
76 ((bus_space_tag_t) ((struct ar531x_config *)((ah)->ah_st))->tag)
77 #else
78 #define BUSTAG(ah) ((ah)->ah_st)
79 #endif
80
81 /*
82 * This lock is used to seralise register access for chips which have
83 * problems w/ SMP CPUs issuing concurrent PCI transactions.
84 *
85 * XXX This is a global lock for now; it should be pushed to
86 * a per-device lock in some platform-independent fashion.
87 */
88 struct lock ah_regser_mtx;
89 LOCK_SYSINIT(ah_regser, &ah_regser_mtx, "Atheros register access mutex", 0);
90
91 extern void ath_hal_printf(struct ath_hal *, const char*, ...)
92 __printflike(2, 3);
93 extern void ath_hal_vprintf(struct ath_hal *, const char*, __va_list)
94 __printflike(2, 0);
95 extern const char* ath_hal_ether_sprintf(const u_int8_t *mac);
96 extern void *ath_hal_malloc(size_t);
97 extern void ath_hal_free(void *);
98 #ifdef AH_ASSERT
99 extern void ath_hal_assert_failed(const char* filename,
100 int lineno, const char* msg);
101 #endif
102 #ifdef AH_DEBUG
103 extern void DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
104 __printflike(3, 4);
105 #endif /* AH_DEBUG */
106
107 /* NB: put this here instead of the driver to avoid circular references */
108 SYSCTL_NODE(_hw, OID_AUTO, ath, CTLFLAG_RD, 0, "Atheros driver parameters");
109 static SYSCTL_NODE(_hw_ath, OID_AUTO, hal, CTLFLAG_RD, 0,
110 "Atheros HAL parameters");
111
112 #ifdef AH_DEBUG
113 int ath_hal_debug = 0;
114 SYSCTL_INT(_hw_ath_hal, OID_AUTO, debug, CTLFLAG_RWTUN, &ath_hal_debug,
115 0, "Atheros HAL debugging printfs");
116 #endif /* AH_DEBUG */
117
118 static MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data");
119
120 void*
ath_hal_malloc(size_t size)121 ath_hal_malloc(size_t size)
122 {
123 return kmalloc(size, M_ATH_HAL, M_INTWAIT | M_ZERO);
124 }
125
126 void
ath_hal_free(void * p)127 ath_hal_free(void* p)
128 {
129 kfree(p, M_ATH_HAL);
130 }
131
132 void
ath_hal_vprintf(struct ath_hal * ah,const char * fmt,__va_list ap)133 ath_hal_vprintf(struct ath_hal *ah, const char* fmt, __va_list ap)
134 {
135 kvprintf(fmt, ap);
136 }
137
138 void
ath_hal_printf(struct ath_hal * ah,const char * fmt,...)139 ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
140 {
141 __va_list ap;
142 __va_start(ap, fmt);
143 ath_hal_vprintf(ah, fmt, ap);
144 __va_end(ap);
145 }
146
147 const char*
ath_hal_ether_sprintf(const u_int8_t * mac)148 ath_hal_ether_sprintf(const u_int8_t *mac)
149 {
150 return ether_sprintf(mac);
151 }
152
153 #ifdef AH_DEBUG
154
155 /*
156 * XXX This is highly relevant only for the AR5416 and later
157 * PCI/PCIe NICs. It'll need adjustment for other hardware
158 * variations.
159 */
160 static int
ath_hal_reg_whilst_asleep(struct ath_hal * ah,uint32_t reg)161 ath_hal_reg_whilst_asleep(struct ath_hal *ah, uint32_t reg)
162 {
163
164 if (reg >= 0x4000 && reg < 0x5000)
165 return (1);
166 if (reg >= 0x6000 && reg < 0x7000)
167 return (1);
168 if (reg >= 0x7000 && reg < 0x8000)
169 return (1);
170 return (0);
171 }
172
173 void
DO_HALDEBUG(struct ath_hal * ah,u_int mask,const char * fmt,...)174 DO_HALDEBUG(struct ath_hal *ah, u_int mask, const char* fmt, ...)
175 {
176 if ((mask == HAL_DEBUG_UNMASKABLE) ||
177 (ah != NULL && ah->ah_config.ah_debug & mask) ||
178 (ath_hal_debug & mask)) {
179 __va_list ap;
180 __va_start(ap, fmt);
181 ath_hal_vprintf(ah, fmt, ap);
182 __va_end(ap);
183 }
184 }
185 #undef HAL_DEBUG_UNMASKABLE
186 #endif /* AH_DEBUG */
187
188 #ifdef AH_DEBUG_ALQ
189 /*
190 * ALQ register tracing support.
191 *
192 * Setting hw.ath.hal.alq=1 enables tracing of all register reads and
193 * writes to the file /tmp/ath_hal.log. The file format is a simple
194 * fixed-size array of records. When done logging set hw.ath.hal.alq=0
195 * and then decode the file with the arcode program (that is part of the
196 * HAL). If you start+stop tracing the data will be appended to an
197 * existing file.
198 *
199 * NB: doesn't handle multiple devices properly; only one DEVICE record
200 * is emitted and the different devices are not identified.
201 */
202 /*#include <sys/alq.h> FreeBSD */
203 /*#include <sys/pcpu.h> FreeBSD */
204 #include <dev/netif/ath/ath_hal/ah_decode.h>
205
206 static struct alq *ath_hal_alq;
207 static int ath_hal_alq_emitdev; /* need to emit DEVICE record */
208 static u_int ath_hal_alq_lost; /* count of lost records */
209 static char ath_hal_logfile[MAXPATHLEN] = "/tmp/ath_hal.log";
210
211 SYSCTL_STRING(_hw_ath_hal, OID_AUTO, alq_logfile, CTLFLAG_RW,
212 &ath_hal_logfile, sizeof(kernelname), "Name of ALQ logfile");
213
214 static u_int ath_hal_alq_qsize = 64*1024;
215
216 static int
ath_hal_setlogging(int enable)217 ath_hal_setlogging(int enable)
218 {
219 int error;
220
221 if (enable) {
222 error = alq_open(&ath_hal_alq, ath_hal_logfile,
223 curthread->td_ucred, ALQ_DEFAULT_CMODE,
224 sizeof (struct athregrec), ath_hal_alq_qsize);
225 ath_hal_alq_lost = 0;
226 ath_hal_alq_emitdev = 1;
227 kprintf("ath_hal: logging to %s enabled\n",
228 ath_hal_logfile);
229 } else {
230 if (ath_hal_alq)
231 alq_close(ath_hal_alq);
232 ath_hal_alq = NULL;
233 kprintf("ath_hal: logging disabled\n");
234 error = 0;
235 }
236 return (error);
237 }
238
239 static int
sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)240 sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS)
241 {
242 int error, enable;
243
244 enable = (ath_hal_alq != NULL);
245 error = sysctl_handle_int(oidp, &enable, 0, req);
246 if (error || !req->newptr)
247 return (error);
248 else
249 return (ath_hal_setlogging(enable));
250 }
251 SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW,
252 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging");
253 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW,
254 &ath_hal_alq_qsize, 0, "In-memory log size (#records)");
255 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW,
256 &ath_hal_alq_lost, 0, "Register operations not logged");
257
258 static struct ale *
ath_hal_alq_get(struct ath_hal * ah)259 ath_hal_alq_get(struct ath_hal *ah)
260 {
261 struct ale *ale;
262
263 if (ath_hal_alq_emitdev) {
264 ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
265 if (ale) {
266 struct athregrec *r =
267 (struct athregrec *) ale->ae_data;
268 r->op = OP_DEVICE;
269 r->reg = 0;
270 r->val = ah->ah_devid;
271 alq_post(ath_hal_alq, ale);
272 ath_hal_alq_emitdev = 0;
273 } else
274 ath_hal_alq_lost++;
275 }
276 ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
277 if (!ale)
278 ath_hal_alq_lost++;
279 return ale;
280 }
281
282 void
ath_hal_reg_write(struct ath_hal * ah,u_int32_t reg,u_int32_t val)283 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
284 {
285 bus_space_tag_t tag = BUSTAG(ah);
286 bus_space_handle_t h = ah->ah_sh;
287
288 #ifdef AH_DEBUG
289 /* Debug - complain if we haven't fully waken things up */
290 if (! ath_hal_reg_whilst_asleep(ah, reg) &&
291 ah->ah_powerMode != HAL_PM_AWAKE) {
292 ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
293 __func__, reg, val, ah->ah_powerMode);
294 }
295 #endif
296
297 if (ath_hal_alq) {
298 struct ale *ale = ath_hal_alq_get(ah);
299 if (ale) {
300 struct athregrec *r = (struct athregrec *) ale->ae_data;
301 r->threadid = curthread->td_tid;
302 r->op = OP_WRITE;
303 r->reg = reg;
304 r->val = val;
305 alq_post(ath_hal_alq, ale);
306 }
307 }
308 if (ah->ah_config.ah_serialise_reg_war)
309 lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
310 bus_space_write_4(tag, h, reg, val);
311 OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
312 if (ah->ah_config.ah_serialise_reg_war)
313 lockmgr(&ah_regser_mtx, LK_RELEASE);
314 }
315
316 u_int32_t
ath_hal_reg_read(struct ath_hal * ah,u_int32_t reg)317 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
318 {
319 bus_space_tag_t tag = BUSTAG(ah);
320 bus_space_handle_t h = ah->ah_sh;
321 u_int32_t val;
322
323 /* Debug - complain if we haven't fully waken things up */
324 if (! ath_hal_reg_whilst_asleep(ah, reg) &&
325 ah->ah_powerMode != HAL_PM_AWAKE) {
326 ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
327 __func__, reg, ah->ah_powerMode);
328 }
329
330 if (ah->ah_config.ah_serialise_reg_war)
331 lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
332 OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
333 val = bus_space_read_4(tag, h, reg);
334 if (ah->ah_config.ah_serialise_reg_war)
335 lockmgr(&ah_regser_mtx, LK_RELEASE);
336 if (ath_hal_alq) {
337 struct ale *ale = ath_hal_alq_get(ah);
338 if (ale) {
339 struct athregrec *r = (struct athregrec *) ale->ae_data;
340 r->threadid = curthread->td_tid;
341 r->op = OP_READ;
342 r->reg = reg;
343 r->val = val;
344 alq_post(ath_hal_alq, ale);
345 }
346 }
347 return val;
348 }
349
350 void
OS_MARK(struct ath_hal * ah,u_int id,u_int32_t v)351 OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
352 {
353 if (ath_hal_alq) {
354 struct ale *ale = ath_hal_alq_get(ah);
355 if (ale) {
356 struct athregrec *r = (struct athregrec *) ale->ae_data;
357 r->threadid = curthread->td_tid;
358 r->op = OP_MARK;
359 r->reg = id;
360 r->val = v;
361 alq_post(ath_hal_alq, ale);
362 }
363 }
364 }
365 #else /* AH_DEBUG_ALQ */
366
367 /*
368 * Memory-mapped device register read/write. These are here
369 * as routines when debugging support is enabled and/or when
370 * explicitly configured to use function calls. The latter is
371 * for architectures that might need to do something before
372 * referencing memory (e.g. remap an i/o window).
373 *
374 * NB: see the comments in ah_osdep.h about byte-swapping register
375 * reads and writes to understand what's going on below.
376 */
377
378 void
ath_hal_reg_write(struct ath_hal * ah,u_int32_t reg,u_int32_t val)379 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
380 {
381 bus_space_tag_t tag = BUSTAG(ah);
382 bus_space_handle_t h = ah->ah_sh;
383
384 #ifdef AH_DEBUG
385 /* Debug - complain if we haven't fully waken things up */
386 if (! ath_hal_reg_whilst_asleep(ah, reg) &&
387 ah->ah_powerMode != HAL_PM_AWAKE) {
388 ath_hal_printf(ah, "%s: reg=0x%08x, val=0x%08x, pm=%d\n",
389 __func__, reg, val, ah->ah_powerMode);
390 }
391 #endif
392
393 if (ah->ah_config.ah_serialise_reg_war)
394 lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
395 bus_space_write_4(tag, h, reg, val);
396 OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_WRITE);
397 if (ah->ah_config.ah_serialise_reg_war)
398 lockmgr(&ah_regser_mtx, LK_RELEASE);
399 }
400
401 u_int32_t
ath_hal_reg_read(struct ath_hal * ah,u_int32_t reg)402 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
403 {
404 bus_space_tag_t tag = BUSTAG(ah);
405 bus_space_handle_t h = ah->ah_sh;
406 u_int32_t val;
407
408 #ifdef AH_DEBUG
409 /* Debug - complain if we haven't fully waken things up */
410 if (! ath_hal_reg_whilst_asleep(ah, reg) &&
411 ah->ah_powerMode != HAL_PM_AWAKE) {
412 ath_hal_printf(ah, "%s: reg=0x%08x, pm=%d\n",
413 __func__, reg, ah->ah_powerMode);
414 }
415 #endif
416
417 if (ah->ah_config.ah_serialise_reg_war)
418 lockmgr(&ah_regser_mtx, LK_EXCLUSIVE);
419 OS_BUS_BARRIER_REG(ah, reg, OS_BUS_BARRIER_READ);
420 val = bus_space_read_4(tag, h, reg);
421 if (ah->ah_config.ah_serialise_reg_war)
422 lockmgr(&ah_regser_mtx, LK_RELEASE);
423 return val;
424 }
425 #endif /* AH_DEBUG_ALQ */
426
427 #ifdef AH_ASSERT
428 void
ath_hal_assert_failed(const char * filename,int lineno,const char * msg)429 ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
430 {
431 kprintf("Atheros HAL assertion failure: %s: line %u: %s\n",
432 filename, lineno, msg);
433 panic("ath_hal_assert");
434 }
435 #endif /* AH_ASSERT */
436
437 /*
438 * Module glue.
439 */
440 static int
ath_hal_modevent(module_t mod,int type,void * unused)441 ath_hal_modevent(module_t mod, int type, void *unused)
442 {
443 int error;
444
445 wlan_serialize_enter();
446
447 switch (type) {
448 case MOD_LOAD:
449 error = 0;
450 break;
451 case MOD_UNLOAD:
452 error = 0;
453 break;
454 default:
455 error = EINVAL;
456 break;
457 }
458 wlan_serialize_exit();
459
460 return error;
461 }
462
463 static moduledata_t ath_hal_mod = {
464 "ath_hal",
465 ath_hal_modevent,
466 0
467 };
468
469 DECLARE_MODULE(ath_hal, ath_hal_mod, SI_SUB_DRIVERS, SI_ORDER_ANY);
470 MODULE_VERSION(ath_hal, 1);
471