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 #include <sys/param.h>
391000Sxc151355 #include <sys/types.h>
401000Sxc151355 #include <sys/signal.h>
411000Sxc151355 #include <sys/stream.h>
421000Sxc151355 #include <sys/termio.h>
431000Sxc151355 #include <sys/errno.h>
441000Sxc151355 #include <sys/file.h>
451000Sxc151355 #include <sys/cmn_err.h>
461000Sxc151355 #include <sys/stropts.h>
471000Sxc151355 #include <sys/strsubr.h>
481000Sxc151355 #include <sys/strtty.h>
491000Sxc151355 #include <sys/kbio.h>
501000Sxc151355 #include <sys/cred.h>
511000Sxc151355 #include <sys/stat.h>
521000Sxc151355 #include <sys/consdev.h>
531000Sxc151355 #include <sys/kmem.h>
541000Sxc151355 #include <sys/modctl.h>
551000Sxc151355 #include <sys/ddi.h>
561000Sxc151355 #include <sys/sunddi.h>
571000Sxc151355 #include <sys/pci.h>
581000Sxc151355 #include <sys/errno.h>
591000Sxc151355 #include <sys/gld.h>
601000Sxc151355 #include <sys/dlpi.h>
611000Sxc151355 #include <sys/ethernet.h>
621000Sxc151355 #include <sys/list.h>
631000Sxc151355 #include <sys/byteorder.h>
641000Sxc151355 #include <sys/strsun.h>
651000Sxc151355 #include <inet/common.h>
661000Sxc151355 #include <inet/nd.h>
671000Sxc151355 #include <inet/mi.h>
681000Sxc151355 #include <inet/wifi_ioctl.h>
691000Sxc151355 #include "ath_hal.h"
701000Sxc151355 #include "ath_impl.h"
711000Sxc151355
721000Sxc151355 static const char *acnames[] = {
731000Sxc151355 "WME_AC_BE",
741000Sxc151355 "WME_AC_BK",
751000Sxc151355 "WME_AC_VI",
761000Sxc151355 "WME_AC_VO",
771000Sxc151355 "WME_UPSD"
781000Sxc151355 };
791000Sxc151355
801000Sxc151355 extern void ath_setup_desc(ath_t *asc, struct ath_buf *bf);
811000Sxc151355
826235Sxc151355
836235Sxc151355 const char *
ath_get_hal_status_desc(HAL_STATUS status)846235Sxc151355 ath_get_hal_status_desc(HAL_STATUS status)
856235Sxc151355 {
866235Sxc151355 static const char *hal_status_desc[] = {
876235Sxc151355 "No error",
886235Sxc151355 "No hardware present or device not yet supported",
896235Sxc151355 "Memory allocation failed",
906235Sxc151355 "Hardware didn't respond as expected",
916235Sxc151355 "EEPROM magic number invalid",
926235Sxc151355 "EEPROM version invalid",
936235Sxc151355 "EEPROM unreadable",
946235Sxc151355 "EEPROM checksum invalid",
956235Sxc151355 "EEPROM read problem",
966235Sxc151355 "EEPROM mac address invalid",
976235Sxc151355 "EEPROM size not supported",
986235Sxc151355 "Attempt to change write-locked EEPROM",
996235Sxc151355 "Invalid parameter to function",
1006235Sxc151355 "Hardware revision not supported",
1016235Sxc151355 "Hardware self-test failed",
1026235Sxc151355 "Operation incomplete"
1036235Sxc151355 };
1046235Sxc151355
1056235Sxc151355 if (status >= 0 && status < sizeof (hal_status_desc)/sizeof (char *))
1066235Sxc151355 return (hal_status_desc[status]);
1076235Sxc151355 else
1086235Sxc151355 return ("");
1096235Sxc151355 }
1106235Sxc151355
1111000Sxc151355 uint32_t
ath_calcrxfilter(ath_t * asc)1121000Sxc151355 ath_calcrxfilter(ath_t *asc)
1131000Sxc151355 {
1143147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc;
1151000Sxc151355 struct ath_hal *ah = asc->asc_ah;
1161000Sxc151355 uint32_t rfilt;
1171000Sxc151355
1181000Sxc151355 rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR)
1191000Sxc151355 | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
1203147Sxc151355 if (ic->ic_opmode != IEEE80211_M_STA)
1211000Sxc151355 rfilt |= HAL_RX_FILTER_PROBEREQ;
1226235Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP && asc->asc_promisc)
1236235Sxc151355 rfilt |= HAL_RX_FILTER_PROM; /* promiscuous */
1243147Sxc151355 if (ic->ic_opmode == IEEE80211_M_STA ||
1253147Sxc151355 ic->ic_opmode == IEEE80211_M_IBSS ||
1263147Sxc151355 ic->ic_state == IEEE80211_S_SCAN)
1271000Sxc151355 rfilt |= HAL_RX_FILTER_BEACON;
1281000Sxc151355 return (rfilt);
1291000Sxc151355 }
1301000Sxc151355
1311000Sxc151355 static int
ath_set_data_queue(ath_t * asc,int ac,int haltype)1321000Sxc151355 ath_set_data_queue(ath_t *asc, int ac, int haltype)
1331000Sxc151355 {
1341000Sxc151355 HAL_TXQ_INFO qi;
1351000Sxc151355 int qnum;
1361000Sxc151355 struct ath_hal *ah = asc->asc_ah;
1371000Sxc151355 struct ath_txq *txq;
1381000Sxc151355
1391000Sxc151355 if (ac >= ATH_N(asc->asc_ac2q)) {
1401000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1411000Sxc151355 "ac %u out of range, max %u!\n",
1421000Sxc151355 ac, ATH_N(asc->asc_ac2q)));
1431000Sxc151355 return (1);
1441000Sxc151355 }
1451000Sxc151355 (void) memset(&qi, 0, sizeof (qi));
1461000Sxc151355 qi.tqi_subtype = haltype;
1471000Sxc151355 /*
1481000Sxc151355 * Enable interrupts only for EOL and DESC conditions.
1491000Sxc151355 * We mark tx descriptors to receive a DESC interrupt
1501000Sxc151355 * when a tx queue gets deep; otherwise waiting for the
1511000Sxc151355 * EOL to reap descriptors. Note that this is done to
1521000Sxc151355 * reduce interrupt load and this only defers reaping
1531000Sxc151355 * descriptors, never transmitting frames. Aside from
1541000Sxc151355 * reducing interrupts this also permits more concurrency.
1551000Sxc151355 * The only potential downside is if the tx queue backs
1561000Sxc151355 * up in which case the top half of the kernel may backup
1571000Sxc151355 * due to a lack of tx descriptors.
1581000Sxc151355 */
1593147Sxc151355 qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE;
1601000Sxc151355 qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi);
1611000Sxc151355 if (qnum == -1) {
1621000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1631000Sxc151355 "Unable to setup hardware queue for %s traffic!\n",
1641000Sxc151355 acnames[ac]));
1651000Sxc151355 return (1);
1661000Sxc151355 }
1671000Sxc151355 if (qnum >= ATH_N(asc->asc_txq)) {
1681000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1691000Sxc151355 "hal qnum %u out of range, max %u!\n",
1701000Sxc151355 qnum, ATH_N(asc->asc_txq)));
1711000Sxc151355 return (1);
1721000Sxc151355 }
1731000Sxc151355 if (!ATH_TXQ_SETUP(asc, qnum)) {
1741000Sxc151355 txq = &asc->asc_txq[qnum];
1751000Sxc151355 txq->axq_qnum = qnum;
1761000Sxc151355 txq->axq_depth = 0;
1771000Sxc151355 txq->axq_intrcnt = 0;
1781000Sxc151355 txq->axq_link = NULL;
1791000Sxc151355 list_create(&txq->axq_list, sizeof (struct ath_buf),
1801000Sxc151355 offsetof(struct ath_buf, bf_node));
1811000Sxc151355 mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL);
1821000Sxc151355 asc->asc_txqsetup |= 1<<qnum;
1831000Sxc151355 }
1841000Sxc151355 asc->asc_ac2q[ac] = &asc->asc_txq[qnum];
1851000Sxc151355 return (0);
1861000Sxc151355 }
1871000Sxc151355
1881000Sxc151355 int
ath_txq_setup(ath_t * asc)1891000Sxc151355 ath_txq_setup(ath_t *asc)
1901000Sxc151355 {
1911000Sxc151355 if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) ||
1921000Sxc151355 ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) ||
1931000Sxc151355 ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) ||
1941000Sxc151355 ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) {
1951000Sxc151355 return (1);
1961000Sxc151355 }
1971000Sxc151355
1981000Sxc151355 return (0);
1991000Sxc151355 }
2001000Sxc151355
2011000Sxc151355 void
ath_txq_cleanup(ath_t * asc)2023147Sxc151355 ath_txq_cleanup(ath_t *asc)
2033147Sxc151355 {
2043147Sxc151355 int i;
2053147Sxc151355
2063147Sxc151355 mutex_destroy(&asc->asc_txbuflock);
2073147Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
2083147Sxc151355 if (ATH_TXQ_SETUP(asc, i)) {
2093147Sxc151355 struct ath_txq *txq = &asc->asc_txq[i];
2103147Sxc151355
2113147Sxc151355 ATH_HAL_RELEASETXQUEUE(asc->asc_ah, txq->axq_qnum);
2123147Sxc151355 mutex_destroy(&txq->axq_lock);
2133147Sxc151355 asc->asc_txqsetup &= ~(1 << txq->axq_qnum);
2143147Sxc151355 }
2153147Sxc151355 }
2163147Sxc151355 }
2173147Sxc151355
2183147Sxc151355 void
ath_setcurmode(ath_t * asc,enum ieee80211_phymode mode)2191000Sxc151355 ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode)
2201000Sxc151355 {
2211000Sxc151355 const HAL_RATE_TABLE *rt;
2221000Sxc151355 int i;
2231000Sxc151355
2241000Sxc151355 for (i = 0; i < sizeof (asc->asc_rixmap); i++)
2251000Sxc151355 asc->asc_rixmap[i] = 0xff;
2261000Sxc151355
2271000Sxc151355 rt = asc->asc_rates[mode];
2281000Sxc151355 ASSERT(rt != NULL);
2291000Sxc151355
2301000Sxc151355 for (i = 0; i < rt->rateCount; i++)
2317274Sff224033 asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] =
2327274Sff224033 (uint8_t)i;
2331000Sxc151355
2341000Sxc151355 asc->asc_currates = rt;
2351000Sxc151355 asc->asc_curmode = mode;
236*8033SWang.Lin@Sun.COM
237*8033SWang.Lin@Sun.COM /*
238*8033SWang.Lin@Sun.COM * All protection frames are transmitted at 2Mb/s for
239*8033SWang.Lin@Sun.COM * 11g, otherwise at 1Mb/s.
240*8033SWang.Lin@Sun.COM * select protection rate index from rate table.
241*8033SWang.Lin@Sun.COM */
242*8033SWang.Lin@Sun.COM asc->asc_protrix = (mode == IEEE80211_MODE_11G ? 1 : 0);
2431000Sxc151355 }
2441000Sxc151355
2451000Sxc151355 /* Set correct parameters for a certain mode */
2461000Sxc151355 void
ath_mode_init(ath_t * asc)2471000Sxc151355 ath_mode_init(ath_t *asc)
2481000Sxc151355 {
2493147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc;
2501000Sxc151355 struct ath_hal *ah = asc->asc_ah;
2511000Sxc151355 uint32_t rfilt;
2521000Sxc151355
2531000Sxc151355 /* configure rx filter */
2541000Sxc151355 rfilt = ath_calcrxfilter(asc);
2551000Sxc151355 ATH_HAL_SETRXFILTER(ah, rfilt);
2561000Sxc151355 ATH_HAL_SETOPMODE(ah);
2576235Sxc151355 ATH_HAL_SETMCASTFILTER(ah, asc->asc_mcast_hash[0],
2586235Sxc151355 asc->asc_mcast_hash[1]);
2591000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): "
2601000Sxc151355 "mode =%d RX filter 0x%x, MC filter %08x:%08x\n",
2613147Sxc151355 ic->ic_opmode, rfilt,
2626235Sxc151355 asc->asc_mcast_hash[0], asc->asc_mcast_hash[1]));
2631000Sxc151355 }
2641000Sxc151355
2651000Sxc151355 /*
2661000Sxc151355 * Disable the receive h/w in preparation for a reset.
2671000Sxc151355 */
2681000Sxc151355 void
ath_stoprecv(ath_t * asc)2691000Sxc151355 ath_stoprecv(ath_t *asc)
2701000Sxc151355 {
2711000Sxc151355 ATH_HAL_STOPPCURECV(asc->asc_ah); /* disable PCU */
2721000Sxc151355 ATH_HAL_SETRXFILTER(asc->asc_ah, 0); /* clear recv filter */
2731000Sxc151355 ATH_HAL_STOPDMARECV(asc->asc_ah); /* disable DMA engine */
2741000Sxc151355 drv_usecwait(3000);
2751000Sxc151355
2761000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n",
2771000Sxc151355 ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink));
2781000Sxc151355 asc->asc_rxlink = NULL;
2791000Sxc151355 }
2801000Sxc151355
2811000Sxc151355 uint32_t
ath_chan2flags(ieee80211com_t * isc,struct ieee80211_channel * chan)2823147Sxc151355 ath_chan2flags(ieee80211com_t *isc, struct ieee80211_channel *chan)
2831000Sxc151355 {
2841000Sxc151355 static const uint32_t modeflags[] = {
2851000Sxc151355 0, /* IEEE80211_MODE_AUTO */
2861000Sxc151355 CHANNEL_A, /* IEEE80211_MODE_11A */
2871000Sxc151355 CHANNEL_B, /* IEEE80211_MODE_11B */
2881000Sxc151355 CHANNEL_PUREG, /* IEEE80211_MODE_11G */
2893147Sxc151355 0, /* IEEE80211_MODE_FH */
2903147Sxc151355 CHANNEL_108A, /* IEEE80211_MODE_TURBO_A */
2913147Sxc151355 CHANNEL_108G /* IEEE80211_MODE_TURBO_G */
2921000Sxc151355 };
2931000Sxc151355 return (modeflags[ieee80211_chan2mode(isc, chan)]);
2941000Sxc151355 }
2951000Sxc151355
2961000Sxc151355
2971000Sxc151355 int
ath_getchannels(ath_t * asc,uint32_t cc,HAL_BOOL outdoor,HAL_BOOL xchanmode)2981000Sxc151355 ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
2991000Sxc151355 {
3003147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc;
3011000Sxc151355 struct ath_hal *ah = asc->asc_ah;
3021000Sxc151355 HAL_CHANNEL *chans;
3031000Sxc151355 int i, ix;
3041000Sxc151355 uint32_t nchan;
3051000Sxc151355
3061000Sxc151355 chans = (HAL_CHANNEL *)
3071000Sxc151355 kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP);
3081000Sxc151355
3091000Sxc151355 if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
3103147Sxc151355 NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) {
3111000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
3126235Sxc151355 "unable to get channel list\n"));
3136235Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
3141000Sxc151355 return (EINVAL);
3151000Sxc151355 }
3161000Sxc151355
3171000Sxc151355 /*
3181000Sxc151355 * Convert HAL channels to ieee80211 ones and insert
3191000Sxc151355 * them in the table according to their channel number.
3201000Sxc151355 */
3211000Sxc151355 for (i = 0; i < nchan; i++) {
3221000Sxc151355 HAL_CHANNEL *c = &chans[i];
3233147Sxc151355 uint16_t flags;
3243147Sxc151355 ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
3251000Sxc151355 if (ix > IEEE80211_CHAN_MAX) {
3261000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
3273147Sxc151355 "bad hal channel %d (%u/%x) ignored\n",
3281000Sxc151355 ix, c->channel, c->channelFlags));
3291000Sxc151355 continue;
3301000Sxc151355 }
3311000Sxc151355 /* NB: flags are known to be compatible */
3323147Sxc151355 if (ix < 0) {
3333147Sxc151355 /*
3343147Sxc151355 * can't handle frequency <2400MHz (negative
3353147Sxc151355 * channels) right now
3363147Sxc151355 */
3373147Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath:ath_getchannels(): "
3383147Sxc151355 "hal channel %d (%u/%x) "
3393147Sxc151355 "cannot be handled, ignored\n",
3403147Sxc151355 ix, c->channel, c->channelFlags));
3413147Sxc151355 continue;
3423147Sxc151355 }
3433147Sxc151355 /*
3443147Sxc151355 * Calculate net80211 flags; most are compatible
3453147Sxc151355 * but some need massaging. Note the static turbo
3463147Sxc151355 * conversion can be removed once net80211 is updated
3473147Sxc151355 * to understand static vs. dynamic turbo.
3483147Sxc151355 */
3493147Sxc151355 flags = c->channelFlags & CHANNEL_COMPAT;
3503147Sxc151355 if (c->channelFlags & CHANNEL_STURBO)
3513147Sxc151355 flags |= IEEE80211_CHAN_TURBO;
3523147Sxc151355 if (ic->ic_sup_channels[ix].ich_freq == 0) {
3533147Sxc151355 ic->ic_sup_channels[ix].ich_freq = c->channel;
3543147Sxc151355 ic->ic_sup_channels[ix].ich_flags = flags;
3551000Sxc151355 } else {
3561000Sxc151355 /* channels overlap; e.g. 11g and 11b */
3573147Sxc151355 ic->ic_sup_channels[ix].ich_flags |= flags;
3581000Sxc151355 }
3591000Sxc151355 if ((c->channelFlags & CHANNEL_G) == CHANNEL_G)
3601000Sxc151355 asc->asc_have11g = 1;
3611000Sxc151355 }
3621000Sxc151355 kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
3631000Sxc151355 return (0);
3641000Sxc151355 }
3651000Sxc151355
3661000Sxc151355 static void
ath_drainq(ath_t * asc,struct ath_txq * txq)3671000Sxc151355 ath_drainq(ath_t *asc, struct ath_txq *txq)
3681000Sxc151355 {
3691000Sxc151355 struct ath_buf *bf;
3701000Sxc151355
3711000Sxc151355 /*
3721000Sxc151355 * This assumes output has been stopped.
3731000Sxc151355 */
3741000Sxc151355 for (;;) {
3751000Sxc151355 mutex_enter(&txq->axq_lock);
3761000Sxc151355 bf = list_head(&txq->axq_list);
3771000Sxc151355 if (bf == NULL) {
3781000Sxc151355 txq->axq_link = NULL;
3791000Sxc151355 mutex_exit(&txq->axq_lock);
3801000Sxc151355 break;
3811000Sxc151355 }
3821000Sxc151355 list_remove(&txq->axq_list, bf);
3831000Sxc151355 mutex_exit(&txq->axq_lock);
3841000Sxc151355 bf->bf_in = NULL;
3851000Sxc151355 mutex_enter(&asc->asc_txbuflock);
3861000Sxc151355 list_insert_tail(&asc->asc_txbuf_list, bf);
3871000Sxc151355 mutex_exit(&asc->asc_txbuflock);
3881000Sxc151355 }
3891000Sxc151355 }
3901000Sxc151355
3911000Sxc151355
3921000Sxc151355 /*
3931000Sxc151355 * Drain the transmit queues and reclaim resources.
3941000Sxc151355 */
3951000Sxc151355 void
ath_draintxq(ath_t * asc)3961000Sxc151355 ath_draintxq(ath_t *asc)
3971000Sxc151355 {
3981000Sxc151355 struct ath_hal *ah = asc->asc_ah;
3991000Sxc151355 struct ath_txq *txq;
4001000Sxc151355 int i;
4011000Sxc151355
4021000Sxc151355 if (!asc->asc_invalid) {
4031000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
4041000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) {
4051000Sxc151355 txq = &asc->asc_txq[i];
4061000Sxc151355 (void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum);
4071000Sxc151355 }
4081000Sxc151355 }
4091000Sxc151355 }
4101000Sxc151355 for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
4111000Sxc151355 if (ATH_TXQ_SETUP(asc, i)) {
4121000Sxc151355 ath_drainq(asc, &asc->asc_txq[i]);
4131000Sxc151355 }
4141000Sxc151355 }
4151000Sxc151355 }
4161000Sxc151355
4171000Sxc151355
4181000Sxc151355 /* Enable the receive h/w following a reset */
4191000Sxc151355 int
ath_startrecv(ath_t * asc)4201000Sxc151355 ath_startrecv(ath_t *asc)
4211000Sxc151355 {
4221000Sxc151355 struct ath_buf *bf;
4231000Sxc151355
4241000Sxc151355 asc->asc_rxlink = NULL;
4251000Sxc151355
4261000Sxc151355 bf = list_head(&asc->asc_rxbuf_list);
4271000Sxc151355 while (bf != NULL) {
4281000Sxc151355 ath_setup_desc(asc, bf);
4291000Sxc151355 bf = list_next(&asc->asc_rxbuf_list, bf);
4301000Sxc151355 }
4311000Sxc151355
4321000Sxc151355 bf = list_head(&asc->asc_rxbuf_list);
4331000Sxc151355 ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr);
4341000Sxc151355 ATH_HAL_RXENA(asc->asc_ah); /* enable recv descriptors */
4351000Sxc151355 ath_mode_init(asc); /* set filters, etc. */
4361000Sxc151355 ATH_HAL_STARTPCURECV(asc->asc_ah); /* re-enable PCU/DMA engine */
4371000Sxc151355 return (0);
4381000Sxc151355 }
4391000Sxc151355
4401000Sxc151355 /*
4413147Sxc151355 * Update internal state after a channel change.
4423147Sxc151355 */
4433147Sxc151355 void
ath_chan_change(ath_t * asc,struct ieee80211_channel * chan)4443147Sxc151355 ath_chan_change(ath_t *asc, struct ieee80211_channel *chan)
4453147Sxc151355 {
4463147Sxc151355 struct ieee80211com *ic = &asc->asc_isc;
4473147Sxc151355 enum ieee80211_phymode mode;
4483147Sxc151355
4493147Sxc151355 /*
4503147Sxc151355 * Change channels and update the h/w rate map
4513147Sxc151355 * if we're switching; e.g. 11a to 11b/g.
4523147Sxc151355 */
4533147Sxc151355 mode = ieee80211_chan2mode(ic, chan);
4543147Sxc151355 if (mode != asc->asc_curmode)
4553147Sxc151355 ath_setcurmode(asc, mode);
4563147Sxc151355 }
4573147Sxc151355
4583147Sxc151355 /*
4591000Sxc151355 * Set/change channels. If the channel is really being changed,
4601000Sxc151355 * it's done by resetting the chip. To accomplish this we must
4611000Sxc151355 * first cleanup any pending DMA.
4621000Sxc151355 */
4631000Sxc151355 int
ath_chan_set(ath_t * asc,struct ieee80211_channel * chan)4643147Sxc151355 ath_chan_set(ath_t *asc, struct ieee80211_channel *chan)
4651000Sxc151355 {
4661000Sxc151355 struct ath_hal *ah = asc->asc_ah;
4673147Sxc151355 ieee80211com_t *ic = &asc->asc_isc;
4681000Sxc151355
4693147Sxc151355 if (chan != ic->ic_ibss_chan) {
4701000Sxc151355 HAL_STATUS status;
4711000Sxc151355 HAL_CHANNEL hchan;
4721000Sxc151355
4731000Sxc151355 /*
4741000Sxc151355 * To switch channels clear any pending DMA operations;
4751000Sxc151355 * wait long enough for the RX fifo to drain, reset the
4761000Sxc151355 * hardware at the new frequency, and then re-enable
4771000Sxc151355 * the relevant bits of the h/w.
4781000Sxc151355 */
4791000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */
4801000Sxc151355 ath_draintxq(asc); /* clear pending tx frames */
4811000Sxc151355 ath_stoprecv(asc); /* turn off frame recv */
4821000Sxc151355 /*
4831000Sxc151355 * Convert to a HAL channel description with
4841000Sxc151355 * the flags constrained to reflect the current
4851000Sxc151355 * operating mode.
4861000Sxc151355 */
4871000Sxc151355 hchan.channel = chan->ich_freq;
4883147Sxc151355 hchan.channelFlags = ath_chan2flags(ic, chan);
4893147Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
4901000Sxc151355 &hchan, AH_TRUE, &status)) {
4911000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():"
4926235Sxc151355 "unable to reset channel %u (%uMhz)\n"
4936235Sxc151355 "flags 0x%x: '%s' (HAL status %u)\n",
4946235Sxc151355 ieee80211_chan2ieee(ic, chan), hchan.channel,
4956235Sxc151355 hchan.channelFlags,
4966235Sxc151355 ath_get_hal_status_desc(status), status));
4971000Sxc151355 return (EIO);
4981000Sxc151355 }
4993147Sxc151355 asc->asc_curchan = hchan;
5001000Sxc151355
5011000Sxc151355 /*
5021000Sxc151355 * Re-enable rx framework.
5031000Sxc151355 */
5041000Sxc151355 if (ath_startrecv(asc) != 0) {
5051000Sxc151355 ath_problem("ath: ath_chan_set(): "
5061000Sxc151355 "restarting receiving logic failed\n");
5071000Sxc151355 return (EIO);
5081000Sxc151355 }
5091000Sxc151355
5101000Sxc151355 /*
5111000Sxc151355 * Change channels and update the h/w rate map
5121000Sxc151355 * if we're switching; e.g. 11a to 11b/g.
5131000Sxc151355 */
5143147Sxc151355 ic->ic_ibss_chan = chan;
5153147Sxc151355 ath_chan_change(asc, chan);
5161000Sxc151355 /*
5171000Sxc151355 * Re-enable interrupts.
5181000Sxc151355 */
5191000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask);
5201000Sxc151355 }
5211000Sxc151355 return (0);
5221000Sxc151355 }
5231000Sxc151355
5241000Sxc151355
5251000Sxc151355 /*
5261000Sxc151355 * Configure the beacon and sleep timers.
5271000Sxc151355 *
5281000Sxc151355 * When operating as an AP this resets the TSF and sets
5291000Sxc151355 * up the hardware to notify us when we need to issue beacons.
5301000Sxc151355 *
5311000Sxc151355 * When operating in station mode this sets up the beacon
5321000Sxc151355 * timers according to the timestamp of the last received
5331000Sxc151355 * beacon and the current TSF, configures PCF and DTIM
5341000Sxc151355 * handling, programs the sleep registers so the hardware
5351000Sxc151355 * will wakeup in time to receive beacons, and configures
5361000Sxc151355 * the beacon miss handling so we'll receive a BMISS
5371000Sxc151355 * interrupt when we stop seeing beacons from the AP
5381000Sxc151355 * we've associated with.
5391000Sxc151355 */
5401000Sxc151355 void
ath_beacon_config(ath_t * asc)5411000Sxc151355 ath_beacon_config(ath_t *asc)
5421000Sxc151355 {
5431000Sxc151355 struct ath_hal *ah = asc->asc_ah;
5443147Sxc151355 ieee80211com_t *ic = (ieee80211com_t *)asc;
5453147Sxc151355 struct ieee80211_node *in = ic->ic_bss;
5461000Sxc151355 uint32_t nexttbtt;
5471000Sxc151355
548*8033SWang.Lin@Sun.COM /* extract tstamp from last beacon and convert to TU */
5493147Sxc151355 nexttbtt = (ATH_LE_READ_4(in->in_tstamp.data + 4) << 22) |
5503147Sxc151355 (ATH_LE_READ_4(in->in_tstamp.data) >> 10);
5511000Sxc151355 nexttbtt += in->in_intval;
5523147Sxc151355 if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
5531000Sxc151355 HAL_BEACON_STATE bs;
5541000Sxc151355
5551000Sxc151355 /* NB: no PCF support right now */
5561000Sxc151355 bzero(&bs, sizeof (bs));
5571000Sxc151355 bs.bs_intval = in->in_intval;
5581000Sxc151355 bs.bs_nexttbtt = nexttbtt;
5591000Sxc151355 bs.bs_dtimperiod = bs.bs_intval;
5601000Sxc151355 bs.bs_nextdtim = nexttbtt;
5611000Sxc151355
5621000Sxc151355 /*
5633147Sxc151355 * Setup the number of consecutive beacons to miss
5643147Sxc151355 * before taking a BMISS interrupt.
5651000Sxc151355 * Note that we clamp the result to at most 10 beacons.
5661000Sxc151355 */
5673147Sxc151355 bs.bs_bmissthreshold = ic->ic_bmissthreshold;
5681000Sxc151355 if (bs.bs_bmissthreshold > 10)
5691000Sxc151355 bs.bs_bmissthreshold = 10;
5706990Sgd78059 else if (bs.bs_bmissthreshold < 1)
5711000Sxc151355 bs.bs_bmissthreshold = 1;
5721000Sxc151355 /*
5731000Sxc151355 * Calculate sleep duration. The configuration is
5741000Sxc151355 * given in ms. We insure a multiple of the beacon
5751000Sxc151355 * period is used. Also, if the sleep duration is
5761000Sxc151355 * greater than the DTIM period then it makes senses
5771000Sxc151355 * to make it a multiple of that.
5781000Sxc151355 */
5791000Sxc151355 bs.bs_sleepduration =
5801000Sxc151355 roundup((100 * 1000) / 1024, bs.bs_intval);
5811000Sxc151355 if (bs.bs_sleepduration > bs.bs_dtimperiod)
5821000Sxc151355 bs.bs_sleepduration =
5831000Sxc151355 roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
5841000Sxc151355
5851000Sxc151355
5861000Sxc151355 ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): "
5871000Sxc151355 "intval %u nexttbtt %u dtim %u"
5881000Sxc151355 " nextdtim %u bmiss %u sleep %u\n",
5891000Sxc151355 bs.bs_intval,
5901000Sxc151355 bs.bs_nexttbtt,
5911000Sxc151355 bs.bs_dtimperiod,
5921000Sxc151355 bs.bs_nextdtim,
5931000Sxc151355 bs.bs_bmissthreshold,
5941000Sxc151355 bs.bs_sleepduration));
5951000Sxc151355 ATH_HAL_INTRSET(ah, 0);
5961000Sxc151355 /*
5971000Sxc151355 * Reset our tsf so the hardware will update the
5981000Sxc151355 * tsf register to reflect timestamps found in
5991000Sxc151355 * received beacons.
6001000Sxc151355 */
6011000Sxc151355 ATH_HAL_RESETTSF(ah);
6021000Sxc151355 ATH_HAL_BEACONTIMERS(ah, &bs);
6031000Sxc151355 asc->asc_imask |= HAL_INT_BMISS;
6041000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask);
6051000Sxc151355 } else {
6061000Sxc151355 ATH_HAL_INTRSET(ah, 0);
6071000Sxc151355 ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval);
6081000Sxc151355 asc->asc_imask |= HAL_INT_SWBA; /* beacon prepare */
6091000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask);
6101000Sxc151355 }
6111000Sxc151355 }
612*8033SWang.Lin@Sun.COM /*
613*8033SWang.Lin@Sun.COM * Allocate tx/rx key slots for TKIP. We allocate one slot for
614*8033SWang.Lin@Sun.COM * each key. MIC is right after the decrypt/encrypt key.
615*8033SWang.Lin@Sun.COM */
616*8033SWang.Lin@Sun.COM static uint16_t
key_alloc_pair(ath_t * asc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)617*8033SWang.Lin@Sun.COM key_alloc_pair(ath_t *asc, ieee80211_keyix *txkeyix,
618*8033SWang.Lin@Sun.COM ieee80211_keyix *rxkeyix)
619*8033SWang.Lin@Sun.COM {
620*8033SWang.Lin@Sun.COM uint16_t i, keyix;
621*8033SWang.Lin@Sun.COM
622*8033SWang.Lin@Sun.COM ASSERT(!asc->asc_splitmic);
623*8033SWang.Lin@Sun.COM for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) {
624*8033SWang.Lin@Sun.COM uint8_t b = asc->asc_keymap[i];
625*8033SWang.Lin@Sun.COM if (b == 0xff)
626*8033SWang.Lin@Sun.COM continue;
627*8033SWang.Lin@Sun.COM for (keyix = i * NBBY; keyix < (i + 1) * NBBY;
628*8033SWang.Lin@Sun.COM keyix++, b >>= 1) {
629*8033SWang.Lin@Sun.COM if ((b & 1) || isset(asc->asc_keymap, keyix+64)) {
630*8033SWang.Lin@Sun.COM /* full pair unavailable */
631*8033SWang.Lin@Sun.COM continue;
632*8033SWang.Lin@Sun.COM }
633*8033SWang.Lin@Sun.COM setbit(asc->asc_keymap, keyix);
634*8033SWang.Lin@Sun.COM setbit(asc->asc_keymap, keyix+64);
635*8033SWang.Lin@Sun.COM ATH_DEBUG((ATH_DBG_AUX,
636*8033SWang.Lin@Sun.COM "key_alloc_pair: key pair %u,%u\n",
637*8033SWang.Lin@Sun.COM keyix, keyix+64));
638*8033SWang.Lin@Sun.COM *txkeyix = *rxkeyix = keyix;
639*8033SWang.Lin@Sun.COM return (1);
640*8033SWang.Lin@Sun.COM }
641*8033SWang.Lin@Sun.COM }
642*8033SWang.Lin@Sun.COM ATH_DEBUG((ATH_DBG_AUX, "key_alloc_pair:"
643*8033SWang.Lin@Sun.COM " out of pair space\n"));
644*8033SWang.Lin@Sun.COM return (0);
645*8033SWang.Lin@Sun.COM }
6461000Sxc151355
6473147Sxc151355 /*
6484126Szf162725 * Allocate tx/rx key slots for TKIP. We allocate two slots for
6494126Szf162725 * each key, one for decrypt/encrypt and the other for the MIC.
6504126Szf162725 */
6514126Szf162725 static int
key_alloc_2pair(ath_t * asc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)6524126Szf162725 key_alloc_2pair(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
6534126Szf162725 {
6544126Szf162725 uint16_t i, keyix;
6554126Szf162725
6564126Szf162725 ASSERT(asc->asc_splitmic);
6574126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) {
6584126Szf162725 uint8_t b = asc->asc_keymap[i];
6594126Szf162725 if (b != 0xff) {
6604126Szf162725 /*
6614126Szf162725 * One or more slots in this byte are free.
6624126Szf162725 */
6634126Szf162725 keyix = i*NBBY;
6644126Szf162725 while (b & 1) {
6654126Szf162725 again:
6664126Szf162725 keyix++;
6674126Szf162725 b >>= 1;
6684126Szf162725 }
6694126Szf162725 /* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
6704126Szf162725 if (isset(asc->asc_keymap, keyix+32) ||
6714126Szf162725 isset(asc->asc_keymap, keyix+64) ||
6724126Szf162725 isset(asc->asc_keymap, keyix+32+64)) {
6734126Szf162725 /* full pair unavailable */
6744126Szf162725 if (keyix == (i+1)*NBBY) {
6754126Szf162725 /* no slots were appropriate, advance */
6764126Szf162725 continue;
6774126Szf162725 }
6784126Szf162725 goto again;
6794126Szf162725 }
6804126Szf162725 setbit(asc->asc_keymap, keyix);
6814126Szf162725 setbit(asc->asc_keymap, keyix+64);
6824126Szf162725 setbit(asc->asc_keymap, keyix+32);
6834126Szf162725 setbit(asc->asc_keymap, keyix+32+64);
6844126Szf162725 ATH_DEBUG((ATH_DBG_AUX,
6854126Szf162725 "key_alloc_2pair: key pair %u,%u %u,%u\n",
6864126Szf162725 keyix, keyix+64,
6874126Szf162725 keyix+32, keyix+32+64));
6884126Szf162725 *txkeyix = *rxkeyix = keyix;
6894126Szf162725 return (1);
6904126Szf162725 }
6914126Szf162725 }
6924126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_2pair:"
6934126Szf162725 " out of pair space\n"));
6944126Szf162725 return (0);
6954126Szf162725 }
6964126Szf162725 /*
6974126Szf162725 * Allocate a single key cache slot.
6984126Szf162725 */
6994126Szf162725 static int
key_alloc_single(ath_t * asc,ieee80211_keyix * txkeyix,ieee80211_keyix * rxkeyix)7004126Szf162725 key_alloc_single(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
7014126Szf162725 {
7024126Szf162725 uint16_t i, keyix;
7034126Szf162725
7044126Szf162725 /* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
7054126Szf162725 for (i = 0; i < ATH_N(asc->asc_keymap); i++) {
7064126Szf162725 uint8_t b = asc->asc_keymap[i];
7074126Szf162725
7084126Szf162725 if (b != 0xff) {
7094126Szf162725 /*
7104126Szf162725 * One or more slots are free.
7114126Szf162725 */
7124126Szf162725 keyix = i*NBBY;
7134126Szf162725 while (b & 1)
7144126Szf162725 keyix++, b >>= 1;
7154126Szf162725 setbit(asc->asc_keymap, keyix);
7164126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "key_alloc_single:"
7174126Szf162725 " key %u\n", keyix));
7184126Szf162725 *txkeyix = *rxkeyix = keyix;
7194126Szf162725 return (1);
7204126Szf162725 }
7214126Szf162725 }
7224126Szf162725 return (0);
7234126Szf162725 }
7244126Szf162725
7254126Szf162725 /*
7263147Sxc151355 * Allocate one or more key cache slots for a unicast key. The
7273147Sxc151355 * key itself is needed only to identify the cipher. For hardware
7283147Sxc151355 * TKIP with split cipher+MIC keys we allocate two key cache slot
7293147Sxc151355 * pairs so that we can setup separate TX and RX MIC keys. Note
7303147Sxc151355 * that the MIC key for a TKIP key at slot i is assumed by the
7313147Sxc151355 * hardware to be at slot i+64. This limits TKIP keys to the first
7323147Sxc151355 * 64 entries.
7333147Sxc151355 */
7343147Sxc151355 /* ARGSUSED */
7353147Sxc151355 int
ath_key_alloc(ieee80211com_t * ic,const struct ieee80211_key * k,ieee80211_keyix * keyix,ieee80211_keyix * rxkeyix)7363147Sxc151355 ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k,
7373147Sxc151355 ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
7383147Sxc151355 {
7394126Szf162725 ath_t *asc = (ath_t *)ic;
7404126Szf162725
7414126Szf162725 /*
7424126Szf162725 * We allocate two pair for TKIP when using the h/w to do
7434126Szf162725 * the MIC. For everything else, including software crypto,
7444126Szf162725 * we allocate a single entry. Note that s/w crypto requires
7454126Szf162725 * a pass-through slot on the 5211 and 5212. The 5210 does
7464126Szf162725 * not support pass-through cache entries and we map all
7474126Szf162725 * those requests to slot 0.
7484126Szf162725 */
7494126Szf162725 if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
7504126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix));
7514126Szf162725 } else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
752*8033SWang.Lin@Sun.COM (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
753*8033SWang.Lin@Sun.COM if (asc->asc_splitmic)
754*8033SWang.Lin@Sun.COM return (key_alloc_2pair(asc, keyix, rxkeyix));
755*8033SWang.Lin@Sun.COM else
756*8033SWang.Lin@Sun.COM return (key_alloc_pair(asc, keyix, rxkeyix));
7574126Szf162725 } else {
7584126Szf162725 return (key_alloc_single(asc, keyix, rxkeyix));
7594126Szf162725 }
7604126Szf162725 }
7614126Szf162725
7624126Szf162725 /*
7634126Szf162725 * Delete an entry in the key cache allocated by ath_key_alloc.
7644126Szf162725 */
7654126Szf162725 int
ath_key_delete(ieee80211com_t * ic,const struct ieee80211_key * k)7664126Szf162725 ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k)
7674126Szf162725 {
7684126Szf162725 ath_t *asc = (ath_t *)ic;
7694126Szf162725 struct ath_hal *ah = asc->asc_ah;
7704126Szf162725 const struct ieee80211_cipher *cip = k->wk_cipher;
7714126Szf162725 ieee80211_keyix keyix = k->wk_keyix;
7724126Szf162725
7734126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "ath_key_delete:"
7744126Szf162725 " delete key %u ic_cipher=0x%x\n", keyix, cip->ic_cipher));
7754126Szf162725
7764126Szf162725 ATH_HAL_KEYRESET(ah, keyix);
7774126Szf162725 /*
7784126Szf162725 * Handle split tx/rx keying required for TKIP with h/w MIC.
7794126Szf162725 */
7804126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
7814126Szf162725 (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic)
7824126Szf162725 ATH_HAL_KEYRESET(ah, keyix+32); /* RX key */
7834126Szf162725
7844126Szf162725 if (keyix >= IEEE80211_WEP_NKID) {
7854126Szf162725 /*
7864126Szf162725 * Don't touch keymap entries for global keys so
7874126Szf162725 * they are never considered for dynamic allocation.
7884126Szf162725 */
7894126Szf162725 clrbit(asc->asc_keymap, keyix);
7904126Szf162725 if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
791*8033SWang.Lin@Sun.COM (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
792*8033SWang.Lin@Sun.COM /*
793*8033SWang.Lin@Sun.COM * If splitmic is true +64 is TX key MIC,
794*8033SWang.Lin@Sun.COM * else +64 is RX key + RX key MIC.
795*8033SWang.Lin@Sun.COM */
796*8033SWang.Lin@Sun.COM clrbit(asc->asc_keymap, keyix+64);
797*8033SWang.Lin@Sun.COM if (asc->asc_splitmic) {
798*8033SWang.Lin@Sun.COM /* Rx key */
799*8033SWang.Lin@Sun.COM clrbit(asc->asc_keymap, keyix+32);
800*8033SWang.Lin@Sun.COM /* RX key MIC */
801*8033SWang.Lin@Sun.COM clrbit(asc->asc_keymap, keyix+32+64);
802*8033SWang.Lin@Sun.COM }
8034126Szf162725 }
8044126Szf162725 }
8053147Sxc151355 return (1);
8063147Sxc151355 }
8071000Sxc151355
8084126Szf162725 static void
ath_keyprint(ath_t * asc,const char * tag,uint_t ix,const HAL_KEYVAL * hk,const uint8_t mac[IEEE80211_ADDR_LEN])809*8033SWang.Lin@Sun.COM ath_keyprint(ath_t *asc, const char *tag, uint_t ix,
8104126Szf162725 const HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
8113147Sxc151355 {
8124126Szf162725 static const char *ciphers[] = {
8134126Szf162725 "WEP",
8144126Szf162725 "AES-OCB",
8154126Szf162725 "AES-CCM",
8164126Szf162725 "CKIP",
8174126Szf162725 "TKIP",
8184126Szf162725 "CLR",
8194126Szf162725 };
8204126Szf162725 int i, n;
8214126Szf162725 char buf[MAX_IEEE80211STR], buft[32];
8224126Szf162725
8234126Szf162725 (void) snprintf(buf, sizeof (buf), "%s: [%02u] %s ",
8244126Szf162725 tag, ix, ciphers[hk->kv_type]);
8254126Szf162725 for (i = 0, n = hk->kv_len; i < n; i++) {
8264126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x", hk->kv_val[i]);
8274126Szf162725 (void) strlcat(buf, buft, sizeof (buf));
8284126Szf162725 }
8294126Szf162725 (void) snprintf(buft, sizeof (buft), " mac %s",
8304126Szf162725 ieee80211_macaddr_sprintf(mac));
8314126Szf162725 (void) strlcat(buf, buft, sizeof (buf));
8324126Szf162725 if (hk->kv_type == HAL_CIPHER_TKIP) {
833*8033SWang.Lin@Sun.COM (void) snprintf(buft, sizeof (buft), " %s ",
834*8033SWang.Lin@Sun.COM asc->asc_splitmic ? "mic" : "rxmic");
8354126Szf162725 (void) strlcat(buf, buft, sizeof (buf));
8364126Szf162725 for (i = 0; i < sizeof (hk->kv_mic); i++) {
8374126Szf162725 (void) snprintf(buft, sizeof (buft), "%02x",
8384126Szf162725 hk->kv_mic[i]);
8394126Szf162725 (void) strlcat(buf, buft, sizeof (buf));
8404126Szf162725 }
841*8033SWang.Lin@Sun.COM if (!asc->asc_splitmic) {
842*8033SWang.Lin@Sun.COM (void) snprintf(buft, sizeof (buft), " txmic ");
843*8033SWang.Lin@Sun.COM (void) strlcat(buf, buft, sizeof (buf));
844*8033SWang.Lin@Sun.COM for (i = 0; i < sizeof (hk->kv_txmic); i++) {
845*8033SWang.Lin@Sun.COM (void) snprintf(buft, sizeof (buft), "%02x",
846*8033SWang.Lin@Sun.COM hk->kv_txmic[i]);
847*8033SWang.Lin@Sun.COM (void) strlcat(buf, buft, sizeof (buf));
848*8033SWang.Lin@Sun.COM }
849*8033SWang.Lin@Sun.COM }
8504126Szf162725 }
8514126Szf162725 ATH_DEBUG((ATH_DBG_AUX, "%s", buf));
8524126Szf162725 }
8533147Sxc151355
8544126Szf162725 /*
8554126Szf162725 * Set a TKIP key into the hardware. This handles the
8564126Szf162725 * potential distribution of key state to multiple key
8574126Szf162725 * cache slots for TKIP.
8584126Szf162725 */
8594126Szf162725 static int
ath_keyset_tkip(ath_t * asc,const struct ieee80211_key * k,HAL_KEYVAL * hk,const uint8_t mac[IEEE80211_ADDR_LEN])8604126Szf162725 ath_keyset_tkip(ath_t *asc, const struct ieee80211_key *k,
8614126Szf162725 HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
8624126Szf162725 {
8634126Szf162725 #define IEEE80211_KEY_XR (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
8644126Szf162725 static const uint8_t zerobssid[IEEE80211_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
8654126Szf162725 struct ath_hal *ah = asc->asc_ah;
8664126Szf162725
8674126Szf162725 ASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP);
8684126Szf162725 if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
869*8033SWang.Lin@Sun.COM if (asc->asc_splitmic) {
870*8033SWang.Lin@Sun.COM /*
871*8033SWang.Lin@Sun.COM * TX key goes at first index, RX key at +32.
872*8033SWang.Lin@Sun.COM * The hal handles the MIC keys at index+64.
873*8033SWang.Lin@Sun.COM */
874*8033SWang.Lin@Sun.COM (void) memcpy(hk->kv_mic, k->wk_txmic,
875*8033SWang.Lin@Sun.COM sizeof (hk->kv_mic));
876*8033SWang.Lin@Sun.COM ath_keyprint(asc, "ath_keyset_tkip:", k->wk_keyix, hk,
877*8033SWang.Lin@Sun.COM zerobssid);
878*8033SWang.Lin@Sun.COM if (!ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid))
879*8033SWang.Lin@Sun.COM return (0);
8804126Szf162725
881*8033SWang.Lin@Sun.COM (void) memcpy(hk->kv_mic, k->wk_rxmic,
882*8033SWang.Lin@Sun.COM sizeof (hk->kv_mic));
883*8033SWang.Lin@Sun.COM ath_keyprint(asc, "ath_keyset_tkip:", k->wk_keyix+32,
884*8033SWang.Lin@Sun.COM hk, mac);
885*8033SWang.Lin@Sun.COM return (ATH_HAL_KEYSET(ah, k->wk_keyix+32, hk, mac));
886*8033SWang.Lin@Sun.COM } else {
887*8033SWang.Lin@Sun.COM /*
888*8033SWang.Lin@Sun.COM * Room for both TX+RX MIC keys in one key cache
889*8033SWang.Lin@Sun.COM * slot, just set key at the first index; the hal
890*8033SWang.Lin@Sun.COM * will handle the reset.
891*8033SWang.Lin@Sun.COM */
892*8033SWang.Lin@Sun.COM (void) memcpy(hk->kv_mic, k->wk_rxmic,
893*8033SWang.Lin@Sun.COM sizeof (hk->kv_mic));
894*8033SWang.Lin@Sun.COM (void) memcpy(hk->kv_txmic, k->wk_txmic,
895*8033SWang.Lin@Sun.COM sizeof (hk->kv_txmic));
896*8033SWang.Lin@Sun.COM ath_keyprint(asc, "ath_keyset_tkip", k->wk_keyix, hk,
897*8033SWang.Lin@Sun.COM mac);
898*8033SWang.Lin@Sun.COM return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, mac));
899*8033SWang.Lin@Sun.COM }
9004126Szf162725 } else if (k->wk_flags & IEEE80211_KEY_XR) {
9014126Szf162725 /*
9024126Szf162725 * TX/RX key goes at first index.
9034126Szf162725 * The hal handles the MIC keys are index+64.
9044126Szf162725 */
9054126Szf162725 (void) memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
9064126Szf162725 k->wk_txmic : k->wk_rxmic, sizeof (hk->kv_mic));
907*8033SWang.Lin@Sun.COM ath_keyprint(asc, "ath_keyset_tkip:", k->wk_keyix, hk,
908*8033SWang.Lin@Sun.COM zerobssid);
9094126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid));
9104126Szf162725 }
9114126Szf162725 return (0);
9124126Szf162725 #undef IEEE80211_KEY_XR
9133147Sxc151355 }
9141000Sxc151355
9151000Sxc151355 /*
9163147Sxc151355 * Set the key cache contents for the specified key. Key cache
9173147Sxc151355 * slot(s) must already have been allocated by ath_key_alloc.
9183147Sxc151355 */
9193147Sxc151355 int
ath_key_set(ieee80211com_t * ic,const struct ieee80211_key * k,const uint8_t mac[IEEE80211_ADDR_LEN])9203147Sxc151355 ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
9213147Sxc151355 const uint8_t mac[IEEE80211_ADDR_LEN])
9223147Sxc151355 {
9233147Sxc151355 static const uint8_t ciphermap[] = {
9243147Sxc151355 HAL_CIPHER_WEP, /* IEEE80211_CIPHER_WEP */
9253147Sxc151355 HAL_CIPHER_TKIP, /* IEEE80211_CIPHER_TKIP */
9263147Sxc151355 HAL_CIPHER_AES_OCB, /* IEEE80211_CIPHER_AES_OCB */
9273147Sxc151355 HAL_CIPHER_AES_CCM, /* IEEE80211_CIPHER_AES_CCM */
9283147Sxc151355 HAL_CIPHER_CKIP, /* IEEE80211_CIPHER_CKIP */
9293147Sxc151355 HAL_CIPHER_CLR, /* IEEE80211_CIPHER_NONE */
9303147Sxc151355 };
9313147Sxc151355 ath_t *asc = (ath_t *)ic;
9323147Sxc151355 struct ath_hal *ah = asc->asc_ah;
9333147Sxc151355 const struct ieee80211_cipher *cip = k->wk_cipher;
9343147Sxc151355 HAL_KEYVAL hk;
9353147Sxc151355
9363147Sxc151355 bzero(&hk, sizeof (hk));
9373147Sxc151355 /*
9383147Sxc151355 * Software crypto uses a "clear key" so non-crypto
9393147Sxc151355 * state kept in the key cache are maintainedd so that
9403147Sxc151355 * rx frames have an entry to match.
9413147Sxc151355 */
9423147Sxc151355 if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
9433147Sxc151355 ASSERT(cip->ic_cipher < ATH_N(ciphermap));
9443147Sxc151355 hk.kv_type = ciphermap[cip->ic_cipher];
9453147Sxc151355 hk.kv_len = k->wk_keylen;
9463147Sxc151355 bcopy(k->wk_key, hk.kv_val, k->wk_keylen);
9473147Sxc151355 } else {
9483147Sxc151355 hk.kv_type = HAL_CIPHER_CLR;
9493147Sxc151355 }
9503147Sxc151355
9514126Szf162725 if (hk.kv_type == HAL_CIPHER_TKIP &&
952*8033SWang.Lin@Sun.COM (k->wk_flags & IEEE80211_KEY_SWMIC) == 0) {
9534126Szf162725 return (ath_keyset_tkip(asc, k, &hk, mac));
9544126Szf162725 } else {
955*8033SWang.Lin@Sun.COM ath_keyprint(asc, "ath_keyset:", k->wk_keyix, &hk, mac);
9564126Szf162725 return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac));
9574126Szf162725 }
9583147Sxc151355 }
9593147Sxc151355
9603147Sxc151355 /*
9613147Sxc151355 * Enable/Disable short slot timing
9621000Sxc151355 */
9631000Sxc151355 void
ath_set_shortslot(ieee80211com_t * ic,int onoff)9643147Sxc151355 ath_set_shortslot(ieee80211com_t *ic, int onoff)
9651000Sxc151355 {
9663147Sxc151355 struct ath_hal *ah = ((ath_t *)ic)->asc_ah;
9671000Sxc151355
9683147Sxc151355 if (onoff)
9693147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9);
9703147Sxc151355 else
9713147Sxc151355 ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20);
9721000Sxc151355 }
9731000Sxc151355
9743147Sxc151355 int
ath_reset(ieee80211com_t * ic)9753147Sxc151355 ath_reset(ieee80211com_t *ic)
9761000Sxc151355 {
9773147Sxc151355 ath_t *asc = (ath_t *)ic;
9781000Sxc151355 struct ath_hal *ah = asc->asc_ah;
9793147Sxc151355 struct ieee80211_channel *ch;
9801000Sxc151355 HAL_STATUS status;
9811000Sxc151355
9821000Sxc151355 /*
9831000Sxc151355 * Convert to a HAL channel description with the flags
9841000Sxc151355 * constrained to reflect the current operating mode.
9851000Sxc151355 */
9863147Sxc151355 ch = ic->ic_curchan;
9873147Sxc151355 asc->asc_curchan.channel = ch->ich_freq;
9883147Sxc151355 asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch);
9891000Sxc151355
9901000Sxc151355 ATH_HAL_INTRSET(ah, 0); /* disable interrupts */
9911000Sxc151355 ath_draintxq(asc); /* stop xmit side */
9923147Sxc151355 if (ATH_IS_RUNNING(asc)) {
9931000Sxc151355 ath_stoprecv(asc); /* stop recv side */
9943147Sxc151355 /* indicate channel change so we do a full reset */
9956235Sxc151355 if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
9966235Sxc151355 &asc->asc_curchan, AH_TRUE, &status)) {
9973147Sxc151355 ath_problem("ath: ath_reset(): "
9986235Sxc151355 "resetting hardware failed, '%s' (HAL status %u)\n",
9996235Sxc151355 ath_get_hal_status_desc(status), status);
10003147Sxc151355 }
10013147Sxc151355 ath_chan_change(asc, ch);
10021000Sxc151355 }
10033147Sxc151355 if (ATH_IS_RUNNING(asc)) {
10041000Sxc151355 if (ath_startrecv(asc) != 0) /* restart recv */
10051000Sxc151355 ath_problem("ath: ath_reset(): "
10061000Sxc151355 "starting receiving logic failed\n");
10073147Sxc151355 if (ic->ic_state == IEEE80211_S_RUN) {
10081000Sxc151355 ath_beacon_config(asc); /* restart beacons */
10091000Sxc151355 }
10101000Sxc151355 ATH_HAL_INTRSET(ah, asc->asc_imask);
10111000Sxc151355 }
10123147Sxc151355 return (0);
10131000Sxc151355 }
1014