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