1*1000Sxc151355 /* 2*1000Sxc151355 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3*1000Sxc151355 * Use is subject to license terms. 4*1000Sxc151355 */ 5*1000Sxc151355 6*1000Sxc151355 /* 7*1000Sxc151355 * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting 8*1000Sxc151355 * All rights reserved. 9*1000Sxc151355 * 10*1000Sxc151355 * Redistribution and use in source and binary forms, with or without 11*1000Sxc151355 * modification, are permitted provided that the following conditions 12*1000Sxc151355 * are met: 13*1000Sxc151355 * 1. Redistributions of source code must retain the above copyright 14*1000Sxc151355 * notice, this list of conditions and the following disclaimer, 15*1000Sxc151355 * without modification. 16*1000Sxc151355 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 17*1000Sxc151355 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 18*1000Sxc151355 * redistribution must be conditioned upon including a substantially 19*1000Sxc151355 * similar Disclaimer requirement for further binary redistribution. 20*1000Sxc151355 * 3. Neither the names of the above-listed copyright holders nor the names 21*1000Sxc151355 * of any contributors may be used to endorse or promote products derived 22*1000Sxc151355 * from this software without specific prior written permission. 23*1000Sxc151355 * 24*1000Sxc151355 * NO WARRANTY 25*1000Sxc151355 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26*1000Sxc151355 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27*1000Sxc151355 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY 28*1000Sxc151355 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 29*1000Sxc151355 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 30*1000Sxc151355 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31*1000Sxc151355 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32*1000Sxc151355 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 33*1000Sxc151355 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34*1000Sxc151355 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 35*1000Sxc151355 * THE POSSIBILITY OF SUCH DAMAGES. 36*1000Sxc151355 */ 37*1000Sxc151355 38*1000Sxc151355 #pragma ident "%Z%%M% %I% %E% SMI" 39*1000Sxc151355 40*1000Sxc151355 #include <sys/param.h> 41*1000Sxc151355 #include <sys/types.h> 42*1000Sxc151355 #include <sys/signal.h> 43*1000Sxc151355 #include <sys/stream.h> 44*1000Sxc151355 #include <sys/termio.h> 45*1000Sxc151355 #include <sys/errno.h> 46*1000Sxc151355 #include <sys/file.h> 47*1000Sxc151355 #include <sys/cmn_err.h> 48*1000Sxc151355 #include <sys/stropts.h> 49*1000Sxc151355 #include <sys/strsubr.h> 50*1000Sxc151355 #include <sys/strtty.h> 51*1000Sxc151355 #include <sys/kbio.h> 52*1000Sxc151355 #include <sys/cred.h> 53*1000Sxc151355 #include <sys/stat.h> 54*1000Sxc151355 #include <sys/consdev.h> 55*1000Sxc151355 #include <sys/kmem.h> 56*1000Sxc151355 #include <sys/modctl.h> 57*1000Sxc151355 #include <sys/ddi.h> 58*1000Sxc151355 #include <sys/sunddi.h> 59*1000Sxc151355 #include <sys/pci.h> 60*1000Sxc151355 #include <sys/errno.h> 61*1000Sxc151355 #include <sys/gld.h> 62*1000Sxc151355 #include <sys/dlpi.h> 63*1000Sxc151355 #include <sys/ethernet.h> 64*1000Sxc151355 #include <sys/list.h> 65*1000Sxc151355 #include <sys/byteorder.h> 66*1000Sxc151355 #include <sys/strsun.h> 67*1000Sxc151355 #include <inet/common.h> 68*1000Sxc151355 #include <inet/nd.h> 69*1000Sxc151355 #include <inet/mi.h> 70*1000Sxc151355 #include <inet/wifi_ioctl.h> 71*1000Sxc151355 #include "ath_hal.h" 72*1000Sxc151355 #include "ath_impl.h" 73*1000Sxc151355 #include "ath_ieee80211.h" 74*1000Sxc151355 75*1000Sxc151355 static const char *acnames[] = { 76*1000Sxc151355 "WME_AC_BE", 77*1000Sxc151355 "WME_AC_BK", 78*1000Sxc151355 "WME_AC_VI", 79*1000Sxc151355 "WME_AC_VO", 80*1000Sxc151355 "WME_UPSD" 81*1000Sxc151355 }; 82*1000Sxc151355 83*1000Sxc151355 extern void ath_setup_desc(ath_t *asc, struct ath_buf *bf); 84*1000Sxc151355 85*1000Sxc151355 uint32_t 86*1000Sxc151355 ath_calcrxfilter(ath_t *asc) 87*1000Sxc151355 { 88*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 89*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 90*1000Sxc151355 uint32_t rfilt; 91*1000Sxc151355 92*1000Sxc151355 rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR) 93*1000Sxc151355 | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST; 94*1000Sxc151355 if (isc->isc_opmode != IEEE80211_M_STA) 95*1000Sxc151355 rfilt |= HAL_RX_FILTER_PROBEREQ; 96*1000Sxc151355 if (isc->isc_opmode != IEEE80211_M_HOSTAP && 97*1000Sxc151355 (asc->asc_promisc & GLD_MAC_PROMISC_PHYS)) /* promiscuous */ 98*1000Sxc151355 rfilt |= HAL_RX_FILTER_PROM; 99*1000Sxc151355 if (isc->isc_opmode == IEEE80211_M_STA || 100*1000Sxc151355 isc->isc_opmode == IEEE80211_M_IBSS || 101*1000Sxc151355 isc->isc_state == IEEE80211_S_SCAN) 102*1000Sxc151355 rfilt |= HAL_RX_FILTER_BEACON; 103*1000Sxc151355 return (rfilt); 104*1000Sxc151355 } 105*1000Sxc151355 106*1000Sxc151355 static int 107*1000Sxc151355 ath_set_data_queue(ath_t *asc, int ac, int haltype) 108*1000Sxc151355 { 109*1000Sxc151355 HAL_TXQ_INFO qi; 110*1000Sxc151355 int qnum; 111*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 112*1000Sxc151355 struct ath_txq *txq; 113*1000Sxc151355 114*1000Sxc151355 if (ac >= ATH_N(asc->asc_ac2q)) { 115*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 116*1000Sxc151355 "ac %u out of range, max %u!\n", 117*1000Sxc151355 ac, ATH_N(asc->asc_ac2q))); 118*1000Sxc151355 return (1); 119*1000Sxc151355 } 120*1000Sxc151355 (void) memset(&qi, 0, sizeof (qi)); 121*1000Sxc151355 qi.tqi_subtype = haltype; 122*1000Sxc151355 /* 123*1000Sxc151355 * Enable interrupts only for EOL and DESC conditions. 124*1000Sxc151355 * We mark tx descriptors to receive a DESC interrupt 125*1000Sxc151355 * when a tx queue gets deep; otherwise waiting for the 126*1000Sxc151355 * EOL to reap descriptors. Note that this is done to 127*1000Sxc151355 * reduce interrupt load and this only defers reaping 128*1000Sxc151355 * descriptors, never transmitting frames. Aside from 129*1000Sxc151355 * reducing interrupts this also permits more concurrency. 130*1000Sxc151355 * The only potential downside is if the tx queue backs 131*1000Sxc151355 * up in which case the top half of the kernel may backup 132*1000Sxc151355 * due to a lack of tx descriptors. 133*1000Sxc151355 */ 134*1000Sxc151355 qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; 135*1000Sxc151355 qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi); 136*1000Sxc151355 if (qnum == -1) { 137*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 138*1000Sxc151355 "Unable to setup hardware queue for %s traffic!\n", 139*1000Sxc151355 acnames[ac])); 140*1000Sxc151355 return (1); 141*1000Sxc151355 } 142*1000Sxc151355 if (qnum >= ATH_N(asc->asc_txq)) { 143*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): " 144*1000Sxc151355 "hal qnum %u out of range, max %u!\n", 145*1000Sxc151355 qnum, ATH_N(asc->asc_txq))); 146*1000Sxc151355 return (1); 147*1000Sxc151355 } 148*1000Sxc151355 if (!ATH_TXQ_SETUP(asc, qnum)) { 149*1000Sxc151355 txq = &asc->asc_txq[qnum]; 150*1000Sxc151355 txq->axq_qnum = qnum; 151*1000Sxc151355 txq->axq_depth = 0; 152*1000Sxc151355 txq->axq_intrcnt = 0; 153*1000Sxc151355 txq->axq_link = NULL; 154*1000Sxc151355 list_create(&txq->axq_list, sizeof (struct ath_buf), 155*1000Sxc151355 offsetof(struct ath_buf, bf_node)); 156*1000Sxc151355 mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL); 157*1000Sxc151355 asc->asc_txqsetup |= 1<<qnum; 158*1000Sxc151355 } 159*1000Sxc151355 asc->asc_ac2q[ac] = &asc->asc_txq[qnum]; 160*1000Sxc151355 return (0); 161*1000Sxc151355 } 162*1000Sxc151355 163*1000Sxc151355 int 164*1000Sxc151355 ath_txq_setup(ath_t *asc) 165*1000Sxc151355 { 166*1000Sxc151355 if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) || 167*1000Sxc151355 ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) || 168*1000Sxc151355 ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) || 169*1000Sxc151355 ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) { 170*1000Sxc151355 return (1); 171*1000Sxc151355 } 172*1000Sxc151355 173*1000Sxc151355 return (0); 174*1000Sxc151355 } 175*1000Sxc151355 176*1000Sxc151355 void 177*1000Sxc151355 ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode) 178*1000Sxc151355 { 179*1000Sxc151355 const HAL_RATE_TABLE *rt; 180*1000Sxc151355 int i; 181*1000Sxc151355 182*1000Sxc151355 for (i = 0; i < sizeof (asc->asc_rixmap); i++) 183*1000Sxc151355 asc->asc_rixmap[i] = 0xff; 184*1000Sxc151355 185*1000Sxc151355 rt = asc->asc_rates[mode]; 186*1000Sxc151355 ASSERT(rt != NULL); 187*1000Sxc151355 188*1000Sxc151355 for (i = 0; i < rt->rateCount; i++) 189*1000Sxc151355 asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i; 190*1000Sxc151355 191*1000Sxc151355 asc->asc_currates = rt; 192*1000Sxc151355 asc->asc_curmode = mode; 193*1000Sxc151355 } 194*1000Sxc151355 195*1000Sxc151355 /* Set correct parameters for a certain mode */ 196*1000Sxc151355 void 197*1000Sxc151355 ath_mode_init(ath_t *asc) 198*1000Sxc151355 { 199*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 200*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 201*1000Sxc151355 uint32_t rfilt; 202*1000Sxc151355 203*1000Sxc151355 /* configure rx filter */ 204*1000Sxc151355 rfilt = ath_calcrxfilter(asc); 205*1000Sxc151355 ATH_HAL_SETRXFILTER(ah, rfilt); 206*1000Sxc151355 ATH_HAL_SETOPMODE(ah); 207*1000Sxc151355 ATH_HAL_SETMCASTFILTER(ah, asc->asc_mfilt[0], asc->asc_mfilt[1]); 208*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): " 209*1000Sxc151355 "mode =%d RX filter 0x%x, MC filter %08x:%08x\n", 210*1000Sxc151355 isc->isc_opmode, rfilt, 211*1000Sxc151355 asc->asc_mfilt[0], asc->asc_mfilt[1])); 212*1000Sxc151355 } 213*1000Sxc151355 214*1000Sxc151355 215*1000Sxc151355 /* 216*1000Sxc151355 * Disable the receive h/w in preparation for a reset. 217*1000Sxc151355 */ 218*1000Sxc151355 void 219*1000Sxc151355 ath_stoprecv(ath_t *asc) 220*1000Sxc151355 { 221*1000Sxc151355 ATH_HAL_STOPPCURECV(asc->asc_ah); /* disable PCU */ 222*1000Sxc151355 ATH_HAL_SETRXFILTER(asc->asc_ah, 0); /* clear recv filter */ 223*1000Sxc151355 ATH_HAL_STOPDMARECV(asc->asc_ah); /* disable DMA engine */ 224*1000Sxc151355 drv_usecwait(3000); 225*1000Sxc151355 226*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n", 227*1000Sxc151355 ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink)); 228*1000Sxc151355 asc->asc_rxlink = NULL; 229*1000Sxc151355 } 230*1000Sxc151355 231*1000Sxc151355 uint32_t 232*1000Sxc151355 ath_chan2flags(ieee80211com_t *isc, struct ieee80211channel *chan) 233*1000Sxc151355 { 234*1000Sxc151355 static const uint32_t modeflags[] = { 235*1000Sxc151355 0, /* IEEE80211_MODE_AUTO */ 236*1000Sxc151355 CHANNEL_A, /* IEEE80211_MODE_11A */ 237*1000Sxc151355 CHANNEL_B, /* IEEE80211_MODE_11B */ 238*1000Sxc151355 CHANNEL_PUREG, /* IEEE80211_MODE_11G */ 239*1000Sxc151355 CHANNEL_T /* IEEE80211_MODE_TURBO */ 240*1000Sxc151355 }; 241*1000Sxc151355 return (modeflags[ieee80211_chan2mode(isc, chan)]); 242*1000Sxc151355 } 243*1000Sxc151355 244*1000Sxc151355 245*1000Sxc151355 int 246*1000Sxc151355 ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode) 247*1000Sxc151355 { 248*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 249*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 250*1000Sxc151355 HAL_CHANNEL *chans; 251*1000Sxc151355 int i, ix; 252*1000Sxc151355 uint32_t nchan; 253*1000Sxc151355 254*1000Sxc151355 chans = (HAL_CHANNEL *) 255*1000Sxc151355 kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP); 256*1000Sxc151355 257*1000Sxc151355 if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan, 258*1000Sxc151355 cc, HAL_MODE_ALL, outdoor, xchanmode)) { 259*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 260*1000Sxc151355 "unable to get channel list\n"); 261*1000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL))); 262*1000Sxc151355 return (EINVAL); 263*1000Sxc151355 } 264*1000Sxc151355 265*1000Sxc151355 /* 266*1000Sxc151355 * Convert HAL channels to ieee80211 ones and insert 267*1000Sxc151355 * them in the table according to their channel number. 268*1000Sxc151355 */ 269*1000Sxc151355 for (i = 0; i < nchan; i++) { 270*1000Sxc151355 HAL_CHANNEL *c = &chans[i]; 271*1000Sxc151355 ix = ath_hal_mhz2ieee(c->channel, c->channelFlags); 272*1000Sxc151355 if (ix > IEEE80211_CHAN_MAX) { 273*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): " 274*1000Sxc151355 "bad hal channel %u (%u/%x) ignored\n", 275*1000Sxc151355 ix, c->channel, c->channelFlags)); 276*1000Sxc151355 continue; 277*1000Sxc151355 } 278*1000Sxc151355 /* NB: flags are known to be compatible */ 279*1000Sxc151355 if (isc->isc_channels[ix].ich_freq == 0) { 280*1000Sxc151355 isc->isc_channels[ix].ich_freq = c->channel; 281*1000Sxc151355 isc->isc_channels[ix].ich_flags = c->channelFlags; 282*1000Sxc151355 } else { 283*1000Sxc151355 /* channels overlap; e.g. 11g and 11b */ 284*1000Sxc151355 isc->isc_channels[ix].ich_flags |= c->channelFlags; 285*1000Sxc151355 } 286*1000Sxc151355 if ((c->channelFlags & CHANNEL_G) == CHANNEL_G) 287*1000Sxc151355 asc->asc_have11g = 1; 288*1000Sxc151355 } 289*1000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL)); 290*1000Sxc151355 return (0); 291*1000Sxc151355 } 292*1000Sxc151355 293*1000Sxc151355 static void 294*1000Sxc151355 ath_drainq(ath_t *asc, struct ath_txq *txq) 295*1000Sxc151355 { 296*1000Sxc151355 struct ath_buf *bf; 297*1000Sxc151355 298*1000Sxc151355 /* 299*1000Sxc151355 * This assumes output has been stopped. 300*1000Sxc151355 */ 301*1000Sxc151355 for (;;) { 302*1000Sxc151355 mutex_enter(&txq->axq_lock); 303*1000Sxc151355 bf = list_head(&txq->axq_list); 304*1000Sxc151355 if (bf == NULL) { 305*1000Sxc151355 txq->axq_link = NULL; 306*1000Sxc151355 mutex_exit(&txq->axq_lock); 307*1000Sxc151355 break; 308*1000Sxc151355 } 309*1000Sxc151355 list_remove(&txq->axq_list, bf); 310*1000Sxc151355 mutex_exit(&txq->axq_lock); 311*1000Sxc151355 bf->bf_in = NULL; 312*1000Sxc151355 mutex_enter(&asc->asc_txbuflock); 313*1000Sxc151355 list_insert_tail(&asc->asc_txbuf_list, bf); 314*1000Sxc151355 mutex_exit(&asc->asc_txbuflock); 315*1000Sxc151355 } 316*1000Sxc151355 } 317*1000Sxc151355 318*1000Sxc151355 319*1000Sxc151355 /* 320*1000Sxc151355 * Drain the transmit queues and reclaim resources. 321*1000Sxc151355 */ 322*1000Sxc151355 void 323*1000Sxc151355 ath_draintxq(ath_t *asc) 324*1000Sxc151355 { 325*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 326*1000Sxc151355 struct ath_txq *txq; 327*1000Sxc151355 int i; 328*1000Sxc151355 329*1000Sxc151355 if (!asc->asc_invalid) { 330*1000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 331*1000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 332*1000Sxc151355 txq = &asc->asc_txq[i]; 333*1000Sxc151355 (void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum); 334*1000Sxc151355 } 335*1000Sxc151355 } 336*1000Sxc151355 } 337*1000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) { 338*1000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) { 339*1000Sxc151355 ath_drainq(asc, &asc->asc_txq[i]); 340*1000Sxc151355 } 341*1000Sxc151355 } 342*1000Sxc151355 } 343*1000Sxc151355 344*1000Sxc151355 345*1000Sxc151355 /* Enable the receive h/w following a reset */ 346*1000Sxc151355 int 347*1000Sxc151355 ath_startrecv(ath_t *asc) 348*1000Sxc151355 { 349*1000Sxc151355 struct ath_buf *bf; 350*1000Sxc151355 351*1000Sxc151355 asc->asc_rxlink = NULL; 352*1000Sxc151355 353*1000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 354*1000Sxc151355 while (bf != NULL) { 355*1000Sxc151355 ath_setup_desc(asc, bf); 356*1000Sxc151355 bf = list_next(&asc->asc_rxbuf_list, bf); 357*1000Sxc151355 } 358*1000Sxc151355 359*1000Sxc151355 bf = list_head(&asc->asc_rxbuf_list); 360*1000Sxc151355 ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr); 361*1000Sxc151355 ATH_HAL_RXENA(asc->asc_ah); /* enable recv descriptors */ 362*1000Sxc151355 ath_mode_init(asc); /* set filters, etc. */ 363*1000Sxc151355 ATH_HAL_STARTPCURECV(asc->asc_ah); /* re-enable PCU/DMA engine */ 364*1000Sxc151355 return (0); 365*1000Sxc151355 } 366*1000Sxc151355 367*1000Sxc151355 /* 368*1000Sxc151355 * Set/change channels. If the channel is really being changed, 369*1000Sxc151355 * it's done by resetting the chip. To accomplish this we must 370*1000Sxc151355 * first cleanup any pending DMA. 371*1000Sxc151355 */ 372*1000Sxc151355 int 373*1000Sxc151355 ath_chan_set(ath_t *asc, struct ieee80211channel *chan) 374*1000Sxc151355 { 375*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 376*1000Sxc151355 ieee80211com_t *isc = &asc->asc_isc; 377*1000Sxc151355 378*1000Sxc151355 if (chan != isc->isc_ibss_chan) { 379*1000Sxc151355 HAL_STATUS status; 380*1000Sxc151355 HAL_CHANNEL hchan; 381*1000Sxc151355 enum ieee80211_phymode mode; 382*1000Sxc151355 383*1000Sxc151355 /* 384*1000Sxc151355 * To switch channels clear any pending DMA operations; 385*1000Sxc151355 * wait long enough for the RX fifo to drain, reset the 386*1000Sxc151355 * hardware at the new frequency, and then re-enable 387*1000Sxc151355 * the relevant bits of the h/w. 388*1000Sxc151355 */ 389*1000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 390*1000Sxc151355 ath_draintxq(asc); /* clear pending tx frames */ 391*1000Sxc151355 ath_stoprecv(asc); /* turn off frame recv */ 392*1000Sxc151355 /* 393*1000Sxc151355 * Convert to a HAL channel description with 394*1000Sxc151355 * the flags constrained to reflect the current 395*1000Sxc151355 * operating mode. 396*1000Sxc151355 */ 397*1000Sxc151355 hchan.channel = chan->ich_freq; 398*1000Sxc151355 hchan.channelFlags = ath_chan2flags(isc, chan); 399*1000Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)isc->isc_opmode, 400*1000Sxc151355 &hchan, AH_TRUE, &status)) { 401*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():" 402*1000Sxc151355 "unable to reset channel %u (%uMhz)\n", 403*1000Sxc151355 ieee80211_chan2ieee(isc, chan), chan->ich_freq)); 404*1000Sxc151355 return (EIO); 405*1000Sxc151355 } 406*1000Sxc151355 407*1000Sxc151355 /* 408*1000Sxc151355 * Re-enable rx framework. 409*1000Sxc151355 */ 410*1000Sxc151355 if (ath_startrecv(asc) != 0) { 411*1000Sxc151355 ath_problem("ath: ath_chan_set(): " 412*1000Sxc151355 "restarting receiving logic failed\n"); 413*1000Sxc151355 return (EIO); 414*1000Sxc151355 } 415*1000Sxc151355 416*1000Sxc151355 /* 417*1000Sxc151355 * Change channels and update the h/w rate map 418*1000Sxc151355 * if we're switching; e.g. 11a to 11b/g. 419*1000Sxc151355 */ 420*1000Sxc151355 isc->isc_ibss_chan = chan; 421*1000Sxc151355 mode = ieee80211_chan2mode(isc, chan); 422*1000Sxc151355 if (mode != asc->asc_curmode) 423*1000Sxc151355 ath_setcurmode(asc, mode); 424*1000Sxc151355 /* 425*1000Sxc151355 * Re-enable interrupts. 426*1000Sxc151355 */ 427*1000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 428*1000Sxc151355 } 429*1000Sxc151355 return (0); 430*1000Sxc151355 } 431*1000Sxc151355 432*1000Sxc151355 433*1000Sxc151355 /* 434*1000Sxc151355 * Configure the beacon and sleep timers. 435*1000Sxc151355 * 436*1000Sxc151355 * When operating as an AP this resets the TSF and sets 437*1000Sxc151355 * up the hardware to notify us when we need to issue beacons. 438*1000Sxc151355 * 439*1000Sxc151355 * When operating in station mode this sets up the beacon 440*1000Sxc151355 * timers according to the timestamp of the last received 441*1000Sxc151355 * beacon and the current TSF, configures PCF and DTIM 442*1000Sxc151355 * handling, programs the sleep registers so the hardware 443*1000Sxc151355 * will wakeup in time to receive beacons, and configures 444*1000Sxc151355 * the beacon miss handling so we'll receive a BMISS 445*1000Sxc151355 * interrupt when we stop seeing beacons from the AP 446*1000Sxc151355 * we've associated with. 447*1000Sxc151355 */ 448*1000Sxc151355 void 449*1000Sxc151355 ath_beacon_config(ath_t *asc) 450*1000Sxc151355 { 451*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 452*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 453*1000Sxc151355 struct ieee80211_node *in = isc->isc_bss; 454*1000Sxc151355 uint32_t nexttbtt; 455*1000Sxc151355 456*1000Sxc151355 nexttbtt = (ATH_LE_READ_4(in->in_tstamp + 4) << 22) | 457*1000Sxc151355 (ATH_LE_READ_4(in->in_tstamp) >> 10); 458*1000Sxc151355 nexttbtt += in->in_intval; 459*1000Sxc151355 if (isc->isc_opmode != IEEE80211_M_HOSTAP) { 460*1000Sxc151355 HAL_BEACON_STATE bs; 461*1000Sxc151355 uint32_t bmisstime; 462*1000Sxc151355 463*1000Sxc151355 /* NB: no PCF support right now */ 464*1000Sxc151355 bzero(&bs, sizeof (bs)); 465*1000Sxc151355 bs.bs_intval = in->in_intval; 466*1000Sxc151355 bs.bs_nexttbtt = nexttbtt; 467*1000Sxc151355 bs.bs_dtimperiod = bs.bs_intval; 468*1000Sxc151355 bs.bs_nextdtim = nexttbtt; 469*1000Sxc151355 470*1000Sxc151355 /* 471*1000Sxc151355 * Calculate the number of consecutive beacons to miss 472*1000Sxc151355 * before taking a BMISS interrupt. The configuration 473*1000Sxc151355 * is specified in ms, so we need to convert that to 474*1000Sxc151355 * TU's and then calculate based on the beacon interval. 475*1000Sxc151355 * Note that we clamp the result to at most 10 beacons. 476*1000Sxc151355 */ 477*1000Sxc151355 bmisstime = (isc->isc_bmisstimeout * 1000) / 1024; 478*1000Sxc151355 bs.bs_bmissthreshold = howmany(bmisstime, in->in_intval); 479*1000Sxc151355 if (bs.bs_bmissthreshold > 10) 480*1000Sxc151355 bs.bs_bmissthreshold = 10; 481*1000Sxc151355 else if (bs.bs_bmissthreshold <= 0) 482*1000Sxc151355 bs.bs_bmissthreshold = 1; 483*1000Sxc151355 /* 484*1000Sxc151355 * Calculate sleep duration. The configuration is 485*1000Sxc151355 * given in ms. We insure a multiple of the beacon 486*1000Sxc151355 * period is used. Also, if the sleep duration is 487*1000Sxc151355 * greater than the DTIM period then it makes senses 488*1000Sxc151355 * to make it a multiple of that. 489*1000Sxc151355 */ 490*1000Sxc151355 bs.bs_sleepduration = 491*1000Sxc151355 roundup((100 * 1000) / 1024, bs.bs_intval); 492*1000Sxc151355 if (bs.bs_sleepduration > bs.bs_dtimperiod) 493*1000Sxc151355 bs.bs_sleepduration = 494*1000Sxc151355 roundup(bs.bs_sleepduration, bs.bs_dtimperiod); 495*1000Sxc151355 496*1000Sxc151355 497*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): " 498*1000Sxc151355 "intval %u nexttbtt %u dtim %u" 499*1000Sxc151355 " nextdtim %u bmiss %u sleep %u\n", 500*1000Sxc151355 bs.bs_intval, 501*1000Sxc151355 bs.bs_nexttbtt, 502*1000Sxc151355 bs.bs_dtimperiod, 503*1000Sxc151355 bs.bs_nextdtim, 504*1000Sxc151355 bs.bs_bmissthreshold, 505*1000Sxc151355 bs.bs_sleepduration)); 506*1000Sxc151355 ATH_HAL_INTRSET(ah, 0); 507*1000Sxc151355 /* 508*1000Sxc151355 * Reset our tsf so the hardware will update the 509*1000Sxc151355 * tsf register to reflect timestamps found in 510*1000Sxc151355 * received beacons. 511*1000Sxc151355 */ 512*1000Sxc151355 ATH_HAL_RESETTSF(ah); 513*1000Sxc151355 ATH_HAL_BEACONTIMERS(ah, &bs); 514*1000Sxc151355 asc->asc_imask |= HAL_INT_BMISS; 515*1000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 516*1000Sxc151355 } else { 517*1000Sxc151355 ATH_HAL_INTRSET(ah, 0); 518*1000Sxc151355 ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval); 519*1000Sxc151355 asc->asc_imask |= HAL_INT_SWBA; /* beacon prepare */ 520*1000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 521*1000Sxc151355 } 522*1000Sxc151355 } 523*1000Sxc151355 524*1000Sxc151355 525*1000Sxc151355 526*1000Sxc151355 /* 527*1000Sxc151355 * Fill the hardware key cache with key entries. 528*1000Sxc151355 */ 529*1000Sxc151355 void 530*1000Sxc151355 ath_initkeytable(ath_t *asc) 531*1000Sxc151355 { 532*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 533*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 534*1000Sxc151355 int32_t i; 535*1000Sxc151355 536*1000Sxc151355 for (i = 0; i < IEEE80211_WEP_NKID; i++) { 537*1000Sxc151355 struct ieee80211_wepkey *k = &isc->isc_nw_keys[i]; 538*1000Sxc151355 if (k->iwk_len == 0) 539*1000Sxc151355 ATH_HAL_KEYRESET(ah, i); 540*1000Sxc151355 else { 541*1000Sxc151355 HAL_KEYVAL hk; 542*1000Sxc151355 543*1000Sxc151355 #ifdef DEBUG 544*1000Sxc151355 char tmp[200], stmp[10]; 545*1000Sxc151355 int j; 546*1000Sxc151355 bzero(tmp, 200); 547*1000Sxc151355 bzero(stmp, 10); 548*1000Sxc151355 for (j = 0; j < k->iwk_len; j++) { 549*1000Sxc151355 (void) sprintf(stmp, "0x%02x ", k->iwk_key[j]); 550*1000Sxc151355 (void) strcat(tmp, stmp); 551*1000Sxc151355 } 552*1000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_initkeytable(): " 553*1000Sxc151355 "key%d val=%s\n", i, tmp)); 554*1000Sxc151355 #endif /* DEBUG */ 555*1000Sxc151355 bzero(&hk, sizeof (hk)); 556*1000Sxc151355 hk.kv_type = HAL_CIPHER_WEP; 557*1000Sxc151355 hk.kv_len = k->iwk_len; 558*1000Sxc151355 bcopy(k->iwk_key, hk.kv_val, k->iwk_len); 559*1000Sxc151355 ATH_HAL_KEYSET(ah, i, &hk); 560*1000Sxc151355 } 561*1000Sxc151355 } 562*1000Sxc151355 } 563*1000Sxc151355 564*1000Sxc151355 void 565*1000Sxc151355 ath_reset(ath_t *asc) 566*1000Sxc151355 { 567*1000Sxc151355 ieee80211com_t *isc = (ieee80211com_t *)asc; 568*1000Sxc151355 struct ath_hal *ah = asc->asc_ah; 569*1000Sxc151355 struct ieee80211channel *ch; 570*1000Sxc151355 HAL_STATUS status; 571*1000Sxc151355 HAL_CHANNEL hchan; 572*1000Sxc151355 573*1000Sxc151355 /* 574*1000Sxc151355 * Convert to a HAL channel description with the flags 575*1000Sxc151355 * constrained to reflect the current operating mode. 576*1000Sxc151355 */ 577*1000Sxc151355 ch = isc->isc_ibss_chan; 578*1000Sxc151355 hchan.channel = ch->ich_freq; 579*1000Sxc151355 hchan.channelFlags = ath_chan2flags(isc, ch); 580*1000Sxc151355 581*1000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */ 582*1000Sxc151355 ath_draintxq(asc); /* stop xmit side */ 583*1000Sxc151355 if (asc->asc_invalid == 0) 584*1000Sxc151355 ath_stoprecv(asc); /* stop recv side */ 585*1000Sxc151355 /* indicate channel change so we do a full reset */ 586*1000Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)isc->isc_opmode, &hchan, 587*1000Sxc151355 AH_TRUE, &status)) { 588*1000Sxc151355 ath_problem("ath: ath_reset(): " 589*1000Sxc151355 "reseting hardware failed, HAL status %u\n", status); 590*1000Sxc151355 } 591*1000Sxc151355 if (asc->asc_invalid == 0) { 592*1000Sxc151355 ath_initkeytable(asc); 593*1000Sxc151355 if (ath_startrecv(asc) != 0) /* restart recv */ 594*1000Sxc151355 ath_problem("ath: ath_reset(): " 595*1000Sxc151355 "starting receiving logic failed\n"); 596*1000Sxc151355 if (isc->isc_state == IEEE80211_S_RUN) { 597*1000Sxc151355 ath_beacon_config(asc); /* restart beacons */ 598*1000Sxc151355 } 599*1000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask); 600*1000Sxc151355 } 601*1000Sxc151355 } 602