xref: /onnv-gate/usr/src/uts/common/io/ath/ath_aux.c (revision 4126:31652d91f33e)
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