xref: /onnv-gate/usr/src/uts/common/io/ath/ath_main.c (revision 3147:2789cc0027be)
11000Sxc151355 /*
2*3147Sxc151355  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
31000Sxc151355  * Use is subject to license terms.
41000Sxc151355  */
51000Sxc151355 
61000Sxc151355 /*
71000Sxc151355  * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
81000Sxc151355  * All rights reserved.
91000Sxc151355  *
101000Sxc151355  * Redistribution and use in source and binary forms, with or without
111000Sxc151355  * modification, are permitted provided that the following conditions
121000Sxc151355  * are met:
131000Sxc151355  * 1. Redistributions of source code must retain the above copyright
141000Sxc151355  * notice, this list of conditions and the following disclaimer,
151000Sxc151355  * without modification.
161000Sxc151355  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
171000Sxc151355  * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
181000Sxc151355  * redistribution must be conditioned upon including a substantially
191000Sxc151355  * similar Disclaimer requirement for further binary redistribution.
201000Sxc151355  * 3. Neither the names of the above-listed copyright holders nor the names
211000Sxc151355  * of any contributors may be used to endorse or promote products derived
221000Sxc151355  * from this software without specific prior written permission.
231000Sxc151355  *
241000Sxc151355  * NO WARRANTY
251000Sxc151355  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
261000Sxc151355  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
271000Sxc151355  * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
281000Sxc151355  * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
291000Sxc151355  * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
301000Sxc151355  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
311000Sxc151355  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
321000Sxc151355  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
331000Sxc151355  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
341000Sxc151355  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
351000Sxc151355  * THE POSSIBILITY OF SUCH DAMAGES.
361000Sxc151355  *
371000Sxc151355  */
381000Sxc151355 
391000Sxc151355 #pragma ident	"%Z%%M%	%I%	%E% SMI"
401000Sxc151355 
411000Sxc151355 /*
421000Sxc151355  * Driver for the Atheros Wireless LAN controller.
431000Sxc151355  *
44*3147Sxc151355  * The Atheros driver calls into net80211 module for IEEE80211 protocol
45*3147Sxc151355  * management functionalities. The driver includes a LLD(Low Level Driver)
46*3147Sxc151355  * part to implement H/W related operations.
471000Sxc151355  * The following is the high level structure of ath driver.
481000Sxc151355  * (The arrows between modules indicate function call direction.)
491000Sxc151355  *
501000Sxc151355  *
51*3147Sxc151355  *                                                  |
52*3147Sxc151355  *                                                  | GLD thread
53*3147Sxc151355  *                                                  V
54*3147Sxc151355  *         ==================  =========================================
55*3147Sxc151355  *         |                |  |[1]                                    |
56*3147Sxc151355  *         |                |  |  GLDv3 Callback functions registered  |
57*3147Sxc151355  *         |   Net80211     |  =========================       by      |
58*3147Sxc151355  *         |    module      |          |               |     driver    |
59*3147Sxc151355  *         |                |          V               |               |
60*3147Sxc151355  *         |                |========================  |               |
61*3147Sxc151355  *         |   Functions exported by net80211       |  |               |
62*3147Sxc151355  *         |                                        |  |               |
63*3147Sxc151355  *         ==========================================  =================
64*3147Sxc151355  *                         |                                  |
65*3147Sxc151355  *                         V                                  |
66*3147Sxc151355  *         +----------------------------------+               |
67*3147Sxc151355  *         |[2]                               |               |
68*3147Sxc151355  *         |    Net80211 Callback functions   |               |
69*3147Sxc151355  *         |      registered by LLD           |               |
70*3147Sxc151355  *         +----------------------------------+               |
71*3147Sxc151355  *                         |                                  |
72*3147Sxc151355  *                         V                                  v
73*3147Sxc151355  *         +-----------------------------------------------------------+
74*3147Sxc151355  *         |[3]                                                        |
75*3147Sxc151355  *         |                LLD Internal functions                     |
76*3147Sxc151355  *         |                                                           |
77*3147Sxc151355  *         +-----------------------------------------------------------+
78*3147Sxc151355  *                                    ^
79*3147Sxc151355  *                                    | Software interrupt thread
80*3147Sxc151355  *                                    |
811000Sxc151355  *
821000Sxc151355  * The short description of each module is as below:
83*3147Sxc151355  *      Module 1: GLD callback functions, which are intercepting the calls from
84*3147Sxc151355  *                GLD to LLD.
85*3147Sxc151355  *      Module 2: Net80211 callback functions registered by LLD, which
86*3147Sxc151355  *                calls into LLD for H/W related functions needed by net80211.
87*3147Sxc151355  *      Module 3: LLD Internal functions, which are responsible for allocing
881000Sxc151355  *                descriptor/buffer, handling interrupt and other H/W
891000Sxc151355  *                operations.
901000Sxc151355  *
911000Sxc151355  * All functions are running in 3 types of thread:
921000Sxc151355  * 1. GLD callbacks threads, such as ioctl, intr, etc.
93*3147Sxc151355  * 2. Clock interruptt thread which is responsible for scan, rate control and
94*3147Sxc151355  *    calibration.
951000Sxc151355  * 3. Software Interrupt thread originated in LLD.
961000Sxc151355  *
971000Sxc151355  * The lock strategy is as below:
981000Sxc151355  * There have 4 queues for tx, each queue has one asc_txqlock[i] to
991000Sxc151355  *      prevent conflicts access to queue resource from different thread.
1001000Sxc151355  *
1011000Sxc151355  * All the transmit buffers are contained in asc_txbuf which are
1021000Sxc151355  *      protected by asc_txbuflock.
1031000Sxc151355  *
1041000Sxc151355  * Each receive buffers are contained in asc_rxbuf which are protected
1051000Sxc151355  *      by asc_rxbuflock.
1061000Sxc151355  *
1071000Sxc151355  * In ath struct, asc_genlock is a general lock, protecting most other
1081000Sxc151355  *      operational data in ath_softc struct and HAL accesses.
1091000Sxc151355  *      It is acquired by the interupt handler and most "mode-ctrl" routines.
1101000Sxc151355  *
1111000Sxc151355  * Any of the locks can be acquired singly, but where multiple
1121000Sxc151355  * locks are acquired, they *must* be in the order:
113*3147Sxc151355  *    asc_genlock >> asc_txqlock[i] >> asc_txbuflock >> asc_rxbuflock
1141000Sxc151355  */
1151000Sxc151355 
1161000Sxc151355 #include <sys/param.h>
1171000Sxc151355 #include <sys/types.h>
1181000Sxc151355 #include <sys/signal.h>
1191000Sxc151355 #include <sys/stream.h>
1201000Sxc151355 #include <sys/termio.h>
1211000Sxc151355 #include <sys/errno.h>
1221000Sxc151355 #include <sys/file.h>
1231000Sxc151355 #include <sys/cmn_err.h>
1241000Sxc151355 #include <sys/stropts.h>
1251000Sxc151355 #include <sys/strsubr.h>
1261000Sxc151355 #include <sys/strtty.h>
1271000Sxc151355 #include <sys/kbio.h>
1281000Sxc151355 #include <sys/cred.h>
1291000Sxc151355 #include <sys/stat.h>
1301000Sxc151355 #include <sys/consdev.h>
1311000Sxc151355 #include <sys/kmem.h>
1321000Sxc151355 #include <sys/modctl.h>
1331000Sxc151355 #include <sys/ddi.h>
1341000Sxc151355 #include <sys/sunddi.h>
1351000Sxc151355 #include <sys/pci.h>
1361000Sxc151355 #include <sys/errno.h>
137*3147Sxc151355 #include <sys/mac.h>
1381000Sxc151355 #include <sys/dlpi.h>
1391000Sxc151355 #include <sys/ethernet.h>
1401000Sxc151355 #include <sys/list.h>
1411000Sxc151355 #include <sys/byteorder.h>
1421000Sxc151355 #include <sys/strsun.h>
1431000Sxc151355 #include <sys/policy.h>
1441000Sxc151355 #include <inet/common.h>
1451000Sxc151355 #include <inet/nd.h>
1461000Sxc151355 #include <inet/mi.h>
1471000Sxc151355 #include <inet/wifi_ioctl.h>
148*3147Sxc151355 #include <sys/mac_wifi.h>
1491000Sxc151355 #include "ath_hal.h"
1501000Sxc151355 #include "ath_impl.h"
1511000Sxc151355 #include "ath_aux.h"
1521000Sxc151355 #include "ath_rate.h"
1531000Sxc151355 
154*3147Sxc151355 #define	ATH_MAX_RSSI	63	/* max rssi */
155*3147Sxc151355 
1561000Sxc151355 extern void ath_halfix_init(void);
1571000Sxc151355 extern void ath_halfix_finit(void);
1581000Sxc151355 extern int32_t ath_getset(ath_t *asc, mblk_t *mp, uint32_t cmd);
1591000Sxc151355 
1601000Sxc151355 /*
1611000Sxc151355  * PIO access attributes for registers
1621000Sxc151355  */
1631000Sxc151355 static ddi_device_acc_attr_t ath_reg_accattr = {
1641000Sxc151355 	DDI_DEVICE_ATTR_V0,
1651000Sxc151355 	DDI_STRUCTURE_LE_ACC,
1661000Sxc151355 	DDI_STRICTORDER_ACC
1671000Sxc151355 };
1681000Sxc151355 
1691000Sxc151355 /*
1701000Sxc151355  * DMA access attributes for descriptors: NOT to be byte swapped.
1711000Sxc151355  */
1721000Sxc151355 static ddi_device_acc_attr_t ath_desc_accattr = {
1731000Sxc151355 	DDI_DEVICE_ATTR_V0,
1741000Sxc151355 	DDI_STRUCTURE_LE_ACC,
1751000Sxc151355 	DDI_STRICTORDER_ACC
1761000Sxc151355 };
1771000Sxc151355 
1781000Sxc151355 /*
1791000Sxc151355  * Describes the chip's DMA engine
1801000Sxc151355  */
1811000Sxc151355 static ddi_dma_attr_t dma_attr = {
1821000Sxc151355 	DMA_ATTR_V0,			/* dma_attr version */
1831000Sxc151355 	0x0000000000000000ull,		/* dma_attr_addr_lo */
1841000Sxc151355 	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_addr_hi */
1851000Sxc151355 	0x00000000FFFFFFFFull,		/* dma_attr_count_max */
1861000Sxc151355 	0x0000000000000001ull,		/* dma_attr_align */
1871000Sxc151355 	0x00000FFF,			/* dma_attr_burstsizes */
1881000Sxc151355 	0x00000001,			/* dma_attr_minxfer */
1891000Sxc151355 	0x000000000000FFFFull,		/* dma_attr_maxxfer */
1901000Sxc151355 	0xFFFFFFFFFFFFFFFFull,		/* dma_attr_seg */
1911000Sxc151355 	1,				/* dma_attr_sgllen */
1921000Sxc151355 	0x00000001,			/* dma_attr_granular */
1931000Sxc151355 	0				/* dma_attr_flags */
1941000Sxc151355 };
1951000Sxc151355 
1961000Sxc151355 static kmutex_t ath_loglock;
1971000Sxc151355 static void *ath_soft_state_p = NULL;
198*3147Sxc151355 static int ath_dwelltime = 150;		/* scan interval, ms */
199*3147Sxc151355 
200*3147Sxc151355 static int	ath_m_stat(void *,  uint_t, uint64_t *);
201*3147Sxc151355 static int	ath_m_start(void *);
202*3147Sxc151355 static void	ath_m_stop(void *);
203*3147Sxc151355 static int	ath_m_promisc(void *, boolean_t);
204*3147Sxc151355 static int	ath_m_multicst(void *, boolean_t, const uint8_t *);
205*3147Sxc151355 static int	ath_m_unicst(void *, const uint8_t *);
206*3147Sxc151355 static mblk_t	*ath_m_tx(void *, mblk_t *);
207*3147Sxc151355 static void	ath_m_ioctl(void *, queue_t *, mblk_t *);
208*3147Sxc151355 static mac_callbacks_t ath_m_callbacks = {
209*3147Sxc151355 	MC_IOCTL,
210*3147Sxc151355 	ath_m_stat,
211*3147Sxc151355 	ath_m_start,
212*3147Sxc151355 	ath_m_stop,
213*3147Sxc151355 	ath_m_promisc,
214*3147Sxc151355 	ath_m_multicst,
215*3147Sxc151355 	ath_m_unicst,
216*3147Sxc151355 	ath_m_tx,
217*3147Sxc151355 	NULL,		/* mc_resources; */
218*3147Sxc151355 	ath_m_ioctl,
219*3147Sxc151355 	NULL		/* mc_getcapab */
220*3147Sxc151355 };
2211000Sxc151355 
2221000Sxc151355 /*
2231000Sxc151355  * Available debug flags:
2241000Sxc151355  * ATH_DBG_INIT, ATH_DBG_GLD, ATH_DBG_HAL, ATH_DBG_INT, ATH_DBG_ATTACH,
2251000Sxc151355  * ATH_DBG_DETACH, ATH_DBG_AUX, ATH_DBG_WIFICFG, ATH_DBG_OSDEP
2261000Sxc151355  */
2271000Sxc151355 uint32_t ath_dbg_flags = 0;
2281000Sxc151355 
2291000Sxc151355 /*
2301000Sxc151355  * Exception/warning cases not leading to panic.
2311000Sxc151355  */
2321000Sxc151355 void
2331000Sxc151355 ath_problem(const int8_t *fmt, ...)
2341000Sxc151355 {
2351000Sxc151355 	va_list args;
2361000Sxc151355 
2371000Sxc151355 	mutex_enter(&ath_loglock);
2381000Sxc151355 
2391000Sxc151355 	va_start(args, fmt);
2401000Sxc151355 	vcmn_err(CE_WARN, fmt, args);
2411000Sxc151355 	va_end(args);
2421000Sxc151355 
2431000Sxc151355 	mutex_exit(&ath_loglock);
2441000Sxc151355 }
2451000Sxc151355 
2461000Sxc151355 /*
2471000Sxc151355  * Normal log information independent of debug.
2481000Sxc151355  */
2491000Sxc151355 void
2501000Sxc151355 ath_log(const int8_t *fmt, ...)
2511000Sxc151355 {
2521000Sxc151355 	va_list args;
2531000Sxc151355 
2541000Sxc151355 	mutex_enter(&ath_loglock);
2551000Sxc151355 
2561000Sxc151355 	va_start(args, fmt);
2571000Sxc151355 	vcmn_err(CE_CONT, fmt, args);
2581000Sxc151355 	va_end(args);
2591000Sxc151355 
2601000Sxc151355 	mutex_exit(&ath_loglock);
2611000Sxc151355 }
2621000Sxc151355 
2631000Sxc151355 void
2641000Sxc151355 ath_dbg(uint32_t dbg_flags, const int8_t *fmt, ...)
2651000Sxc151355 {
2661000Sxc151355 	va_list args;
2671000Sxc151355 
2681000Sxc151355 	if (dbg_flags & ath_dbg_flags) {
2691000Sxc151355 		mutex_enter(&ath_loglock);
2701000Sxc151355 		va_start(args, fmt);
2711000Sxc151355 		vcmn_err(CE_CONT, fmt, args);
2721000Sxc151355 		va_end(args);
2731000Sxc151355 		mutex_exit(&ath_loglock);
2741000Sxc151355 	}
2751000Sxc151355 }
2761000Sxc151355 
2771000Sxc151355 void
2781000Sxc151355 ath_setup_desc(ath_t *asc, struct ath_buf *bf)
2791000Sxc151355 {
2801000Sxc151355 	struct ath_desc *ds;
2811000Sxc151355 
2821000Sxc151355 	ds = bf->bf_desc;
2831000Sxc151355 	ds->ds_link = bf->bf_daddr;
2841000Sxc151355 	ds->ds_data = bf->bf_dma.cookie.dmac_address;
285*3147Sxc151355 	ds->ds_vdata = bf->bf_dma.mem_va;
2861000Sxc151355 	ATH_HAL_SETUPRXDESC(asc->asc_ah, ds,
2871000Sxc151355 	    bf->bf_dma.alength,		/* buffer size */
2881000Sxc151355 	    0);
2891000Sxc151355 
2901000Sxc151355 	if (asc->asc_rxlink != NULL)
2911000Sxc151355 		*asc->asc_rxlink = bf->bf_daddr;
2921000Sxc151355 	asc->asc_rxlink = &ds->ds_link;
2931000Sxc151355 }
2941000Sxc151355 
2951000Sxc151355 
2961000Sxc151355 /*
2971000Sxc151355  * Allocate an area of memory and a DMA handle for accessing it
2981000Sxc151355  */
2991000Sxc151355 static int
3001000Sxc151355 ath_alloc_dma_mem(dev_info_t *devinfo, size_t memsize,
3011000Sxc151355 	ddi_device_acc_attr_t *attr_p, uint_t alloc_flags,
3021000Sxc151355 	uint_t bind_flags, dma_area_t *dma_p)
3031000Sxc151355 {
3041000Sxc151355 	int err;
3051000Sxc151355 
3061000Sxc151355 	/*
3071000Sxc151355 	 * Allocate handle
3081000Sxc151355 	 */
3091000Sxc151355 	err = ddi_dma_alloc_handle(devinfo, &dma_attr,
3101000Sxc151355 		DDI_DMA_SLEEP, NULL, &dma_p->dma_hdl);
3111000Sxc151355 	if (err != DDI_SUCCESS)
3121000Sxc151355 		return (DDI_FAILURE);
3131000Sxc151355 
3141000Sxc151355 	/*
3151000Sxc151355 	 * Allocate memory
3161000Sxc151355 	 */
3171000Sxc151355 	err = ddi_dma_mem_alloc(dma_p->dma_hdl, memsize, attr_p,
3181000Sxc151355 	    alloc_flags, DDI_DMA_SLEEP, NULL, &dma_p->mem_va,
3191000Sxc151355 	    &dma_p->alength, &dma_p->acc_hdl);
3201000Sxc151355 	if (err != DDI_SUCCESS)
3211000Sxc151355 		return (DDI_FAILURE);
3221000Sxc151355 
3231000Sxc151355 	/*
3241000Sxc151355 	 * Bind the two together
3251000Sxc151355 	 */
3261000Sxc151355 	err = ddi_dma_addr_bind_handle(dma_p->dma_hdl, NULL,
3271000Sxc151355 		dma_p->mem_va, dma_p->alength, bind_flags,
3281000Sxc151355 		DDI_DMA_SLEEP, NULL, &dma_p->cookie, &dma_p->ncookies);
3291000Sxc151355 	if (err != DDI_DMA_MAPPED)
3301000Sxc151355 		return (DDI_FAILURE);
3311000Sxc151355 
3321000Sxc151355 	dma_p->nslots = ~0U;
3331000Sxc151355 	dma_p->size = ~0U;
3341000Sxc151355 	dma_p->token = ~0U;
3351000Sxc151355 	dma_p->offset = 0;
3361000Sxc151355 	return (DDI_SUCCESS);
3371000Sxc151355 }
3381000Sxc151355 
3391000Sxc151355 /*
3401000Sxc151355  * Free one allocated area of DMAable memory
3411000Sxc151355  */
3421000Sxc151355 static void
3431000Sxc151355 ath_free_dma_mem(dma_area_t *dma_p)
3441000Sxc151355 {
3451000Sxc151355 	if (dma_p->dma_hdl != NULL) {
3461000Sxc151355 		(void) ddi_dma_unbind_handle(dma_p->dma_hdl);
3471000Sxc151355 		if (dma_p->acc_hdl != NULL) {
3481000Sxc151355 			ddi_dma_mem_free(&dma_p->acc_hdl);
3491000Sxc151355 			dma_p->acc_hdl = NULL;
3501000Sxc151355 		}
3511000Sxc151355 		ddi_dma_free_handle(&dma_p->dma_hdl);
3521000Sxc151355 		dma_p->ncookies = 0;
3531000Sxc151355 		dma_p->dma_hdl = NULL;
3541000Sxc151355 	}
3551000Sxc151355 }
3561000Sxc151355 
3571000Sxc151355 
3581000Sxc151355 static int
3591000Sxc151355 ath_desc_alloc(dev_info_t *devinfo, ath_t *asc)
3601000Sxc151355 {
3611000Sxc151355 	int i, err;
3621000Sxc151355 	size_t size;
3631000Sxc151355 	struct ath_desc *ds;
3641000Sxc151355 	struct ath_buf *bf;
3651000Sxc151355 
3661000Sxc151355 	size = sizeof (struct ath_desc) * (ATH_TXBUF + ATH_RXBUF);
3671000Sxc151355 
3681000Sxc151355 	err = ath_alloc_dma_mem(devinfo, size, &ath_desc_accattr,
3691000Sxc151355 	    DDI_DMA_CONSISTENT, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
3701000Sxc151355 	    &asc->asc_desc_dma);
3711000Sxc151355 
3721000Sxc151355 	/* virtual address of the first descriptor */
3731000Sxc151355 	asc->asc_desc = (struct ath_desc *)asc->asc_desc_dma.mem_va;
3741000Sxc151355 
3751000Sxc151355 	ds = asc->asc_desc;
3761000Sxc151355 	ATH_DEBUG((ATH_DBG_INIT, "ath: ath_desc_alloc(): DMA map: "
3771000Sxc151355 	    "%p (%d) -> %p\n",
3781000Sxc151355 	    asc->asc_desc, asc->asc_desc_dma.alength,
3791000Sxc151355 	    asc->asc_desc_dma.cookie.dmac_address));
3801000Sxc151355 
3811000Sxc151355 	/* allocate data structures to describe TX/RX DMA buffers */
3821000Sxc151355 	asc->asc_vbuflen = sizeof (struct ath_buf) * (ATH_TXBUF + ATH_RXBUF);
3831000Sxc151355 	bf = (struct ath_buf *)kmem_zalloc(asc->asc_vbuflen, KM_SLEEP);
3841000Sxc151355 	asc->asc_vbufptr = bf;
3851000Sxc151355 
3861000Sxc151355 	/* DMA buffer size for each TX/RX packet */
3871000Sxc151355 	asc->asc_dmabuf_size = roundup(1000 + sizeof (struct ieee80211_frame) +
3881000Sxc151355 	    IEEE80211_MTU + IEEE80211_CRC_LEN +
3891000Sxc151355 	    (IEEE80211_WEP_IVLEN + IEEE80211_WEP_KIDLEN +
3901000Sxc151355 	    IEEE80211_WEP_CRCLEN), asc->asc_cachelsz);
3911000Sxc151355 
3921000Sxc151355 	/* create RX buffer list and allocate DMA memory */
3931000Sxc151355 	list_create(&asc->asc_rxbuf_list, sizeof (struct ath_buf),
3941000Sxc151355 	    offsetof(struct ath_buf, bf_node));
3951000Sxc151355 	for (i = 0; i < ATH_RXBUF; i++, bf++, ds++) {
3961000Sxc151355 		bf->bf_desc = ds;
3971000Sxc151355 		bf->bf_daddr = asc->asc_desc_dma.cookie.dmac_address +
3981000Sxc151355 		    ((caddr_t)ds - (caddr_t)asc->asc_desc);
3991000Sxc151355 		list_insert_tail(&asc->asc_rxbuf_list, bf);
4001000Sxc151355 
4011000Sxc151355 		/* alloc DMA memory */
4021000Sxc151355 		err = ath_alloc_dma_mem(devinfo, asc->asc_dmabuf_size,
4031000Sxc151355 		    &ath_desc_accattr,
4041000Sxc151355 		    DDI_DMA_STREAMING, DDI_DMA_READ | DDI_DMA_STREAMING,
4051000Sxc151355 		    &bf->bf_dma);
4061000Sxc151355 		if (err != DDI_SUCCESS)
4071000Sxc151355 			return (err);
4081000Sxc151355 	}
4091000Sxc151355 
4101000Sxc151355 	/* create TX buffer list and allocate DMA memory */
4111000Sxc151355 	list_create(&asc->asc_txbuf_list, sizeof (struct ath_buf),
4121000Sxc151355 	    offsetof(struct ath_buf, bf_node));
4131000Sxc151355 	for (i = 0; i < ATH_TXBUF; i++, bf++, ds++) {
4141000Sxc151355 		bf->bf_desc = ds;
4151000Sxc151355 		bf->bf_daddr = asc->asc_desc_dma.cookie.dmac_address +
4161000Sxc151355 		    ((caddr_t)ds - (caddr_t)asc->asc_desc);
4171000Sxc151355 		list_insert_tail(&asc->asc_txbuf_list, bf);
4181000Sxc151355 
4191000Sxc151355 		/* alloc DMA memory */
420*3147Sxc151355 		err = ath_alloc_dma_mem(devinfo, asc->asc_dmabuf_size,
421*3147Sxc151355 		    &ath_desc_accattr,
4221000Sxc151355 		    DDI_DMA_STREAMING, DDI_DMA_STREAMING, &bf->bf_dma);
4231000Sxc151355 		if (err != DDI_SUCCESS)
4241000Sxc151355 			return (err);
4251000Sxc151355 	}
4261000Sxc151355 
4271000Sxc151355 	return (DDI_SUCCESS);
4281000Sxc151355 }
4291000Sxc151355 
4301000Sxc151355 static void
4311000Sxc151355 ath_desc_free(ath_t *asc)
4321000Sxc151355 {
4331000Sxc151355 	struct ath_buf *bf;
4341000Sxc151355 
4351000Sxc151355 	/* Free TX DMA buffer */
4361000Sxc151355 	bf = list_head(&asc->asc_txbuf_list);
4371000Sxc151355 	while (bf != NULL) {
4381000Sxc151355 		ath_free_dma_mem(&bf->bf_dma);
4391000Sxc151355 		list_remove(&asc->asc_txbuf_list, bf);
4401000Sxc151355 		bf = list_head(&asc->asc_txbuf_list);
4411000Sxc151355 	}
4421000Sxc151355 	list_destroy(&asc->asc_txbuf_list);
4431000Sxc151355 
4441000Sxc151355 	/* Free RX DMA uffer */
4451000Sxc151355 	bf = list_head(&asc->asc_rxbuf_list);
4461000Sxc151355 	while (bf != NULL) {
4471000Sxc151355 		ath_free_dma_mem(&bf->bf_dma);
4481000Sxc151355 		list_remove(&asc->asc_rxbuf_list, bf);
4491000Sxc151355 		bf = list_head(&asc->asc_rxbuf_list);
4501000Sxc151355 	}
4511000Sxc151355 	list_destroy(&asc->asc_rxbuf_list);
4521000Sxc151355 
4531000Sxc151355 	/* Free descriptor DMA buffer */
4541000Sxc151355 	ath_free_dma_mem(&asc->asc_desc_dma);
4551000Sxc151355 
4561000Sxc151355 	kmem_free((void *)asc->asc_vbufptr, asc->asc_vbuflen);
4571000Sxc151355 	asc->asc_vbufptr = NULL;
4581000Sxc151355 }
4591000Sxc151355 
4601000Sxc151355 static void
4611000Sxc151355 ath_printrxbuf(struct ath_buf *bf, int32_t done)
4621000Sxc151355 {
4631000Sxc151355 	struct ath_desc *ds = bf->bf_desc;
4641000Sxc151355 
4651000Sxc151355 	ATH_DEBUG((ATH_DBG_RECV, "ath: R (%p %p) %08x %08x %08x "
4661000Sxc151355 	    "%08x %08x %08x %c\n",
4671000Sxc151355 	    ds, bf->bf_daddr,
4681000Sxc151355 	    ds->ds_link, ds->ds_data,
4691000Sxc151355 	    ds->ds_ctl0, ds->ds_ctl1,
4701000Sxc151355 	    ds->ds_hw[0], ds->ds_hw[1],
4711000Sxc151355 	    !done ? ' ' : (ds->ds_rxstat.rs_status == 0) ? '*' : '!'));
4721000Sxc151355 }
4731000Sxc151355 
4741000Sxc151355 static void
4751000Sxc151355 ath_rx_handler(ath_t *asc)
4761000Sxc151355 {
477*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
4781000Sxc151355 	struct ath_buf *bf;
4791000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
4801000Sxc151355 	struct ath_desc *ds;
4811000Sxc151355 	mblk_t *rx_mp;
482*3147Sxc151355 	struct ieee80211_frame *wh;
4831000Sxc151355 	int32_t len, loop = 1;
4841000Sxc151355 	uint8_t phyerr;
4851000Sxc151355 	HAL_STATUS status;
4861000Sxc151355 	HAL_NODE_STATS hal_node_stats;
487*3147Sxc151355 	struct ieee80211_node *in;
4881000Sxc151355 
4891000Sxc151355 	do {
4901000Sxc151355 		mutex_enter(&asc->asc_rxbuflock);
4911000Sxc151355 		bf = list_head(&asc->asc_rxbuf_list);
4921000Sxc151355 		if (bf == NULL) {
4931000Sxc151355 			ATH_DEBUG((ATH_DBG_RECV, "ath: ath_rx_handler(): "
4941000Sxc151355 			    "no buffer\n"));
4951000Sxc151355 			mutex_exit(&asc->asc_rxbuflock);
4961000Sxc151355 			break;
4971000Sxc151355 		}
4981000Sxc151355 		ASSERT(bf->bf_dma.cookie.dmac_address != NULL);
4991000Sxc151355 		ds = bf->bf_desc;
5001000Sxc151355 		if (ds->ds_link == bf->bf_daddr) {
5011000Sxc151355 			/*
5021000Sxc151355 			 * Never process the self-linked entry at the end,
5031000Sxc151355 			 * this may be met at heavy load.
5041000Sxc151355 			 */
5051000Sxc151355 			mutex_exit(&asc->asc_rxbuflock);
5061000Sxc151355 			break;
5071000Sxc151355 		}
5081000Sxc151355 
5091000Sxc151355 		status = ATH_HAL_RXPROCDESC(ah, ds,
5101000Sxc151355 		    bf->bf_daddr,
5111000Sxc151355 		    ATH_PA2DESC(asc, ds->ds_link));
5121000Sxc151355 		if (status == HAL_EINPROGRESS) {
5131000Sxc151355 			mutex_exit(&asc->asc_rxbuflock);
5141000Sxc151355 			break;
5151000Sxc151355 		}
5161000Sxc151355 		list_remove(&asc->asc_rxbuf_list, bf);
5171000Sxc151355 		mutex_exit(&asc->asc_rxbuflock);
5181000Sxc151355 
5191000Sxc151355 		if (ds->ds_rxstat.rs_status != 0) {
5201000Sxc151355 			if (ds->ds_rxstat.rs_status & HAL_RXERR_CRC)
5211000Sxc151355 				asc->asc_stats.ast_rx_crcerr++;
5221000Sxc151355 			if (ds->ds_rxstat.rs_status & HAL_RXERR_FIFO)
5231000Sxc151355 				asc->asc_stats.ast_rx_fifoerr++;
5241000Sxc151355 			if (ds->ds_rxstat.rs_status & HAL_RXERR_DECRYPT)
5251000Sxc151355 				asc->asc_stats.ast_rx_badcrypt++;
5261000Sxc151355 			if (ds->ds_rxstat.rs_status & HAL_RXERR_PHY) {
5271000Sxc151355 				asc->asc_stats.ast_rx_phyerr++;
5281000Sxc151355 				phyerr = ds->ds_rxstat.rs_phyerr & 0x1f;
5291000Sxc151355 				asc->asc_stats.ast_rx_phy[phyerr]++;
5301000Sxc151355 			}
5311000Sxc151355 			goto rx_next;
5321000Sxc151355 		}
5331000Sxc151355 		len = ds->ds_rxstat.rs_datalen;
5341000Sxc151355 
5351000Sxc151355 		/* less than sizeof(struct ieee80211_frame) */
5361000Sxc151355 		if (len < 20) {
5371000Sxc151355 			asc->asc_stats.ast_rx_tooshort++;
5381000Sxc151355 			goto rx_next;
5391000Sxc151355 		}
5401000Sxc151355 
5411000Sxc151355 		if ((rx_mp = allocb(asc->asc_dmabuf_size, BPRI_MED)) == NULL) {
5421000Sxc151355 			ath_problem("ath: ath_rx_handler(): "
5431000Sxc151355 			    "allocing mblk buffer failed.\n");
5441000Sxc151355 			return;
5451000Sxc151355 		}
5461000Sxc151355 
5471000Sxc151355 		ATH_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORCPU);
5481000Sxc151355 		bcopy(bf->bf_dma.mem_va, rx_mp->b_rptr, len);
5491000Sxc151355 
5501000Sxc151355 		rx_mp->b_wptr += len;
5511000Sxc151355 		wh = (struct ieee80211_frame *)rx_mp->b_rptr;
552*3147Sxc151355 		if ((wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) ==
5531000Sxc151355 		    IEEE80211_FC0_TYPE_CTL) {
5541000Sxc151355 			/*
5551000Sxc151355 			 * Ignore control frame received in promisc mode.
5561000Sxc151355 			 */
5571000Sxc151355 			freemsg(rx_mp);
5581000Sxc151355 			goto rx_next;
5591000Sxc151355 		}
5601000Sxc151355 		/* Remove the CRC at the end of IEEE80211 frame */
5611000Sxc151355 		rx_mp->b_wptr -= IEEE80211_CRC_LEN;
5621000Sxc151355 #ifdef DEBUG
5631000Sxc151355 		ath_printrxbuf(bf, status == HAL_OK);
5641000Sxc151355 #endif /* DEBUG */
565*3147Sxc151355 		/*
566*3147Sxc151355 		 * Locate the node for sender, track state, and then
567*3147Sxc151355 		 * pass the (referenced) node up to the 802.11 layer
568*3147Sxc151355 		 * for its use.
569*3147Sxc151355 		 */
570*3147Sxc151355 		in = ieee80211_find_rxnode(ic, wh);
571*3147Sxc151355 
572*3147Sxc151355 		/*
573*3147Sxc151355 		 * Send frame up for processing.
574*3147Sxc151355 		 */
575*3147Sxc151355 		(void) ieee80211_input(ic, rx_mp, in,
5761000Sxc151355 		    ds->ds_rxstat.rs_rssi,
577*3147Sxc151355 		    ds->ds_rxstat.rs_tstamp);
578*3147Sxc151355 
579*3147Sxc151355 		ieee80211_free_node(in);
580*3147Sxc151355 
5811000Sxc151355 rx_next:
5821000Sxc151355 		mutex_enter(&asc->asc_rxbuflock);
5831000Sxc151355 		list_insert_tail(&asc->asc_rxbuf_list, bf);
5841000Sxc151355 		mutex_exit(&asc->asc_rxbuflock);
5851000Sxc151355 		ath_setup_desc(asc, bf);
5861000Sxc151355 	} while (loop);
5871000Sxc151355 
5881000Sxc151355 	/* rx signal state monitoring */
589*3147Sxc151355 	ATH_HAL_RXMONITOR(ah, &hal_node_stats, &asc->asc_curchan);
5901000Sxc151355 }
5911000Sxc151355 
5921000Sxc151355 static void
5931000Sxc151355 ath_printtxbuf(struct ath_buf *bf, int done)
5941000Sxc151355 {
5951000Sxc151355 	struct ath_desc *ds = bf->bf_desc;
5961000Sxc151355 
5971000Sxc151355 	ATH_DEBUG((ATH_DBG_SEND, "ath: T(%p %p) %08x %08x %08x %08x %08x"
5981000Sxc151355 	    " %08x %08x %08x %c\n",
5991000Sxc151355 	    ds, bf->bf_daddr,
6001000Sxc151355 	    ds->ds_link, ds->ds_data,
6011000Sxc151355 	    ds->ds_ctl0, ds->ds_ctl1,
6021000Sxc151355 	    ds->ds_hw[0], ds->ds_hw[1], ds->ds_hw[2], ds->ds_hw[3],
6031000Sxc151355 	    !done ? ' ' : (ds->ds_txstat.ts_status == 0) ? '*' : '!'));
6041000Sxc151355 }
6051000Sxc151355 
6061000Sxc151355 /*
6071000Sxc151355  * The input parameter mp has following assumption:
608*3147Sxc151355  * For data packets, GLDv3 mac_wifi plugin allocates and fills the
609*3147Sxc151355  * ieee80211 header. For management packets, net80211 allocates and
610*3147Sxc151355  * fills the ieee80211 header. In both cases, enough spaces in the
611*3147Sxc151355  * header are left for encryption option.
6121000Sxc151355  */
6131000Sxc151355 static int32_t
614*3147Sxc151355 ath_tx_start(ath_t *asc, struct ieee80211_node *in, struct ath_buf *bf,
615*3147Sxc151355     mblk_t *mp)
6161000Sxc151355 {
617*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
6181000Sxc151355 	struct ieee80211_frame *wh;
6191000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
620*3147Sxc151355 	uint32_t subtype, flags, ctsduration;
6211000Sxc151355 	int32_t keyix, iswep, hdrlen, pktlen, mblen, mbslen, try0;
622*3147Sxc151355 	uint8_t rix, cix, txrate, ctsrate;
6231000Sxc151355 	struct ath_desc *ds;
6241000Sxc151355 	struct ath_txq *txq;
6251000Sxc151355 	HAL_PKT_TYPE atype;
6261000Sxc151355 	const HAL_RATE_TABLE *rt;
6271000Sxc151355 	HAL_BOOL shortPreamble;
6281000Sxc151355 	struct ath_node *an;
629*3147Sxc151355 	caddr_t dest;
6301000Sxc151355 
6311000Sxc151355 	/*
6321000Sxc151355 	 * CRC are added by H/W, not encaped by driver,
6331000Sxc151355 	 * but we must count it in pkt length.
6341000Sxc151355 	 */
6351000Sxc151355 	pktlen = IEEE80211_CRC_LEN;
6361000Sxc151355 
637*3147Sxc151355 	wh = (struct ieee80211_frame *)mp->b_rptr;
638*3147Sxc151355 	iswep = wh->i_fc[1] & IEEE80211_FC1_WEP;
6391000Sxc151355 	keyix = HAL_TXKEYIX_INVALID;
6401000Sxc151355 	hdrlen = sizeof (struct ieee80211_frame);
641*3147Sxc151355 	if (iswep != 0) {
642*3147Sxc151355 		const struct ieee80211_cipher *cip;
643*3147Sxc151355 		struct ieee80211_key *k;
6441000Sxc151355 
645*3147Sxc151355 		/*
646*3147Sxc151355 		 * Construct the 802.11 header+trailer for an encrypted
647*3147Sxc151355 		 * frame. The only reason this can fail is because of an
648*3147Sxc151355 		 * unknown or unsupported cipher/key type.
649*3147Sxc151355 		 */
650*3147Sxc151355 		k = ieee80211_crypto_encap(ic, mp);
651*3147Sxc151355 		if (k == NULL) {
652*3147Sxc151355 			ATH_DEBUG((ATH_DBG_AUX, "crypto_encap failed\n"));
653*3147Sxc151355 			/*
654*3147Sxc151355 			 * This can happen when the key is yanked after the
655*3147Sxc151355 			 * frame was queued.  Just discard the frame; the
656*3147Sxc151355 			 * 802.11 layer counts failures and provides
657*3147Sxc151355 			 * debugging/diagnostics.
658*3147Sxc151355 			 */
659*3147Sxc151355 			return (EIO);
660*3147Sxc151355 		}
661*3147Sxc151355 		cip = k->wk_cipher;
6621000Sxc151355 		/*
663*3147Sxc151355 		 * Adjust the packet + header lengths for the crypto
664*3147Sxc151355 		 * additions and calculate the h/w key index.  When
665*3147Sxc151355 		 * a s/w mic is done the frame will have had any mic
666*3147Sxc151355 		 * added to it prior to entry so m0->m_pkthdr.len above will
667*3147Sxc151355 		 * account for it. Otherwise we need to add it to the
668*3147Sxc151355 		 * packet length.
6691000Sxc151355 		 */
670*3147Sxc151355 		hdrlen += cip->ic_header;
671*3147Sxc151355 		pktlen += cip->ic_header + cip->ic_trailer;
672*3147Sxc151355 		if ((k->wk_flags & IEEE80211_KEY_SWMIC) == 0)
673*3147Sxc151355 			pktlen += cip->ic_miclen;
674*3147Sxc151355 		keyix = k->wk_keyix;
6751000Sxc151355 
676*3147Sxc151355 		/* packet header may have moved, reset our local pointer */
677*3147Sxc151355 		wh = (struct ieee80211_frame *)mp->b_rptr;
6781000Sxc151355 	}
6791000Sxc151355 
680*3147Sxc151355 	dest = bf->bf_dma.mem_va;
681*3147Sxc151355 	for (; mp != NULL; mp = mp->b_cont) {
682*3147Sxc151355 		mblen = MBLKL(mp);
683*3147Sxc151355 		bcopy(mp->b_rptr, dest, mblen);
684*3147Sxc151355 		dest += mblen;
685*3147Sxc151355 	}
686*3147Sxc151355 	mbslen = dest - bf->bf_dma.mem_va;
687*3147Sxc151355 	pktlen += mbslen;
688*3147Sxc151355 
6891000Sxc151355 	bf->bf_in = in;
6901000Sxc151355 
6911000Sxc151355 	/* setup descriptors */
6921000Sxc151355 	ds = bf->bf_desc;
6931000Sxc151355 	rt = asc->asc_currates;
694*3147Sxc151355 	ASSERT(rt != NULL);
6951000Sxc151355 
6961000Sxc151355 	/*
6971000Sxc151355 	 * The 802.11 layer marks whether or not we should
6981000Sxc151355 	 * use short preamble based on the current mode and
6991000Sxc151355 	 * negotiated parameters.
7001000Sxc151355 	 */
701*3147Sxc151355 	if ((ic->ic_flags & IEEE80211_F_SHPREAMBLE) &&
7021000Sxc151355 	    (in->in_capinfo & IEEE80211_CAPINFO_SHORT_PREAMBLE)) {
7031000Sxc151355 		shortPreamble = AH_TRUE;
7041000Sxc151355 		asc->asc_stats.ast_tx_shortpre++;
7051000Sxc151355 	} else {
7061000Sxc151355 		shortPreamble = AH_FALSE;
7071000Sxc151355 	}
7081000Sxc151355 
7091000Sxc151355 	an = ATH_NODE(in);
7101000Sxc151355 
7111000Sxc151355 	/*
7121000Sxc151355 	 * Calculate Atheros packet type from IEEE80211 packet header
7131000Sxc151355 	 * and setup for rate calculations.
7141000Sxc151355 	 */
715*3147Sxc151355 	switch (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) {
7161000Sxc151355 	case IEEE80211_FC0_TYPE_MGT:
717*3147Sxc151355 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
7181000Sxc151355 		if (subtype == IEEE80211_FC0_SUBTYPE_BEACON)
7191000Sxc151355 			atype = HAL_PKT_TYPE_BEACON;
7201000Sxc151355 		else if (subtype == IEEE80211_FC0_SUBTYPE_PROBE_RESP)
7211000Sxc151355 			atype = HAL_PKT_TYPE_PROBE_RESP;
7221000Sxc151355 		else if (subtype == IEEE80211_FC0_SUBTYPE_ATIM)
7231000Sxc151355 			atype = HAL_PKT_TYPE_ATIM;
7241000Sxc151355 		else
7251000Sxc151355 			atype = HAL_PKT_TYPE_NORMAL;
7261000Sxc151355 		rix = 0;	/* lowest rate */
7271000Sxc151355 		try0 = ATH_TXMAXTRY;
7281000Sxc151355 		if (shortPreamble)
7291000Sxc151355 			txrate = an->an_tx_mgtratesp;
7301000Sxc151355 		else
7311000Sxc151355 			txrate = an->an_tx_mgtrate;
7321000Sxc151355 		/* force all ctl frames to highest queue */
7331000Sxc151355 		txq = asc->asc_ac2q[WME_AC_VO];
7341000Sxc151355 		break;
7351000Sxc151355 	case IEEE80211_FC0_TYPE_CTL:
7361000Sxc151355 		atype = HAL_PKT_TYPE_PSPOLL;
737*3147Sxc151355 		subtype = wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK;
7381000Sxc151355 		rix = 0;	/* lowest rate */
7391000Sxc151355 		try0 = ATH_TXMAXTRY;
7401000Sxc151355 		if (shortPreamble)
7411000Sxc151355 			txrate = an->an_tx_mgtratesp;
7421000Sxc151355 		else
7431000Sxc151355 			txrate = an->an_tx_mgtrate;
7441000Sxc151355 		/* force all ctl frames to highest queue */
7451000Sxc151355 		txq = asc->asc_ac2q[WME_AC_VO];
7461000Sxc151355 		break;
7471000Sxc151355 	case IEEE80211_FC0_TYPE_DATA:
7481000Sxc151355 		atype = HAL_PKT_TYPE_NORMAL;
7491000Sxc151355 		rix = an->an_tx_rix0;
7501000Sxc151355 		try0 = an->an_tx_try0;
7511000Sxc151355 		if (shortPreamble)
7521000Sxc151355 			txrate = an->an_tx_rate0sp;
7531000Sxc151355 		else
7541000Sxc151355 			txrate = an->an_tx_rate0;
7551000Sxc151355 		/* Always use background queue */
7561000Sxc151355 		txq = asc->asc_ac2q[WME_AC_BK];
7571000Sxc151355 		break;
7581000Sxc151355 	default:
7591000Sxc151355 		/* Unknown 802.11 frame */
7601000Sxc151355 		asc->asc_stats.ast_tx_invalid++;
7611000Sxc151355 		return (1);
7621000Sxc151355 	}
7631000Sxc151355 	/*
7641000Sxc151355 	 * Calculate miscellaneous flags.
7651000Sxc151355 	 */
7661000Sxc151355 	flags = HAL_TXDESC_CLRDMASK;
767*3147Sxc151355 	if (IEEE80211_IS_MULTICAST(wh->i_addr1)) {
7681000Sxc151355 		flags |= HAL_TXDESC_NOACK;	/* no ack on broad/multicast */
7691000Sxc151355 		asc->asc_stats.ast_tx_noack++;
770*3147Sxc151355 	} else if (pktlen > ic->ic_rtsthreshold) {
7711000Sxc151355 		flags |= HAL_TXDESC_RTSENA;	/* RTS based on frame length */
7721000Sxc151355 		asc->asc_stats.ast_tx_rts++;
7731000Sxc151355 	}
7741000Sxc151355 
7751000Sxc151355 	/*
7761000Sxc151355 	 * Calculate duration.  This logically belongs in the 802.11
7771000Sxc151355 	 * layer but it lacks sufficient information to calculate it.
7781000Sxc151355 	 */
7791000Sxc151355 	if ((flags & HAL_TXDESC_NOACK) == 0 &&
780*3147Sxc151355 	    (wh->i_fc[0] & IEEE80211_FC0_TYPE_MASK) !=
7811000Sxc151355 	    IEEE80211_FC0_TYPE_CTL) {
7821000Sxc151355 		uint16_t dur;
7831000Sxc151355 		dur = ath_hal_computetxtime(ah, rt, IEEE80211_ACK_SIZE,
7841000Sxc151355 		    rix, shortPreamble);
785*3147Sxc151355 		*(uint16_t *)wh->i_dur = LE_16(dur);
7861000Sxc151355 	}
7871000Sxc151355 
7881000Sxc151355 	/*
7891000Sxc151355 	 * Calculate RTS/CTS rate and duration if needed.
7901000Sxc151355 	 */
7911000Sxc151355 	ctsduration = 0;
7921000Sxc151355 	if (flags & (HAL_TXDESC_RTSENA|HAL_TXDESC_CTSENA)) {
7931000Sxc151355 		/*
7941000Sxc151355 		 * CTS transmit rate is derived from the transmit rate
7951000Sxc151355 		 * by looking in the h/w rate table.  We must also factor
7961000Sxc151355 		 * in whether or not a short preamble is to be used.
7971000Sxc151355 		 */
7981000Sxc151355 		cix = rt->info[rix].controlRate;
7991000Sxc151355 		ctsrate = rt->info[cix].rateCode;
8001000Sxc151355 		if (shortPreamble)
8011000Sxc151355 			ctsrate |= rt->info[cix].shortPreamble;
8021000Sxc151355 		/*
8031000Sxc151355 		 * Compute the transmit duration based on the size
8041000Sxc151355 		 * of an ACK frame.  We call into the HAL to do the
8051000Sxc151355 		 * computation since it depends on the characteristics
8061000Sxc151355 		 * of the actual PHY being used.
8071000Sxc151355 		 */
8081000Sxc151355 		if (flags & HAL_TXDESC_RTSENA) {	/* SIFS + CTS */
8091000Sxc151355 			ctsduration += ath_hal_computetxtime(ah,
8101000Sxc151355 			    rt, IEEE80211_ACK_SIZE, cix, shortPreamble);
8111000Sxc151355 		}
8121000Sxc151355 		/* SIFS + data */
8131000Sxc151355 		ctsduration += ath_hal_computetxtime(ah,
8141000Sxc151355 		    rt, pktlen, rix, shortPreamble);
8151000Sxc151355 		if ((flags & HAL_TXDESC_NOACK) == 0) {	/* SIFS + ACK */
8161000Sxc151355 			ctsduration += ath_hal_computetxtime(ah,
8171000Sxc151355 			    rt, IEEE80211_ACK_SIZE, cix, shortPreamble);
8181000Sxc151355 		}
8191000Sxc151355 	} else
8201000Sxc151355 		ctsrate = 0;
8211000Sxc151355 
8221000Sxc151355 	if (++txq->axq_intrcnt >= ATH_TXINTR_PERIOD) {
8231000Sxc151355 		flags |= HAL_TXDESC_INTREQ;
8241000Sxc151355 		txq->axq_intrcnt = 0;
8251000Sxc151355 	}
8261000Sxc151355 
8271000Sxc151355 	/*
8281000Sxc151355 	 * Formulate first tx descriptor with tx controls.
8291000Sxc151355 	 */
8301000Sxc151355 	ATH_HAL_SETUPTXDESC(ah, ds,
8311000Sxc151355 	    pktlen,			/* packet length */
8321000Sxc151355 	    hdrlen,			/* header length */
8331000Sxc151355 	    atype,			/* Atheros packet type */
8341000Sxc151355 	    MIN(in->in_txpower, 60),	/* txpower */
8351000Sxc151355 	    txrate, try0,		/* series 0 rate/tries */
836*3147Sxc151355 	    keyix,			/* key cache index */
837*3147Sxc151355 	    an->an_tx_antenna,		/* antenna mode */
8381000Sxc151355 	    flags,			/* flags */
8391000Sxc151355 	    ctsrate,			/* rts/cts rate */
8401000Sxc151355 	    ctsduration);		/* rts/cts duration */
841*3147Sxc151355 	bf->bf_flags = flags;
8421000Sxc151355 
8431000Sxc151355 	ATH_DEBUG((ATH_DBG_SEND, "ath: ath_xmit(): to %s totlen=%d "
8441000Sxc151355 	    "an->an_tx_rate1sp=%d tx_rate2sp=%d tx_rate3sp=%d "
8451000Sxc151355 	    "qnum=%d rix=%d sht=%d dur = %d\n",
846*3147Sxc151355 	    ieee80211_macaddr_sprintf(wh->i_addr1), mbslen, an->an_tx_rate1sp,
8471000Sxc151355 	    an->an_tx_rate2sp, an->an_tx_rate3sp,
848*3147Sxc151355 	    txq->axq_qnum, rix, shortPreamble, *(uint16_t *)wh->i_dur));
8491000Sxc151355 
8501000Sxc151355 	/*
8511000Sxc151355 	 * Setup the multi-rate retry state only when we're
8521000Sxc151355 	 * going to use it.  This assumes ath_hal_setuptxdesc
8531000Sxc151355 	 * initializes the descriptors (so we don't have to)
8541000Sxc151355 	 * when the hardware supports multi-rate retry and
8551000Sxc151355 	 * we don't use it.
8561000Sxc151355 	 */
8571000Sxc151355 	if (try0 != ATH_TXMAXTRY)
8581000Sxc151355 		ATH_HAL_SETUPXTXDESC(ah, ds,
8591000Sxc151355 		    an->an_tx_rate1sp, 2,	/* series 1 */
8601000Sxc151355 		    an->an_tx_rate2sp, 2,	/* series 2 */
8611000Sxc151355 		    an->an_tx_rate3sp, 2);	/* series 3 */
8621000Sxc151355 
8631000Sxc151355 	ds->ds_link = 0;
8641000Sxc151355 	ds->ds_data = bf->bf_dma.cookie.dmac_address;
8651000Sxc151355 	ATH_HAL_FILLTXDESC(ah, ds,
8661000Sxc151355 	    mbslen,		/* segment length */
8671000Sxc151355 	    AH_TRUE,		/* first segment */
8681000Sxc151355 	    AH_TRUE,		/* last segment */
8691000Sxc151355 	    ds);		/* first descriptor */
8701000Sxc151355 
8711000Sxc151355 	ATH_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV);
8721000Sxc151355 
8731000Sxc151355 	mutex_enter(&txq->axq_lock);
8741000Sxc151355 	list_insert_tail(&txq->axq_list, bf);
8751000Sxc151355 	if (txq->axq_link == NULL) {
8761000Sxc151355 		ATH_HAL_PUTTXBUF(ah, txq->axq_qnum, bf->bf_daddr);
8771000Sxc151355 	} else {
8781000Sxc151355 		*txq->axq_link = bf->bf_daddr;
8791000Sxc151355 	}
8801000Sxc151355 	txq->axq_link = &ds->ds_link;
8811000Sxc151355 	mutex_exit(&txq->axq_lock);
8821000Sxc151355 
8831000Sxc151355 	ATH_HAL_TXSTART(ah, txq->axq_qnum);
8841000Sxc151355 
885*3147Sxc151355 	ic->ic_stats.is_tx_frags++;
886*3147Sxc151355 	ic->ic_stats.is_tx_bytes += pktlen;
887*3147Sxc151355 
8881000Sxc151355 	return (0);
8891000Sxc151355 }
8901000Sxc151355 
891*3147Sxc151355 /*
892*3147Sxc151355  * Transmit a management frame.  On failure we reclaim the skbuff.
893*3147Sxc151355  * Note that management frames come directly from the 802.11 layer
894*3147Sxc151355  * and do not honor the send queue flow control.  Need to investigate
895*3147Sxc151355  * using priority queueing so management frames can bypass data.
896*3147Sxc151355  */
8971000Sxc151355 static int
898*3147Sxc151355 ath_xmit(ieee80211com_t *ic, mblk_t *mp, uint8_t type)
8991000Sxc151355 {
900*3147Sxc151355 	ath_t *asc = (ath_t *)ic;
901*3147Sxc151355 	struct ath_hal *ah = asc->asc_ah;
902*3147Sxc151355 	struct ieee80211_node *in = NULL;
9031000Sxc151355 	struct ath_buf *bf = NULL;
904*3147Sxc151355 	struct ieee80211_frame *wh;
905*3147Sxc151355 	int error = 0;
906*3147Sxc151355 
907*3147Sxc151355 	ASSERT(mp->b_next == NULL);
908*3147Sxc151355 
909*3147Sxc151355 	/* Grab a TX buffer */
910*3147Sxc151355 	mutex_enter(&asc->asc_txbuflock);
911*3147Sxc151355 	bf = list_head(&asc->asc_txbuf_list);
912*3147Sxc151355 	if (bf != NULL)
913*3147Sxc151355 		list_remove(&asc->asc_txbuf_list, bf);
914*3147Sxc151355 	if (list_empty(&asc->asc_txbuf_list)) {
915*3147Sxc151355 		ATH_DEBUG((ATH_DBG_SEND, "ath: ath_mgmt_send(): "
916*3147Sxc151355 		    "stop queue\n"));
917*3147Sxc151355 		asc->asc_stats.ast_tx_qstop++;
918*3147Sxc151355 	}
919*3147Sxc151355 	mutex_exit(&asc->asc_txbuflock);
920*3147Sxc151355 	if (bf == NULL) {
921*3147Sxc151355 		ATH_DEBUG((ATH_DBG_SEND, "ath: ath_mgmt_send(): discard, "
922*3147Sxc151355 		    "no xmit buf\n"));
923*3147Sxc151355 		ic->ic_stats.is_tx_nobuf++;
924*3147Sxc151355 		if ((type & IEEE80211_FC0_TYPE_MASK) ==
925*3147Sxc151355 		    IEEE80211_FC0_TYPE_DATA) {
926*3147Sxc151355 			asc->asc_stats.ast_tx_nobuf++;
927*3147Sxc151355 			mutex_enter(&asc->asc_resched_lock);
928*3147Sxc151355 			asc->asc_resched_needed = B_TRUE;
929*3147Sxc151355 			mutex_exit(&asc->asc_resched_lock);
930*3147Sxc151355 		} else {
931*3147Sxc151355 			asc->asc_stats.ast_tx_nobufmgt++;
932*3147Sxc151355 			freemsg(mp);
933*3147Sxc151355 		}
934*3147Sxc151355 		return (ENOMEM);
935*3147Sxc151355 	}
936*3147Sxc151355 
937*3147Sxc151355 	wh = (struct ieee80211_frame *)mp->b_rptr;
938*3147Sxc151355 
939*3147Sxc151355 	/* Locate node */
940*3147Sxc151355 	in = ieee80211_find_txnode(ic,  wh->i_addr1);
941*3147Sxc151355 	if (in == NULL) {
942*3147Sxc151355 		error = EIO;
943*3147Sxc151355 		goto bad;
944*3147Sxc151355 	}
945*3147Sxc151355 
946*3147Sxc151355 	in->in_inact = 0;
947*3147Sxc151355 	switch (type & IEEE80211_FC0_TYPE_MASK) {
948*3147Sxc151355 	case IEEE80211_FC0_TYPE_DATA:
949*3147Sxc151355 		(void) ieee80211_encap(ic, mp, in);
950*3147Sxc151355 		break;
951*3147Sxc151355 	default:
952*3147Sxc151355 		if ((wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK) ==
953*3147Sxc151355 		    IEEE80211_FC0_SUBTYPE_PROBE_RESP) {
954*3147Sxc151355 			/* fill time stamp */
955*3147Sxc151355 			uint64_t tsf;
956*3147Sxc151355 			uint32_t *tstamp;
957*3147Sxc151355 
958*3147Sxc151355 			tsf = ATH_HAL_GETTSF64(ah);
959*3147Sxc151355 			/* adjust 100us delay to xmit */
960*3147Sxc151355 			tsf += 100;
961*3147Sxc151355 			tstamp = (uint32_t *)&wh[1];
962*3147Sxc151355 			tstamp[0] = LE_32(tsf & 0xffffffff);
963*3147Sxc151355 			tstamp[1] = LE_32(tsf >> 32);
964*3147Sxc151355 		}
965*3147Sxc151355 		asc->asc_stats.ast_tx_mgmt++;
966*3147Sxc151355 		break;
967*3147Sxc151355 	}
968*3147Sxc151355 
969*3147Sxc151355 	error = ath_tx_start(asc, in, bf, mp);
970*3147Sxc151355 	if (error != 0) {
971*3147Sxc151355 bad:
972*3147Sxc151355 		ic->ic_stats.is_tx_failed++;
973*3147Sxc151355 		if (bf != NULL) {
974*3147Sxc151355 			mutex_enter(&asc->asc_txbuflock);
975*3147Sxc151355 			list_insert_tail(&asc->asc_txbuf_list, bf);
976*3147Sxc151355 			mutex_exit(&asc->asc_txbuflock);
977*3147Sxc151355 		}
978*3147Sxc151355 	}
979*3147Sxc151355 	if (in != NULL)
980*3147Sxc151355 		ieee80211_free_node(in);
981*3147Sxc151355 	if ((type & IEEE80211_FC0_TYPE_MASK) != IEEE80211_FC0_TYPE_DATA ||
982*3147Sxc151355 	    error == 0) {
983*3147Sxc151355 		freemsg(mp);
984*3147Sxc151355 	}
985*3147Sxc151355 
986*3147Sxc151355 	return (error);
987*3147Sxc151355 }
988*3147Sxc151355 
989*3147Sxc151355 static mblk_t *
990*3147Sxc151355 ath_m_tx(void *arg, mblk_t *mp)
991*3147Sxc151355 {
992*3147Sxc151355 	ath_t *asc = arg;
993*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
994*3147Sxc151355 	mblk_t *next;
9951000Sxc151355 
9961000Sxc151355 	/*
9971000Sxc151355 	 * No data frames go out unless we're associated; this
9981000Sxc151355 	 * should not happen as the 802.11 layer does not enable
9991000Sxc151355 	 * the xmit queue until we enter the RUN state.
10001000Sxc151355 	 */
1001*3147Sxc151355 	if (ic->ic_state != IEEE80211_S_RUN) {
1002*3147Sxc151355 		ATH_DEBUG((ATH_DBG_SEND, "ath: ath_m_tx(): "
1003*3147Sxc151355 		    "discard, state %u\n", ic->ic_state));
1004*3147Sxc151355 		asc->asc_stats.ast_tx_discard ++;
1005*3147Sxc151355 		return (mp);
10061000Sxc151355 	}
10071000Sxc151355 
1008*3147Sxc151355 	while (mp != NULL) {
1009*3147Sxc151355 		next = mp->b_next;
1010*3147Sxc151355 		mp->b_next = NULL;
10111000Sxc151355 
1012*3147Sxc151355 		if (ath_xmit(ic, mp, IEEE80211_FC0_TYPE_DATA) != 0) {
1013*3147Sxc151355 			mp->b_next = next;
1014*3147Sxc151355 			break;
1015*3147Sxc151355 		}
1016*3147Sxc151355 		mp = next;
10171000Sxc151355 	}
10181000Sxc151355 
1019*3147Sxc151355 	return (mp);
10201000Sxc151355 
10211000Sxc151355 }
10221000Sxc151355 
1023*3147Sxc151355 static int
10241000Sxc151355 ath_tx_processq(ath_t *asc, struct ath_txq *txq)
10251000Sxc151355 {
1026*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
10271000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
10281000Sxc151355 	struct ath_buf *bf;
10291000Sxc151355 	struct ath_desc *ds;
10301000Sxc151355 	struct ieee80211_node *in;
1031*3147Sxc151355 	int32_t sr, lr, nacked = 0;
10321000Sxc151355 	HAL_STATUS status;
10331000Sxc151355 	struct ath_node *an;
10341000Sxc151355 
10351000Sxc151355 	for (;;) {
10361000Sxc151355 		mutex_enter(&txq->axq_lock);
10371000Sxc151355 		bf = list_head(&txq->axq_list);
10381000Sxc151355 		if (bf == NULL) {
10391000Sxc151355 			txq->axq_link = NULL;
10401000Sxc151355 			mutex_exit(&txq->axq_lock);
10411000Sxc151355 			break;
10421000Sxc151355 		}
10431000Sxc151355 		ds = bf->bf_desc;	/* last decriptor */
10441000Sxc151355 		status = ATH_HAL_TXPROCDESC(ah, ds);
10451000Sxc151355 #ifdef DEBUG
10461000Sxc151355 		ath_printtxbuf(bf, status == HAL_OK);
10471000Sxc151355 #endif
10481000Sxc151355 		if (status == HAL_EINPROGRESS) {
10491000Sxc151355 			mutex_exit(&txq->axq_lock);
10501000Sxc151355 			break;
10511000Sxc151355 		}
10521000Sxc151355 		list_remove(&txq->axq_list, bf);
10531000Sxc151355 		mutex_exit(&txq->axq_lock);
10541000Sxc151355 		in = bf->bf_in;
10551000Sxc151355 		if (in != NULL) {
10561000Sxc151355 			an = ATH_NODE(in);
10571000Sxc151355 			/* Successful transmition */
10581000Sxc151355 			if (ds->ds_txstat.ts_status == 0) {
10591000Sxc151355 				an->an_tx_ok++;
10601000Sxc151355 				an->an_tx_antenna =
10611000Sxc151355 				    ds->ds_txstat.ts_antenna;
10621000Sxc151355 				if (ds->ds_txstat.ts_rate &
10631000Sxc151355 				    HAL_TXSTAT_ALTRATE)
10641000Sxc151355 					asc->asc_stats.ast_tx_altrate++;
10651000Sxc151355 				asc->asc_stats.ast_tx_rssidelta =
10661000Sxc151355 				    ds->ds_txstat.ts_rssi -
10671000Sxc151355 				    asc->asc_stats.ast_tx_rssi;
10681000Sxc151355 				asc->asc_stats.ast_tx_rssi =
10691000Sxc151355 				    ds->ds_txstat.ts_rssi;
10701000Sxc151355 			} else {
10711000Sxc151355 				an->an_tx_err++;
10721000Sxc151355 				if (ds->ds_txstat.ts_status &
10731000Sxc151355 				    HAL_TXERR_XRETRY)
10741000Sxc151355 					asc->asc_stats.
10751000Sxc151355 					    ast_tx_xretries++;
10761000Sxc151355 				if (ds->ds_txstat.ts_status &
10771000Sxc151355 				    HAL_TXERR_FIFO)
10781000Sxc151355 					asc->asc_stats.ast_tx_fifoerr++;
10791000Sxc151355 				if (ds->ds_txstat.ts_status &
10801000Sxc151355 				    HAL_TXERR_FILT)
10811000Sxc151355 					asc->asc_stats.
10821000Sxc151355 					    ast_tx_filtered++;
10831000Sxc151355 				an->an_tx_antenna = 0;	/* invalidate */
10841000Sxc151355 			}
10851000Sxc151355 			sr = ds->ds_txstat.ts_shortretry;
10861000Sxc151355 			lr = ds->ds_txstat.ts_longretry;
10871000Sxc151355 			asc->asc_stats.ast_tx_shortretry += sr;
10881000Sxc151355 			asc->asc_stats.ast_tx_longretry += lr;
1089*3147Sxc151355 			/*
1090*3147Sxc151355 			 * Hand the descriptor to the rate control algorithm.
1091*3147Sxc151355 			 */
1092*3147Sxc151355 			if ((ds->ds_txstat.ts_status & HAL_TXERR_FILT) == 0 &&
1093*3147Sxc151355 			    (bf->bf_flags & HAL_TXDESC_NOACK) == 0) {
1094*3147Sxc151355 				/*
1095*3147Sxc151355 				 * If frame was ack'd update the last rx time
1096*3147Sxc151355 				 * used to workaround phantom bmiss interrupts.
1097*3147Sxc151355 				 */
1098*3147Sxc151355 				if (ds->ds_txstat.ts_status == 0) {
1099*3147Sxc151355 					nacked++;
1100*3147Sxc151355 					an->an_tx_ok++;
1101*3147Sxc151355 				} else {
1102*3147Sxc151355 					an->an_tx_err++;
1103*3147Sxc151355 				}
1104*3147Sxc151355 				an->an_tx_retr += sr + lr;
1105*3147Sxc151355 			}
11061000Sxc151355 		}
11071000Sxc151355 		bf->bf_in = NULL;
11081000Sxc151355 		mutex_enter(&asc->asc_txbuflock);
11091000Sxc151355 		list_insert_tail(&asc->asc_txbuf_list, bf);
11101000Sxc151355 		mutex_exit(&asc->asc_txbuflock);
11111000Sxc151355 		/*
11121000Sxc151355 		 * Reschedule stalled outbound packets
11131000Sxc151355 		 */
1114*3147Sxc151355 		mutex_enter(&asc->asc_resched_lock);
1115*3147Sxc151355 		if (asc->asc_resched_needed) {
1116*3147Sxc151355 			asc->asc_resched_needed = B_FALSE;
1117*3147Sxc151355 			mac_tx_update(ic->ic_mach);
11181000Sxc151355 		}
1119*3147Sxc151355 		mutex_exit(&asc->asc_resched_lock);
11201000Sxc151355 	}
1121*3147Sxc151355 	return (nacked);
11221000Sxc151355 }
11231000Sxc151355 
11241000Sxc151355 
11251000Sxc151355 static void
11261000Sxc151355 ath_tx_handler(ath_t *asc)
11271000Sxc151355 {
11281000Sxc151355 	int i;
11291000Sxc151355 
11301000Sxc151355 	/*
11311000Sxc151355 	 * Process each active queue.
11321000Sxc151355 	 */
11331000Sxc151355 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
11341000Sxc151355 		if (ATH_TXQ_SETUP(asc, i)) {
1135*3147Sxc151355 			(void) ath_tx_processq(asc, &asc->asc_txq[i]);
11361000Sxc151355 		}
11371000Sxc151355 	}
11381000Sxc151355 }
11391000Sxc151355 
11401000Sxc151355 static struct ieee80211_node *
1141*3147Sxc151355 ath_node_alloc(ieee80211com_t *ic)
11421000Sxc151355 {
11431000Sxc151355 	struct ath_node *an;
1144*3147Sxc151355 	ath_t *asc = (ath_t *)ic;
11451000Sxc151355 
11461000Sxc151355 	an = kmem_zalloc(sizeof (struct ath_node), KM_SLEEP);
11471000Sxc151355 	ath_rate_update(asc, &an->an_node, 0);
11481000Sxc151355 	return (&an->an_node);
11491000Sxc151355 }
11501000Sxc151355 
11511000Sxc151355 static void
1152*3147Sxc151355 ath_node_free(struct ieee80211_node *in)
11531000Sxc151355 {
1154*3147Sxc151355 	ieee80211com_t *ic = in->in_ic;
1155*3147Sxc151355 	ath_t *asc = (ath_t *)ic;
11561000Sxc151355 	struct ath_buf *bf;
11571000Sxc151355 	struct ath_txq *txq;
11581000Sxc151355 	int32_t i;
11591000Sxc151355 
11601000Sxc151355 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
11611000Sxc151355 		if (ATH_TXQ_SETUP(asc, i)) {
11621000Sxc151355 			txq = &asc->asc_txq[i];
11631000Sxc151355 			mutex_enter(&txq->axq_lock);
11641000Sxc151355 			bf = list_head(&txq->axq_list);
11651000Sxc151355 			while (bf != NULL) {
11661000Sxc151355 				if (bf->bf_in == in) {
11671000Sxc151355 					bf->bf_in = NULL;
11681000Sxc151355 				}
11691000Sxc151355 				bf = list_next(&txq->axq_list, bf);
11701000Sxc151355 			}
11711000Sxc151355 			mutex_exit(&txq->axq_lock);
11721000Sxc151355 		}
11731000Sxc151355 	}
1174*3147Sxc151355 	ic->ic_node_cleanup(in);
11751000Sxc151355 	kmem_free(in, sizeof (struct ath_node));
11761000Sxc151355 }
11771000Sxc151355 
11781000Sxc151355 static void
1179*3147Sxc151355 ath_next_scan(void *arg)
11801000Sxc151355 {
1181*3147Sxc151355 	ieee80211com_t *ic = arg;
1182*3147Sxc151355 	ath_t *asc = (ath_t *)ic;
1183*3147Sxc151355 
1184*3147Sxc151355 	asc->asc_scan_timer = 0;
1185*3147Sxc151355 	if (ic->ic_state == IEEE80211_S_SCAN) {
1186*3147Sxc151355 		asc->asc_scan_timer = timeout(ath_next_scan, (void *)asc,
1187*3147Sxc151355 		    drv_usectohz(ath_dwelltime * 1000));
1188*3147Sxc151355 		ieee80211_next_scan(ic);
1189*3147Sxc151355 	}
11901000Sxc151355 }
11911000Sxc151355 
1192*3147Sxc151355 static void
1193*3147Sxc151355 ath_stop_scantimer(ath_t *asc)
11941000Sxc151355 {
1195*3147Sxc151355 	timeout_id_t tmp_id = 0;
11961000Sxc151355 
1197*3147Sxc151355 	while ((asc->asc_scan_timer != 0) && (tmp_id != asc->asc_scan_timer)) {
1198*3147Sxc151355 		tmp_id = asc->asc_scan_timer;
1199*3147Sxc151355 		(void) untimeout(tmp_id);
12001000Sxc151355 	}
1201*3147Sxc151355 	asc->asc_scan_timer = 0;
12021000Sxc151355 }
12031000Sxc151355 
12041000Sxc151355 static int32_t
1205*3147Sxc151355 ath_newstate(ieee80211com_t *ic, enum ieee80211_state nstate, int arg)
12061000Sxc151355 {
1207*3147Sxc151355 	ath_t *asc = (ath_t *)ic;
12081000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
12091000Sxc151355 	struct ieee80211_node *in;
12101000Sxc151355 	int32_t i, error;
12111000Sxc151355 	uint8_t *bssid;
12121000Sxc151355 	uint32_t rfilt;
12131000Sxc151355 	enum ieee80211_state ostate;
12141000Sxc151355 
12151000Sxc151355 	static const HAL_LED_STATE leds[] = {
12161000Sxc151355 	    HAL_LED_INIT,	/* IEEE80211_S_INIT */
12171000Sxc151355 	    HAL_LED_SCAN,	/* IEEE80211_S_SCAN */
12181000Sxc151355 	    HAL_LED_AUTH,	/* IEEE80211_S_AUTH */
12191000Sxc151355 	    HAL_LED_ASSOC, 	/* IEEE80211_S_ASSOC */
12201000Sxc151355 	    HAL_LED_RUN, 	/* IEEE80211_S_RUN */
12211000Sxc151355 	};
1222*3147Sxc151355 	if (!ATH_IS_RUNNING(asc))
12231000Sxc151355 		return (0);
12241000Sxc151355 
1225*3147Sxc151355 	ostate = ic->ic_state;
1226*3147Sxc151355 	if (nstate != IEEE80211_S_SCAN)
1227*3147Sxc151355 		ath_stop_scantimer(asc);
12281000Sxc151355 
1229*3147Sxc151355 	ATH_LOCK(asc);
12301000Sxc151355 	ATH_HAL_SETLEDSTATE(ah, leds[nstate]);	/* set LED */
12311000Sxc151355 
12321000Sxc151355 	if (nstate == IEEE80211_S_INIT) {
12331000Sxc151355 		asc->asc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
1234*3147Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask &~ HAL_INT_GLOBAL);
1235*3147Sxc151355 		ATH_UNLOCK(asc);
1236*3147Sxc151355 		goto done;
12371000Sxc151355 	}
1238*3147Sxc151355 	in = ic->ic_bss;
1239*3147Sxc151355 	error = ath_chan_set(asc, ic->ic_curchan);
1240*3147Sxc151355 	if (error != 0) {
1241*3147Sxc151355 		if (nstate != IEEE80211_S_SCAN) {
1242*3147Sxc151355 			ATH_UNLOCK(asc);
1243*3147Sxc151355 			ieee80211_reset_chan(ic);
1244*3147Sxc151355 			goto bad;
1245*3147Sxc151355 		}
1246*3147Sxc151355 	}
12471000Sxc151355 
12481000Sxc151355 	rfilt = ath_calcrxfilter(asc);
12491000Sxc151355 	if (nstate == IEEE80211_S_SCAN)
1250*3147Sxc151355 		bssid = ic->ic_macaddr;
12511000Sxc151355 	else
12521000Sxc151355 		bssid = in->in_bssid;
12531000Sxc151355 	ATH_HAL_SETRXFILTER(ah, rfilt);
12541000Sxc151355 
1255*3147Sxc151355 	if (nstate == IEEE80211_S_RUN && ic->ic_opmode != IEEE80211_M_IBSS)
12561000Sxc151355 		ATH_HAL_SETASSOCID(ah, bssid, in->in_associd);
12571000Sxc151355 	else
12581000Sxc151355 		ATH_HAL_SETASSOCID(ah, bssid, 0);
1259*3147Sxc151355 	if (ic->ic_flags & IEEE80211_F_PRIVACY) {
12601000Sxc151355 		for (i = 0; i < IEEE80211_WEP_NKID; i++) {
12611000Sxc151355 			if (ATH_HAL_KEYISVALID(ah, i))
12621000Sxc151355 				ATH_HAL_KEYSETMAC(ah, i, bssid);
12631000Sxc151355 		}
12641000Sxc151355 	}
12651000Sxc151355 
12661000Sxc151355 	if ((nstate == IEEE80211_S_RUN) &&
12671000Sxc151355 	    (ostate != IEEE80211_S_RUN)) {
12681000Sxc151355 		/* Configure the beacon and sleep timers. */
12691000Sxc151355 		ath_beacon_config(asc);
12701000Sxc151355 	} else {
12711000Sxc151355 		asc->asc_imask &= ~(HAL_INT_SWBA | HAL_INT_BMISS);
12721000Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask);
12731000Sxc151355 	}
12741000Sxc151355 	/*
12751000Sxc151355 	 * Reset the rate control state.
12761000Sxc151355 	 */
12771000Sxc151355 	ath_rate_ctl_reset(asc, nstate);
12781000Sxc151355 
1279*3147Sxc151355 	if (nstate == IEEE80211_S_RUN && (ostate != IEEE80211_S_RUN)) {
12801000Sxc151355 		nvlist_t *attr_list = NULL;
12811000Sxc151355 		sysevent_id_t eid;
12821000Sxc151355 		int32_t err = 0;
12831000Sxc151355 		char *str_name = "ATH";
12841000Sxc151355 		char str_value[256] = {0};
12851000Sxc151355 
12861000Sxc151355 		ATH_DEBUG((ATH_DBG_80211, "ath: ath new state(RUN): "
12871000Sxc151355 		    "ic_flags=0x%08x iv=%d"
12881000Sxc151355 		    " bssid=%s capinfo=0x%04x chan=%d\n",
1289*3147Sxc151355 		    ic->ic_flags,
12901000Sxc151355 		    in->in_intval,
1291*3147Sxc151355 		    ieee80211_macaddr_sprintf(in->in_bssid),
12921000Sxc151355 		    in->in_capinfo,
1293*3147Sxc151355 		    ieee80211_chan2ieee(ic, in->in_chan)));
12941000Sxc151355 
12951000Sxc151355 		(void) sprintf(str_value, "%s%s%d", "-i ",
12961000Sxc151355 		    ddi_driver_name(asc->asc_dev),
12971000Sxc151355 		    ddi_get_instance(asc->asc_dev));
12981000Sxc151355 		if (nvlist_alloc(&attr_list,
12991000Sxc151355 		    NV_UNIQUE_NAME_TYPE, KM_SLEEP) == 0) {
13001000Sxc151355 			err = nvlist_add_string(attr_list,
13011000Sxc151355 			    str_name, str_value);
13021000Sxc151355 			if (err != DDI_SUCCESS)
13031000Sxc151355 				ATH_DEBUG((ATH_DBG_80211, "ath: "
13041000Sxc151355 				    "ath_new_state: error log event\n"));
13051000Sxc151355 			err = ddi_log_sysevent(asc->asc_dev,
13061000Sxc151355 			    DDI_VENDOR_SUNW, "class",
13071000Sxc151355 			    "subclass", attr_list,
13081000Sxc151355 			    &eid, DDI_NOSLEEP);
13091000Sxc151355 			if (err != DDI_SUCCESS)
13101000Sxc151355 				ATH_DEBUG((ATH_DBG_80211, "ath: "
13111000Sxc151355 				    "ath_new_state(): error log event\n"));
13121000Sxc151355 			nvlist_free(attr_list);
13131000Sxc151355 		}
13141000Sxc151355 	}
13151000Sxc151355 
1316*3147Sxc151355 	ATH_UNLOCK(asc);
1317*3147Sxc151355 done:
1318*3147Sxc151355 	/*
1319*3147Sxc151355 	 * Invoke the parent method to complete the work.
1320*3147Sxc151355 	 */
1321*3147Sxc151355 	error = asc->asc_newstate(ic, nstate, arg);
1322*3147Sxc151355 	/*
1323*3147Sxc151355 	 * Finally, start any timers.
1324*3147Sxc151355 	 */
1325*3147Sxc151355 	if (nstate == IEEE80211_S_RUN) {
1326*3147Sxc151355 		ieee80211_start_watchdog(ic, 1);
1327*3147Sxc151355 	} else if ((nstate == IEEE80211_S_SCAN) && (ostate != nstate)) {
1328*3147Sxc151355 		/* start ap/neighbor scan timer */
1329*3147Sxc151355 		ASSERT(asc->asc_scan_timer == 0);
1330*3147Sxc151355 		asc->asc_scan_timer = timeout(ath_next_scan, (void *)asc,
1331*3147Sxc151355 		    drv_usectohz(ath_dwelltime * 1000));
1332*3147Sxc151355 	}
13331000Sxc151355 bad:
13341000Sxc151355 	return (error);
13351000Sxc151355 }
13361000Sxc151355 
13371000Sxc151355 /*
13381000Sxc151355  * Periodically recalibrate the PHY to account
13391000Sxc151355  * for temperature/environment changes.
13401000Sxc151355  */
13411000Sxc151355 static void
1342*3147Sxc151355 ath_calibrate(ath_t *asc)
13431000Sxc151355 {
13441000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
1345*3147Sxc151355 	HAL_BOOL iqcaldone;
13461000Sxc151355 
13471000Sxc151355 	asc->asc_stats.ast_per_cal++;
13481000Sxc151355 
13491000Sxc151355 	if (ATH_HAL_GETRFGAIN(ah) == HAL_RFGAIN_NEED_CHANGE) {
13501000Sxc151355 		/*
13511000Sxc151355 		 * Rfgain is out of bounds, reset the chip
13521000Sxc151355 		 * to load new gain values.
13531000Sxc151355 		 */
13541000Sxc151355 		ATH_DEBUG((ATH_DBG_HAL, "ath: ath_calibrate(): "
13551000Sxc151355 		    "Need change RFgain\n"));
13561000Sxc151355 		asc->asc_stats.ast_per_rfgain++;
1357*3147Sxc151355 		(void) ath_reset(&asc->asc_isc);
13581000Sxc151355 	}
1359*3147Sxc151355 	if (!ATH_HAL_CALIBRATE(ah, &asc->asc_curchan, &iqcaldone)) {
13601000Sxc151355 		ATH_DEBUG((ATH_DBG_HAL, "ath: ath_calibrate(): "
13611000Sxc151355 		    "calibration of channel %u failed\n",
1362*3147Sxc151355 		    asc->asc_curchan.channel));
13631000Sxc151355 		asc->asc_stats.ast_per_calfail++;
13641000Sxc151355 	}
13651000Sxc151355 }
13661000Sxc151355 
1367*3147Sxc151355 static void
1368*3147Sxc151355 ath_watchdog(void *arg)
1369*3147Sxc151355 {
1370*3147Sxc151355 	ath_t *asc = arg;
1371*3147Sxc151355 	ieee80211com_t *ic = &asc->asc_isc;
1372*3147Sxc151355 	int ntimer = 0;
1373*3147Sxc151355 
1374*3147Sxc151355 	ATH_LOCK(asc);
1375*3147Sxc151355 	ic->ic_watchdog_timer = 0;
1376*3147Sxc151355 	if (!ATH_IS_RUNNING(asc)) {
1377*3147Sxc151355 		ATH_UNLOCK(asc);
1378*3147Sxc151355 		return;
1379*3147Sxc151355 	}
1380*3147Sxc151355 
1381*3147Sxc151355 	if (ic->ic_state == IEEE80211_S_RUN) {
1382*3147Sxc151355 		/* periodic recalibration */
1383*3147Sxc151355 		ath_calibrate(asc);
1384*3147Sxc151355 
1385*3147Sxc151355 		/*
1386*3147Sxc151355 		 * Start the background rate control thread if we
1387*3147Sxc151355 		 * are not configured to use a fixed xmit rate.
1388*3147Sxc151355 		 */
1389*3147Sxc151355 		if (ic->ic_fixed_rate == IEEE80211_FIXED_RATE_NONE) {
1390*3147Sxc151355 			asc->asc_stats.ast_rate_calls ++;
1391*3147Sxc151355 			if (ic->ic_opmode == IEEE80211_M_STA)
1392*3147Sxc151355 				ath_rate_ctl(ic, ic->ic_bss);
1393*3147Sxc151355 			else
1394*3147Sxc151355 				ieee80211_iterate_nodes(&ic->ic_sta,
1395*3147Sxc151355 				    ath_rate_cb, asc);
1396*3147Sxc151355 		}
1397*3147Sxc151355 
1398*3147Sxc151355 		ntimer = 1;
1399*3147Sxc151355 	}
1400*3147Sxc151355 	ATH_UNLOCK(asc);
1401*3147Sxc151355 
1402*3147Sxc151355 	ieee80211_watchdog(ic);
1403*3147Sxc151355 	if (ntimer != 0)
1404*3147Sxc151355 		ieee80211_start_watchdog(ic, ntimer);
1405*3147Sxc151355 }
1406*3147Sxc151355 
14071000Sxc151355 static uint_t
1408*3147Sxc151355 ath_intr(caddr_t arg)
14091000Sxc151355 {
1410*3147Sxc151355 	ath_t *asc = (ath_t *)arg;
14111000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
14121000Sxc151355 	HAL_INT status;
1413*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
1414*3147Sxc151355 
1415*3147Sxc151355 	ATH_LOCK(asc);
14161000Sxc151355 
1417*3147Sxc151355 	if (!ATH_IS_RUNNING(asc)) {
1418*3147Sxc151355 		/*
1419*3147Sxc151355 		 * The hardware is not ready/present, don't touch anything.
1420*3147Sxc151355 		 * Note this can happen early on if the IRQ is shared.
1421*3147Sxc151355 		 */
1422*3147Sxc151355 		ATH_UNLOCK(asc);
1423*3147Sxc151355 		return (DDI_INTR_UNCLAIMED);
1424*3147Sxc151355 	}
14251000Sxc151355 
14261000Sxc151355 	if (!ATH_HAL_INTRPEND(ah)) {	/* shared irq, not for us */
1427*3147Sxc151355 		ATH_UNLOCK(asc);
14281000Sxc151355 		return (DDI_INTR_UNCLAIMED);
14291000Sxc151355 	}
14301000Sxc151355 
14311000Sxc151355 	ATH_HAL_GETISR(ah, &status);
14321000Sxc151355 	status &= asc->asc_imask;
14331000Sxc151355 	if (status & HAL_INT_FATAL) {
14341000Sxc151355 		asc->asc_stats.ast_hardware++;
14351000Sxc151355 		goto reset;
14361000Sxc151355 	} else if (status & HAL_INT_RXORN) {
14371000Sxc151355 		asc->asc_stats.ast_rxorn++;
14381000Sxc151355 		goto reset;
14391000Sxc151355 	} else {
14401000Sxc151355 		if (status & HAL_INT_RXEOL) {
14411000Sxc151355 			asc->asc_stats.ast_rxeol++;
14421000Sxc151355 			asc->asc_rxlink = NULL;
14431000Sxc151355 		}
14441000Sxc151355 		if (status & HAL_INT_TXURN) {
14451000Sxc151355 			asc->asc_stats.ast_txurn++;
14461000Sxc151355 			ATH_HAL_UPDATETXTRIGLEVEL(ah, AH_TRUE);
14471000Sxc151355 		}
1448*3147Sxc151355 
14491000Sxc151355 		if (status & HAL_INT_RX) {
14501000Sxc151355 			asc->asc_rx_pend = 1;
14511000Sxc151355 			ddi_trigger_softintr(asc->asc_softint_id);
14521000Sxc151355 		}
14531000Sxc151355 		if (status & HAL_INT_TX) {
14541000Sxc151355 			ath_tx_handler(asc);
14551000Sxc151355 		}
1456*3147Sxc151355 		ATH_UNLOCK(asc);
14571000Sxc151355 
14581000Sxc151355 		if (status & HAL_INT_SWBA) {
14591000Sxc151355 			/* This will occur only in Host-AP or Ad-Hoc mode */
14601000Sxc151355 			return (DDI_INTR_CLAIMED);
14611000Sxc151355 		}
14621000Sxc151355 		if (status & HAL_INT_BMISS) {
1463*3147Sxc151355 			if (ic->ic_state == IEEE80211_S_RUN) {
1464*3147Sxc151355 				(void) ieee80211_new_state(ic,
14651000Sxc151355 				    IEEE80211_S_ASSOC, -1);
14661000Sxc151355 			}
14671000Sxc151355 		}
14681000Sxc151355 	}
14691000Sxc151355 
14701000Sxc151355 	return (DDI_INTR_CLAIMED);
14711000Sxc151355 reset:
1472*3147Sxc151355 	(void) ath_reset(ic);
1473*3147Sxc151355 	ATH_UNLOCK(asc);
14741000Sxc151355 	return (DDI_INTR_CLAIMED);
14751000Sxc151355 }
14761000Sxc151355 
14771000Sxc151355 static uint_t
14781000Sxc151355 ath_softint_handler(caddr_t data)
14791000Sxc151355 {
14801000Sxc151355 	ath_t *asc = (ath_t *)data;
14811000Sxc151355 
14821000Sxc151355 	/*
14831000Sxc151355 	 * Check if the soft interrupt is triggered by another
14841000Sxc151355 	 * driver at the same level.
14851000Sxc151355 	 */
1486*3147Sxc151355 	ATH_LOCK(asc);
14871000Sxc151355 	if (asc->asc_rx_pend) { /* Soft interrupt for this driver */
14881000Sxc151355 		asc->asc_rx_pend = 0;
1489*3147Sxc151355 		ATH_UNLOCK(asc);
1490*3147Sxc151355 		ath_rx_handler(asc);
14911000Sxc151355 		return (DDI_INTR_CLAIMED);
14921000Sxc151355 	}
1493*3147Sxc151355 	ATH_UNLOCK(asc);
14941000Sxc151355 	return (DDI_INTR_UNCLAIMED);
14951000Sxc151355 }
14961000Sxc151355 
14971000Sxc151355 /*
14981000Sxc151355  * following are gld callback routine
14991000Sxc151355  * ath_gld_send, ath_gld_ioctl, ath_gld_gstat
15001000Sxc151355  * are listed in other corresponding sections.
15011000Sxc151355  * reset the hardware w/o losing operational state.  this is
15021000Sxc151355  * basically a more efficient way of doing ath_gld_stop, ath_gld_start,
15031000Sxc151355  * followed by state transitions to the current 802.11
15041000Sxc151355  * operational state.  used to recover from errors rx overrun
15051000Sxc151355  * and to reset the hardware when rf gain settings must be reset.
15061000Sxc151355  */
15071000Sxc151355 
1508*3147Sxc151355 static void
1509*3147Sxc151355 ath_stop_locked(ath_t *asc)
15101000Sxc151355 {
1511*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
1512*3147Sxc151355 	struct ath_hal *ah = asc->asc_ah;
15131000Sxc151355 
1514*3147Sxc151355 	ATH_LOCK_ASSERT(asc);
1515*3147Sxc151355 	/*
1516*3147Sxc151355 	 * Shutdown the hardware and driver:
1517*3147Sxc151355 	 *    reset 802.11 state machine
1518*3147Sxc151355 	 *    turn off timers
1519*3147Sxc151355 	 *    disable interrupts
1520*3147Sxc151355 	 *    turn off the radio
1521*3147Sxc151355 	 *    clear transmit machinery
1522*3147Sxc151355 	 *    clear receive machinery
1523*3147Sxc151355 	 *    drain and release tx queues
1524*3147Sxc151355 	 *    reclaim beacon resources
1525*3147Sxc151355 	 *    power down hardware
1526*3147Sxc151355 	 *
1527*3147Sxc151355 	 * Note that some of this work is not possible if the
1528*3147Sxc151355 	 * hardware is gone (invalid).
1529*3147Sxc151355 	 */
1530*3147Sxc151355 	ATH_UNLOCK(asc);
1531*3147Sxc151355 	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
1532*3147Sxc151355 	ieee80211_stop_watchdog(ic);
1533*3147Sxc151355 	ATH_LOCK(asc);
1534*3147Sxc151355 	ATH_HAL_INTRSET(ah, 0);
1535*3147Sxc151355 	ath_draintxq(asc);
1536*3147Sxc151355 	if (ATH_IS_RUNNING(asc)) {
1537*3147Sxc151355 		ath_stoprecv(asc);
1538*3147Sxc151355 		ATH_HAL_PHYDISABLE(ah);
1539*3147Sxc151355 	} else {
1540*3147Sxc151355 		asc->asc_rxlink = NULL;
1541*3147Sxc151355 	}
15421000Sxc151355 }
15431000Sxc151355 
1544*3147Sxc151355 static void
1545*3147Sxc151355 ath_m_stop(void *arg)
15461000Sxc151355 {
1547*3147Sxc151355 	ath_t *asc = arg;
15481000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
15491000Sxc151355 
1550*3147Sxc151355 	ATH_LOCK(asc);
1551*3147Sxc151355 	ath_stop_locked(asc);
1552*3147Sxc151355 	ATH_HAL_SETPOWER(ah, HAL_PM_AWAKE);
15531000Sxc151355 	asc->asc_invalid = 1;
1554*3147Sxc151355 	ATH_UNLOCK(asc);
15551000Sxc151355 }
15561000Sxc151355 
15571000Sxc151355 int
1558*3147Sxc151355 ath_m_start(void *arg)
15591000Sxc151355 {
1560*3147Sxc151355 	ath_t *asc = arg;
1561*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
15621000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
15631000Sxc151355 	HAL_STATUS status;
15641000Sxc151355 
1565*3147Sxc151355 	ATH_LOCK(asc);
15661000Sxc151355 	/*
15671000Sxc151355 	 * Stop anything previously setup.  This is safe
15681000Sxc151355 	 * whether this is the first time through or not.
15691000Sxc151355 	 */
1570*3147Sxc151355 	ath_stop_locked(asc);
15711000Sxc151355 
15721000Sxc151355 	/*
15731000Sxc151355 	 * The basic interface to setting the hardware in a good
15741000Sxc151355 	 * state is ``reset''.  On return the hardware is known to
15751000Sxc151355 	 * be powered up and with interrupts disabled.  This must
15761000Sxc151355 	 * be followed by initialization of the appropriate bits
15771000Sxc151355 	 * and then setup of the interrupt mask.
15781000Sxc151355 	 */
1579*3147Sxc151355 	asc->asc_curchan.channel = ic->ic_curchan->ich_freq;
1580*3147Sxc151355 	asc->asc_curchan.channelFlags = ath_chan2flags(ic, ic->ic_curchan);
1581*3147Sxc151355 	if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
1582*3147Sxc151355 	    &asc->asc_curchan, AH_FALSE, &status)) {
1583*3147Sxc151355 		ATH_DEBUG((ATH_DBG_HAL, "ath: ath_m_start(): "
1584*3147Sxc151355 		    "reset hardware failed, hal status %u\n", status));
1585*3147Sxc151355 		ATH_UNLOCK(asc);
1586*3147Sxc151355 		return (ENOTACTIVE);
15871000Sxc151355 	}
15881000Sxc151355 
1589*3147Sxc151355 	(void) ath_startrecv(asc);
15901000Sxc151355 
15911000Sxc151355 	/*
15921000Sxc151355 	 * Enable interrupts.
15931000Sxc151355 	 */
15941000Sxc151355 	asc->asc_imask = HAL_INT_RX | HAL_INT_TX
15951000Sxc151355 	    | HAL_INT_RXEOL | HAL_INT_RXORN
15961000Sxc151355 	    | HAL_INT_FATAL | HAL_INT_GLOBAL;
15971000Sxc151355 	ATH_HAL_INTRSET(ah, asc->asc_imask);
15981000Sxc151355 
1599*3147Sxc151355 	ic->ic_state = IEEE80211_S_INIT;
16001000Sxc151355 
16011000Sxc151355 	/*
16021000Sxc151355 	 * The hardware should be ready to go now so it's safe
16031000Sxc151355 	 * to kick the 802.11 state machine as it's likely to
16041000Sxc151355 	 * immediately call back to us to send mgmt frames.
16051000Sxc151355 	 */
1606*3147Sxc151355 	ath_chan_change(asc, ic->ic_curchan);
16071000Sxc151355 	asc->asc_invalid = 0;
1608*3147Sxc151355 	ATH_UNLOCK(asc);
1609*3147Sxc151355 	return (0);
16101000Sxc151355 }
16111000Sxc151355 
16121000Sxc151355 
1613*3147Sxc151355 static int
1614*3147Sxc151355 ath_m_unicst(void *arg, const uint8_t *macaddr)
16151000Sxc151355 {
1616*3147Sxc151355 	ath_t *asc = arg;
16171000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
16181000Sxc151355 
16191000Sxc151355 	ATH_DEBUG((ATH_DBG_GLD, "ath: ath_gld_saddr(): "
16201000Sxc151355 	    "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
16211000Sxc151355 	    macaddr[0], macaddr[1], macaddr[2],
16221000Sxc151355 	    macaddr[3], macaddr[4], macaddr[5]));
16231000Sxc151355 
1624*3147Sxc151355 	ATH_LOCK(asc);
1625*3147Sxc151355 	IEEE80211_ADDR_COPY(asc->asc_isc.ic_macaddr, macaddr);
1626*3147Sxc151355 	ATH_HAL_SETMAC(ah, asc->asc_isc.ic_macaddr);
16271000Sxc151355 
1628*3147Sxc151355 	(void) ath_reset(&asc->asc_isc);
1629*3147Sxc151355 	ATH_UNLOCK(asc);
1630*3147Sxc151355 	return (0);
16311000Sxc151355 }
16321000Sxc151355 
16331000Sxc151355 static int
1634*3147Sxc151355 ath_m_promisc(void *arg, boolean_t on)
16351000Sxc151355 {
1636*3147Sxc151355 	ath_t *asc = arg;
16371000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
16381000Sxc151355 	uint32_t rfilt;
16391000Sxc151355 
1640*3147Sxc151355 	ATH_LOCK(asc);
16411000Sxc151355 	rfilt = ATH_HAL_GETRXFILTER(ah);
1642*3147Sxc151355 	if (on)
1643*3147Sxc151355 		rfilt |= HAL_RX_FILTER_PROM;
1644*3147Sxc151355 	else
16451000Sxc151355 		rfilt &= ~HAL_RX_FILTER_PROM;
1646*3147Sxc151355 	ATH_HAL_SETRXFILTER(ah, rfilt);
1647*3147Sxc151355 	ATH_UNLOCK(asc);
16481000Sxc151355 
1649*3147Sxc151355 	return (0);
16501000Sxc151355 }
16511000Sxc151355 
16521000Sxc151355 static int
1653*3147Sxc151355 ath_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
16541000Sxc151355 {
1655*3147Sxc151355 	ath_t *asc = arg;
1656*3147Sxc151355 	struct ath_hal *ah = asc->asc_ah;
16571000Sxc151355 	uint32_t mfilt[2], val, rfilt;
16581000Sxc151355 	uint8_t pos;
16591000Sxc151355 
1660*3147Sxc151355 	ATH_LOCK(asc);
16611000Sxc151355 	rfilt = ATH_HAL_GETRXFILTER(ah);
16621000Sxc151355 
16631000Sxc151355 	/* disable multicast */
1664*3147Sxc151355 	if (!add) {
16651000Sxc151355 		ATH_HAL_SETRXFILTER(ah, rfilt & (~HAL_RX_FILTER_MCAST));
1666*3147Sxc151355 		ATH_UNLOCK(asc);
1667*3147Sxc151355 		return (0);
16681000Sxc151355 	}
16691000Sxc151355 
16701000Sxc151355 	/* enable multicast */
16711000Sxc151355 	ATH_HAL_SETRXFILTER(ah, rfilt | HAL_RX_FILTER_MCAST);
16721000Sxc151355 
16731000Sxc151355 	mfilt[0] = mfilt[1] = 0;
16741000Sxc151355 
16751000Sxc151355 	/* calculate XOR of eight 6bit values */
16761000Sxc151355 	val = ATH_LE_READ_4(mca + 0);
16771000Sxc151355 	pos = (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
16781000Sxc151355 	val = ATH_LE_READ_4(mca + 3);
16791000Sxc151355 	pos ^= (val >> 18) ^ (val >> 12) ^ (val >> 6) ^ val;
16801000Sxc151355 	pos &= 0x3f;
16811000Sxc151355 	mfilt[pos / 32] |= (1 << (pos % 32));
16821000Sxc151355 	ATH_HAL_SETMCASTFILTER(ah, mfilt[0], mfilt[1]);
16831000Sxc151355 
1684*3147Sxc151355 	ATH_UNLOCK(asc);
1685*3147Sxc151355 	return (0);
16861000Sxc151355 }
16871000Sxc151355 
16881000Sxc151355 static void
1689*3147Sxc151355 ath_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
16901000Sxc151355 {
1691*3147Sxc151355 	ath_t *asc = arg;
1692*3147Sxc151355 	int32_t err;
16931000Sxc151355 
1694*3147Sxc151355 	err = ieee80211_ioctl(&asc->asc_isc, wq, mp);
1695*3147Sxc151355 	ATH_LOCK(asc);
1696*3147Sxc151355 	if (err == ENETRESET) {
1697*3147Sxc151355 		if (ATH_IS_RUNNING(asc)) {
1698*3147Sxc151355 			ATH_UNLOCK(asc);
1699*3147Sxc151355 			(void) ath_m_start(asc);
1700*3147Sxc151355 			(void) ieee80211_new_state(&asc->asc_isc,
1701*3147Sxc151355 			    IEEE80211_S_SCAN, -1);
1702*3147Sxc151355 			ATH_LOCK(asc);
1703*3147Sxc151355 		}
17041000Sxc151355 	}
1705*3147Sxc151355 	ATH_UNLOCK(asc);
17061000Sxc151355 }
17071000Sxc151355 
17081000Sxc151355 static int
1709*3147Sxc151355 ath_m_stat(void *arg, uint_t stat, uint64_t *val)
17101000Sxc151355 {
1711*3147Sxc151355 	ath_t *asc = arg;
1712*3147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
1713*3147Sxc151355 	struct ieee80211_node *in = ic->ic_bss;
17141000Sxc151355 	struct ieee80211_rateset *rs = &in->in_rates;
17151000Sxc151355 
1716*3147Sxc151355 	ATH_LOCK(asc);
1717*3147Sxc151355 	switch (stat) {
1718*3147Sxc151355 	case MAC_STAT_IFSPEED:
1719*3147Sxc151355 		*val = (rs->ir_rates[in->in_txrate] & IEEE80211_RATE_VAL) / 2 *
1720*3147Sxc151355 		    1000000ull;
1721*3147Sxc151355 		break;
1722*3147Sxc151355 	case MAC_STAT_NOXMTBUF:
1723*3147Sxc151355 		*val = asc->asc_stats.ast_tx_nobuf +
1724*3147Sxc151355 		    asc->asc_stats.ast_tx_nobufmgt;
1725*3147Sxc151355 		break;
1726*3147Sxc151355 	case MAC_STAT_IERRORS:
1727*3147Sxc151355 		*val = asc->asc_stats.ast_rx_tooshort;
1728*3147Sxc151355 		break;
1729*3147Sxc151355 	case MAC_STAT_OERRORS:
1730*3147Sxc151355 		*val = asc->asc_stats.ast_tx_fifoerr +
1731*3147Sxc151355 		    asc->asc_stats.ast_tx_xretries;
1732*3147Sxc151355 		break;
1733*3147Sxc151355 	case MAC_STAT_RBYTES:
1734*3147Sxc151355 		*val = ic->ic_stats.is_rx_bytes;
1735*3147Sxc151355 		break;
1736*3147Sxc151355 	case MAC_STAT_IPACKETS:
1737*3147Sxc151355 		*val = ic->ic_stats.is_rx_frags;
1738*3147Sxc151355 		break;
1739*3147Sxc151355 	case MAC_STAT_OBYTES:
1740*3147Sxc151355 		*val = ic->ic_stats.is_tx_bytes;
1741*3147Sxc151355 		break;
1742*3147Sxc151355 	case MAC_STAT_OPACKETS:
1743*3147Sxc151355 		*val = ic->ic_stats.is_tx_frags;
1744*3147Sxc151355 		break;
1745*3147Sxc151355 	case WIFI_STAT_TX_FAILED:
1746*3147Sxc151355 		*val = asc->asc_stats.ast_tx_fifoerr +
1747*3147Sxc151355 			asc->asc_stats.ast_tx_xretries;
1748*3147Sxc151355 		break;
1749*3147Sxc151355 	case WIFI_STAT_TX_RETRANS:
1750*3147Sxc151355 		*val = asc->asc_stats.ast_tx_xretries;
1751*3147Sxc151355 		break;
1752*3147Sxc151355 	case WIFI_STAT_FCS_ERRORS:
1753*3147Sxc151355 		*val = asc->asc_stats.ast_rx_crcerr;
1754*3147Sxc151355 		break;
1755*3147Sxc151355 	case WIFI_STAT_WEP_ERRORS:
1756*3147Sxc151355 		*val = asc->asc_stats.ast_rx_badcrypt;
1757*3147Sxc151355 		break;
1758*3147Sxc151355 	case WIFI_STAT_TX_FRAGS:
1759*3147Sxc151355 	case WIFI_STAT_MCAST_TX:
1760*3147Sxc151355 	case WIFI_STAT_RTS_SUCCESS:
1761*3147Sxc151355 	case WIFI_STAT_RTS_FAILURE:
1762*3147Sxc151355 	case WIFI_STAT_ACK_FAILURE:
1763*3147Sxc151355 	case WIFI_STAT_RX_FRAGS:
1764*3147Sxc151355 	case WIFI_STAT_MCAST_RX:
1765*3147Sxc151355 	case WIFI_STAT_RX_DUPS:
1766*3147Sxc151355 		ATH_UNLOCK(asc);
1767*3147Sxc151355 		return (ieee80211_stat(ic, stat, val));
1768*3147Sxc151355 	default:
1769*3147Sxc151355 		ATH_UNLOCK(asc);
1770*3147Sxc151355 		return (ENOTSUP);
1771*3147Sxc151355 	}
1772*3147Sxc151355 	ATH_UNLOCK(asc);
17731000Sxc151355 
1774*3147Sxc151355 	return (0);
17751000Sxc151355 }
17761000Sxc151355 
17771000Sxc151355 static int
17781000Sxc151355 ath_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
17791000Sxc151355 {
17801000Sxc151355 	ath_t *asc;
1781*3147Sxc151355 	ieee80211com_t *ic;
17821000Sxc151355 	struct ath_hal *ah;
17831000Sxc151355 	uint8_t csz;
17841000Sxc151355 	HAL_STATUS status;
17851000Sxc151355 	caddr_t regs;
17861000Sxc151355 	uint32_t i, val;
17871000Sxc151355 	uint16_t vendor_id, device_id, command;
17881000Sxc151355 	const char *athname;
17891000Sxc151355 	int32_t ath_countrycode = CTRY_DEFAULT;	/* country code */
17901000Sxc151355 	int32_t err, ath_regdomain = 0; /* regulatory domain */
17911000Sxc151355 	char strbuf[32];
1792*3147Sxc151355 	int instance;
1793*3147Sxc151355 	wifi_data_t wd = { 0 };
1794*3147Sxc151355 	mac_register_t *macp;
17951000Sxc151355 
1796*3147Sxc151355 	if (cmd != DDI_ATTACH)
17971000Sxc151355 		return (DDI_FAILURE);
17981000Sxc151355 
1799*3147Sxc151355 	instance = ddi_get_instance(devinfo);
1800*3147Sxc151355 	if (ddi_soft_state_zalloc(ath_soft_state_p, instance) != DDI_SUCCESS) {
18011000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18021000Sxc151355 		    "Unable to alloc softstate\n"));
18031000Sxc151355 		return (DDI_FAILURE);
18041000Sxc151355 	}
18051000Sxc151355 
18061000Sxc151355 	asc = ddi_get_soft_state(ath_soft_state_p, ddi_get_instance(devinfo));
1807*3147Sxc151355 	ic = (ieee80211com_t *)asc;
18081000Sxc151355 	asc->asc_dev = devinfo;
18091000Sxc151355 
18101000Sxc151355 	mutex_init(&asc->asc_genlock, NULL, MUTEX_DRIVER, NULL);
18111000Sxc151355 	mutex_init(&asc->asc_txbuflock, NULL, MUTEX_DRIVER, NULL);
18121000Sxc151355 	mutex_init(&asc->asc_rxbuflock, NULL, MUTEX_DRIVER, NULL);
1813*3147Sxc151355 	mutex_init(&asc->asc_resched_lock, NULL, MUTEX_DRIVER, NULL);
18141000Sxc151355 
18151000Sxc151355 	err = pci_config_setup(devinfo, &asc->asc_cfg_handle);
18161000Sxc151355 	if (err != DDI_SUCCESS) {
18171000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18181000Sxc151355 		    "pci_config_setup() failed"));
18191000Sxc151355 		goto attach_fail0;
18201000Sxc151355 	}
18211000Sxc151355 
18221000Sxc151355 	csz = pci_config_get8(asc->asc_cfg_handle, PCI_CONF_CACHE_LINESZ);
18231000Sxc151355 	asc->asc_cachelsz = csz << 2;
18241000Sxc151355 	vendor_id = pci_config_get16(asc->asc_cfg_handle, PCI_CONF_VENID);
18251000Sxc151355 	device_id = pci_config_get16(asc->asc_cfg_handle, PCI_CONF_DEVID);
18261000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): vendor 0x%x, "
18271000Sxc151355 	    "device id 0x%x, cache size %d\n", vendor_id, device_id, csz));
18281000Sxc151355 
18291000Sxc151355 	athname = ath_hal_probe(vendor_id, device_id);
18301000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): athname: %s\n",
18311000Sxc151355 	    athname ? athname : "Atheros ???"));
18321000Sxc151355 
18331000Sxc151355 	/*
18341000Sxc151355 	 * Enable response to memory space accesses,
18351000Sxc151355 	 * and enabe bus master.
18361000Sxc151355 	 */
18371000Sxc151355 	command = PCI_COMM_MAE | PCI_COMM_ME;
18381000Sxc151355 	pci_config_put16(asc->asc_cfg_handle, PCI_CONF_COMM, command);
18391000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18401000Sxc151355 	    "set command reg to 0x%x \n", command));
18411000Sxc151355 
18421000Sxc151355 	pci_config_put8(asc->asc_cfg_handle, PCI_CONF_LATENCY_TIMER, 0xa8);
18431000Sxc151355 	val = pci_config_get32(asc->asc_cfg_handle, 0x40);
18441000Sxc151355 	if ((val & 0x0000ff00) != 0)
18451000Sxc151355 		pci_config_put32(asc->asc_cfg_handle, 0x40, val & 0xffff00ff);
18461000Sxc151355 
18471000Sxc151355 	err = ddi_regs_map_setup(devinfo, 1,
18481000Sxc151355 	    &regs, 0, 0, &ath_reg_accattr, &asc->asc_io_handle);
18491000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18501000Sxc151355 	    "regs map1 = %x err=%d\n", regs, err));
18511000Sxc151355 	if (err != DDI_SUCCESS) {
18521000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18531000Sxc151355 		    "ddi_regs_map_setup() failed"));
18541000Sxc151355 		goto attach_fail1;
18551000Sxc151355 	}
18561000Sxc151355 
18571000Sxc151355 	ah = ath_hal_attach(device_id, asc, 0, regs, &status);
18581000Sxc151355 	if (ah == NULL) {
18591000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18601000Sxc151355 		    "unable to attach hw; HAL status %u\n", status));
18611000Sxc151355 		goto attach_fail2;
18621000Sxc151355 	}
18631000Sxc151355 	ATH_HAL_INTRSET(ah, 0);
18641000Sxc151355 	asc->asc_ah = ah;
18651000Sxc151355 
18661000Sxc151355 	if (ah->ah_abi != HAL_ABI_VERSION) {
18671000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18681000Sxc151355 		    "HAL ABI mismatch detected (0x%x != 0x%x)\n",
18691000Sxc151355 		    ah->ah_abi, HAL_ABI_VERSION));
18701000Sxc151355 		goto attach_fail3;
18711000Sxc151355 	}
18721000Sxc151355 
18731000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18741000Sxc151355 	    "HAL ABI version 0x%x\n", ah->ah_abi));
18751000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18761000Sxc151355 	    "HAL mac version %d.%d, phy version %d.%d\n",
18771000Sxc151355 	    ah->ah_macVersion, ah->ah_macRev,
18781000Sxc151355 	    ah->ah_phyRev >> 4, ah->ah_phyRev & 0xf));
18791000Sxc151355 	if (ah->ah_analog5GhzRev)
18801000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18811000Sxc151355 		    "HAL 5ghz radio version %d.%d\n",
18821000Sxc151355 		    ah->ah_analog5GhzRev >> 4,
18831000Sxc151355 		    ah->ah_analog5GhzRev & 0xf));
18841000Sxc151355 	if (ah->ah_analog2GhzRev)
18851000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18861000Sxc151355 		    "HAL 2ghz radio version %d.%d\n",
18871000Sxc151355 		    ah->ah_analog2GhzRev >> 4,
18881000Sxc151355 		    ah->ah_analog2GhzRev & 0xf));
18891000Sxc151355 
18901000Sxc151355 	/*
18911000Sxc151355 	 * Check if the MAC has multi-rate retry support.
18921000Sxc151355 	 * We do this by trying to setup a fake extended
18931000Sxc151355 	 * descriptor.  MAC's that don't have support will
18941000Sxc151355 	 * return false w/o doing anything.  MAC's that do
18951000Sxc151355 	 * support it will return true w/o doing anything.
18961000Sxc151355 	 */
18971000Sxc151355 	asc->asc_mrretry = ATH_HAL_SETUPXTXDESC(ah, NULL, 0, 0, 0, 0, 0, 0);
18981000Sxc151355 	ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
18991000Sxc151355 	    "multi rate retry support=%x\n",
19001000Sxc151355 	    asc->asc_mrretry));
19011000Sxc151355 
19021000Sxc151355 	ATH_HAL_GETREGDOMAIN(ah, (uint32_t *)&ath_regdomain);
19031000Sxc151355 	ATH_HAL_GETCOUNTRYCODE(ah, &ath_countrycode);
19041000Sxc151355 	/*
19051000Sxc151355 	 * Collect the channel list using the default country
19061000Sxc151355 	 * code and including outdoor channels.  The 802.11 layer
19071000Sxc151355 	 * is resposible for filtering this list to a set of
19081000Sxc151355 	 * channels that it considers ok to use.
19091000Sxc151355 	 */
19101000Sxc151355 	asc->asc_have11g = 0;
19111000Sxc151355 
19121000Sxc151355 	/* enable outdoor use, enable extended channels */
19131000Sxc151355 	err = ath_getchannels(asc, ath_countrycode, AH_FALSE, AH_TRUE);
19141000Sxc151355 	if (err != 0)
19151000Sxc151355 		goto attach_fail3;
19161000Sxc151355 
19171000Sxc151355 	/*
19181000Sxc151355 	 * Setup rate tables for all potential media types.
19191000Sxc151355 	 */
19201000Sxc151355 	ath_rate_setup(asc, IEEE80211_MODE_11A);
19211000Sxc151355 	ath_rate_setup(asc, IEEE80211_MODE_11B);
19221000Sxc151355 	ath_rate_setup(asc, IEEE80211_MODE_11G);
1923*3147Sxc151355 	ath_rate_setup(asc, IEEE80211_MODE_TURBO_A);
19241000Sxc151355 
19251000Sxc151355 	/* Setup here so ath_rate_update is happy */
19261000Sxc151355 	ath_setcurmode(asc, IEEE80211_MODE_11A);
19271000Sxc151355 
19281000Sxc151355 	err = ath_desc_alloc(devinfo, asc);
19291000Sxc151355 	if (err != DDI_SUCCESS) {
19301000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
19311000Sxc151355 		    "failed to allocate descriptors: %d\n", err));
19321000Sxc151355 		goto attach_fail3;
19331000Sxc151355 	}
19341000Sxc151355 
19351000Sxc151355 	/* Setup transmit queues in the HAL */
19361000Sxc151355 	if (ath_txq_setup(asc))
19371000Sxc151355 		goto attach_fail4;
19381000Sxc151355 
1939*3147Sxc151355 	ATH_HAL_GETMAC(ah, ic->ic_macaddr);
19401000Sxc151355 
1941*3147Sxc151355 	/*
1942*3147Sxc151355 	 * Initialize pointers to device specific functions which
1943*3147Sxc151355 	 * will be used by the generic layer.
1944*3147Sxc151355 	 */
19451000Sxc151355 	/* 11g support is identified when we fetch the channel set */
19461000Sxc151355 	if (asc->asc_have11g)
1947*3147Sxc151355 		ic->ic_caps |= IEEE80211_C_SHPREAMBLE;
1948*3147Sxc151355 	/*
1949*3147Sxc151355 	 * Query the hal to figure out h/w crypto support.
1950*3147Sxc151355 	 */
1951*3147Sxc151355 	if (ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_WEP))
1952*3147Sxc151355 		ic->ic_caps |= IEEE80211_C_WEP;
1953*3147Sxc151355 	if (ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_AES_OCB))
1954*3147Sxc151355 		ic->ic_caps |= IEEE80211_C_AES;
1955*3147Sxc151355 	if (ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_AES_CCM))
1956*3147Sxc151355 		ic->ic_caps |= IEEE80211_C_AES_CCM;
1957*3147Sxc151355 	if (ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_CKIP)) {
1958*3147Sxc151355 		ic->ic_caps |= IEEE80211_C_CKIP;
1959*3147Sxc151355 		/*
1960*3147Sxc151355 		 * Check if h/w does the MIC and/or whether the
1961*3147Sxc151355 		 * separate key cache entries are required to
1962*3147Sxc151355 		 * handle both tx+rx MIC keys.
1963*3147Sxc151355 		 */
1964*3147Sxc151355 		if (ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_MIC))
1965*3147Sxc151355 			ic->ic_caps |= IEEE80211_C_TKIPMIC;
1966*3147Sxc151355 		if (ATH_HAL_TKIPSPLIT(ah))
1967*3147Sxc151355 			asc->asc_splitmic = 1;
1968*3147Sxc151355 	}
1969*3147Sxc151355 	asc->asc_hasclrkey = ATH_HAL_CIPHERSUPPORTED(ah, HAL_CIPHER_CLR);
1970*3147Sxc151355 	ic->ic_phytype = IEEE80211_T_OFDM;
1971*3147Sxc151355 	ic->ic_opmode = IEEE80211_M_STA;
1972*3147Sxc151355 	ic->ic_state = IEEE80211_S_INIT;
1973*3147Sxc151355 	ic->ic_maxrssi = ATH_MAX_RSSI;
1974*3147Sxc151355 	ic->ic_set_shortslot = ath_set_shortslot;
1975*3147Sxc151355 	ic->ic_xmit = ath_xmit;
1976*3147Sxc151355 	ieee80211_attach(ic);
19771000Sxc151355 
1978*3147Sxc151355 	/* Override 80211 default routines */
1979*3147Sxc151355 	ic->ic_reset = ath_reset;
1980*3147Sxc151355 	asc->asc_newstate = ic->ic_newstate;
1981*3147Sxc151355 	ic->ic_newstate = ath_newstate;
1982*3147Sxc151355 	ic->ic_watchdog = ath_watchdog;
1983*3147Sxc151355 	ic->ic_node_alloc = ath_node_alloc;
1984*3147Sxc151355 	ic->ic_node_free = ath_node_free;
1985*3147Sxc151355 	ic->ic_crypto.cs_key_alloc = ath_key_alloc;
1986*3147Sxc151355 	ic->ic_crypto.cs_key_delete = ath_key_delete;
1987*3147Sxc151355 	ic->ic_crypto.cs_key_set = ath_key_set;
1988*3147Sxc151355 	ieee80211_media_init(ic);
19891000Sxc151355 
19901000Sxc151355 	asc->asc_rx_pend = 0;
19911000Sxc151355 	ATH_HAL_INTRSET(ah, 0);
19921000Sxc151355 	err = ddi_add_softintr(devinfo, DDI_SOFTINT_LOW,
19931000Sxc151355 	    &asc->asc_softint_id, NULL, 0, ath_softint_handler, (caddr_t)asc);
19941000Sxc151355 	if (err != DDI_SUCCESS) {
19951000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
1996*3147Sxc151355 		    "ddi_add_softintr() failed\n"));
19971000Sxc151355 		goto attach_fail5;
19981000Sxc151355 	}
19991000Sxc151355 
20001000Sxc151355 	if (ddi_get_iblock_cookie(devinfo, 0, &asc->asc_iblock)
20011000Sxc151355 	    != DDI_SUCCESS) {
20021000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
20031000Sxc151355 		    "Can not get iblock cookie for INT\n"));
20041000Sxc151355 		goto attach_fail6;
20051000Sxc151355 	}
20061000Sxc151355 
2007*3147Sxc151355 	if (ddi_add_intr(devinfo, 0, NULL, NULL, ath_intr,
2008*3147Sxc151355 	    (caddr_t)asc) != DDI_SUCCESS) {
20091000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
20101000Sxc151355 		    "Can not set intr for ATH driver\n"));
20111000Sxc151355 		goto attach_fail6;
20121000Sxc151355 	}
2013*3147Sxc151355 
2014*3147Sxc151355 	/*
2015*3147Sxc151355 	 * Provide initial settings for the WiFi plugin; whenever this
2016*3147Sxc151355 	 * information changes, we need to call mac_plugindata_update()
2017*3147Sxc151355 	 */
2018*3147Sxc151355 	wd.wd_opmode = ic->ic_opmode;
2019*3147Sxc151355 	wd.wd_secalloc = WIFI_SEC_NONE;
2020*3147Sxc151355 	IEEE80211_ADDR_COPY(wd.wd_bssid, ic->ic_bss->in_bssid);
2021*3147Sxc151355 
2022*3147Sxc151355 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
2023*3147Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
2024*3147Sxc151355 		    "MAC version mismatch\n"));
2025*3147Sxc151355 		goto attach_fail7;
2026*3147Sxc151355 	}
20271000Sxc151355 
2028*3147Sxc151355 	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
2029*3147Sxc151355 	macp->m_driver		= asc;
2030*3147Sxc151355 	macp->m_dip		= devinfo;
2031*3147Sxc151355 	macp->m_src_addr	= ic->ic_macaddr;
2032*3147Sxc151355 	macp->m_callbacks	= &ath_m_callbacks;
2033*3147Sxc151355 	macp->m_min_sdu		= 0;
2034*3147Sxc151355 	macp->m_max_sdu		= IEEE80211_MTU;
2035*3147Sxc151355 	macp->m_pdata		= &wd;
2036*3147Sxc151355 	macp->m_pdata_size	= sizeof (wd);
2037*3147Sxc151355 
2038*3147Sxc151355 	err = mac_register(macp, &ic->ic_mach);
2039*3147Sxc151355 	mac_free(macp);
2040*3147Sxc151355 	if (err != 0) {
20411000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "ath: ath_attach(): "
2042*3147Sxc151355 		    "mac_register err %x\n", err));
20431000Sxc151355 		goto attach_fail7;
20441000Sxc151355 	}
20451000Sxc151355 
20461000Sxc151355 	/* Create minor node of type DDI_NT_NET_WIFI */
20471000Sxc151355 	(void) snprintf(strbuf, sizeof (strbuf), "%s%d",
2048*3147Sxc151355 	    ATH_NODENAME, instance);
20491000Sxc151355 	err = ddi_create_minor_node(devinfo, strbuf, S_IFCHR,
2050*3147Sxc151355 	    instance + 1, DDI_NT_NET_WIFI, 0);
20511000Sxc151355 	if (err != DDI_SUCCESS)
20521000Sxc151355 		ATH_DEBUG((ATH_DBG_ATTACH, "WARN: ath: ath_attach(): "
20531000Sxc151355 		    "Create minor node failed - %d\n", err));
20541000Sxc151355 
2055*3147Sxc151355 	mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
20561000Sxc151355 	asc->asc_invalid = 1;
20571000Sxc151355 	return (DDI_SUCCESS);
20581000Sxc151355 attach_fail7:
20591000Sxc151355 	ddi_remove_intr(devinfo, 0, asc->asc_iblock);
20601000Sxc151355 attach_fail6:
20611000Sxc151355 	ddi_remove_softintr(asc->asc_softint_id);
20621000Sxc151355 attach_fail5:
2063*3147Sxc151355 	(void) ieee80211_detach(ic);
20641000Sxc151355 attach_fail4:
20651000Sxc151355 	ath_desc_free(asc);
20661000Sxc151355 attach_fail3:
20671000Sxc151355 	ah->ah_detach(asc->asc_ah);
20681000Sxc151355 attach_fail2:
20691000Sxc151355 	ddi_regs_map_free(&asc->asc_io_handle);
20701000Sxc151355 attach_fail1:
20711000Sxc151355 	pci_config_teardown(&asc->asc_cfg_handle);
20721000Sxc151355 attach_fail0:
20731000Sxc151355 	asc->asc_invalid = 1;
20741000Sxc151355 	mutex_destroy(&asc->asc_txbuflock);
20751000Sxc151355 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
20761000Sxc151355 		if (ATH_TXQ_SETUP(asc, i)) {
20771000Sxc151355 			struct ath_txq *txq = &asc->asc_txq[i];
20781000Sxc151355 			mutex_destroy(&txq->axq_lock);
20791000Sxc151355 		}
20801000Sxc151355 	}
20811000Sxc151355 	mutex_destroy(&asc->asc_rxbuflock);
20821000Sxc151355 	mutex_destroy(&asc->asc_genlock);
2083*3147Sxc151355 	mutex_destroy(&asc->asc_resched_lock);
2084*3147Sxc151355 	ddi_soft_state_free(ath_soft_state_p, instance);
20851000Sxc151355 
20861000Sxc151355 	return (DDI_FAILURE);
20871000Sxc151355 }
20881000Sxc151355 
20891000Sxc151355 static int32_t
20901000Sxc151355 ath_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
20911000Sxc151355 {
20921000Sxc151355 	ath_t *asc;
20931000Sxc151355 
20941000Sxc151355 	asc = ddi_get_soft_state(ath_soft_state_p, ddi_get_instance(devinfo));
20951000Sxc151355 	ASSERT(asc != NULL);
20961000Sxc151355 
2097*3147Sxc151355 	if (cmd != DDI_DETACH)
20981000Sxc151355 		return (DDI_FAILURE);
20991000Sxc151355 
2100*3147Sxc151355 	ath_stop_scantimer(asc);
21011000Sxc151355 
21021000Sxc151355 	/* disable interrupts */
21031000Sxc151355 	ATH_HAL_INTRSET(asc->asc_ah, 0);
21041000Sxc151355 
2105*3147Sxc151355 	/*
2106*3147Sxc151355 	 * Unregister from the MAC layer subsystem
2107*3147Sxc151355 	 */
2108*3147Sxc151355 	if (mac_unregister(asc->asc_isc.ic_mach) != 0)
2109*3147Sxc151355 		return (DDI_FAILURE);
2110*3147Sxc151355 
21111000Sxc151355 	/* free intterrupt resources */
21121000Sxc151355 	ddi_remove_intr(devinfo, 0, asc->asc_iblock);
21131000Sxc151355 	ddi_remove_softintr(asc->asc_softint_id);
21141000Sxc151355 
2115*3147Sxc151355 	/*
2116*3147Sxc151355 	 * NB: the order of these is important:
2117*3147Sxc151355 	 * o call the 802.11 layer before detaching the hal to
2118*3147Sxc151355 	 *   insure callbacks into the driver to delete global
2119*3147Sxc151355 	 *   key cache entries can be handled
2120*3147Sxc151355 	 * o reclaim the tx queue data structures after calling
2121*3147Sxc151355 	 *   the 802.11 layer as we'll get called back to reclaim
2122*3147Sxc151355 	 *   node state and potentially want to use them
2123*3147Sxc151355 	 * o to cleanup the tx queues the hal is called, so detach
2124*3147Sxc151355 	 *   it last
2125*3147Sxc151355 	 */
2126*3147Sxc151355 	ieee80211_detach(&asc->asc_isc);
21271000Sxc151355 	ath_desc_free(asc);
2128*3147Sxc151355 	ath_txq_cleanup(asc);
21291000Sxc151355 	asc->asc_ah->ah_detach(asc->asc_ah);
21301000Sxc151355 
21311000Sxc151355 	/* free io handle */
21321000Sxc151355 	ddi_regs_map_free(&asc->asc_io_handle);
21331000Sxc151355 	pci_config_teardown(&asc->asc_cfg_handle);
21341000Sxc151355 
21351000Sxc151355 	/* destroy locks */
21361000Sxc151355 	mutex_destroy(&asc->asc_rxbuflock);
21371000Sxc151355 	mutex_destroy(&asc->asc_genlock);
2138*3147Sxc151355 	mutex_destroy(&asc->asc_resched_lock);
21391000Sxc151355 
21401000Sxc151355 	ddi_remove_minor_node(devinfo, NULL);
21411000Sxc151355 	ddi_soft_state_free(ath_soft_state_p, ddi_get_instance(devinfo));
21421000Sxc151355 
21431000Sxc151355 	return (DDI_SUCCESS);
21441000Sxc151355 }
21451000Sxc151355 
2146*3147Sxc151355 DDI_DEFINE_STREAM_OPS(ath_dev_ops, nulldev, nulldev, ath_attach, ath_detach,
2147*3147Sxc151355     nodev, NULL, D_MP, NULL);
21481000Sxc151355 
21491000Sxc151355 static struct modldrv ath_modldrv = {
21501000Sxc151355 	&mod_driverops,		/* Type of module.  This one is a driver */
2151*3147Sxc151355 	"ath driver 1.2/HAL 0.9.17.2",	/* short description */
21521000Sxc151355 	&ath_dev_ops		/* driver specific ops */
21531000Sxc151355 };
21541000Sxc151355 
21551000Sxc151355 static struct modlinkage modlinkage = {
21561000Sxc151355 	MODREV_1, (void *)&ath_modldrv, NULL
21571000Sxc151355 };
21581000Sxc151355 
21591000Sxc151355 
21601000Sxc151355 int
21611000Sxc151355 _info(struct modinfo *modinfop)
21621000Sxc151355 {
21631000Sxc151355 	return (mod_info(&modlinkage, modinfop));
21641000Sxc151355 }
21651000Sxc151355 
21661000Sxc151355 int
21671000Sxc151355 _init(void)
21681000Sxc151355 {
21691000Sxc151355 	int status;
21701000Sxc151355 
21711000Sxc151355 	status = ddi_soft_state_init(&ath_soft_state_p, sizeof (ath_t), 1);
21721000Sxc151355 	if (status != 0)
21731000Sxc151355 		return (status);
21741000Sxc151355 
21751000Sxc151355 	mutex_init(&ath_loglock, NULL, MUTEX_DRIVER, NULL);
2176*3147Sxc151355 	ath_halfix_init();
2177*3147Sxc151355 	mac_init_ops(&ath_dev_ops, "ath");
21781000Sxc151355 	status = mod_install(&modlinkage);
21791000Sxc151355 	if (status != 0) {
2180*3147Sxc151355 		mac_fini_ops(&ath_dev_ops);
2181*3147Sxc151355 		ath_halfix_finit();
2182*3147Sxc151355 		mutex_destroy(&ath_loglock);
21831000Sxc151355 		ddi_soft_state_fini(&ath_soft_state_p);
21841000Sxc151355 	}
21851000Sxc151355 
21861000Sxc151355 	return (status);
21871000Sxc151355 }
21881000Sxc151355 
21891000Sxc151355 int
21901000Sxc151355 _fini(void)
21911000Sxc151355 {
21921000Sxc151355 	int status;
21931000Sxc151355 
21941000Sxc151355 	status = mod_remove(&modlinkage);
21951000Sxc151355 	if (status == 0) {
2196*3147Sxc151355 		mac_fini_ops(&ath_dev_ops);
2197*3147Sxc151355 		ath_halfix_finit();
2198*3147Sxc151355 		mutex_destroy(&ath_loglock);
21991000Sxc151355 		ddi_soft_state_fini(&ath_soft_state_p);
22001000Sxc151355 	}
22011000Sxc151355 	return (status);
22021000Sxc151355 }
2203