11000Sxc151355 /* 2*4126Szf162725 * Copyright 2007 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 841000Sxc151355 uint32_t 851000Sxc151355 ath_calcrxfilter(ath_t *asc) 861000Sxc151355 { 873147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 881000Sxc151355 struct ath_hal *ah = asc->asc_ah; 891000Sxc151355 uint32_t rfilt; 901000Sxc151355 911000Sxc151355 rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR) 921000Sxc151355 | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 933147Sxc151355 if (ic->ic_opmode != IEEE80211_M_STA) 941000Sxc151355 rfilt |= HAL_RX_FILTER_PROBEREQ; 953147Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP && 961000Sxc151355 (asc->asc_promisc & GLD_MAC_PROMISC_PHYS)) /* promiscuous */ 971000Sxc151355 rfilt |= HAL_RX_FILTER_PROM; 983147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA || 993147Sxc151355 ic->ic_opmode == IEEE80211_M_IBSS || 1003147Sxc151355 ic->ic_state == IEEE80211_S_SCAN) 1011000Sxc151355 rfilt |= HAL_RX_FILTER_BEACON; 1021000Sxc151355 return (rfilt); 1031000Sxc151355 } 1041000Sxc151355 1051000Sxc151355 static int 1061000Sxc151355 ath_set_data_queue(ath_t *asc, int ac, int haltype) 1071000Sxc151355 { 1081000Sxc151355 HAL_TXQ_INFO qi; 1091000Sxc151355 int qnum; 1101000Sxc151355 struct ath_hal *ah = asc->asc_ah; 1111000Sxc151355 struct ath_txq *txq; 1121000Sxc151355 1131000Sxc151355 if (ac >= ATH_N(asc->asc_ac2q)) { 1141000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1151000Sxc151355 "ac %u out of range, max %u!\n", 1161000Sxc151355 ac, ATH_N(asc->asc_ac2q))); 1171000Sxc151355 return (1); 1181000Sxc151355 } 1191000Sxc151355 (void) memset(&qi, 0, sizeof (qi)); 1201000Sxc151355 qi.tqi_subtype = haltype; 1211000Sxc151355 /* 1221000Sxc151355 * Enable interrupts only for EOL and DESC conditions. 1231000Sxc151355 * We mark tx descriptors to receive a DESC interrupt 1241000Sxc151355 * when a tx queue gets deep; otherwise waiting for the 1251000Sxc151355 * EOL to reap descriptors. Note that this is done to 1261000Sxc151355 * reduce interrupt load and this only defers reaping 1271000Sxc151355 * descriptors, never transmitting frames. Aside from 1281000Sxc151355 * reducing interrupts this also permits more concurrency. 1291000Sxc151355 * The only potential downside is if the tx queue backs 1301000Sxc151355 * up in which case the top half of the kernel may backup 1311000Sxc151355 * due to a lack of tx descriptors. 1321000Sxc151355 */ 1333147Sxc151355 qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE; 1341000Sxc151355 qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi); 1351000Sxc151355 if (qnum == -1) { 1361000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1371000Sxc151355 "Unable to setup hardware queue for %s traffic!\n", 1381000Sxc151355 acnames[ac])); 1391000Sxc151355 return (1); 1401000Sxc151355 } 1411000Sxc151355 if (qnum >= ATH_N(asc->asc_txq)) { 1421000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 1431000Sxc151355 "hal qnum %u out of range, max %u!\n", 1441000Sxc151355 qnum, ATH_N(asc->asc_txq))); 1451000Sxc151355 return (1); 1461000Sxc151355 } 1471000Sxc151355 if (!ATH_TXQ_SETUP(asc, qnum)) { 1481000Sxc151355 txq = &asc->asc_txq[qnum]; 1491000Sxc151355 txq->axq_qnum = qnum; 1501000Sxc151355 txq->axq_depth = 0; 1511000Sxc151355 txq->axq_intrcnt = 0; 1521000Sxc151355 txq->axq_link = NULL; 1531000Sxc151355 list_create(&txq->axq_list, sizeof (struct ath_buf), 1541000Sxc151355 offsetof(struct ath_buf, bf_node)); 1551000Sxc151355 mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL); 1561000Sxc151355 asc->asc_txqsetup |= 1<<qnum; 1571000Sxc151355 } 1581000Sxc151355 asc->asc_ac2q[ac] = &asc->asc_txq[qnum]; 1591000Sxc151355 return (0); 1601000Sxc151355 } 1611000Sxc151355 1621000Sxc151355 int 1631000Sxc151355 ath_txq_setup(ath_t *asc) 1641000Sxc151355 { 1651000Sxc151355 if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) || 1661000Sxc151355 ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) || 1671000Sxc151355 ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) || 1681000Sxc151355 ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) { 1691000Sxc151355 return (1); 1701000Sxc151355 } 1711000Sxc151355 1721000Sxc151355 return (0); 1731000Sxc151355 } 1741000Sxc151355 1751000Sxc151355 void 1763147Sxc151355 ath_txq_cleanup(ath_t *asc) 1773147Sxc151355 { 1783147Sxc151355 int i; 1793147Sxc151355 1803147Sxc151355 mutex_destroy(&asc->asc_txbuflock); 1813147Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 1823147Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 1833147Sxc151355 struct ath_txq *txq = &asc->asc_txq[i]; 1843147Sxc151355 1853147Sxc151355 ATH_HAL_RELEASETXQUEUE(asc->asc_ah, txq->axq_qnum); 1863147Sxc151355 mutex_destroy(&txq->axq_lock); 1873147Sxc151355 asc->asc_txqsetup &= ~(1 << txq->axq_qnum); 1883147Sxc151355 } 1893147Sxc151355 } 1903147Sxc151355 } 1913147Sxc151355 1923147Sxc151355 void 1931000Sxc151355 ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode) 1941000Sxc151355 { 1951000Sxc151355 const HAL_RATE_TABLE *rt; 1961000Sxc151355 int i; 1971000Sxc151355 1981000Sxc151355 for (i = 0; i < sizeof (asc->asc_rixmap); i++) 1991000Sxc151355 asc->asc_rixmap[i] = 0xff; 2001000Sxc151355 2011000Sxc151355 rt = asc->asc_rates[mode]; 2021000Sxc151355 ASSERT(rt != NULL); 2031000Sxc151355 2041000Sxc151355 for (i = 0; i < rt->rateCount; i++) 2051000Sxc151355 asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; 2061000Sxc151355 2071000Sxc151355 asc->asc_currates = rt; 2081000Sxc151355 asc->asc_curmode = mode; 2091000Sxc151355 } 2101000Sxc151355 2111000Sxc151355 /* Set correct parameters for a certain mode */ 2121000Sxc151355 void 2131000Sxc151355 ath_mode_init(ath_t *asc) 2141000Sxc151355 { 2153147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 2161000Sxc151355 struct ath_hal *ah = asc->asc_ah; 2171000Sxc151355 uint32_t rfilt; 2181000Sxc151355 2191000Sxc151355 /* configure rx filter */ 2201000Sxc151355 rfilt = ath_calcrxfilter(asc); 2211000Sxc151355 ATH_HAL_SETRXFILTER(ah, rfilt); 2221000Sxc151355 ATH_HAL_SETOPMODE(ah); 2231000Sxc151355 ATH_HAL_SETMCASTFILTER(ah, asc->asc_mfilt[0], asc->asc_mfilt[1]); 2241000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): " 2251000Sxc151355 "mode =%d RX filter 0x%x, MC filter %08x:%08x\n", 2263147Sxc151355 ic->ic_opmode, rfilt, 2271000Sxc151355 asc->asc_mfilt[0], asc->asc_mfilt[1])); 2281000Sxc151355 } 2291000Sxc151355 2301000Sxc151355 2311000Sxc151355 /* 2321000Sxc151355 * Disable the receive h/w in preparation for a reset. 2331000Sxc151355 */ 2341000Sxc151355 void 2351000Sxc151355 ath_stoprecv(ath_t *asc) 2361000Sxc151355 { 2371000Sxc151355 ATH_HAL_STOPPCURECV(asc->asc_ah); /* disable PCU */ 2381000Sxc151355 ATH_HAL_SETRXFILTER(asc->asc_ah, 0); /* clear recv filter */ 2391000Sxc151355 ATH_HAL_STOPDMARECV(asc->asc_ah); /* disable DMA engine */ 2401000Sxc151355 drv_usecwait(3000); 2411000Sxc151355 2421000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n", 2431000Sxc151355 ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink)); 2441000Sxc151355 asc->asc_rxlink = NULL; 2451000Sxc151355 } 2461000Sxc151355 2471000Sxc151355 uint32_t 2483147Sxc151355 ath_chan2flags(ieee80211com_t *isc, struct ieee80211_channel *chan) 2491000Sxc151355 { 2501000Sxc151355 static const uint32_t modeflags[] = { 2511000Sxc151355 0, /* IEEE80211_MODE_AUTO */ 2521000Sxc151355 CHANNEL_A, /* IEEE80211_MODE_11A */ 2531000Sxc151355 CHANNEL_B, /* IEEE80211_MODE_11B */ 2541000Sxc151355 CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 2553147Sxc151355 0, /* IEEE80211_MODE_FH */ 2563147Sxc151355 CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */ 2573147Sxc151355 CHANNEL_108G /* IEEE80211_MODE_TURBO_G */ 2581000Sxc151355 }; 2591000Sxc151355 return (modeflags[ieee80211_chan2mode(isc, chan)]); 2601000Sxc151355 } 2611000Sxc151355 2621000Sxc151355 2631000Sxc151355 int 2641000Sxc151355 ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) 2651000Sxc151355 { 2663147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 2671000Sxc151355 struct ath_hal *ah = asc->asc_ah; 2681000Sxc151355 HAL_CHANNEL *chans; 2691000Sxc151355 int i, ix; 2701000Sxc151355 uint32_t nchan; 2711000Sxc151355 2721000Sxc151355 chans = (HAL_CHANNEL *) 2731000Sxc151355 kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP); 2741000Sxc151355 2751000Sxc151355 if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, 2763147Sxc151355 NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) { 2771000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 2781000Sxc151355 "unable to get channel list\n"); 2791000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL))); 2801000Sxc151355 return (EINVAL); 2811000Sxc151355 } 2821000Sxc151355 2831000Sxc151355 /* 2841000Sxc151355 * Convert HAL channels to ieee80211 ones and insert 2851000Sxc151355 * them in the table according to their channel number. 2861000Sxc151355 */ 2871000Sxc151355 for (i = 0; i < nchan; i++) { 2881000Sxc151355 HAL_CHANNEL *c = &chans[i]; 2893147Sxc151355 uint16_t flags; 2903147Sxc151355 ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags); 2911000Sxc151355 if (ix > IEEE80211_CHAN_MAX) { 2921000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 2933147Sxc151355 "bad hal channel %d (%u/%x) ignored\n", 2941000Sxc151355 ix, c->channel, c->channelFlags)); 2951000Sxc151355 continue; 2961000Sxc151355 } 2971000Sxc151355 /* NB: flags are known to be compatible */ 2983147Sxc151355 if (ix < 0) { 2993147Sxc151355 /* 3003147Sxc151355 * can't handle frequency <2400MHz (negative 3013147Sxc151355 * channels) right now 3023147Sxc151355 */ 3033147Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath:ath_getchannels(): " 3043147Sxc151355 "hal channel %d (%u/%x) " 3053147Sxc151355 "cannot be handled, ignored\n", 3063147Sxc151355 ix, c->channel, c->channelFlags)); 3073147Sxc151355 continue; 3083147Sxc151355 } 3093147Sxc151355 /* 3103147Sxc151355 * Calculate net80211 flags; most are compatible 3113147Sxc151355 * but some need massaging. Note the static turbo 3123147Sxc151355 * conversion can be removed once net80211 is updated 3133147Sxc151355 * to understand static vs. dynamic turbo. 3143147Sxc151355 */ 3153147Sxc151355 flags = c->channelFlags & CHANNEL_COMPAT; 3163147Sxc151355 if (c->channelFlags & CHANNEL_STURBO) 3173147Sxc151355 flags |= IEEE80211_CHAN_TURBO; 3183147Sxc151355 if (ic->ic_sup_channels[ix].ich_freq == 0) { 3193147Sxc151355 ic->ic_sup_channels[ix].ich_freq = c->channel; 3203147Sxc151355 ic->ic_sup_channels[ix].ich_flags = flags; 3211000Sxc151355 } else { 3221000Sxc151355 /* channels overlap; e.g. 11g and 11b */ 3233147Sxc151355 ic->ic_sup_channels[ix].ich_flags |= flags; 3241000Sxc151355 } 3251000Sxc151355 if ((c->channelFlags & CHANNEL_G) == CHANNEL_G) 3261000Sxc151355 asc->asc_have11g = 1; 3271000Sxc151355 } 3281000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL)); 3291000Sxc151355 return (0); 3301000Sxc151355 } 3311000Sxc151355 3321000Sxc151355 static void 3331000Sxc151355 ath_drainq(ath_t *asc, struct ath_txq *txq) 3341000Sxc151355 { 3351000Sxc151355 struct ath_buf *bf; 3361000Sxc151355 3371000Sxc151355 /* 3381000Sxc151355 * This assumes output has been stopped. 3391000Sxc151355 */ 3401000Sxc151355 for (;;) { 3411000Sxc151355 mutex_enter(&txq->axq_lock); 3421000Sxc151355 bf = list_head(&txq->axq_list); 3431000Sxc151355 if (bf == NULL) { 3441000Sxc151355 txq->axq_link = NULL; 3451000Sxc151355 mutex_exit(&txq->axq_lock); 3461000Sxc151355 break; 3471000Sxc151355 } 3481000Sxc151355 list_remove(&txq->axq_list, bf); 3491000Sxc151355 mutex_exit(&txq->axq_lock); 3501000Sxc151355 bf->bf_in = NULL; 3511000Sxc151355 mutex_enter(&asc->asc_txbuflock); 3521000Sxc151355 list_insert_tail(&asc->asc_txbuf_list, bf); 3531000Sxc151355 mutex_exit(&asc->asc_txbuflock); 3541000Sxc151355 } 3551000Sxc151355 } 3561000Sxc151355 3571000Sxc151355 3581000Sxc151355 /* 3591000Sxc151355 * Drain the transmit queues and reclaim resources. 3601000Sxc151355 */ 3611000Sxc151355 void 3621000Sxc151355 ath_draintxq(ath_t *asc) 3631000Sxc151355 { 3641000Sxc151355 struct ath_hal *ah = asc->asc_ah; 3651000Sxc151355 struct ath_txq *txq; 3661000Sxc151355 int i; 3671000Sxc151355 3681000Sxc151355 if (!asc->asc_invalid) { 3691000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 3701000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 3711000Sxc151355 txq = &asc->asc_txq[i]; 3721000Sxc151355 (void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum); 3731000Sxc151355 } 3741000Sxc151355 } 3751000Sxc151355 } 3761000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 3771000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 3781000Sxc151355 ath_drainq(asc, &asc->asc_txq[i]); 3791000Sxc151355 } 3801000Sxc151355 } 3811000Sxc151355 } 3821000Sxc151355 3831000Sxc151355 3841000Sxc151355 /* Enable the receive h/w following a reset */ 3851000Sxc151355 int 3861000Sxc151355 ath_startrecv(ath_t *asc) 3871000Sxc151355 { 3881000Sxc151355 struct ath_buf *bf; 3891000Sxc151355 3901000Sxc151355 asc->asc_rxlink = NULL; 3911000Sxc151355 3921000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 3931000Sxc151355 while (bf != NULL) { 3941000Sxc151355 ath_setup_desc(asc, bf); 3951000Sxc151355 bf = list_next(&asc->asc_rxbuf_list, bf); 3961000Sxc151355 } 3971000Sxc151355 3981000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 3991000Sxc151355 ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr); 4001000Sxc151355 ATH_HAL_RXENA(asc->asc_ah); /* enable recv descriptors */ 4011000Sxc151355 ath_mode_init(asc); /* set filters, etc. */ 4021000Sxc151355 ATH_HAL_STARTPCURECV(asc->asc_ah); /* re-enable PCU/DMA engine */ 4031000Sxc151355 return (0); 4041000Sxc151355 } 4051000Sxc151355 4061000Sxc151355 /* 4073147Sxc151355 * Update internal state after a channel change. 4083147Sxc151355 */ 4093147Sxc151355 void 4103147Sxc151355 ath_chan_change(ath_t *asc, struct ieee80211_channel *chan) 4113147Sxc151355 { 4123147Sxc151355 struct ieee80211com *ic = &asc->asc_isc; 4133147Sxc151355 enum ieee80211_phymode mode; 4143147Sxc151355 4153147Sxc151355 /* 4163147Sxc151355 * Change channels and update the h/w rate map 4173147Sxc151355 * if we're switching; e.g. 11a to 11b/g. 4183147Sxc151355 */ 4193147Sxc151355 mode = ieee80211_chan2mode(ic, chan); 4203147Sxc151355 if (mode != asc->asc_curmode) 4213147Sxc151355 ath_setcurmode(asc, mode); 4223147Sxc151355 } 4233147Sxc151355 4243147Sxc151355 /* 4251000Sxc151355 * Set/change channels. If the channel is really being changed, 4261000Sxc151355 * it's done by resetting the chip. To accomplish this we must 4271000Sxc151355 * first cleanup any pending DMA. 4281000Sxc151355 */ 4291000Sxc151355 int 4303147Sxc151355 ath_chan_set(ath_t *asc, struct ieee80211_channel *chan) 4311000Sxc151355 { 4321000Sxc151355 struct ath_hal *ah = asc->asc_ah; 4333147Sxc151355 ieee80211com_t *ic = &asc->asc_isc; 4341000Sxc151355 4353147Sxc151355 if (chan != ic->ic_ibss_chan) { 4361000Sxc151355 HAL_STATUS status; 4371000Sxc151355 HAL_CHANNEL hchan; 4381000Sxc151355 4391000Sxc151355 /* 4401000Sxc151355 * To switch channels clear any pending DMA operations; 4411000Sxc151355 * wait long enough for the RX fifo to drain, reset the 4421000Sxc151355 * hardware at the new frequency, and then re-enable 4431000Sxc151355 * the relevant bits of the h/w. 4441000Sxc151355 */ 4451000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 4461000Sxc151355 ath_draintxq(asc); /* clear pending tx frames */ 4471000Sxc151355 ath_stoprecv(asc); /* turn off frame recv */ 4481000Sxc151355 /* 4491000Sxc151355 * Convert to a HAL channel description with 4501000Sxc151355 * the flags constrained to reflect the current 4511000Sxc151355 * operating mode. 4521000Sxc151355 */ 4531000Sxc151355 hchan.channel = chan->ich_freq; 4543147Sxc151355 hchan.channelFlags = ath_chan2flags(ic, chan); 4553147Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode, 4561000Sxc151355 &hchan, AH_TRUE, &status)) { 4571000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():" 4581000Sxc151355 "unable to reset channel %u (%uMhz)\n", 4593147Sxc151355 ieee80211_chan2ieee(ic, chan), chan->ich_freq)); 4601000Sxc151355 return (EIO); 4611000Sxc151355 } 4623147Sxc151355 asc->asc_curchan = hchan; 4631000Sxc151355 4641000Sxc151355 /* 4651000Sxc151355 * Re-enable rx framework. 4661000Sxc151355 */ 4671000Sxc151355 if (ath_startrecv(asc) != 0) { 4681000Sxc151355 ath_problem("ath: ath_chan_set(): " 4691000Sxc151355 "restarting receiving logic failed\n"); 4701000Sxc151355 return (EIO); 4711000Sxc151355 } 4721000Sxc151355 4731000Sxc151355 /* 4741000Sxc151355 * Change channels and update the h/w rate map 4751000Sxc151355 * if we're switching; e.g. 11a to 11b/g. 4761000Sxc151355 */ 4773147Sxc151355 ic->ic_ibss_chan = chan; 4783147Sxc151355 ath_chan_change(asc, chan); 4791000Sxc151355 /* 4801000Sxc151355 * Re-enable interrupts. 4811000Sxc151355 */ 4821000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 4831000Sxc151355 } 4841000Sxc151355 return (0); 4851000Sxc151355 } 4861000Sxc151355 4871000Sxc151355 4881000Sxc151355 /* 4891000Sxc151355 * Configure the beacon and sleep timers. 4901000Sxc151355 * 4911000Sxc151355 * When operating as an AP this resets the TSF and sets 4921000Sxc151355 * up the hardware to notify us when we need to issue beacons. 4931000Sxc151355 * 4941000Sxc151355 * When operating in station mode this sets up the beacon 4951000Sxc151355 * timers according to the timestamp of the last received 4961000Sxc151355 * beacon and the current TSF, configures PCF and DTIM 4971000Sxc151355 * handling, programs the sleep registers so the hardware 4981000Sxc151355 * will wakeup in time to receive beacons, and configures 4991000Sxc151355 * the beacon miss handling so we'll receive a BMISS 5001000Sxc151355 * interrupt when we stop seeing beacons from the AP 5011000Sxc151355 * we've associated with. 5021000Sxc151355 */ 5031000Sxc151355 void 5041000Sxc151355 ath_beacon_config(ath_t *asc) 5051000Sxc151355 { 5061000Sxc151355 struct ath_hal *ah = asc->asc_ah; 5073147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc; 5083147Sxc151355 struct ieee80211_node *in = ic->ic_bss; 5091000Sxc151355 uint32_t nexttbtt; 5101000Sxc151355 5113147Sxc151355 nexttbtt = (ATH_LE_READ_4(in->in_tstamp.data + 4) << 22) | 5123147Sxc151355 (ATH_LE_READ_4(in->in_tstamp.data) >> 10); 5131000Sxc151355 nexttbtt += in->in_intval; 5143147Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP) { 5151000Sxc151355 HAL_BEACON_STATE bs; 5161000Sxc151355 5171000Sxc151355 /* NB: no PCF support right now */ 5181000Sxc151355 bzero(&bs, sizeof (bs)); 5191000Sxc151355 bs.bs_intval = in->in_intval; 5201000Sxc151355 bs.bs_nexttbtt = nexttbtt; 5211000Sxc151355 bs.bs_dtimperiod = bs.bs_intval; 5221000Sxc151355 bs.bs_nextdtim = nexttbtt; 5231000Sxc151355 5241000Sxc151355 /* 5253147Sxc151355 * Setup the number of consecutive beacons to miss 5263147Sxc151355 * before taking a BMISS interrupt. 5271000Sxc151355 * Note that we clamp the result to at most 10 beacons. 5281000Sxc151355 */ 5293147Sxc151355 bs.bs_bmissthreshold = ic->ic_bmissthreshold; 5301000Sxc151355 if (bs.bs_bmissthreshold > 10) 5311000Sxc151355 bs.bs_bmissthreshold = 10; 5321000Sxc151355 else if (bs.bs_bmissthreshold <= 0) 5331000Sxc151355 bs.bs_bmissthreshold = 1; 5341000Sxc151355 /* 5351000Sxc151355 * Calculate sleep duration. The configuration is 5361000Sxc151355 * given in ms. We insure a multiple of the beacon 5371000Sxc151355 * period is used. Also, if the sleep duration is 5381000Sxc151355 * greater than the DTIM period then it makes senses 5391000Sxc151355 * to make it a multiple of that. 5401000Sxc151355 */ 5411000Sxc151355 bs.bs_sleepduration = 5421000Sxc151355 roundup((100 * 1000) / 1024, bs.bs_intval); 5431000Sxc151355 if (bs.bs_sleepduration > bs.bs_dtimperiod) 5441000Sxc151355 bs.bs_sleepduration = 5451000Sxc151355 roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 5461000Sxc151355 5471000Sxc151355 5481000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): " 5491000Sxc151355 "intval %u nexttbtt %u dtim %u" 5501000Sxc151355 " nextdtim %u bmiss %u sleep %u\n", 5511000Sxc151355 bs.bs_intval, 5521000Sxc151355 bs.bs_nexttbtt, 5531000Sxc151355 bs.bs_dtimperiod, 5541000Sxc151355 bs.bs_nextdtim, 5551000Sxc151355 bs.bs_bmissthreshold, 5561000Sxc151355 bs.bs_sleepduration)); 5571000Sxc151355 ATH_HAL_INTRSET(ah, 0); 5581000Sxc151355 /* 5591000Sxc151355 * Reset our tsf so the hardware will update the 5601000Sxc151355 * tsf register to reflect timestamps found in 5611000Sxc151355 * received beacons. 5621000Sxc151355 */ 5631000Sxc151355 ATH_HAL_RESETTSF(ah); 5641000Sxc151355 ATH_HAL_BEACONTIMERS(ah, &bs); 5651000Sxc151355 asc->asc_imask |= HAL_INT_BMISS; 5661000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 5671000Sxc151355 } else { 5681000Sxc151355 ATH_HAL_INTRSET(ah, 0); 5691000Sxc151355 ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval); 5701000Sxc151355 asc->asc_imask |= HAL_INT_SWBA; /* beacon prepare */ 5711000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 5721000Sxc151355 } 5731000Sxc151355 } 5741000Sxc151355 5753147Sxc151355 /* 576*4126Szf162725 * Allocate tx/rx key slots for TKIP. We allocate two slots for 577*4126Szf162725 * each key, one for decrypt/encrypt and the other for the MIC. 578*4126Szf162725 */ 579*4126Szf162725 static int 580*4126Szf162725 key_alloc_2pair(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 581*4126Szf162725 { 582*4126Szf162725 uint16_t i, keyix; 583*4126Szf162725 584*4126Szf162725 ASSERT(asc->asc_splitmic); 585*4126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) { 586*4126Szf162725 uint8_t b = asc->asc_keymap[i]; 587*4126Szf162725 if (b != 0xff) { 588*4126Szf162725 /* 589*4126Szf162725 * One or more slots in this byte are free. 590*4126Szf162725 */ 591*4126Szf162725 keyix = i*NBBY; 592*4126Szf162725 while (b & 1) { 593*4126Szf162725 again: 594*4126Szf162725 keyix++; 595*4126Szf162725 b >>= 1; 596*4126Szf162725 } 597*4126Szf162725 /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */ 598*4126Szf162725 if (isset(asc->asc_keymap, keyix+32) || 599*4126Szf162725 isset(asc->asc_keymap, keyix+64) || 600*4126Szf162725 isset(asc->asc_keymap, keyix+32+64)) { 601*4126Szf162725 /* full pair unavailable */ 602*4126Szf162725 if (keyix == (i+1)*NBBY) { 603*4126Szf162725 /* no slots were appropriate, advance */ 604*4126Szf162725 continue; 605*4126Szf162725 } 606*4126Szf162725 goto again; 607*4126Szf162725 } 608*4126Szf162725 setbit(asc->asc_keymap, keyix); 609*4126Szf162725 setbit(asc->asc_keymap, keyix+64); 610*4126Szf162725 setbit(asc->asc_keymap, keyix+32); 611*4126Szf162725 setbit(asc->asc_keymap, keyix+32+64); 612*4126Szf162725 ATH_DEBUG((ATH_DBG_AUX, 613*4126Szf162725 "key_alloc_2pair: key pair %u,%u %u,%u\n", 614*4126Szf162725 keyix, keyix+64, 615*4126Szf162725 keyix+32, keyix+32+64)); 616*4126Szf162725 *txkeyix = *rxkeyix = keyix; 617*4126Szf162725 return (1); 618*4126Szf162725 } 619*4126Szf162725 } 620*4126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_2pair:" 621*4126Szf162725 " out of pair space\n")); 622*4126Szf162725 return (0); 623*4126Szf162725 } 624*4126Szf162725 /* 625*4126Szf162725 * Allocate a single key cache slot. 626*4126Szf162725 */ 627*4126Szf162725 static int 628*4126Szf162725 key_alloc_single(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix) 629*4126Szf162725 { 630*4126Szf162725 uint16_t i, keyix; 631*4126Szf162725 632*4126Szf162725 /* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */ 633*4126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap); i++) { 634*4126Szf162725 uint8_t b = asc->asc_keymap[i]; 635*4126Szf162725 636*4126Szf162725 if (b != 0xff) { 637*4126Szf162725 /* 638*4126Szf162725 * One or more slots are free. 639*4126Szf162725 */ 640*4126Szf162725 keyix = i*NBBY; 641*4126Szf162725 while (b & 1) 642*4126Szf162725 keyix++, b >>= 1; 643*4126Szf162725 setbit(asc->asc_keymap, keyix); 644*4126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_single:" 645*4126Szf162725 " key %u\n", keyix)); 646*4126Szf162725 *txkeyix = *rxkeyix = keyix; 647*4126Szf162725 return (1); 648*4126Szf162725 } 649*4126Szf162725 } 650*4126Szf162725 return (0); 651*4126Szf162725 } 652*4126Szf162725 653*4126Szf162725 /* 6543147Sxc151355 * Allocate one or more key cache slots for a unicast key. The 6553147Sxc151355 * key itself is needed only to identify the cipher. For hardware 6563147Sxc151355 * TKIP with split cipher+MIC keys we allocate two key cache slot 6573147Sxc151355 * pairs so that we can setup separate TX and RX MIC keys. Note 6583147Sxc151355 * that the MIC key for a TKIP key at slot i is assumed by the 6593147Sxc151355 * hardware to be at slot i+64. This limits TKIP keys to the first 6603147Sxc151355 * 64 entries. 6613147Sxc151355 */ 6623147Sxc151355 /* ARGSUSED */ 6633147Sxc151355 int 6643147Sxc151355 ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k, 6653147Sxc151355 ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix) 6663147Sxc151355 { 667*4126Szf162725 ath_t *asc = (ath_t *)ic; 668*4126Szf162725 669*4126Szf162725 /* 670*4126Szf162725 * We allocate two pair for TKIP when using the h/w to do 671*4126Szf162725 * the MIC. For everything else, including software crypto, 672*4126Szf162725 * we allocate a single entry. Note that s/w crypto requires 673*4126Szf162725 * a pass-through slot on the 5211 and 5212. The 5210 does 674*4126Szf162725 * not support pass-through cache entries and we map all 675*4126Szf162725 * those requests to slot 0. 676*4126Szf162725 */ 677*4126Szf162725 if (k->wk_flags & IEEE80211_KEY_SWCRYPT) { 678*4126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix)); 679*4126Szf162725 } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP && 680*4126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) { 681*4126Szf162725 return (key_alloc_2pair(asc, keyix, rxkeyix)); 682*4126Szf162725 } else { 683*4126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix)); 684*4126Szf162725 } 685*4126Szf162725 } 686*4126Szf162725 687*4126Szf162725 /* 688*4126Szf162725 * Delete an entry in the key cache allocated by ath_key_alloc. 689*4126Szf162725 */ 690*4126Szf162725 int 691*4126Szf162725 ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k) 692*4126Szf162725 { 693*4126Szf162725 ath_t *asc = (ath_t *)ic; 694*4126Szf162725 struct ath_hal *ah = asc->asc_ah; 695*4126Szf162725 const struct ieee80211_cipher *cip = k->wk_cipher; 696*4126Szf162725 ieee80211_keyix keyix = k->wk_keyix; 697*4126Szf162725 698*4126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "ath_key_delete:" 699*4126Szf162725 " delete key %u ic_cipher=0x%x\n", keyix, cip->ic_cipher)); 700*4126Szf162725 701*4126Szf162725 ATH_HAL_KEYRESET(ah, keyix); 702*4126Szf162725 /* 703*4126Szf162725 * Handle split tx/rx keying required for TKIP with h/w MIC. 704*4126Szf162725 */ 705*4126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 706*4126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) 707*4126Szf162725 ATH_HAL_KEYRESET(ah, keyix+32); /* RX key */ 708*4126Szf162725 709*4126Szf162725 if (keyix >= IEEE80211_WEP_NKID) { 710*4126Szf162725 /* 711*4126Szf162725 * Don't touch keymap entries for global keys so 712*4126Szf162725 * they are never considered for dynamic allocation. 713*4126Szf162725 */ 714*4126Szf162725 clrbit(asc->asc_keymap, keyix); 715*4126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP && 716*4126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && 717*4126Szf162725 asc->asc_splitmic) { 718*4126Szf162725 clrbit(asc->asc_keymap, keyix+64); /* TX key MIC */ 719*4126Szf162725 clrbit(asc->asc_keymap, keyix+32); /* RX key */ 720*4126Szf162725 clrbit(asc->asc_keymap, keyix+32+64); /* RX key MIC */ 721*4126Szf162725 } 722*4126Szf162725 } 7233147Sxc151355 return (1); 7243147Sxc151355 } 7251000Sxc151355 726*4126Szf162725 static void 727*4126Szf162725 ath_keyprint(const char *tag, uint_t ix, 728*4126Szf162725 const HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN]) 7293147Sxc151355 { 730*4126Szf162725 static const char *ciphers[] = { 731*4126Szf162725 "WEP", 732*4126Szf162725 "AES-OCB", 733*4126Szf162725 "AES-CCM", 734*4126Szf162725 "CKIP", 735*4126Szf162725 "TKIP", 736*4126Szf162725 "CLR", 737*4126Szf162725 }; 738*4126Szf162725 int i, n; 739*4126Szf162725 char buf[MAX_IEEE80211STR], buft[32]; 740*4126Szf162725 741*4126Szf162725 (void) snprintf(buf, sizeof (buf), "%s: [%02u] %s ", 742*4126Szf162725 tag, ix, ciphers[hk->kv_type]); 743*4126Szf162725 for (i = 0, n = hk->kv_len; i < n; i++) { 744*4126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x", hk->kv_val[i]); 745*4126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 746*4126Szf162725 } 747*4126Szf162725 (void) snprintf(buft, sizeof (buft), " mac %s", 748*4126Szf162725 ieee80211_macaddr_sprintf(mac)); 749*4126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 750*4126Szf162725 if (hk->kv_type == HAL_CIPHER_TKIP) { 751*4126Szf162725 (void) snprintf(buft, sizeof (buft), " mic "); 752*4126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 753*4126Szf162725 for (i = 0; i < sizeof (hk->kv_mic); i++) { 754*4126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x", 755*4126Szf162725 hk->kv_mic[i]); 756*4126Szf162725 (void) strlcat(buf, buft, sizeof (buf)); 757*4126Szf162725 } 758*4126Szf162725 } 759*4126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "%s", buf)); 760*4126Szf162725 } 7613147Sxc151355 762*4126Szf162725 /* 763*4126Szf162725 * Set a TKIP key into the hardware. This handles the 764*4126Szf162725 * potential distribution of key state to multiple key 765*4126Szf162725 * cache slots for TKIP. 766*4126Szf162725 */ 767*4126Szf162725 static int 768*4126Szf162725 ath_keyset_tkip(ath_t *asc, const struct ieee80211_key *k, 769*4126Szf162725 HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN]) 770*4126Szf162725 { 771*4126Szf162725 #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV) 772*4126Szf162725 static const uint8_t zerobssid[IEEE80211_ADDR_LEN] = {0, 0, 0, 0, 0, 0}; 773*4126Szf162725 struct ath_hal *ah = asc->asc_ah; 774*4126Szf162725 775*4126Szf162725 ASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP); 776*4126Szf162725 if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) { 777*4126Szf162725 /* 778*4126Szf162725 * TX key goes at first index, RX key at +32. 779*4126Szf162725 * The hal handles the MIC keys at index+64. 780*4126Szf162725 */ 781*4126Szf162725 (void) memcpy(hk->kv_mic, k->wk_txmic, sizeof (hk->kv_mic)); 782*4126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid); 783*4126Szf162725 if (!ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid)) 784*4126Szf162725 return (0); 785*4126Szf162725 786*4126Szf162725 (void) memcpy(hk->kv_mic, k->wk_rxmic, sizeof (hk->kv_mic)); 787*4126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix+32, hk, mac); 788*4126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix+32, hk, mac)); 789*4126Szf162725 } else if (k->wk_flags & IEEE80211_KEY_XR) { 790*4126Szf162725 /* 791*4126Szf162725 * TX/RX key goes at first index. 792*4126Szf162725 * The hal handles the MIC keys are index+64. 793*4126Szf162725 */ 794*4126Szf162725 (void) memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ? 795*4126Szf162725 k->wk_txmic : k->wk_rxmic, sizeof (hk->kv_mic)); 796*4126Szf162725 ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid); 797*4126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid)); 798*4126Szf162725 } 799*4126Szf162725 return (0); 800*4126Szf162725 #undef IEEE80211_KEY_XR 8013147Sxc151355 } 8021000Sxc151355 8031000Sxc151355 /* 8043147Sxc151355 * Set the key cache contents for the specified key. Key cache 8053147Sxc151355 * slot(s) must already have been allocated by ath_key_alloc. 8063147Sxc151355 */ 8073147Sxc151355 int 8083147Sxc151355 ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k, 8093147Sxc151355 const uint8_t mac[IEEE80211_ADDR_LEN]) 8103147Sxc151355 { 8113147Sxc151355 static const uint8_t ciphermap[] = { 8123147Sxc151355 HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */ 8133147Sxc151355 HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */ 8143147Sxc151355 HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */ 8153147Sxc151355 HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */ 8163147Sxc151355 HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */ 8173147Sxc151355 HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */ 8183147Sxc151355 }; 8193147Sxc151355 ath_t *asc = (ath_t *)ic; 8203147Sxc151355 struct ath_hal *ah = asc->asc_ah; 8213147Sxc151355 const struct ieee80211_cipher *cip = k->wk_cipher; 8223147Sxc151355 HAL_KEYVAL hk; 8233147Sxc151355 8243147Sxc151355 bzero(&hk, sizeof (hk)); 8253147Sxc151355 /* 8263147Sxc151355 * Software crypto uses a "clear key" so non-crypto 8273147Sxc151355 * state kept in the key cache are maintainedd so that 8283147Sxc151355 * rx frames have an entry to match. 8293147Sxc151355 */ 8303147Sxc151355 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) { 8313147Sxc151355 ASSERT(cip->ic_cipher < ATH_N(ciphermap)); 8323147Sxc151355 hk.kv_type = ciphermap[cip->ic_cipher]; 8333147Sxc151355 hk.kv_len = k->wk_keylen; 8343147Sxc151355 bcopy(k->wk_key, hk.kv_val, k->wk_keylen); 8353147Sxc151355 } else { 8363147Sxc151355 hk.kv_type = HAL_CIPHER_CLR; 8373147Sxc151355 } 8383147Sxc151355 839*4126Szf162725 if (hk.kv_type == HAL_CIPHER_TKIP && 840*4126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && 841*4126Szf162725 asc->asc_splitmic) { 842*4126Szf162725 return (ath_keyset_tkip(asc, k, &hk, mac)); 843*4126Szf162725 } else { 844*4126Szf162725 ath_keyprint("ath_keyset:", k->wk_keyix, &hk, mac); 845*4126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac)); 846*4126Szf162725 } 8473147Sxc151355 } 8483147Sxc151355 8493147Sxc151355 /* 8503147Sxc151355 * Enable/Disable short slot timing 8511000Sxc151355 */ 8521000Sxc151355 void 8533147Sxc151355 ath_set_shortslot(ieee80211com_t *ic, int onoff) 8541000Sxc151355 { 8553147Sxc151355 struct ath_hal *ah = ((ath_t *)ic)->asc_ah; 8561000Sxc151355 8573147Sxc151355 if (onoff) 8583147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9); 8593147Sxc151355 else 8603147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20); 8611000Sxc151355 } 8621000Sxc151355 8633147Sxc151355 int 8643147Sxc151355 ath_reset(ieee80211com_t *ic) 8651000Sxc151355 { 8663147Sxc151355 ath_t *asc = (ath_t *)ic; 8671000Sxc151355 struct ath_hal *ah = asc->asc_ah; 8683147Sxc151355 struct ieee80211_channel *ch; 8691000Sxc151355 HAL_STATUS status; 8701000Sxc151355 HAL_CHANNEL hchan; 8711000Sxc151355 8721000Sxc151355 /* 8731000Sxc151355 * Convert to a HAL channel description with the flags 8741000Sxc151355 * constrained to reflect the current operating mode. 8751000Sxc151355 */ 8763147Sxc151355 ch = ic->ic_curchan; 8773147Sxc151355 asc->asc_curchan.channel = ch->ich_freq; 8783147Sxc151355 asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch); 8791000Sxc151355 8801000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 8811000Sxc151355 ath_draintxq(asc); /* stop xmit side */ 8823147Sxc151355 if (ATH_IS_RUNNING(asc)) { 8831000Sxc151355 ath_stoprecv(asc); /* stop recv side */ 8843147Sxc151355 /* indicate channel change so we do a full reset */ 8853147Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode, &hchan, 8863147Sxc151355 AH_TRUE, &status)) { 8873147Sxc151355 ath_problem("ath: ath_reset(): " 8883147Sxc151355 "resetting hardware failed, HAL status %u\n", 8893147Sxc151355 status); 8903147Sxc151355 } 8913147Sxc151355 ath_chan_change(asc, ch); 8921000Sxc151355 } 8933147Sxc151355 if (ATH_IS_RUNNING(asc)) { 8941000Sxc151355 if (ath_startrecv(asc) != 0) /* restart recv */ 8951000Sxc151355 ath_problem("ath: ath_reset(): " 8961000Sxc151355 "starting receiving logic failed\n"); 8973147Sxc151355 if (ic->ic_state == IEEE80211_S_RUN) { 8981000Sxc151355 ath_beacon_config(asc); /* restart beacons */ 8991000Sxc151355 } 9001000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 9011000Sxc151355 } 9023147Sxc151355 return (0); 9031000Sxc151355 } 904