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 ®s, 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