11000Sxc151355 /* 26235Sxc151355 * Copyright 2008 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 #pragma ident "%Z%%M% %I% %E% SMI" 391000Sxc151355 401000Sxc151355 #include <sys/param.h> 411000Sxc151355 #include <sys/types.h> 421000Sxc151355 #include <sys/signal.h> 431000Sxc151355 #include <sys/stream.h> 441000Sxc151355 #include <sys/termio.h> 451000Sxc151355 #include <sys/errno.h> 461000Sxc151355 #include <sys/file.h> 471000Sxc151355 #include <sys/cmn_err.h> 481000Sxc151355 #include <sys/stropts.h> 491000Sxc151355 #include <sys/strsubr.h> 501000Sxc151355 #include <sys/strtty.h> 511000Sxc151355 #include <sys/kbio.h> 521000Sxc151355 #include <sys/cred.h> 531000Sxc151355 #include <sys/stat.h> 541000Sxc151355 #include <sys/consdev.h> 551000Sxc151355 #include <sys/kmem.h> 561000Sxc151355 #include <sys/modctl.h> 571000Sxc151355 #include <sys/ddi.h> 581000Sxc151355 #include <sys/sunddi.h> 591000Sxc151355 #include <sys/pci.h> 601000Sxc151355 #include <sys/errno.h> 611000Sxc151355 #include <sys/gld.h> 621000Sxc151355 #include <sys/dlpi.h> 631000Sxc151355 #include <sys/ethernet.h> 641000Sxc151355 #include <sys/list.h> 651000Sxc151355 #include <sys/byteorder.h> 661000Sxc151355 #include <sys/strsun.h> 671000Sxc151355 #include <inet/common.h> 681000Sxc151355 #include <inet/nd.h> 691000Sxc151355 #include <inet/mi.h> 701000Sxc151355 #include <inet/wifi_ioctl.h> 711000Sxc151355 #include "ath_hal.h" 721000Sxc151355 #include "ath_impl.h" 731000Sxc151355 741000Sxc151355 static const char *acnames[] = { 751000Sxc151355 "WME_AC_BE", 761000Sxc151355 "WME_AC_BK", 771000Sxc151355 "WME_AC_VI", 781000Sxc151355 "WME_AC_VO", 791000Sxc151355 "WME_UPSD" 801000Sxc151355 }; 811000Sxc151355 821000Sxc151355 extern void ath_setup_desc(ath_t *asc, struct ath_buf *bf); 831000Sxc151355 846235Sxc151355 856235Sxc151355 const char * 866235Sxc151355 ath_get_hal_status_desc(HAL_STATUS status) 876235Sxc151355 { 886235Sxc151355 static const char *hal_status_desc[] = { 896235Sxc151355 "No error", 906235Sxc151355 "No hardware present or device not yet supported", 916235Sxc151355 "Memory allocation failed", 926235Sxc151355 "Hardware didn't respond as expected", 936235Sxc151355 "EEPROM magic number invalid", 946235Sxc151355 "EEPROM version invalid", 956235Sxc151355 "EEPROM unreadable", 966235Sxc151355 "EEPROM checksum invalid", 976235Sxc151355 "EEPROM read problem", 986235Sxc151355 "EEPROM mac address invalid", 996235Sxc151355 "EEPROM size not supported", 1006235Sxc151355 "Attempt to change write-locked EEPROM", 1016235Sxc151355 "Invalid parameter to function", 1026235Sxc151355 "Hardware revision not supported", 1036235Sxc151355 "Hardware self-test failed", 1046235Sxc151355 "Operation incomplete" 1056235Sxc151355 }; 1066235Sxc151355 1076235Sxc151355 if (status >= 0 && status < sizeof (hal_status_desc)/sizeof (char *)) 1086235Sxc151355 return (hal_status_desc[status]); 1096235Sxc151355 else 1106235Sxc151355 return (""); 1116235Sxc151355 } 1126235Sxc151355 1131000Sxc151355 uint32_t 1141000Sxc151355 ath_calcrxfilter(ath_t *asc) 1151000Sxc151355 { 1163147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 1171000Sxc151355 struct ath_hal *ah = asc->asc_ah; 1181000Sxc151355 uint32_t rfilt; 1191000Sxc151355 1201000Sxc151355 rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR) 1211000Sxc151355 | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 1223147Sxc151355 if (ic->ic_opmode != IEEE80211_M_STA) 1231000Sxc151355 rfilt |= HAL_RX_FILTER_PROBEREQ; 1246235Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP && asc->asc_promisc) 1256235Sxc151355 rfilt |= HAL_RX_FILTER_PROM; /* promiscuous */ 1263147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA || 1273147Sxc151355 ic->ic_opmode == IEEE80211_M_IBSS || 1283147Sxc151355 ic->ic_state == IEEE80211_S_SCAN) 1291000Sxc151355 rfilt |= HAL_RX_FILTER_BEACON; 1301000Sxc151355 return (rfilt); 1311000Sxc151355 } 1321000Sxc151355 1331000Sxc151355 static int 1341000Sxc151355 ath_set_data_queue(ath_t *asc, int ac, int haltype) 1351000Sxc151355 { 1361000Sxc151355 HAL_TXQ_INFO qi; 1371000Sxc151355 int qnum; 1381000Sxc151355 struct ath_hal *ah = asc->asc_ah; 1391000Sxc151355 struct ath_txq *txq; 1401000Sxc151355 1411000Sxc151355 if (ac >= ATH_N(asc->asc_ac2q)) { 1421000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1431000Sxc151355 "ac %u out of range, max %u!\n", 1441000Sxc151355 ac, ATH_N(asc->asc_ac2q))); 1451000Sxc151355 return (1); 1461000Sxc151355 } 1471000Sxc151355 (void) memset(&qi, 0, sizeof (qi)); 1481000Sxc151355 qi.tqi_subtype = haltype; 1491000Sxc151355 /* 1501000Sxc151355 * Enable interrupts only for EOL and DESC conditions. 1511000Sxc151355 * We mark tx descriptors to receive a DESC interrupt 1521000Sxc151355 * when a tx queue gets deep; otherwise waiting for the 1531000Sxc151355 * EOL to reap descriptors. Note that this is done to 1541000Sxc151355 * reduce interrupt load and this only defers reaping 1551000Sxc151355 * descriptors, never transmitting frames. Aside from 1561000Sxc151355 * reducing interrupts this also permits more concurrency. 1571000Sxc151355 * The only potential downside is if the tx queue backs 1581000Sxc151355 * up in which case the top half of the kernel may backup 1591000Sxc151355 * due to a lack of tx descriptors. 1601000Sxc151355 */ 1613147Sxc151355 qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; 1621000Sxc151355 qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi); 1631000Sxc151355 if (qnum == -1) { 1641000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1651000Sxc151355 "Unable to setup hardware queue for %s traffic!\n", 1661000Sxc151355 acnames[ac])); 1671000Sxc151355 return (1); 1681000Sxc151355 } 1691000Sxc151355 if (qnum >= ATH_N(asc->asc_txq)) { 1701000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1711000Sxc151355 "hal qnum %u out of range, max %u!\n", 1721000Sxc151355 qnum, ATH_N(asc->asc_txq))); 1731000Sxc151355 return (1); 1741000Sxc151355 } 1751000Sxc151355 if (!ATH_TXQ_SETUP(asc, qnum)) { 1761000Sxc151355 txq = &asc->asc_txq[qnum]; 1771000Sxc151355 txq->axq_qnum = qnum; 1781000Sxc151355 txq->axq_depth = 0; 1791000Sxc151355 txq->axq_intrcnt = 0; 1801000Sxc151355 txq->axq_link = NULL; 1811000Sxc151355 list_create(&txq->axq_list, sizeof (struct ath_buf), 1821000Sxc151355 offsetof(struct ath_buf, bf_node)); 1831000Sxc151355 mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL); 1841000Sxc151355 asc->asc_txqsetup |= 1<<qnum; 1851000Sxc151355 } 1861000Sxc151355 asc->asc_ac2q[ac] = &asc->asc_txq[qnum]; 1871000Sxc151355 return (0); 1881000Sxc151355 } 1891000Sxc151355 1901000Sxc151355 int 1911000Sxc151355 ath_txq_setup(ath_t *asc) 1921000Sxc151355 { 1931000Sxc151355 if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) || 1941000Sxc151355 ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) || 1951000Sxc151355 ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) || 1961000Sxc151355 ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) { 1971000Sxc151355 return (1); 1981000Sxc151355 } 1991000Sxc151355 2001000Sxc151355 return (0); 2011000Sxc151355 } 2021000Sxc151355 2031000Sxc151355 void 2043147Sxc151355 ath_txq_cleanup(ath_t *asc) 2053147Sxc151355 { 2063147Sxc151355 int i; 2073147Sxc151355 2083147Sxc151355 mutex_destroy(&asc->asc_txbuflock); 2093147Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 2103147Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 2113147Sxc151355 struct ath_txq *txq = &asc->asc_txq[i]; 2123147Sxc151355 2133147Sxc151355 ATH_HAL_RELEASETXQUEUE(asc->asc_ah, txq->axq_qnum); 2143147Sxc151355 mutex_destroy(&txq->axq_lock); 2153147Sxc151355 asc->asc_txqsetup &= ~(1 << txq->axq_qnum); 2163147Sxc151355 } 2173147Sxc151355 } 2183147Sxc151355 } 2193147Sxc151355 2203147Sxc151355 void 2211000Sxc151355 ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode) 2221000Sxc151355 { 2231000Sxc151355 const HAL_RATE_TABLE *rt; 2241000Sxc151355 int i; 2251000Sxc151355 2261000Sxc151355 for (i = 0; i < sizeof (asc->asc_rixmap); i++) 2271000Sxc151355 asc->asc_rixmap[i] = 0xff; 2281000Sxc151355 2291000Sxc151355 rt = asc->asc_rates[mode]; 2301000Sxc151355 ASSERT(rt != NULL); 2311000Sxc151355 2321000Sxc151355 for (i = 0; i < rt->rateCount; i++) 2331000Sxc151355 asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; 2341000Sxc151355 2351000Sxc151355 asc->asc_currates = rt; 2361000Sxc151355 asc->asc_curmode = mode; 2371000Sxc151355 } 2381000Sxc151355 2391000Sxc151355 /* Set correct parameters for a certain mode */ 2401000Sxc151355 void 2411000Sxc151355 ath_mode_init(ath_t *asc) 2421000Sxc151355 { 2433147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 2441000Sxc151355 struct ath_hal *ah = asc->asc_ah; 2451000Sxc151355 uint32_t rfilt; 2461000Sxc151355 2471000Sxc151355 /* configure rx filter */ 2481000Sxc151355 rfilt = ath_calcrxfilter(asc); 2491000Sxc151355 ATH_HAL_SETRXFILTER(ah, rfilt); 2501000Sxc151355 ATH_HAL_SETOPMODE(ah); 2516235Sxc151355 ATH_HAL_SETMCASTFILTER(ah, asc->asc_mcast_hash[0], 2526235Sxc151355 asc->asc_mcast_hash[1]); 2531000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): " 2541000Sxc151355 "mode =%d RX filter 0x%x, MC filter %08x:%08x\n", 2553147Sxc151355 ic->ic_opmode, rfilt, 2566235Sxc151355 asc->asc_mcast_hash[0], asc->asc_mcast_hash[1])); 2571000Sxc151355 } 2581000Sxc151355 2591000Sxc151355 /* 2601000Sxc151355 * Disable the receive h/w in preparation for a reset. 2611000Sxc151355 */ 2621000Sxc151355 void 2631000Sxc151355 ath_stoprecv(ath_t *asc) 2641000Sxc151355 { 2651000Sxc151355 ATH_HAL_STOPPCURECV(asc->asc_ah); /* disable PCU */ 2661000Sxc151355 ATH_HAL_SETRXFILTER(asc->asc_ah, 0); /* clear recv filter */ 2671000Sxc151355 ATH_HAL_STOPDMARECV(asc->asc_ah); /* disable DMA engine */ 2681000Sxc151355 drv_usecwait(3000); 2691000Sxc151355 2701000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n", 2711000Sxc151355 ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink)); 2721000Sxc151355 asc->asc_rxlink = NULL; 2731000Sxc151355 } 2741000Sxc151355 2751000Sxc151355 uint32_t 2763147Sxc151355 ath_chan2flags(ieee80211com_t *isc, struct ieee80211_channel *chan) 2771000Sxc151355 { 2781000Sxc151355 static const uint32_t modeflags[] = { 2791000Sxc151355 0, /* IEEE80211_MODE_AUTO */ 2801000Sxc151355 CHANNEL_A, /* IEEE80211_MODE_11A */ 2811000Sxc151355 CHANNEL_B, /* IEEE80211_MODE_11B */ 2821000Sxc151355 CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 2833147Sxc151355 0, /* IEEE80211_MODE_FH */ 2843147Sxc151355 CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */ 2853147Sxc151355 CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ 2861000Sxc151355 }; 2871000Sxc151355 return (modeflags[ieee80211_chan2mode(isc, chan)]); 2881000Sxc151355 } 2891000Sxc151355 2901000Sxc151355 2911000Sxc151355 int 2921000Sxc151355 ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) 2931000Sxc151355 { 2943147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 2951000Sxc151355 struct ath_hal *ah = asc->asc_ah; 2961000Sxc151355 HAL_CHANNEL *chans; 2971000Sxc151355 int i, ix; 2981000Sxc151355 uint32_t nchan; 2991000Sxc151355 3001000Sxc151355 chans = (HAL_CHANNEL *) 3011000Sxc151355 kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP); 3021000Sxc151355 3031000Sxc151355 if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, 3043147Sxc151355 NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) { 3051000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 3066235Sxc151355 "unable to get channel list\n")); 3076235Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL)); 3081000Sxc151355 return (EINVAL); 3091000Sxc151355 } 3101000Sxc151355 3111000Sxc151355 /* 3121000Sxc151355 * Convert HAL channels to ieee80211 ones and insert 3131000Sxc151355 * them in the table according to their channel number. 3141000Sxc151355 */ 3151000Sxc151355 for (i = 0; i < nchan; i++) { 3161000Sxc151355 HAL_CHANNEL *c = &chans[i]; 3173147Sxc151355 uint16_t flags; 3183147Sxc151355 ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags); 3191000Sxc151355 if (ix > IEEE80211_CHAN_MAX) { 3201000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 3213147Sxc151355 "bad hal channel %d (%u/%x) ignored\n", 3221000Sxc151355 ix, c->channel, c->channelFlags)); 3231000Sxc151355 continue; 3241000Sxc151355 } 3251000Sxc151355 /* NB: flags are known to be compatible */ 3263147Sxc151355 if (ix < 0) { 3273147Sxc151355 /* 3283147Sxc151355 * can't handle frequency <2400MHz (negative 3293147Sxc151355 * channels) right now 3303147Sxc151355 */ 3313147Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath:ath_getchannels(): " 3323147Sxc151355 "hal channel %d (%u/%x) " 3333147Sxc151355 "cannot be handled, ignored\n", 3343147Sxc151355 ix, c->channel, c->channelFlags)); 3353147Sxc151355 continue; 3363147Sxc151355 } 3373147Sxc151355 /* 3383147Sxc151355 * Calculate net80211 flags; most are compatible 3393147Sxc151355 * but some need massaging. Note the static turbo 3403147Sxc151355 * conversion can be removed once net80211 is updated 3413147Sxc151355 * to understand static vs. dynamic turbo. 3423147Sxc151355 */ 3433147Sxc151355 flags = c->channelFlags & CHANNEL_COMPAT; 3443147Sxc151355 if (c->channelFlags & CHANNEL_STURBO) 3453147Sxc151355 flags |= IEEE80211_CHAN_TURBO; 3463147Sxc151355 if (ic->ic_sup_channels[ix].ich_freq == 0) { 3473147Sxc151355 ic->ic_sup_channels[ix].ich_freq = c->channel; 3483147Sxc151355 ic->ic_sup_channels[ix].ich_flags = flags; 3491000Sxc151355 } else { 3501000Sxc151355 /* channels overlap; e.g. 11g and 11b */ 3513147Sxc151355 ic->ic_sup_channels[ix].ich_flags |= flags; 3521000Sxc151355 } 3531000Sxc151355 if ((c->channelFlags & CHANNEL_G) == CHANNEL_G) 3541000Sxc151355 asc->asc_have11g = 1; 3551000Sxc151355 } 3561000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL)); 3571000Sxc151355 return (0); 3581000Sxc151355 } 3591000Sxc151355 3601000Sxc151355 static void 3611000Sxc151355 ath_drainq(ath_t *asc, struct ath_txq *txq) 3621000Sxc151355 { 3631000Sxc151355 struct ath_buf *bf; 3641000Sxc151355 3651000Sxc151355 /* 3661000Sxc151355 * This assumes output has been stopped. 3671000Sxc151355 */ 3681000Sxc151355 for (;;) { 3691000Sxc151355 mutex_enter(&txq->axq_lock); 3701000Sxc151355 bf = list_head(&txq->axq_list); 3711000Sxc151355 if (bf == NULL) { 3721000Sxc151355 txq->axq_link = NULL; 3731000Sxc151355 mutex_exit(&txq->axq_lock); 3741000Sxc151355 break; 3751000Sxc151355 } 3761000Sxc151355 list_remove(&txq->axq_list, bf); 3771000Sxc151355 mutex_exit(&txq->axq_lock); 3781000Sxc151355 bf->bf_in = NULL; 3791000Sxc151355 mutex_enter(&asc->asc_txbuflock); 3801000Sxc151355 list_insert_tail(&asc->asc_txbuf_list, bf); 3811000Sxc151355 mutex_exit(&asc->asc_txbuflock); 3821000Sxc151355 } 3831000Sxc151355 } 3841000Sxc151355 3851000Sxc151355 3861000Sxc151355 /* 3871000Sxc151355 * Drain the transmit queues and reclaim resources. 3881000Sxc151355 */ 3891000Sxc151355 void 3901000Sxc151355 ath_draintxq(ath_t *asc) 3911000Sxc151355 { 3921000Sxc151355 struct ath_hal *ah = asc->asc_ah; 3931000Sxc151355 struct ath_txq *txq; 3941000Sxc151355 int i; 3951000Sxc151355 3961000Sxc151355 if (!asc->asc_invalid) { 3971000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 3981000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 3991000Sxc151355 txq = &asc->asc_txq[i]; 4001000Sxc151355 (void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum); 4011000Sxc151355 } 4021000Sxc151355 } 4031000Sxc151355 } 4041000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 4051000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 4061000Sxc151355 ath_drainq(asc, &asc->asc_txq[i]); 4071000Sxc151355 } 4081000Sxc151355 } 4091000Sxc151355 } 4101000Sxc151355 4111000Sxc151355 4121000Sxc151355 /* Enable the receive h/w following a reset */ 4131000Sxc151355 int 4141000Sxc151355 ath_startrecv(ath_t *asc) 4151000Sxc151355 { 4161000Sxc151355 struct ath_buf *bf; 4171000Sxc151355 4181000Sxc151355 asc->asc_rxlink = NULL; 4191000Sxc151355 4201000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 4211000Sxc151355 while (bf != NULL) { 4221000Sxc151355 ath_setup_desc(asc, bf); 4231000Sxc151355 bf = list_next(&asc->asc_rxbuf_list, bf); 4241000Sxc151355 } 4251000Sxc151355 4261000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 4271000Sxc151355 ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr); 4281000Sxc151355 ATH_HAL_RXENA(asc->asc_ah); /* enable recv descriptors */ 4291000Sxc151355 ath_mode_init(asc); /* set filters, etc. */ 4301000Sxc151355 ATH_HAL_STARTPCURECV(asc->asc_ah); /* re-enable PCU/DMA engine */ 4311000Sxc151355 return (0); 4321000Sxc151355 } 4331000Sxc151355 4341000Sxc151355 /* 4353147Sxc151355 * Update internal state after a channel change. 4363147Sxc151355 */ 4373147Sxc151355 void 4383147Sxc151355 ath_chan_change(ath_t *asc, struct ieee80211_channel *chan) 4393147Sxc151355 { 4403147Sxc151355 struct ieee80211com *ic = &asc->asc_isc; 4413147Sxc151355 enum ieee80211_phymode mode; 4423147Sxc151355 4433147Sxc151355 /* 4443147Sxc151355 * Change channels and update the h/w rate map 4453147Sxc151355 * if we're switching; e.g. 11a to 11b/g. 4463147Sxc151355 */ 4473147Sxc151355 mode = ieee80211_chan2mode(ic, chan); 4483147Sxc151355 if (mode != asc->asc_curmode) 4493147Sxc151355 ath_setcurmode(asc, mode); 4503147Sxc151355 } 4513147Sxc151355 4523147Sxc151355 /* 4531000Sxc151355 * Set/change channels. If the channel is really being changed, 4541000Sxc151355 * it's done by resetting the chip. To accomplish this we must 4551000Sxc151355 * first cleanup any pending DMA. 4561000Sxc151355 */ 4571000Sxc151355 int 4583147Sxc151355 ath_chan_set(ath_t *asc, struct ieee80211_channel *chan) 4591000Sxc151355 { 4601000Sxc151355 struct ath_hal *ah = asc->asc_ah; 4613147Sxc151355 ieee80211com_t *ic = &asc->asc_isc; 4621000Sxc151355 4633147Sxc151355 if (chan != ic->ic_ibss_chan) { 4641000Sxc151355 HAL_STATUS status; 4651000Sxc151355 HAL_CHANNEL hchan; 4661000Sxc151355 4671000Sxc151355 /* 4681000Sxc151355 * To switch channels clear any pending DMA operations; 4691000Sxc151355 * wait long enough for the RX fifo to drain, reset the 4701000Sxc151355 * hardware at the new frequency, and then re-enable 4711000Sxc151355 * the relevant bits of the h/w. 4721000Sxc151355 */ 4731000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 4741000Sxc151355 ath_draintxq(asc); /* clear pending tx frames */ 4751000Sxc151355 ath_stoprecv(asc); /* turn off frame recv */ 4761000Sxc151355 /* 4771000Sxc151355 * Convert to a HAL channel description with 4781000Sxc151355 * the flags constrained to reflect the current 4791000Sxc151355 * operating mode. 4801000Sxc151355 */ 4811000Sxc151355 hchan.channel = chan->ich_freq; 4823147Sxc151355 hchan.channelFlags = ath_chan2flags(ic, chan); 4833147Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode, 4841000Sxc151355 &hchan, AH_TRUE, &status)) { 4851000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():" 4866235Sxc151355 "unable to reset channel %u (%uMhz)\n" 4876235Sxc151355 "flags 0x%x: '%s' (HAL status %u)\n", 4886235Sxc151355 ieee80211_chan2ieee(ic, chan), hchan.channel, 4896235Sxc151355 hchan.channelFlags, 4906235Sxc151355 ath_get_hal_status_desc(status), status)); 4911000Sxc151355 return (EIO); 4921000Sxc151355 } 4933147Sxc151355 asc->asc_curchan = hchan; 4941000Sxc151355 4951000Sxc151355 /* 4961000Sxc151355 * Re-enable rx framework. 4971000Sxc151355 */ 4981000Sxc151355 if (ath_startrecv(asc) != 0) { 4991000Sxc151355 ath_problem("ath: ath_chan_set(): " 5001000Sxc151355 "restarting receiving logic failed\n"); 5011000Sxc151355 return (EIO); 5021000Sxc151355 } 5031000Sxc151355 5041000Sxc151355 /* 5051000Sxc151355 * Change channels and update the h/w rate map 5061000Sxc151355 * if we're switching; e.g. 11a to 11b/g. 5071000Sxc151355 */ 5083147Sxc151355 ic->ic_ibss_chan = chan; 5093147Sxc151355 ath_chan_change(asc, chan); 5101000Sxc151355 /* 5111000Sxc151355 * Re-enable interrupts. 5121000Sxc151355 */ 5131000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 5141000Sxc151355 } 5151000Sxc151355 return (0); 5161000Sxc151355 } 5171000Sxc151355 5181000Sxc151355 5191000Sxc151355 /* 5201000Sxc151355 * Configure the beacon and sleep timers. 5211000Sxc151355 * 5221000Sxc151355 * When operating as an AP this resets the TSF and sets 5231000Sxc151355 * up the hardware to notify us when we need to issue beacons. 5241000Sxc151355 * 5251000Sxc151355 * When operating in station mode this sets up the beacon 5261000Sxc151355 * timers according to the timestamp of the last received 5271000Sxc151355 * beacon and the current TSF, configures PCF and DTIM 5281000Sxc151355 * handling, programs the sleep registers so the hardware 5291000Sxc151355 * will wakeup in time to receive beacons, and configures 5301000Sxc151355 * the beacon miss handling so we'll receive a BMISS 5311000Sxc151355 * interrupt when we stop seeing beacons from the AP 5321000Sxc151355 * we've associated with. 5331000Sxc151355 */ 5341000Sxc151355 void 5351000Sxc151355 ath_beacon_config(ath_t *asc) 5361000Sxc151355 { 5371000Sxc151355 struct ath_hal *ah = asc->asc_ah; 5383147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 5393147Sxc151355 struct ieee80211_node *in = ic->ic_bss; 5401000Sxc151355 uint32_t nexttbtt; 5411000Sxc151355 5423147Sxc151355 nexttbtt = (ATH_LE_READ_4(in->in_tstamp.data + 4) << 22) | 5433147Sxc151355 (ATH_LE_READ_4(in->in_tstamp.data) >> 10); 5441000Sxc151355 nexttbtt += in->in_intval; 5453147Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 5461000Sxc151355 HAL_BEACON_STATE bs; 5471000Sxc151355 5481000Sxc151355 /* NB: no PCF support right now */ 5491000Sxc151355 bzero(&bs, sizeof (bs)); 5501000Sxc151355 bs.bs_intval = in->in_intval; 5511000Sxc151355 bs.bs_nexttbtt = nexttbtt; 5521000Sxc151355 bs.bs_dtimperiod = bs.bs_intval; 5531000Sxc151355 bs.bs_nextdtim = nexttbtt; 5541000Sxc151355 5551000Sxc151355 /* 5563147Sxc151355 * Setup the number of consecutive beacons to miss 5573147Sxc151355 * before taking a BMISS interrupt. 5581000Sxc151355 * Note that we clamp the result to at most 10 beacons. 5591000Sxc151355 */ 5603147Sxc151355 bs.bs_bmissthreshold = ic->ic_bmissthreshold; 5611000Sxc151355 if (bs.bs_bmissthreshold > 10) 5621000Sxc151355 bs.bs_bmissthreshold = 10; 563*6990Sgd78059 else if (bs.bs_bmissthreshold < 1) 5641000Sxc151355 bs.bs_bmissthreshold = 1; 5651000Sxc151355 /* 5661000Sxc151355 * Calculate sleep duration. The configuration is 5671000Sxc151355 * given in ms. We insure a multiple of the beacon 5681000Sxc151355 * period is used. Also, if the sleep duration is 5691000Sxc151355 * greater than the DTIM period then it makes senses 5701000Sxc151355 * to make it a multiple of that. 5711000Sxc151355 */ 5721000Sxc151355 bs.bs_sleepduration = 5731000Sxc151355 roundup((100 * 1000) / 1024, bs.bs_intval); 5741000Sxc151355 if (bs.bs_sleepduration > bs.bs_dtimperiod) 5751000Sxc151355 bs.bs_sleepduration = 5761000Sxc151355 roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 5771000Sxc151355 5781000Sxc151355 5791000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): " 5801000Sxc151355 "intval %u nexttbtt %u dtim %u" 5811000Sxc151355 " nextdtim %u bmiss %u sleep %u\n", 5821000Sxc151355 bs.bs_intval, 5831000Sxc151355 bs.bs_nexttbtt, 5841000Sxc151355 bs.bs_dtimperiod, 5851000Sxc151355 bs.bs_nextdtim, 5861000Sxc151355 bs.bs_bmissthreshold, 5871000Sxc151355 bs.bs_sleepduration)); 5881000Sxc151355 ATH_HAL_INTRSET(ah, 0); 5891000Sxc151355 /* 5901000Sxc151355 * Reset our tsf so the hardware will update the 5911000Sxc151355 * tsf register to reflect timestamps found in 5921000Sxc151355 * received beacons. 5931000Sxc151355 */ 5941000Sxc151355 ATH_HAL_RESETTSF(ah); 5951000Sxc151355 ATH_HAL_BEACONTIMERS(ah, &bs); 5961000Sxc151355 asc->asc_imask |= HAL_INT_BMISS; 5971000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 5981000Sxc151355 } else { 5991000Sxc151355 ATH_HAL_INTRSET(ah, 0); 6001000Sxc151355 ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval); 6011000Sxc151355 asc->asc_imask |= HAL_INT_SWBA; /* beacon prepare */ 6021000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 6031000Sxc151355 } 6041000Sxc151355 } 6051000Sxc151355 6063147Sxc151355 /* 6074126Szf162725 * Allocate tx/rx key slots for TKIP. We allocate two slots for 6084126Szf162725 * each key, one for decrypt/encrypt and the other for the MIC. 6094126Szf162725 */ 6104126Szf162725 static int 6114126Szf162725 key_alloc_2pair(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 6124126Szf162725 { 6134126Szf162725 uint16_t i, keyix; 6144126Szf162725 6154126Szf162725 ASSERT(asc->asc_splitmic); 6164126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) { 6174126Szf162725 uint8_t b = asc->asc_keymap[i]; 6184126Szf162725 if (b != 0xff) { 6194126Szf162725 /* 6204126Szf162725 * One or more slots in this byte are free. 6214126Szf162725 */ 6224126Szf162725 keyix = i*NBBY; 6234126Szf162725 while (b & 1) { 6244126Szf162725 again: 6254126Szf162725 keyix++; 6264126Szf162725 b >>= 1; 6274126Szf162725 } 6284126Szf162725 /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ 6294126Szf162725 if (isset(asc->asc_keymap, keyix+32) || 6304126Szf162725 isset(asc->asc_keymap, keyix+64) || 6314126Szf162725 isset(asc->asc_keymap, keyix+32+64)) { 6324126Szf162725 /* full pair unavailable */ 6334126Szf162725 if (keyix == (i+1)*NBBY) { 6344126Szf162725 /* no slots were appropriate, advance */ 6354126Szf162725 continue; 6364126Szf162725 } 6374126Szf162725 goto again; 6384126Szf162725 } 6394126Szf162725 setbit(asc->asc_keymap, keyix); 6404126Szf162725 setbit(asc->asc_keymap, keyix+64); 6414126Szf162725 setbit(asc->asc_keymap, keyix+32); 6424126Szf162725 setbit(asc->asc_keymap, keyix+32+64); 6434126Szf162725 ATH_DEBUG((ATH_DBG_AUX, 6444126Szf162725 "key_alloc_2pair: key pair %u,%u %u,%u\n", 6454126Szf162725 keyix, keyix+64, 6464126Szf162725 keyix+32, keyix+32+64)); 6474126Szf162725 *txkeyix = *rxkeyix = keyix; 6484126Szf162725 return (1); 6494126Szf162725 } 6504126Szf162725 } 6514126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_2pair:" 6524126Szf162725 " out of pair space\n")); 6534126Szf162725 return (0); 6544126Szf162725 } 6554126Szf162725 /* 6564126Szf162725 * Allocate a single key cache slot. 6574126Szf162725 */ 6584126Szf162725 static int 6594126Szf162725 key_alloc_single(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 6604126Szf162725 { 6614126Szf162725 uint16_t i, keyix; 6624126Szf162725 6634126Szf162725 /* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ 6644126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap); i++) { 6654126Szf162725 uint8_t b = asc->asc_keymap[i]; 6664126Szf162725 6674126Szf162725 if (b != 0xff) { 6684126Szf162725 /* 6694126Szf162725 * One or more slots are free. 6704126Szf162725 */ 6714126Szf162725 keyix = i*NBBY; 6724126Szf162725 while (b & 1) 6734126Szf162725 keyix++, b >>= 1; 6744126Szf162725 setbit(asc->asc_keymap, keyix); 6754126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_single:" 6764126Szf162725 " key %u\n", keyix)); 6774126Szf162725 *txkeyix = *rxkeyix = keyix; 6784126Szf162725 return (1); 6794126Szf162725 } 6804126Szf162725 } 6814126Szf162725 return (0); 6824126Szf162725 } 6834126Szf162725 6844126Szf162725 /* 6853147Sxc151355 * Allocate one or more key cache slots for a unicast key. The 6863147Sxc151355 * key itself is needed only to identify the cipher. For hardware 6873147Sxc151355 * TKIP with split cipher+MIC keys we allocate two key cache slot 6883147Sxc151355 * pairs so that we can setup separate TX and RX MIC keys. Note 6893147Sxc151355 * that the MIC key for a TKIP key at slot i is assumed by the 6903147Sxc151355 * hardware to be at slot i+64. This limits TKIP keys to the first 6913147Sxc151355 * 64 entries. 6923147Sxc151355 */ 6933147Sxc151355 /* ARGSUSED */ 6943147Sxc151355 int 6953147Sxc151355 ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k, 6963147Sxc151355 ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 6973147Sxc151355 { 6984126Szf162725 ath_t *asc = (ath_t *)ic; 6994126Szf162725 7004126Szf162725 /* 7014126Szf162725 * We allocate two pair for TKIP when using the h/w to do 7024126Szf162725 * the MIC. For everything else, including software crypto, 7034126Szf162725 * we allocate a single entry. Note that s/w crypto requires 7044126Szf162725 * a pass-through slot on the 5211 and 5212. The 5210 does 7054126Szf162725 * not support pass-through cache entries and we map all 7064126Szf162725 * those requests to slot 0. 7074126Szf162725 */ 7084126Szf162725 if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 7094126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix)); 7104126Szf162725 } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP && 7114126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) { 7124126Szf162725 return (key_alloc_2pair(asc, keyix, rxkeyix)); 7134126Szf162725 } else { 7144126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix)); 7154126Szf162725 } 7164126Szf162725 } 7174126Szf162725 7184126Szf162725 /* 7194126Szf162725 * Delete an entry in the key cache allocated by ath_key_alloc. 7204126Szf162725 */ 7214126Szf162725 int 7224126Szf162725 ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k) 7234126Szf162725 { 7244126Szf162725 ath_t *asc = (ath_t *)ic; 7254126Szf162725 struct ath_hal *ah = asc->asc_ah; 7264126Szf162725 const struct ieee80211_cipher *cip = k->wk_cipher; 7274126Szf162725 ieee80211_keyix keyix = k->wk_keyix; 7284126Szf162725 7294126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "ath_key_delete:" 7304126Szf162725 " delete key %u ic_cipher=0x%x\n", keyix, cip->ic_cipher)); 7314126Szf162725 7324126Szf162725 ATH_HAL_KEYRESET(ah, keyix); 7334126Szf162725 /* 7344126Szf162725 * Handle split tx/rx keying required for TKIP with h/w MIC. 7354126Szf162725 */ 7364126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 7374126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) 7384126Szf162725 ATH_HAL_KEYRESET(ah, keyix+32); /* RX key */ 7394126Szf162725 7404126Szf162725 if (keyix >= IEEE80211_WEP_NKID) { 7414126Szf162725 /* 7424126Szf162725 * Don't touch keymap entries for global keys so 7434126Szf162725 * they are never considered for dynamic allocation. 7444126Szf162725 */ 7454126Szf162725 clrbit(asc->asc_keymap, keyix); 7464126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 7474126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && 7484126Szf162725 asc->asc_splitmic) { 7494126Szf162725 clrbit(asc->asc_keymap, keyix+64); /* TX key MIC */ 7504126Szf162725 clrbit(asc->asc_keymap, keyix+32); /* RX key */ 7514126Szf162725 clrbit(asc->asc_keymap, keyix+32+64); /* RX key MIC */ 7524126Szf162725 } 7534126Szf162725 } 7543147Sxc151355 return (1); 7553147Sxc151355 } 7561000Sxc151355 7574126Szf162725 static void 7584126Szf162725 ath_keyprint(const char *tag, uint_t ix, 7594126Szf162725 const HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN]) 7603147Sxc151355 { 7614126Szf162725 static const char *ciphers[] = { 7624126Szf162725 "WEP", 7634126Szf162725 "AES-OCB", 7644126Szf162725 "AES-CCM", 7654126Szf162725 "CKIP", 7664126Szf162725 "TKIP", 7674126Szf162725 "CLR", 7684126Szf162725 }; 7694126Szf162725 int i, n; 7704126Szf162725 char buf[MAX_IEEE80211STR], buft[32]; 7714126Szf162725 7724126Szf162725 (void) snprintf(buf, sizeof (buf), "%s: [%02u] %s ", 7734126Szf162725 tag, ix, ciphers[hk->kv_type]); 7744126Szf162725 for (i = 0, n = hk->kv_len; i < n; i++) { 7754126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x", hk->kv_val[i]); 7764126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 7774126Szf162725 } 7784126Szf162725 (void) snprintf(buft, sizeof (buft), " mac %s", 7794126Szf162725 ieee80211_macaddr_sprintf(mac)); 7804126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 7814126Szf162725 if (hk->kv_type == HAL_CIPHER_TKIP) { 7824126Szf162725 (void) snprintf(buft, sizeof (buft), " mic "); 7834126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 7844126Szf162725 for (i = 0; i < sizeof (hk->kv_mic); i++) { 7854126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x", 7864126Szf162725 hk->kv_mic[i]); 7874126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 7884126Szf162725 } 7894126Szf162725 } 7904126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "%s", buf)); 7914126Szf162725 } 7923147Sxc151355 7934126Szf162725 /* 7944126Szf162725 * Set a TKIP key into the hardware. This handles the 7954126Szf162725 * potential distribution of key state to multiple key 7964126Szf162725 * cache slots for TKIP. 7974126Szf162725 */ 7984126Szf162725 static int 7994126Szf162725 ath_keyset_tkip(ath_t *asc, const struct ieee80211_key *k, 8004126Szf162725 HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN]) 8014126Szf162725 { 8024126Szf162725 #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) 8034126Szf162725 static const uint8_t zerobssid[IEEE80211_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 8044126Szf162725 struct ath_hal *ah = asc->asc_ah; 8054126Szf162725 8064126Szf162725 ASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP); 8074126Szf162725 if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { 8084126Szf162725 /* 8094126Szf162725 * TX key goes at first index, RX key at +32. 8104126Szf162725 * The hal handles the MIC keys at index+64. 8114126Szf162725 */ 8124126Szf162725 (void) memcpy(hk->kv_mic, k->wk_txmic, sizeof (hk->kv_mic)); 8134126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid); 8144126Szf162725 if (!ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid)) 8154126Szf162725 return (0); 8164126Szf162725 8174126Szf162725 (void) memcpy(hk->kv_mic, k->wk_rxmic, sizeof (hk->kv_mic)); 8184126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix+32, hk, mac); 8194126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix+32, hk, mac)); 8204126Szf162725 } else if (k->wk_flags & IEEE80211_KEY_XR) { 8214126Szf162725 /* 8224126Szf162725 * TX/RX key goes at first index. 8234126Szf162725 * The hal handles the MIC keys are index+64. 8244126Szf162725 */ 8254126Szf162725 (void) memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ? 8264126Szf162725 k->wk_txmic : k->wk_rxmic, sizeof (hk->kv_mic)); 8274126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid); 8284126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid)); 8294126Szf162725 } 8304126Szf162725 return (0); 8314126Szf162725 #undef IEEE80211_KEY_XR 8323147Sxc151355 } 8331000Sxc151355 8341000Sxc151355 /* 8353147Sxc151355 * Set the key cache contents for the specified key. Key cache 8363147Sxc151355 * slot(s) must already have been allocated by ath_key_alloc. 8373147Sxc151355 */ 8383147Sxc151355 int 8393147Sxc151355 ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k, 8403147Sxc151355 const uint8_t mac[IEEE80211_ADDR_LEN]) 8413147Sxc151355 { 8423147Sxc151355 static const uint8_t ciphermap[] = { 8433147Sxc151355 HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ 8443147Sxc151355 HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ 8453147Sxc151355 HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ 8463147Sxc151355 HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ 8473147Sxc151355 HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ 8483147Sxc151355 HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ 8493147Sxc151355 }; 8503147Sxc151355 ath_t *asc = (ath_t *)ic; 8513147Sxc151355 struct ath_hal *ah = asc->asc_ah; 8523147Sxc151355 const struct ieee80211_cipher *cip = k->wk_cipher; 8533147Sxc151355 HAL_KEYVAL hk; 8543147Sxc151355 8553147Sxc151355 bzero(&hk, sizeof (hk)); 8563147Sxc151355 /* 8573147Sxc151355 * Software crypto uses a "clear key" so non-crypto 8583147Sxc151355 * state kept in the key cache are maintainedd so that 8593147Sxc151355 * rx frames have an entry to match. 8603147Sxc151355 */ 8613147Sxc151355 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 8623147Sxc151355 ASSERT(cip->ic_cipher < ATH_N(ciphermap)); 8633147Sxc151355 hk.kv_type = ciphermap[cip->ic_cipher]; 8643147Sxc151355 hk.kv_len = k->wk_keylen; 8653147Sxc151355 bcopy(k->wk_key, hk.kv_val, k->wk_keylen); 8663147Sxc151355 } else { 8673147Sxc151355 hk.kv_type = HAL_CIPHER_CLR; 8683147Sxc151355 } 8693147Sxc151355 8704126Szf162725 if (hk.kv_type == HAL_CIPHER_TKIP && 8714126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && 8724126Szf162725 asc->asc_splitmic) { 8734126Szf162725 return (ath_keyset_tkip(asc, k, &hk, mac)); 8744126Szf162725 } else { 8754126Szf162725 ath_keyprint("ath_keyset:", k->wk_keyix, &hk, mac); 8764126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac)); 8774126Szf162725 } 8783147Sxc151355 } 8793147Sxc151355 8803147Sxc151355 /* 8813147Sxc151355 * Enable/Disable short slot timing 8821000Sxc151355 */ 8831000Sxc151355 void 8843147Sxc151355 ath_set_shortslot(ieee80211com_t *ic, int onoff) 8851000Sxc151355 { 8863147Sxc151355 struct ath_hal *ah = ((ath_t *)ic)->asc_ah; 8871000Sxc151355 8883147Sxc151355 if (onoff) 8893147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9); 8903147Sxc151355 else 8913147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20); 8921000Sxc151355 } 8931000Sxc151355 8943147Sxc151355 int 8953147Sxc151355 ath_reset(ieee80211com_t *ic) 8961000Sxc151355 { 8973147Sxc151355 ath_t *asc = (ath_t *)ic; 8981000Sxc151355 struct ath_hal *ah = asc->asc_ah; 8993147Sxc151355 struct ieee80211_channel *ch; 9001000Sxc151355 HAL_STATUS status; 9011000Sxc151355 9021000Sxc151355 /* 9031000Sxc151355 * Convert to a HAL channel description with the flags 9041000Sxc151355 * constrained to reflect the current operating mode. 9051000Sxc151355 */ 9063147Sxc151355 ch = ic->ic_curchan; 9073147Sxc151355 asc->asc_curchan.channel = ch->ich_freq; 9083147Sxc151355 asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch); 9091000Sxc151355 9101000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 9111000Sxc151355 ath_draintxq(asc); /* stop xmit side */ 9123147Sxc151355 if (ATH_IS_RUNNING(asc)) { 9131000Sxc151355 ath_stoprecv(asc); /* stop recv side */ 9143147Sxc151355 /* indicate channel change so we do a full reset */ 9156235Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode, 9166235Sxc151355 &asc->asc_curchan, AH_TRUE, &status)) { 9173147Sxc151355 ath_problem("ath: ath_reset(): " 9186235Sxc151355 "resetting hardware failed, '%s' (HAL status %u)\n", 9196235Sxc151355 ath_get_hal_status_desc(status), status); 9203147Sxc151355 } 9213147Sxc151355 ath_chan_change(asc, ch); 9221000Sxc151355 } 9233147Sxc151355 if (ATH_IS_RUNNING(asc)) { 9241000Sxc151355 if (ath_startrecv(asc) != 0) /* restart recv */ 9251000Sxc151355 ath_problem("ath: ath_reset(): " 9261000Sxc151355 "starting receiving logic failed\n"); 9273147Sxc151355 if (ic->ic_state == IEEE80211_S_RUN) { 9281000Sxc151355 ath_beacon_config(asc); /* restart beacons */ 9291000Sxc151355 } 9301000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 9311000Sxc151355 } 9323147Sxc151355 return (0); 9331000Sxc151355 } 934