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.7 2021/09/21 14:51:28 christos Exp $ 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: ah_osdep.c,v 1.7 2021/09/21 14:51:28 christos 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, u_int mask, const char* fmt, ...) 69 __printflike(3,4); 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, u_int mask, const char* fmt, ...) 175 { 176 if (ath_hal_debug & mask) { 177 va_list ap; 178 va_start(ap, fmt); 179 ath_hal_vprintf(ah, fmt, ap); 180 va_end(ap); 181 } 182 } 183 #endif /* ATHHAL_DEBUG */ 184 185 #ifdef ATHHAL_DEBUG_ALQ 186 /* 187 * ALQ register tracing support. 188 * 189 * Setting hw.ath.hal.alq=1 enables tracing of all register reads and 190 * writes to the file /tmp/ath_hal.log. The file format is a simple 191 * fixed-size array of records. When done logging set hw.ath.hal.alq=0 192 * and then decode the file with the arcode program (that is part of the 193 * HAL). If you start+stop tracing the data will be appended to an 194 * existing file. 195 * 196 * NB: doesn't handle multiple devices properly; only one DEVICE record 197 * is emitted and the different devices are not identified. 198 */ 199 #include <sys/alq.h> 200 #include <sys/pcpu.h> 201 202 static struct alq *ath_hal_alq; 203 static int ath_hal_alq_emitdev; /* need to emit DEVICE record */ 204 static u_int ath_hal_alq_lost; /* count of lost records */ 205 static const char *ath_hal_logfile = "/tmp/ath_hal.log"; 206 static u_int ath_hal_alq_qsize = 64*1024; 207 208 static int 209 ath_hal_setlogging(int enable) 210 { 211 int error; 212 213 if (enable) { 214 error = kauth_authorize_network(kauth_cred_get(), 215 KAUTH_NETWORK_INTERFACE, 216 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, NULL, NULL, NULL); 217 if (error == 0) { 218 error = alq_open(&ath_hal_alq, ath_hal_logfile, 219 curproc->p_ucred, 220 sizeof (struct athregrec), ath_hal_alq_qsize); 221 ath_hal_alq_lost = 0; 222 ath_hal_alq_emitdev = 1; 223 printf("ath_hal: logging to %s enabled\n", 224 ath_hal_logfile); 225 } 226 } else { 227 if (ath_hal_alq) 228 alq_close(ath_hal_alq); 229 ath_hal_alq = NULL; 230 printf("ath_hal: logging disabled\n"); 231 error = 0; 232 } 233 return (error); 234 } 235 236 static int 237 sysctl_hw_ath_hal_log(SYSCTL_HANDLER_ARGS) 238 { 239 int error, enable; 240 241 enable = (ath_hal_alq != NULL); 242 error = sysctl_handle_int(oidp, &enable, 0, req); 243 if (error || !req->newptr) 244 return (error); 245 else 246 return (ath_hal_setlogging(enable)); 247 } 248 SYSCTL_PROC(_hw_ath_hal, OID_AUTO, alq, CTLTYPE_INT|CTLFLAG_RW, 249 0, 0, sysctl_hw_ath_hal_log, "I", "Enable HAL register logging"); 250 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_size, CTLFLAG_RW, 251 &ath_hal_alq_qsize, 0, "In-memory log size (#records)"); 252 SYSCTL_INT(_hw_ath_hal, OID_AUTO, alq_lost, CTLFLAG_RW, 253 &ath_hal_alq_lost, 0, "Register operations not logged"); 254 255 static struct ale * 256 ath_hal_alq_get(struct ath_hal *ah) 257 { 258 struct ale *ale; 259 260 if (ath_hal_alq_emitdev) { 261 ale = alq_get(ath_hal_alq, ALQ_NOWAIT); 262 if (ale) { 263 struct athregrec *r = 264 (struct athregrec *) ale->ae_data; 265 r->op = OP_DEVICE; 266 r->reg = 0; 267 r->val = ah->ah_devid; 268 alq_post(ath_hal_alq, ale); 269 ath_hal_alq_emitdev = 0; 270 } else 271 ath_hal_alq_lost++; 272 } 273 ale = alq_get(ath_hal_alq, ALQ_NOWAIT); 274 if (!ale) 275 ath_hal_alq_lost++; 276 return ale; 277 } 278 279 void 280 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) 281 { 282 bus_space_tag_t t = BUSTAG(ah); 283 284 if (ath_hal_alq) { 285 struct ale *ale = ath_hal_alq_get(ah); 286 if (ale) { 287 struct athregrec *r = (struct athregrec *) ale->ae_data; 288 r->op = OP_WRITE; 289 r->reg = reg; 290 r->val = val; 291 alq_post(ath_hal_alq, ale); 292 } 293 } 294 #if _BYTE_ORDER == _BIG_ENDIAN 295 if (reg >= 0x4000 && reg < 0x5000) 296 bus_space_write_4(t, h, reg, val); 297 else 298 #endif 299 bus_space_write_stream_4(t, h, reg, val); 300 } 301 302 u_int32_t 303 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) 304 { 305 u_int32_t val; 306 bus_space_handle_t h = BUSHANDLE(ah); 307 bus_space_tag_t t = BUSTAG(ah); 308 309 #if _BYTE_ORDER == _BIG_ENDIAN 310 if (reg >= 0x4000 && reg < 0x5000) 311 val = bus_space_read_4(t, h, reg); 312 else 313 #endif 314 val = bus_space_read_stream_4(t, h, reg); 315 316 if (ath_hal_alq) { 317 struct ale *ale = ath_hal_alq_get(ah); 318 if (ale) { 319 struct athregrec *r = (struct athregrec *) ale->ae_data; 320 r->op = OP_READ; 321 r->reg = reg; 322 r->val = val; 323 alq_post(ath_hal_alq, ale); 324 } 325 } 326 327 return val; 328 } 329 330 void 331 OS_MARK(struct ath_hal *ah, u_int id, u_int32_t v) 332 { 333 if (ath_hal_alq) { 334 struct ale *ale = ath_hal_alq_get(ah); 335 336 if (ale) { 337 struct athregrec *r = (struct athregrec *) ale->ae_data; 338 r->op = OP_MARK; 339 r->reg = id; 340 r->val = v; 341 alq_post(ath_hal_alq, ale); 342 } 343 } 344 } 345 #elif defined(ATHHAL_DEBUG) || defined(AH_REGOPS_FUNC) 346 /* 347 * Memory-mapped device register read/write. These are here 348 * as routines when debugging support is enabled and/or when 349 * explicitly configured to use function calls. The latter is 350 * for architectures that might need to do something before 351 * referencing memory (e.g. remap an i/o window). 352 * 353 * NB: see the comments in ah_osdep.h about byte-swapping register 354 * reads and writes to understand what's going on below. 355 */ 356 357 void 358 ath_hal_reg_write(struct ath_hal *ah, u_int32_t reg, u_int32_t val) 359 { 360 bus_space_handle_t h = BUSHANDLE(ah); 361 bus_space_tag_t t = BUSTAG(ah); 362 363 #if _BYTE_ORDER == _BIG_ENDIAN 364 if (reg >= 0x4000 && reg < 0x5000) 365 bus_space_write_4(t, h, reg, val); 366 else 367 #endif 368 bus_space_write_stream_4(t, h, reg, val); 369 } 370 371 u_int32_t 372 ath_hal_reg_read(struct ath_hal *ah, u_int32_t reg) 373 { 374 bus_space_handle_t h = BUSHANDLE(ah); 375 bus_space_tag_t t = BUSTAG(ah); 376 uint32_t ret; 377 378 #if _BYTE_ORDER == _BIG_ENDIAN 379 if (reg >= 0x4000 && reg < 0x5000) 380 ret = bus_space_read_4(t, h, reg); 381 else 382 #endif 383 ret = bus_space_read_stream_4(t, h, reg); 384 385 return ret; 386 } 387 #endif /* ATHHAL_DEBUG || AH_REGOPS_FUNC */ 388 389 #ifdef ATHHAL_ASSERT 390 void 391 ath_hal_assert_failed(const char* filename, int lineno, const char *msg) 392 { 393 printf("Atheros HAL assertion failure: %s: line %u: %s\n", 394 filename, lineno, msg); 395 panic("ath_hal_assert"); 396 } 397 #endif /* ATHHAL_ASSERT */ 398 399 /* 400 * Delay n microseconds. 401 */ 402 void 403 ath_hal_delay(int n) 404 { 405 DELAY(n); 406 } 407 408 u_int32_t 409 ath_hal_getuptime(struct ath_hal *ah) 410 { 411 struct bintime bt; 412 uint32_t ret; 413 getbinuptime(&bt); 414 ret = (bt.sec * 1000) + 415 (((uint64_t)1000 * (uint32_t)(bt.frac >> 32)) >> 32); 416 return ret; 417 } 418 419 void 420 ath_hal_memzero(void *dst, size_t n) 421 { 422 (void)memset(dst, 0, n); 423 } 424 425 void * 426 ath_hal_memcpy(void *dst, const void *src, size_t n) 427 { 428 return memcpy(dst, src, n); 429 } 430 431 MODULE(MODULE_CLASS_MISC, ath_hal, NULL); 432 433 static int 434 ath_hal_modcmd(modcmd_t cmd, void *opaque) 435 { 436 switch (cmd) { 437 case MODULE_CMD_INIT: 438 case MODULE_CMD_FINI: 439 return 0; 440 default: 441 return ENOTTY; 442 } 443 } 444