New upstream snapshot.
[debian/madwifi.git] / ath_hal / ah_os.c
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  * $Id: ah_os.c 4162 2011-08-03 06:25:42Z proski $
37  */
38 #include "opt_ah.h"
39
40 #ifndef EXPORT_SYMTAB
41 #define EXPORT_SYMTAB
42 #endif
43
44 /* Don't use virtualized timer in Linux 2.6.20+ */
45 #define USE_REAL_TIME_DELAY
46
47 #if !defined(AUTOCONF_INCLUDED) && !defined(CONFIG_LOCALVERSION)
48 #include <linux/config.h>
49 #endif
50 #include <linux/version.h>
51 #include <linux/module.h>
52 #include <linux/init.h>
53
54 #include <linux/kernel.h>
55 #include <linux/slab.h>
56 #include <linux/delay.h>
57 #include <linux/sched.h>
58
59 #include <linux/sysctl.h>
60 #include <linux/proc_fs.h>
61
62 #include <asm/io.h>
63
64 #include <ah.h>
65 #include <ah_os.h>
66
67 #ifndef __MOD_INC_USE_COUNT
68 #define AH_MOD_INC_USE_COUNT(_m)                                        \
69         if (!try_module_get(_m)) {                                      \
70                 printk(KERN_WARNING "try_module_get failed\n");         \
71                 return NULL;                                            \
72         }
73 #define AH_MOD_DEC_USE_COUNT(_m)        module_put(_m)
74 #else
75 #define AH_MOD_INC_USE_COUNT(_m)        MOD_INC_USE_COUNT
76 #define AH_MOD_DEC_USE_COUNT(_m)        MOD_DEC_USE_COUNT
77 #endif
78
79 #ifdef AH_DEBUG
80 static  int ath_hal_debug = 0;
81 #endif
82
83 int     ath_hal_dma_beacon_response_time = 2;   /* in TU's */
84 int     ath_hal_sw_beacon_response_time = 10;   /* in TU's */
85 int     ath_hal_additional_swba_backoff = 0;    /* in TU's */
86
87 struct ath_hal *
88 _ath_hal_attach(u_int16_t devid, HAL_SOFTC sc,
89                 HAL_BUS_TAG t, HAL_BUS_HANDLE h, HAL_STATUS *s)
90 {
91         struct ath_hal *ah = ath_hal_attach(devid, sc, t, h, s);
92
93         if (ah)
94                 AH_MOD_INC_USE_COUNT(THIS_MODULE);
95         return ah;
96 }
97
98 void
99 ath_hal_detach(struct ath_hal *ah)
100 {
101         (*ah->ah_detach)(ah);
102         AH_MOD_DEC_USE_COUNT(THIS_MODULE);
103 }
104
105 /*
106  * Print/log message support.
107  */
108
109 void __ahdecl
110 ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap)
111 {
112         char buf[256];                                  /* XXX */
113         vsnprintf(buf, sizeof(buf), fmt, ap);
114         printk("%s", buf);
115 }
116
117 void __ahdecl
118 ath_hal_printf(struct ath_hal *ah, const char* fmt, ...)
119 {
120         va_list ap;
121         va_start(ap, fmt);
122         ath_hal_vprintf(ah, fmt, ap);
123         va_end(ap);
124 }
125 EXPORT_SYMBOL(ath_hal_printf);
126
127 /*
128  * Format an Ethernet MAC for printing.
129  */
130 const char* __ahdecl
131 ath_hal_ether_sprintf(const u_int8_t *mac)
132 {
133         static char etherbuf[18];
134         snprintf(etherbuf, sizeof(etherbuf), "%02x:%02x:%02x:%02x:%02x:%02x",
135                 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
136         return etherbuf;
137 }
138
139 #ifdef AH_ASSERT
140 void __ahdecl
141 ath_hal_assert_failed(const char* filename, int lineno, const char *msg)
142 {
143         printk("Atheros HAL assertion failure: %s: line %u: %s\n",
144                 filename, lineno, msg);
145         panic("ath_hal_assert");
146 }
147 #endif /* AH_ASSERT */
148
149 #ifdef AH_DEBUG_ALQ
150 /*
151  * ALQ register tracing support.
152  *
153  * Setting hw.ath.hal.alq=1 enables tracing of all register reads and
154  * writes to the file /tmp/ath_hal.log.  The file format is a simple
155  * fixed-size array of records.  When done logging set hw.ath.hal.alq=0
156  * and then decode the file with the ardecode program (that is part of the
157  * HAL).  If you start+stop tracing the data will be appended to an
158  * existing file.
159  *
160  * NB: doesn't handle multiple devices properly; only one DEVICE record
161  *     is emitted and the different devices are not identified.
162  */
163 #include "alq/alq.h"
164 #include "ah_decode.h"
165
166 static  struct alq *ath_hal_alq;
167 static  int ath_hal_alq_emitdev;        /* need to emit DEVICE record */
168 static  u_int ath_hal_alq_lost;         /* count of lost records */
169 static  const char *ath_hal_logfile = "/tmp/ath_hal.log";
170 static  u_int ath_hal_alq_qsize = 8*1024;
171
172 static int
173 ath_hal_setlogging(int enable)
174 {
175         int error;
176
177         if (enable) {
178                 if (!capable(CAP_NET_ADMIN))
179                         return -EPERM;
180                 error = alq_open(&ath_hal_alq, ath_hal_logfile,
181                                 sizeof (struct athregrec), ath_hal_alq_qsize);
182                 ath_hal_alq_lost = 0;
183                 ath_hal_alq_emitdev = 1;
184                 printk("ath_hal: logging to %s %s\n", ath_hal_logfile,
185                         error == 0 ? "enabled" : "could not be setup");
186         } else {
187                 if (ath_hal_alq)
188                         alq_close(ath_hal_alq);
189                 ath_hal_alq = NULL;
190                 printk("ath_hal: logging disabled\n");
191                 error = 0;
192         }
193         return error;
194 }
195
196 /*
197  * Deal with the sysctl handler api changing.
198  */
199 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,8)
200 #define AH_SYSCTL_ARGS_DECL \
201         ctl_table *ctl, int write, struct file *filp, void *buffer, \
202                 size_t *lenp
203 #define AH_SYSCTL_ARGS          ctl, write, filp, buffer, lenp
204 #else /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8) */
205 #define AH_SYSCTL_ARGS_DECL \
206         ctl_table *ctl, int write, struct file *filp, void *buffer,\
207                 size_t *lenp, loff_t *ppos
208 #define AH_SYSCTL_ARGS          ctl, write, filp, buffer, lenp, ppos
209 #endif
210
211 static int
212 sysctl_hw_ath_hal_log(AH_SYSCTL_ARGS_DECL)
213 {
214         int error, enable;
215
216         ctl->data = &enable;
217         ctl->maxlen = sizeof(enable);
218         enable = (ath_hal_alq != NULL);
219         error = proc_dointvec(AH_SYSCTL_ARGS);
220         if (error || !write)
221                 return error;
222         else
223                 return ath_hal_setlogging(enable);
224 }
225
226 static struct ale *
227 ath_hal_alq_get(struct ath_hal *ah)
228 {
229         struct ale *ale;
230
231         if (ath_hal_alq_emitdev) {
232                 ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
233                 if (ale) {
234                         struct athregrec *r =
235                                 (struct athregrec *) ale->ae_data;
236                         r->op = OP_DEVICE;
237                         r->reg = 0;
238                         r->val = ah->ah_devid;
239                         alq_post(ath_hal_alq, ale);
240                         ath_hal_alq_emitdev = 0;
241                 } else
242                         ath_hal_alq_lost++;
243         }
244         ale = alq_get(ath_hal_alq, ALQ_NOWAIT);
245         if (!ale)
246                 ath_hal_alq_lost++;
247         return ale;
248 }
249
250 void __ahdecl
251 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val)
252 {
253         if (ath_hal_alq) {
254                 unsigned long flags;
255                 struct ale *ale;
256
257                 local_irq_save(flags);
258                 ale = ath_hal_alq_get(ah);
259                 if (ale) {
260                         struct athregrec *r = (struct athregrec *) ale->ae_data;
261                         r->op = OP_WRITE;
262                         r->reg = reg;
263                         r->val = val;
264                         alq_post(ath_hal_alq, ale);
265                 }
266                 local_irq_restore(flags);
267         }
268         _OS_REG_WRITE(ah, reg, val);
269 }
270 EXPORT_SYMBOL(ath_hal_reg_write);
271
272 u_int32_t __ahdecl
273 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg)
274 {
275         u_int32_t val;
276
277         val = _OS_REG_READ(ah, reg);
278         if (ath_hal_alq) {
279                 unsigned long flags;
280                 struct ale *ale;
281
282                 local_irq_save(flags);
283                 ale = ath_hal_alq_get(ah);
284                 if (ale) {
285                         struct athregrec *r = (struct athregrec *) ale->ae_data;
286                         r->op = OP_READ;
287                         r->reg = reg;
288                         r->val = val;
289                         alq_post(ath_hal_alq, ale);
290                 }
291                 local_irq_restore(flags);
292         }
293         return val;
294 }
295 EXPORT_SYMBOL(ath_hal_reg_read);
296
297 void __ahdecl
298 OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v)
299 {
300         if (ath_hal_alq) {
301                 unsigned long flags;
302                 struct ale *ale;
303
304                 local_irq_save(flags);
305                 ale = ath_hal_alq_get(ah);
306                 if (ale) {
307                         struct athregrec *r = (struct athregrec *) ale->ae_data;
308                         r->op = OP_MARK;
309                         r->reg = id;
310                         r->val = v;
311                         alq_post(ath_hal_alq, ale);
312                 }
313                 local_irq_restore(flags);
314         }
315 }
316 EXPORT_SYMBOL(OS_MARK);
317 #elif defined(AH_DEBUG) || defined(AH_REGOPS_FUNC)
318 /*
319  * Memory-mapped device register read/write.  These are here
320  * as routines when debugging support is enabled and/or when
321  * explicitly configured to use function calls.  The latter is
322  * for architectures that might need to do something before
323  * referencing memory (e.g. remap an i/o window).
324  *
325  * NB: see the comments in ah_osdep.h about byte-swapping register
326  *     reads and writes to understand what's going on below.
327  */
328 void __ahdecl
329 ath_hal_reg_write(struct ath_hal *ah, u_int reg, u_int32_t val)
330 {
331 #ifdef AH_DEBUG
332         if (ath_hal_debug > 1)
333                 ath_hal_printf(ah, "WRITE 0x%x <= 0x%x\n", reg, val);
334 #endif
335         _OS_REG_WRITE(ah, reg, val);
336 }
337 EXPORT_SYMBOL(ath_hal_reg_write);
338
339 u_int32_t __ahdecl
340 ath_hal_reg_read(struct ath_hal *ah, u_int reg)
341 {
342         u_int32_t val;
343
344         val = _OS_REG_READ(ah, reg);
345 #ifdef AH_DEBUG
346         if (ath_hal_debug > 1)
347                 ath_hal_printf(ah, "READ 0x%x => 0x%x\n", reg, val);
348 #endif
349         return val;
350 }
351 EXPORT_SYMBOL(ath_hal_reg_read);
352 #endif /* AH_DEBUG || AH_REGOPS_FUNC */
353
354 #ifdef AH_DEBUG
355 void __ahdecl
356 HALDEBUG(struct ath_hal *ah, const char* fmt, ...)
357 {
358         if (ath_hal_debug) {
359                 __va_list ap;
360                 va_start(ap, fmt);
361                 ath_hal_vprintf(ah, fmt, ap);
362                 va_end(ap);
363         }
364 }
365
366
367 void __ahdecl
368 HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...)
369 {
370         if (ath_hal_debug >= level) {
371                 __va_list ap;
372                 va_start(ap, fmt);
373                 ath_hal_vprintf(ah, fmt, ap);
374                 va_end(ap);
375         }
376 }
377 #endif /* AH_DEBUG */
378
379 /*
380  * Delay n microseconds.
381  */
382 void __ahdecl
383 ath_hal_delay(int n)
384 {
385         udelay(n);
386 }
387
388 u_int32_t __ahdecl
389 ath_hal_getuptime(struct ath_hal *ah)
390 {
391         return ((jiffies / HZ) * 1000) + (jiffies % HZ) * (1000 / HZ);
392 }
393 EXPORT_SYMBOL(ath_hal_getuptime);
394
395 /*
396  * Allocate/free memory.
397  */
398
399 void * __ahdecl
400 ath_hal_malloc(size_t size)
401 {
402         void *p;
403         p = kmalloc(size, GFP_KERNEL);
404         if (p)
405                 OS_MEMZERO(p, size);
406         return p;
407                 
408 }
409
410 void __ahdecl
411 ath_hal_free(void* p)
412 {
413         kfree(p);
414 }
415
416 void __ahdecl
417 ath_hal_memzero(void *dst, size_t n)
418 {
419         memset(dst, 0, n);
420 }
421 EXPORT_SYMBOL(ath_hal_memzero);
422
423 void * __ahdecl
424 ath_hal_memcpy(void *dst, const void *src, size_t n)
425 {
426         return memcpy(dst, src, n);
427 }
428 EXPORT_SYMBOL(ath_hal_memcpy);
429
430 int __ahdecl
431 ath_hal_memcmp(const void *a, const void *b, size_t n)
432 {
433         return memcmp(a, b, n);
434 }
435 EXPORT_SYMBOL(ath_hal_memcmp);
436
437 static ctl_table ath_hal_sysctls[] = {
438 #ifdef AH_DEBUG
439         { ATH_INIT_CTL_NAME(CTL_AUTO)
440           .procname     = "debug",
441           .mode         = 0644,
442           .data         = &ath_hal_debug,
443           .maxlen       = sizeof(ath_hal_debug),
444           .proc_handler = proc_dointvec
445         },
446 #endif
447         { ATH_INIT_CTL_NAME(CTL_AUTO)
448           .procname     = "dma_beacon_response_time",
449           .data         = &ath_hal_dma_beacon_response_time,
450           .maxlen       = sizeof(ath_hal_dma_beacon_response_time),
451           .mode         = 0644,
452           .proc_handler = proc_dointvec
453         },
454         { ATH_INIT_CTL_NAME(CTL_AUTO)
455           .procname     = "sw_beacon_response_time",
456           .mode         = 0644,
457           .data         = &ath_hal_sw_beacon_response_time,
458           .maxlen       = sizeof(ath_hal_sw_beacon_response_time),
459           .proc_handler = proc_dointvec
460         },
461         { ATH_INIT_CTL_NAME(CTL_AUTO)
462           .procname     = "swba_backoff",
463           .mode         = 0644,
464           .data         = &ath_hal_additional_swba_backoff,
465           .maxlen       = sizeof(ath_hal_additional_swba_backoff),
466           .proc_handler = proc_dointvec
467         },
468 #ifdef AH_DEBUG_ALQ
469         { ATH_INIT_CTL_NAME(CTL_AUTO)
470           .procname     = "alq",
471           .mode         = 0644,
472           .proc_handler = sysctl_hw_ath_hal_log
473         },
474         { ATH_INIT_CTL_NAME(CTL_AUTO)
475           .procname     = "alq_size",
476           .mode         = 0644,
477           .data         = &ath_hal_alq_qsize,
478           .maxlen       = sizeof(ath_hal_alq_qsize),
479           .proc_handler = proc_dointvec
480         },
481         { ATH_INIT_CTL_NAME(CTL_AUTO)
482           .procname     = "alq_lost",
483           .mode         = 0644,
484           .data         = &ath_hal_alq_lost,
485           .maxlen       = sizeof(ath_hal_alq_lost),
486           .proc_handler = proc_dointvec
487         },
488 #endif
489         { }
490 };
491 static ctl_table ath_hal_table[] = {
492         { ATH_INIT_CTL_NAME(CTL_AUTO)
493           .procname     = "hal",
494           .mode         = 0555,
495           .child        = ath_hal_sysctls
496         }, { }
497 };
498 static ctl_table ath_ath_table[] = {
499         { ATH_INIT_CTL_NAME(DEV_ATH)
500           .procname     = "ath",
501           .mode         = 0555,
502           .child        = ath_hal_table
503         }, { }
504 };
505 static ctl_table ath_root_table[] = {
506         { ATH_INIT_CTL_NAME(CTL_DEV)
507           .procname     = "dev",
508           .mode         = 0555,
509           .child        = ath_ath_table
510         }, { }
511 };
512 static struct ctl_table_header *ath_hal_sysctl_header;
513
514 static void
515 ath_hal_sysctl_register(void)
516 {
517         static int initialized = 0;
518
519         if (!initialized) {
520                 ath_hal_sysctl_header =
521                         ATH_REGISTER_SYSCTL_TABLE(ath_root_table);
522                 initialized = 1;
523         }
524 }
525
526 static void
527 ath_hal_sysctl_unregister(void)
528 {
529         if (ath_hal_sysctl_header)
530                 unregister_sysctl_table(ath_hal_sysctl_header);
531 }
532
533 /*
534  * Module glue.
535  */
536 #include "version.h"
537 static char *dev_info = "ath_hal";
538
539 MODULE_AUTHOR("Errno Consulting, Sam Leffler");
540 MODULE_DESCRIPTION("Atheros Hardware Access Layer (HAL)");
541 MODULE_SUPPORTED_DEVICE("Atheros WLAN devices");
542 #ifdef MODULE_VERSION
543 MODULE_VERSION(ATH_HAL_VERSION);
544 #endif
545 #ifdef MODULE_LICENSE
546 MODULE_LICENSE("Proprietary");
547 #endif
548
549 EXPORT_SYMBOL(ath_hal_probe);
550 EXPORT_SYMBOL(_ath_hal_attach);
551 EXPORT_SYMBOL(ath_hal_detach);
552 EXPORT_SYMBOL(ath_hal_init_channels);
553 EXPORT_SYMBOL(ath_hal_getwirelessmodes);
554 EXPORT_SYMBOL(ath_hal_computetxtime);
555 EXPORT_SYMBOL(ath_hal_mhz2ieee);
556 EXPORT_SYMBOL(ath_hal_process_noisefloor);
557
558 static int __init
559 init_ath_hal(void)
560 {
561         const char *sep;
562         int i;
563
564         printk(KERN_INFO "%s: %s (", dev_info, ath_hal_version);
565         sep = "";
566         for (i = 0; ath_hal_buildopts[i] != NULL; i++) {
567                 printk("%s%s", sep, ath_hal_buildopts[i]);
568                 sep = ", ";
569         }
570         printk(")\n");
571         ath_hal_sysctl_register();
572         return (0);
573 }
574 module_init(init_ath_hal);
575
576 static void __exit
577 exit_ath_hal(void)
578 {
579         ath_hal_sysctl_unregister();
580         printk(KERN_INFO "%s: driver unloaded\n", dev_info);
581 }
582 module_exit(exit_ath_hal);