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, 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 * $Id: ah_osdep.c,v 1.5 2011/07/17 20:54:51 joerg Exp $ 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: ah_osdep.c,v 1.5 2011/07/17 20:54:51 joerg Exp $"); 34 35 #ifdef _KERNEL_OPT 36 #include "opt_athhal.h" 37 #endif 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/sysctl.h> 43 #include <sys/malloc.h> 44 #include <sys/proc.h> 45 #include <sys/kauth.h> 46 #include <sys/module.h> 47 48 #include <net/if.h> 49 #include <net/if_dl.h> 50 #include <net/if_media.h> 51 #include <net/if_arp.h> 52 #include <net/if_ether.h> 53 54 #include <external/isc/atheros_hal/dist/ah.h> 55 56 extern void ath_hal_printf(struct ath_hal *, const char*, ...) 57 __printflike(2,3); 58 extern void ath_hal_vprintf(struct ath_hal *, const char*, va_list) 59 __printflike(2, 0); 60 extern const char* ath_hal_ether_sprintf(const u_int8_t *mac); 61 extern void *ath_hal_malloc(size_t); 62 extern void ath_hal_free(void *); 63 #ifdef ATHHAL_ASSERT 64 extern void ath_hal_assert_failed(const char* filename, 65 int lineno, const char* msg); 66 #endif 67 #ifdef ATHHAL_DEBUG 68 extern void HALDEBUG(struct ath_hal *ah, const char* fmt, ...); 69 extern void HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...); 70 #endif /* ATHHAL_DEBUG */ 71 72 #ifdef ATHHAL_DEBUG 73 static int ath_hal_debug = 0; 74 #endif /* ATHHAL_DEBUG */ 75 76 int ath_hal_dma_beacon_response_time = 2; /* in TU's */ 77 int ath_hal_sw_beacon_response_time = 10; /* in TU's */ 78 int ath_hal_additional_swba_backoff = 0; /* in TU's */ 79 80 SYSCTL_SETUP(sysctl_ath_hal, "sysctl ath.hal subtree setup") 81 { 82 int rc; 83 const struct sysctlnode *cnode, *rnode; 84 85 if ((rc = sysctl_createv(clog, 0, NULL, &rnode, CTLFLAG_PERMANENT, 86 CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL)) != 0) 87 goto err; 88 89 if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, 90 CTLTYPE_NODE, "ath", SYSCTL_DESCR("Atheros driver parameters"), 91 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 92 goto err; 93 94 if ((rc = sysctl_createv(clog, 0, &rnode, &rnode, CTLFLAG_PERMANENT, 95 CTLTYPE_NODE, "hal", SYSCTL_DESCR("Atheros HAL parameters"), 96 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0) 97 goto err; 98 99 #if 0 100 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, 101 CTLFLAG_PERMANENT|CTLFLAG_READONLY, CTLTYPE_STRING, "version", 102 SYSCTL_DESCR("Atheros HAL version"), NULL, 0, &ath_hal_version, 0, 103 CTL_CREATE, CTL_EOL)) != 0) 104 goto err; 105 #endif 106 107 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, 108 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "dma_brt", 109 SYSCTL_DESCR("Atheros HAL DMA beacon response time"), NULL, 0, 110 &ath_hal_dma_beacon_response_time, 0, CTL_CREATE, CTL_EOL)) != 0) 111 goto err; 112 113 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, 114 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "sw_brt", 115 SYSCTL_DESCR("Atheros HAL software beacon response time"), NULL, 0, 116 &ath_hal_sw_beacon_response_time, 0, CTL_CREATE, CTL_EOL)) != 0) 117 goto err; 118 119 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, 120 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "swba_backoff", 121 SYSCTL_DESCR("Atheros HAL additional SWBA backoff time"), NULL, 0, 122 &ath_hal_additional_swba_backoff, 0, CTL_CREATE, CTL_EOL)) != 0) 123 goto err; 124 125 #ifdef ATHHAL_DEBUG 126 if ((rc = sysctl_createv(clog, 0, &rnode, &cnode, 127 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, CTLTYPE_INT, "debug", 128 SYSCTL_DESCR("Atheros HAL debugging printfs"), NULL, 0, 129 &ath_hal_debug, 0, CTL_CREATE, CTL_EOL)) != 0) 130 goto err; 131 #endif /* ATHHAL_DEBUG */ 132 return; 133 err: 134 printf("%s: sysctl_createv failed (rc = %d)\n", __func__, rc); 135 } 136 137 MALLOC_DEFINE(M_ATH_HAL, "ath_hal", "ath hal data"); 138 139 void* 140 ath_hal_malloc(size_t size) 141 { 142 return malloc(size, M_ATH_HAL, M_NOWAIT | M_ZERO); 143 } 144 145 void 146 ath_hal_free(void* p) 147 { 148 free(p, M_ATH_HAL); 149 } 150 151 void 152 ath_hal_vprintf(struct ath_hal *ah, const char* fmt, va_list ap) 153 { 154 vprintf(fmt, ap); 155 } 156 157 void 158 ath_hal_printf(struct ath_hal *ah, const char* fmt, ...) 159 { 160 va_list ap; 161 va_start(ap, fmt); 162 ath_hal_vprintf(ah, fmt, ap); 163 va_end(ap); 164 } 165 166 const char* 167 ath_hal_ether_sprintf(const u_int8_t *mac) 168 { 169 return ether_sprintf(mac); 170 } 171 172 #ifdef ATHHAL_DEBUG 173 void 174 HALDEBUG(struct ath_hal *ah, const char* fmt, ...) 175 { 176 if (ath_hal_debug) { 177 va_list ap; 178 va_start(ap, fmt); 179 ath_hal_vprintf(ah, fmt, ap); 180 va_end(ap); 181 } 182 } 183 184 void 185 HALDEBUGn(struct ath_hal *ah, u_int level, const char* fmt, ...) 186 { 187 if (ath_hal_debug >= level) { 188 va_list ap; 189 va_start(ap, fmt); 190 ath_hal_vprintf(ah, fmt, ap); 191 va_end(ap); 192 } 193 } 194 #endif /* ATHHAL_DEBUG */ 195 196 #ifdef ATHHAL_DEBUG_ALQ 197 /* 198 * ALQ register tracing support. 199 * 200 * Setting hw.ath.hal.alq=1 enables tracing of all register reads and 201 * writes to the file /tmp/ath_hal.log. The file format is a simple 202 * fixed-size array of records. When done logging set hw.ath.hal.alq=0 203 * and then decode the file with the arcode program (that is part of the 204 * HAL). If you start+stop tracing the data will be appended to an 205 * existing file. 206 * 207 * NB: doesn't handle multiple devices properly; only one DEVICE record 208 * is emitted and the different devices are not identified. 209 */ 210 #include <sys/alq.h> 211 #include <sys/pcpu.h> 212 213 static struct alq *ath_hal_alq; 214 static int ath_hal_alq_emitdev; /* need to emit DEVICE record */ 215 static u_int ath_hal_alq_lost; /* count of lost records */ 216 static const char *ath_hal_logfile = "/tmp/ath_hal.log"; 217 static u_int ath_hal_alq_qsize = 64*1024; 218 219 static int 220 ath_hal_setlogging(int enable) 221 { 222 int error; 223 224 if (enable) { 225 error = kauth_authorize_network(curlwp->l_cred, 226 KAUTH_NETWORK_INTERFACE, 227 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, NULL, NULL, NULL); 228 if (error == 0) { 229 error = alq_open(&ath_hal_alq, ath_hal_logfile, 230 curproc->p_ucred, 231 sizeof (struct athregrec), ath_hal_alq_qsize); 232 ath_hal_alq_lost = 0; 233 ath_hal_alq_emitdev = 1; 234 printf("ath_hal: logging to %s enabled\n", 235 ath_hal_logfile); 236 } 237 } else { 238 if (ath_hal_alq) 239 alq_close(ath_hal_alq); 240 ath_hal_alq = NULL; 241 printf("ath_hal: logging disabled\n"); 242 error = 0; 243 } 244 return (error); 245 } 246 247 static int 248 sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS) 249 { 250 int error, enable; 251 252 enable = (ath_hal_alq != NULL); 253 error = sysctl_handle_int(oidp, &enable, 0, req); 254 if (error || !req->newptr) 255 return (error); 256 else 257 return (ath_hal_setlogging(enable)); 258 } 259 SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW, 260 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging"); 261 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW, 262 &ath_hal_alq_qsize, 0, "In-memory log size (#records)"); 263 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW, 264 &ath_hal_alq_lost, 0, "Register operations not logged"); 265 266 static struct ale * 267 ath_hal_alq_get(struct ath_hal *ah) 268 { 269 struct ale *ale; 270 271 if (ath_hal_alq_emitdev) { 272 ale = alq_get(ath_hal_alq, ALQ_NOWAIT); 273 if (ale) { 274 struct athregrec *r = 275 (struct athregrec *) ale->ae_data; 276 r->op = OP_DEVICE; 277 r->reg = 0; 278 r->val = ah->ah_devid; 279 alq_post(ath_hal_alq, ale); 280 ath_hal_alq_emitdev = 0; 281 } else 282 ath_hal_alq_lost++; 283 } 284 ale = alq_get(ath_hal_alq, ALQ_NOWAIT); 285 if (!ale) 286 ath_hal_alq_lost++; 287 return ale; 288 } 289 290 void 291 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) 292 { 293 bus_space_tag_t t = BUSTAG(ah); 294 295 if (ath_hal_alq) { 296 struct ale *ale = ath_hal_alq_get(ah); 297 if (ale) { 298 struct athregrec *r = (struct athregrec *) ale->ae_data; 299 r->op = OP_WRITE; 300 r->reg = reg; 301 r->val = val; 302 alq_post(ath_hal_alq, ale); 303 } 304 } 305 #if _BYTE_ORDER == _BIG_ENDIAN 306 if (reg >= 0x4000 && reg < 0x5000) 307 bus_space_write_4(t, h, reg, val); 308 else 309 #endif 310 bus_space_write_stream_4(t, h, reg, val); 311 } 312 313 u_int32_t 314 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) 315 { 316 u_int32_t val; 317 bus_space_handle_t h = BUSHANDLE(ah); 318 bus_space_tag_t t = BUSTAG(ah); 319 320 #if _BYTE_ORDER == _BIG_ENDIAN 321 if (reg >= 0x4000 && reg < 0x5000) 322 val = bus_space_read_4(t, h, reg); 323 else 324 #endif 325 val = bus_space_read_stream_4(t, h, reg); 326 327 if (ath_hal_alq) { 328 struct ale *ale = ath_hal_alq_get(ah); 329 if (ale) { 330 struct athregrec *r = (struct athregrec *) ale->ae_data; 331 r->op = OP_READ; 332 r->reg = reg; 333 r->val = val; 334 alq_post(ath_hal_alq, ale); 335 } 336 } 337 338 return val; 339 } 340 341 void 342 OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v) 343 { 344 if (ath_hal_alq) { 345 struct ale *ale = ath_hal_alq_get(ah); 346 347 if (ale) { 348 struct athregrec *r = (struct athregrec *) ale->ae_data; 349 r->op = OP_MARK; 350 r->reg = id; 351 r->val = v; 352 alq_post(ath_hal_alq, ale); 353 } 354 } 355 } 356 #elif defined(ATHHAL_DEBUG) || defined(AH_REGOPS_FUNC) 357 /* 358 * Memory-mapped device register read/write. These are here 359 * as routines when debugging support is enabled and/or when 360 * explicitly configured to use function calls. The latter is 361 * for architectures that might need to do something before 362 * referencing memory (e.g. remap an i/o window). 363 * 364 * NB: see the comments in ah_osdep.h about byte-swapping register 365 * reads and writes to understand what's going on below. 366 */ 367 368 void 369 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) 370 { 371 bus_space_handle_t h = BUSHANDLE(ah); 372 bus_space_tag_t t = BUSTAG(ah); 373 374 #if _BYTE_ORDER == _BIG_ENDIAN 375 if (reg >= 0x4000 && reg < 0x5000) 376 bus_space_write_4(t, h, reg, val); 377 else 378 #endif 379 bus_space_write_stream_4(t, h, reg, val); 380 } 381 382 u_int32_t 383 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) 384 { 385 bus_space_handle_t h = BUSHANDLE(ah); 386 bus_space_tag_t t = BUSTAG(ah); 387 uint32_t ret; 388 389 #if _BYTE_ORDER == _BIG_ENDIAN 390 if (reg >= 0x4000 && reg < 0x5000) 391 ret = bus_space_read_4(t, h, reg); 392 else 393 #endif 394 ret = bus_space_read_stream_4(t, h, reg); 395 396 return ret; 397 } 398 #endif /* ATHHAL_DEBUG || AH_REGOPS_FUNC */ 399 400 #ifdef ATHHAL_ASSERT 401 void 402 ath_hal_assert_failed(const char* filename, int lineno, const char *msg) 403 { 404 printf("Atheros HAL assertion failure: %s: line %u: %s\n", 405 filename, lineno, msg); 406 panic("ath_hal_assert"); 407 } 408 #endif /* ATHHAL_ASSERT */ 409 410 /* 411 * Delay n microseconds. 412 */ 413 void 414 ath_hal_delay(int n) 415 { 416 DELAY(n); 417 } 418 419 u_int32_t 420 ath_hal_getuptime(struct ath_hal *ah) 421 { 422 struct bintime bt; 423 uint32_t ret; 424 getbinuptime(&bt); 425 ret = (bt.sec * 1000) + 426 (((uint64_t)1000 * (uint32_t)(bt.frac >> 32)) >> 32); 427 return ret; 428 } 429 430 void 431 ath_hal_memzero(void *dst, size_t n) 432 { 433 (void)memset(dst, 0, n); 434 } 435 436 void * 437 ath_hal_memcpy(void *dst, const void *src, size_t n) 438 { 439 return memcpy(dst, src, n); 440 } 441 442 MODULE(MODULE_CLASS_MISC, ath_hal, NULL); 443 444 static int 445 ath_hal_modcmd(modcmd_t cmd, void *opaque) 446 { 447 switch (cmd) { 448 case MODULE_CMD_INIT: 449 case MODULE_CMD_FINI: 450 return 0; 451 default: 452 return ENOTTY; 453 } 454 } 455