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