xref: /onnv-gate/usr/src/uts/common/io/ath/ath_aux.c (revision 7274:63f4bccf097e)
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 #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 
846235Sxc151355 
856235Sxc151355 const char *
866235Sxc151355 ath_get_hal_status_desc(HAL_STATUS status)
876235Sxc151355 {
886235Sxc151355 	static const char *hal_status_desc[] = {
896235Sxc151355 	    "No error",
906235Sxc151355 	    "No hardware present or device not yet supported",
916235Sxc151355 	    "Memory allocation failed",
926235Sxc151355 	    "Hardware didn't respond as expected",
936235Sxc151355 	    "EEPROM magic number invalid",
946235Sxc151355 	    "EEPROM version invalid",
956235Sxc151355 	    "EEPROM unreadable",
966235Sxc151355 	    "EEPROM checksum invalid",
976235Sxc151355 	    "EEPROM read problem",
986235Sxc151355 	    "EEPROM mac address invalid",
996235Sxc151355 	    "EEPROM size not supported",
1006235Sxc151355 	    "Attempt to change write-locked EEPROM",
1016235Sxc151355 	    "Invalid parameter to function",
1026235Sxc151355 	    "Hardware revision not supported",
1036235Sxc151355 	    "Hardware self-test failed",
1046235Sxc151355 	    "Operation incomplete"
1056235Sxc151355 	};
1066235Sxc151355 
1076235Sxc151355 	if (status >= 0 && status < sizeof (hal_status_desc)/sizeof (char *))
1086235Sxc151355 		return (hal_status_desc[status]);
1096235Sxc151355 	else
1106235Sxc151355 		return ("");
1116235Sxc151355 }
1126235Sxc151355 
1131000Sxc151355 uint32_t
1141000Sxc151355 ath_calcrxfilter(ath_t *asc)
1151000Sxc151355 {
1163147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
1171000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
1181000Sxc151355 	uint32_t rfilt;
1191000Sxc151355 
1201000Sxc151355 	rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR)
1211000Sxc151355 	    | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
1223147Sxc151355 	if (ic->ic_opmode != IEEE80211_M_STA)
1231000Sxc151355 		rfilt |= HAL_RX_FILTER_PROBEREQ;
1246235Sxc151355 	if (ic->ic_opmode != IEEE80211_M_HOSTAP && asc->asc_promisc)
1256235Sxc151355 		rfilt |= HAL_RX_FILTER_PROM;	/* promiscuous */
1263147Sxc151355 	if (ic->ic_opmode == IEEE80211_M_STA ||
1273147Sxc151355 	    ic->ic_opmode == IEEE80211_M_IBSS ||
1283147Sxc151355 	    ic->ic_state == IEEE80211_S_SCAN)
1291000Sxc151355 		rfilt |= HAL_RX_FILTER_BEACON;
1301000Sxc151355 	return (rfilt);
1311000Sxc151355 }
1321000Sxc151355 
1331000Sxc151355 static int
1341000Sxc151355 ath_set_data_queue(ath_t *asc, int ac, int haltype)
1351000Sxc151355 {
1361000Sxc151355 	HAL_TXQ_INFO qi;
1371000Sxc151355 	int qnum;
1381000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
1391000Sxc151355 	struct ath_txq *txq;
1401000Sxc151355 
1411000Sxc151355 	if (ac >= ATH_N(asc->asc_ac2q)) {
1421000Sxc151355 		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1431000Sxc151355 		    "ac %u out of range, max %u!\n",
1441000Sxc151355 		    ac, ATH_N(asc->asc_ac2q)));
1451000Sxc151355 		return (1);
1461000Sxc151355 	}
1471000Sxc151355 	(void) memset(&qi, 0, sizeof (qi));
1481000Sxc151355 	qi.tqi_subtype = haltype;
1491000Sxc151355 	/*
1501000Sxc151355 	 * Enable interrupts only for EOL and DESC conditions.
1511000Sxc151355 	 * We mark tx descriptors to receive a DESC interrupt
1521000Sxc151355 	 * when a tx queue gets deep; otherwise waiting for the
1531000Sxc151355 	 * EOL to reap descriptors.  Note that this is done to
1541000Sxc151355 	 * reduce interrupt load and this only defers reaping
1551000Sxc151355 	 * descriptors, never transmitting frames.  Aside from
1561000Sxc151355 	 * reducing interrupts this also permits more concurrency.
1571000Sxc151355 	 * The only potential downside is if the tx queue backs
1581000Sxc151355 	 * up in which case the top half of the kernel may backup
1591000Sxc151355 	 * due to a lack of tx descriptors.
1601000Sxc151355 	 */
1613147Sxc151355 	qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE;
1621000Sxc151355 	qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi);
1631000Sxc151355 	if (qnum == -1) {
1641000Sxc151355 		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1651000Sxc151355 		    "Unable to setup hardware queue for %s traffic!\n",
1661000Sxc151355 		    acnames[ac]));
1671000Sxc151355 		return (1);
1681000Sxc151355 	}
1691000Sxc151355 	if (qnum >= ATH_N(asc->asc_txq)) {
1701000Sxc151355 		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
1711000Sxc151355 		    "hal qnum %u out of range, max %u!\n",
1721000Sxc151355 		    qnum, ATH_N(asc->asc_txq)));
1731000Sxc151355 		return (1);
1741000Sxc151355 	}
1751000Sxc151355 	if (!ATH_TXQ_SETUP(asc, qnum)) {
1761000Sxc151355 		txq = &asc->asc_txq[qnum];
1771000Sxc151355 		txq->axq_qnum = qnum;
1781000Sxc151355 		txq->axq_depth = 0;
1791000Sxc151355 		txq->axq_intrcnt = 0;
1801000Sxc151355 		txq->axq_link = NULL;
1811000Sxc151355 		list_create(&txq->axq_list, sizeof (struct ath_buf),
1821000Sxc151355 		    offsetof(struct ath_buf, bf_node));
1831000Sxc151355 		mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL);
1841000Sxc151355 		asc->asc_txqsetup |= 1<<qnum;
1851000Sxc151355 	}
1861000Sxc151355 	asc->asc_ac2q[ac] = &asc->asc_txq[qnum];
1871000Sxc151355 	return (0);
1881000Sxc151355 }
1891000Sxc151355 
1901000Sxc151355 int
1911000Sxc151355 ath_txq_setup(ath_t *asc)
1921000Sxc151355 {
1931000Sxc151355 	if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) ||
1941000Sxc151355 	    ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) ||
1951000Sxc151355 	    ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) ||
1961000Sxc151355 	    ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) {
1971000Sxc151355 		return (1);
1981000Sxc151355 	}
1991000Sxc151355 
2001000Sxc151355 	return (0);
2011000Sxc151355 }
2021000Sxc151355 
2031000Sxc151355 void
2043147Sxc151355 ath_txq_cleanup(ath_t *asc)
2053147Sxc151355 {
2063147Sxc151355 	int i;
2073147Sxc151355 
2083147Sxc151355 	mutex_destroy(&asc->asc_txbuflock);
2093147Sxc151355 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
2103147Sxc151355 		if (ATH_TXQ_SETUP(asc, i)) {
2113147Sxc151355 			struct ath_txq *txq = &asc->asc_txq[i];
2123147Sxc151355 
2133147Sxc151355 			ATH_HAL_RELEASETXQUEUE(asc->asc_ah, txq->axq_qnum);
2143147Sxc151355 			mutex_destroy(&txq->axq_lock);
2153147Sxc151355 			asc->asc_txqsetup &= ~(1 << txq->axq_qnum);
2163147Sxc151355 		}
2173147Sxc151355 	}
2183147Sxc151355 }
2193147Sxc151355 
2203147Sxc151355 void
2211000Sxc151355 ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode)
2221000Sxc151355 {
2231000Sxc151355 	const HAL_RATE_TABLE *rt;
2241000Sxc151355 	int i;
2251000Sxc151355 
2261000Sxc151355 	for (i = 0; i < sizeof (asc->asc_rixmap); i++)
2271000Sxc151355 		asc->asc_rixmap[i] = 0xff;
2281000Sxc151355 
2291000Sxc151355 	rt = asc->asc_rates[mode];
2301000Sxc151355 	ASSERT(rt != NULL);
2311000Sxc151355 
2321000Sxc151355 	for (i = 0; i < rt->rateCount; i++)
233*7274Sff224033 		asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] =
234*7274Sff224033 		    (uint8_t)i;
2351000Sxc151355 
2361000Sxc151355 	asc->asc_currates = rt;
2371000Sxc151355 	asc->asc_curmode = mode;
2381000Sxc151355 }
2391000Sxc151355 
2401000Sxc151355 /* Set correct parameters for a certain mode */
2411000Sxc151355 void
2421000Sxc151355 ath_mode_init(ath_t *asc)
2431000Sxc151355 {
2443147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
2451000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
2461000Sxc151355 	uint32_t rfilt;
2471000Sxc151355 
2481000Sxc151355 	/* configure rx filter */
2491000Sxc151355 	rfilt = ath_calcrxfilter(asc);
2501000Sxc151355 	ATH_HAL_SETRXFILTER(ah, rfilt);
2511000Sxc151355 	ATH_HAL_SETOPMODE(ah);
2526235Sxc151355 	ATH_HAL_SETMCASTFILTER(ah, asc->asc_mcast_hash[0],
2536235Sxc151355 	    asc->asc_mcast_hash[1]);
2541000Sxc151355 	ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): "
2551000Sxc151355 	    "mode =%d RX filter 0x%x, MC filter %08x:%08x\n",
2563147Sxc151355 	    ic->ic_opmode, rfilt,
2576235Sxc151355 	    asc->asc_mcast_hash[0], asc->asc_mcast_hash[1]));
2581000Sxc151355 }
2591000Sxc151355 
2601000Sxc151355 /*
2611000Sxc151355  * Disable the receive h/w in preparation for a reset.
2621000Sxc151355  */
2631000Sxc151355 void
2641000Sxc151355 ath_stoprecv(ath_t *asc)
2651000Sxc151355 {
2661000Sxc151355 	ATH_HAL_STOPPCURECV(asc->asc_ah);	/* disable PCU */
2671000Sxc151355 	ATH_HAL_SETRXFILTER(asc->asc_ah, 0);	/* clear recv filter */
2681000Sxc151355 	ATH_HAL_STOPDMARECV(asc->asc_ah);	/* disable DMA engine */
2691000Sxc151355 	drv_usecwait(3000);
2701000Sxc151355 
2711000Sxc151355 	ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n",
2721000Sxc151355 	    ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink));
2731000Sxc151355 	asc->asc_rxlink = NULL;
2741000Sxc151355 }
2751000Sxc151355 
2761000Sxc151355 uint32_t
2773147Sxc151355 ath_chan2flags(ieee80211com_t *isc, struct ieee80211_channel *chan)
2781000Sxc151355 {
2791000Sxc151355 	static const uint32_t modeflags[] = {
2801000Sxc151355 	    0,				/* IEEE80211_MODE_AUTO */
2811000Sxc151355 	    CHANNEL_A,			/* IEEE80211_MODE_11A */
2821000Sxc151355 	    CHANNEL_B,			/* IEEE80211_MODE_11B */
2831000Sxc151355 	    CHANNEL_PUREG,		/* IEEE80211_MODE_11G */
2843147Sxc151355 	    0,				/* IEEE80211_MODE_FH */
2853147Sxc151355 	    CHANNEL_108A,		/* IEEE80211_MODE_TURBO_A */
2863147Sxc151355 	    CHANNEL_108G		/* IEEE80211_MODE_TURBO_G */
2871000Sxc151355 	};
2881000Sxc151355 	return (modeflags[ieee80211_chan2mode(isc, chan)]);
2891000Sxc151355 }
2901000Sxc151355 
2911000Sxc151355 
2921000Sxc151355 int
2931000Sxc151355 ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
2941000Sxc151355 {
2953147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
2961000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
2971000Sxc151355 	HAL_CHANNEL *chans;
2981000Sxc151355 	int i, ix;
2991000Sxc151355 	uint32_t nchan;
3001000Sxc151355 
3011000Sxc151355 	chans = (HAL_CHANNEL *)
3021000Sxc151355 	    kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP);
3031000Sxc151355 
3041000Sxc151355 	if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
3053147Sxc151355 	    NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) {
3061000Sxc151355 		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
3076235Sxc151355 		    "unable to get channel list\n"));
3086235Sxc151355 		kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
3091000Sxc151355 		return (EINVAL);
3101000Sxc151355 	}
3111000Sxc151355 
3121000Sxc151355 	/*
3131000Sxc151355 	 * Convert HAL channels to ieee80211 ones and insert
3141000Sxc151355 	 * them in the table according to their channel number.
3151000Sxc151355 	 */
3161000Sxc151355 	for (i = 0; i < nchan; i++) {
3171000Sxc151355 		HAL_CHANNEL *c = &chans[i];
3183147Sxc151355 		uint16_t flags;
3193147Sxc151355 		ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
3201000Sxc151355 		if (ix > IEEE80211_CHAN_MAX) {
3211000Sxc151355 			ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
3223147Sxc151355 			    "bad hal channel %d (%u/%x) ignored\n",
3231000Sxc151355 			    ix, c->channel, c->channelFlags));
3241000Sxc151355 			continue;
3251000Sxc151355 		}
3261000Sxc151355 		/* NB: flags are known to be compatible */
3273147Sxc151355 		if (ix < 0) {
3283147Sxc151355 			/*
3293147Sxc151355 			 * can't handle frequency <2400MHz (negative
3303147Sxc151355 			 * channels) right now
3313147Sxc151355 			 */
3323147Sxc151355 			ATH_DEBUG((ATH_DBG_AUX, "ath:ath_getchannels(): "
3333147Sxc151355 			    "hal channel %d (%u/%x) "
3343147Sxc151355 			    "cannot be handled, ignored\n",
3353147Sxc151355 			    ix, c->channel, c->channelFlags));
3363147Sxc151355 			continue;
3373147Sxc151355 		}
3383147Sxc151355 		/*
3393147Sxc151355 		 * Calculate net80211 flags; most are compatible
3403147Sxc151355 		 * but some need massaging.  Note the static turbo
3413147Sxc151355 		 * conversion can be removed once net80211 is updated
3423147Sxc151355 		 * to understand static vs. dynamic turbo.
3433147Sxc151355 		 */
3443147Sxc151355 		flags = c->channelFlags & CHANNEL_COMPAT;
3453147Sxc151355 		if (c->channelFlags & CHANNEL_STURBO)
3463147Sxc151355 			flags |= IEEE80211_CHAN_TURBO;
3473147Sxc151355 		if (ic->ic_sup_channels[ix].ich_freq == 0) {
3483147Sxc151355 			ic->ic_sup_channels[ix].ich_freq = c->channel;
3493147Sxc151355 			ic->ic_sup_channels[ix].ich_flags = flags;
3501000Sxc151355 		} else {
3511000Sxc151355 			/* channels overlap; e.g. 11g and 11b */
3523147Sxc151355 			ic->ic_sup_channels[ix].ich_flags |= flags;
3531000Sxc151355 		}
3541000Sxc151355 		if ((c->channelFlags & CHANNEL_G) == CHANNEL_G)
3551000Sxc151355 			asc->asc_have11g = 1;
3561000Sxc151355 	}
3571000Sxc151355 	kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
3581000Sxc151355 	return (0);
3591000Sxc151355 }
3601000Sxc151355 
3611000Sxc151355 static void
3621000Sxc151355 ath_drainq(ath_t *asc, struct ath_txq *txq)
3631000Sxc151355 {
3641000Sxc151355 	struct ath_buf *bf;
3651000Sxc151355 
3661000Sxc151355 	/*
3671000Sxc151355 	 * This assumes output has been stopped.
3681000Sxc151355 	 */
3691000Sxc151355 	for (;;) {
3701000Sxc151355 		mutex_enter(&txq->axq_lock);
3711000Sxc151355 		bf = list_head(&txq->axq_list);
3721000Sxc151355 		if (bf == NULL) {
3731000Sxc151355 			txq->axq_link = NULL;
3741000Sxc151355 			mutex_exit(&txq->axq_lock);
3751000Sxc151355 			break;
3761000Sxc151355 		}
3771000Sxc151355 		list_remove(&txq->axq_list, bf);
3781000Sxc151355 		mutex_exit(&txq->axq_lock);
3791000Sxc151355 		bf->bf_in = NULL;
3801000Sxc151355 		mutex_enter(&asc->asc_txbuflock);
3811000Sxc151355 		list_insert_tail(&asc->asc_txbuf_list, bf);
3821000Sxc151355 		mutex_exit(&asc->asc_txbuflock);
3831000Sxc151355 	}
3841000Sxc151355 }
3851000Sxc151355 
3861000Sxc151355 
3871000Sxc151355 /*
3881000Sxc151355  * Drain the transmit queues and reclaim resources.
3891000Sxc151355  */
3901000Sxc151355 void
3911000Sxc151355 ath_draintxq(ath_t *asc)
3921000Sxc151355 {
3931000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
3941000Sxc151355 	struct ath_txq *txq;
3951000Sxc151355 	int i;
3961000Sxc151355 
3971000Sxc151355 	if (!asc->asc_invalid) {
3981000Sxc151355 		for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
3991000Sxc151355 			if (ATH_TXQ_SETUP(asc, i)) {
4001000Sxc151355 				txq = &asc->asc_txq[i];
4011000Sxc151355 				(void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum);
4021000Sxc151355 			}
4031000Sxc151355 		}
4041000Sxc151355 	}
4051000Sxc151355 	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
4061000Sxc151355 		if (ATH_TXQ_SETUP(asc, i)) {
4071000Sxc151355 			ath_drainq(asc, &asc->asc_txq[i]);
4081000Sxc151355 		}
4091000Sxc151355 	}
4101000Sxc151355 }
4111000Sxc151355 
4121000Sxc151355 
4131000Sxc151355 /* Enable the receive h/w following a reset */
4141000Sxc151355 int
4151000Sxc151355 ath_startrecv(ath_t *asc)
4161000Sxc151355 {
4171000Sxc151355 	struct ath_buf *bf;
4181000Sxc151355 
4191000Sxc151355 	asc->asc_rxlink = NULL;
4201000Sxc151355 
4211000Sxc151355 	bf = list_head(&asc->asc_rxbuf_list);
4221000Sxc151355 	while (bf != NULL) {
4231000Sxc151355 		ath_setup_desc(asc, bf);
4241000Sxc151355 		bf = list_next(&asc->asc_rxbuf_list, bf);
4251000Sxc151355 	}
4261000Sxc151355 
4271000Sxc151355 	bf = list_head(&asc->asc_rxbuf_list);
4281000Sxc151355 	ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr);
4291000Sxc151355 	ATH_HAL_RXENA(asc->asc_ah);		/* enable recv descriptors */
4301000Sxc151355 	ath_mode_init(asc);			/* set filters, etc. */
4311000Sxc151355 	ATH_HAL_STARTPCURECV(asc->asc_ah);	/* re-enable PCU/DMA engine */
4321000Sxc151355 	return (0);
4331000Sxc151355 }
4341000Sxc151355 
4351000Sxc151355 /*
4363147Sxc151355  * Update internal state after a channel change.
4373147Sxc151355  */
4383147Sxc151355 void
4393147Sxc151355 ath_chan_change(ath_t *asc, struct ieee80211_channel *chan)
4403147Sxc151355 {
4413147Sxc151355 	struct ieee80211com *ic = &asc->asc_isc;
4423147Sxc151355 	enum ieee80211_phymode mode;
4433147Sxc151355 
4443147Sxc151355 	/*
4453147Sxc151355 	 * Change channels and update the h/w rate map
4463147Sxc151355 	 * if we're switching; e.g. 11a to 11b/g.
4473147Sxc151355 	 */
4483147Sxc151355 	mode = ieee80211_chan2mode(ic, chan);
4493147Sxc151355 	if (mode != asc->asc_curmode)
4503147Sxc151355 		ath_setcurmode(asc, mode);
4513147Sxc151355 }
4523147Sxc151355 
4533147Sxc151355 /*
4541000Sxc151355  * Set/change channels.  If the channel is really being changed,
4551000Sxc151355  * it's done by resetting the chip.  To accomplish this we must
4561000Sxc151355  * first cleanup any pending DMA.
4571000Sxc151355  */
4581000Sxc151355 int
4593147Sxc151355 ath_chan_set(ath_t *asc, struct ieee80211_channel *chan)
4601000Sxc151355 {
4611000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
4623147Sxc151355 	ieee80211com_t *ic = &asc->asc_isc;
4631000Sxc151355 
4643147Sxc151355 	if (chan != ic->ic_ibss_chan) {
4651000Sxc151355 		HAL_STATUS status;
4661000Sxc151355 		HAL_CHANNEL hchan;
4671000Sxc151355 
4681000Sxc151355 		/*
4691000Sxc151355 		 * To switch channels clear any pending DMA operations;
4701000Sxc151355 		 * wait long enough for the RX fifo to drain, reset the
4711000Sxc151355 		 * hardware at the new frequency, and then re-enable
4721000Sxc151355 		 * the relevant bits of the h/w.
4731000Sxc151355 		 */
4741000Sxc151355 		ATH_HAL_INTRSET(ah, 0);		/* disable interrupts */
4751000Sxc151355 		ath_draintxq(asc);		/* clear pending tx frames */
4761000Sxc151355 		ath_stoprecv(asc);		/* turn off frame recv */
4771000Sxc151355 		/*
4781000Sxc151355 		 * Convert to a HAL channel description with
4791000Sxc151355 		 * the flags constrained to reflect the current
4801000Sxc151355 		 * operating mode.
4811000Sxc151355 		 */
4821000Sxc151355 		hchan.channel = chan->ich_freq;
4833147Sxc151355 		hchan.channelFlags = ath_chan2flags(ic, chan);
4843147Sxc151355 		if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
4851000Sxc151355 		    &hchan, AH_TRUE, &status)) {
4861000Sxc151355 			ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():"
4876235Sxc151355 			    "unable to reset channel %u (%uMhz)\n"
4886235Sxc151355 			    "flags 0x%x: '%s' (HAL status %u)\n",
4896235Sxc151355 			    ieee80211_chan2ieee(ic, chan), hchan.channel,
4906235Sxc151355 			    hchan.channelFlags,
4916235Sxc151355 			    ath_get_hal_status_desc(status), status));
4921000Sxc151355 			return (EIO);
4931000Sxc151355 		}
4943147Sxc151355 		asc->asc_curchan = hchan;
4951000Sxc151355 
4961000Sxc151355 		/*
4971000Sxc151355 		 * Re-enable rx framework.
4981000Sxc151355 		 */
4991000Sxc151355 		if (ath_startrecv(asc) != 0) {
5001000Sxc151355 			ath_problem("ath: ath_chan_set(): "
5011000Sxc151355 			    "restarting receiving logic failed\n");
5021000Sxc151355 			return (EIO);
5031000Sxc151355 		}
5041000Sxc151355 
5051000Sxc151355 		/*
5061000Sxc151355 		 * Change channels and update the h/w rate map
5071000Sxc151355 		 * if we're switching; e.g. 11a to 11b/g.
5081000Sxc151355 		 */
5093147Sxc151355 		ic->ic_ibss_chan = chan;
5103147Sxc151355 		ath_chan_change(asc, chan);
5111000Sxc151355 		/*
5121000Sxc151355 		 * Re-enable interrupts.
5131000Sxc151355 		 */
5141000Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask);
5151000Sxc151355 	}
5161000Sxc151355 	return (0);
5171000Sxc151355 }
5181000Sxc151355 
5191000Sxc151355 
5201000Sxc151355 /*
5211000Sxc151355  * Configure the beacon and sleep timers.
5221000Sxc151355  *
5231000Sxc151355  * When operating as an AP this resets the TSF and sets
5241000Sxc151355  * up the hardware to notify us when we need to issue beacons.
5251000Sxc151355  *
5261000Sxc151355  * When operating in station mode this sets up the beacon
5271000Sxc151355  * timers according to the timestamp of the last received
5281000Sxc151355  * beacon and the current TSF, configures PCF and DTIM
5291000Sxc151355  * handling, programs the sleep registers so the hardware
5301000Sxc151355  * will wakeup in time to receive beacons, and configures
5311000Sxc151355  * the beacon miss handling so we'll receive a BMISS
5321000Sxc151355  * interrupt when we stop seeing beacons from the AP
5331000Sxc151355  * we've associated with.
5341000Sxc151355  */
5351000Sxc151355 void
5361000Sxc151355 ath_beacon_config(ath_t *asc)
5371000Sxc151355 {
5381000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
5393147Sxc151355 	ieee80211com_t *ic = (ieee80211com_t *)asc;
5403147Sxc151355 	struct ieee80211_node *in = ic->ic_bss;
5411000Sxc151355 	uint32_t nexttbtt;
5421000Sxc151355 
5433147Sxc151355 	nexttbtt = (ATH_LE_READ_4(in->in_tstamp.data + 4) << 22) |
5443147Sxc151355 	    (ATH_LE_READ_4(in->in_tstamp.data) >> 10);
5451000Sxc151355 	nexttbtt += in->in_intval;
5463147Sxc151355 	if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
5471000Sxc151355 		HAL_BEACON_STATE bs;
5481000Sxc151355 
5491000Sxc151355 		/* NB: no PCF support right now */
5501000Sxc151355 		bzero(&bs, sizeof (bs));
5511000Sxc151355 		bs.bs_intval = in->in_intval;
5521000Sxc151355 		bs.bs_nexttbtt = nexttbtt;
5531000Sxc151355 		bs.bs_dtimperiod = bs.bs_intval;
5541000Sxc151355 		bs.bs_nextdtim = nexttbtt;
5551000Sxc151355 
5561000Sxc151355 		/*
5573147Sxc151355 		 * Setup the number of consecutive beacons to miss
5583147Sxc151355 		 * before taking a BMISS interrupt.
5591000Sxc151355 		 * Note that we clamp the result to at most 10 beacons.
5601000Sxc151355 		 */
5613147Sxc151355 		bs.bs_bmissthreshold = ic->ic_bmissthreshold;
5621000Sxc151355 		if (bs.bs_bmissthreshold > 10)
5631000Sxc151355 			bs.bs_bmissthreshold = 10;
5646990Sgd78059 		else if (bs.bs_bmissthreshold < 1)
5651000Sxc151355 			bs.bs_bmissthreshold = 1;
5661000Sxc151355 		/*
5671000Sxc151355 		 * Calculate sleep duration.  The configuration is
5681000Sxc151355 		 * given in ms.  We insure a multiple of the beacon
5691000Sxc151355 		 * period is used.  Also, if the sleep duration is
5701000Sxc151355 		 * greater than the DTIM period then it makes senses
5711000Sxc151355 		 * to make it a multiple of that.
5721000Sxc151355 		 */
5731000Sxc151355 		bs.bs_sleepduration =
5741000Sxc151355 		    roundup((100 * 1000) / 1024, bs.bs_intval);
5751000Sxc151355 		if (bs.bs_sleepduration > bs.bs_dtimperiod)
5761000Sxc151355 			bs.bs_sleepduration =
5771000Sxc151355 			    roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
5781000Sxc151355 
5791000Sxc151355 
5801000Sxc151355 		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): "
5811000Sxc151355 		    "intval %u nexttbtt %u dtim %u"
5821000Sxc151355 		    " nextdtim %u bmiss %u sleep %u\n",
5831000Sxc151355 		    bs.bs_intval,
5841000Sxc151355 		    bs.bs_nexttbtt,
5851000Sxc151355 		    bs.bs_dtimperiod,
5861000Sxc151355 		    bs.bs_nextdtim,
5871000Sxc151355 		    bs.bs_bmissthreshold,
5881000Sxc151355 		    bs.bs_sleepduration));
5891000Sxc151355 		ATH_HAL_INTRSET(ah, 0);
5901000Sxc151355 		/*
5911000Sxc151355 		 * Reset our tsf so the hardware will update the
5921000Sxc151355 		 * tsf register to reflect timestamps found in
5931000Sxc151355 		 * received beacons.
5941000Sxc151355 		 */
5951000Sxc151355 		ATH_HAL_RESETTSF(ah);
5961000Sxc151355 		ATH_HAL_BEACONTIMERS(ah, &bs);
5971000Sxc151355 		asc->asc_imask |= HAL_INT_BMISS;
5981000Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask);
5991000Sxc151355 	} else {
6001000Sxc151355 		ATH_HAL_INTRSET(ah, 0);
6011000Sxc151355 		ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval);
6021000Sxc151355 		asc->asc_imask |= HAL_INT_SWBA;	/* beacon prepare */
6031000Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask);
6041000Sxc151355 	}
6051000Sxc151355 }
6061000Sxc151355 
6073147Sxc151355 /*
6084126Szf162725  * Allocate tx/rx key slots for TKIP.  We allocate two slots for
6094126Szf162725  * each key, one for decrypt/encrypt and the other for the MIC.
6104126Szf162725  */
6114126Szf162725 static int
6124126Szf162725 key_alloc_2pair(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
6134126Szf162725 {
6144126Szf162725 	uint16_t i, keyix;
6154126Szf162725 
6164126Szf162725 	ASSERT(asc->asc_splitmic);
6174126Szf162725 	for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) {
6184126Szf162725 		uint8_t b = asc->asc_keymap[i];
6194126Szf162725 		if (b != 0xff) {
6204126Szf162725 			/*
6214126Szf162725 			 * One or more slots in this byte are free.
6224126Szf162725 			 */
6234126Szf162725 			keyix = i*NBBY;
6244126Szf162725 			while (b & 1) {
6254126Szf162725 		again:
6264126Szf162725 				keyix++;
6274126Szf162725 				b >>= 1;
6284126Szf162725 			}
6294126Szf162725 			/* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
6304126Szf162725 			if (isset(asc->asc_keymap, keyix+32) ||
6314126Szf162725 			    isset(asc->asc_keymap, keyix+64) ||
6324126Szf162725 			    isset(asc->asc_keymap, keyix+32+64)) {
6334126Szf162725 				/* full pair unavailable */
6344126Szf162725 				if (keyix == (i+1)*NBBY) {
6354126Szf162725 					/* no slots were appropriate, advance */
6364126Szf162725 					continue;
6374126Szf162725 				}
6384126Szf162725 				goto again;
6394126Szf162725 			}
6404126Szf162725 			setbit(asc->asc_keymap, keyix);
6414126Szf162725 			setbit(asc->asc_keymap, keyix+64);
6424126Szf162725 			setbit(asc->asc_keymap, keyix+32);
6434126Szf162725 			setbit(asc->asc_keymap, keyix+32+64);
6444126Szf162725 			ATH_DEBUG((ATH_DBG_AUX,
6454126Szf162725 			    "key_alloc_2pair: key pair %u,%u %u,%u\n",
6464126Szf162725 			    keyix, keyix+64,
6474126Szf162725 			    keyix+32, keyix+32+64));
6484126Szf162725 			*txkeyix = *rxkeyix = keyix;
6494126Szf162725 			return (1);
6504126Szf162725 		}
6514126Szf162725 	}
6524126Szf162725 	ATH_DEBUG((ATH_DBG_AUX, "key_alloc_2pair:"
6534126Szf162725 	    " out of pair space\n"));
6544126Szf162725 	return (0);
6554126Szf162725 }
6564126Szf162725 /*
6574126Szf162725  * Allocate a single key cache slot.
6584126Szf162725  */
6594126Szf162725 static int
6604126Szf162725 key_alloc_single(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
6614126Szf162725 {
6624126Szf162725 	uint16_t i, keyix;
6634126Szf162725 
6644126Szf162725 	/* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
6654126Szf162725 	for (i = 0; i < ATH_N(asc->asc_keymap); i++) {
6664126Szf162725 		uint8_t b = asc->asc_keymap[i];
6674126Szf162725 
6684126Szf162725 		if (b != 0xff) {
6694126Szf162725 			/*
6704126Szf162725 			 * One or more slots are free.
6714126Szf162725 			 */
6724126Szf162725 			keyix = i*NBBY;
6734126Szf162725 			while (b & 1)
6744126Szf162725 				keyix++, b >>= 1;
6754126Szf162725 			setbit(asc->asc_keymap, keyix);
6764126Szf162725 			ATH_DEBUG((ATH_DBG_AUX, "key_alloc_single:"
6774126Szf162725 			    " key %u\n", keyix));
6784126Szf162725 			*txkeyix = *rxkeyix = keyix;
6794126Szf162725 			return (1);
6804126Szf162725 		}
6814126Szf162725 	}
6824126Szf162725 	return (0);
6834126Szf162725 }
6844126Szf162725 
6854126Szf162725 /*
6863147Sxc151355  * Allocate one or more key cache slots for a unicast key.  The
6873147Sxc151355  * key itself is needed only to identify the cipher.  For hardware
6883147Sxc151355  * TKIP with split cipher+MIC keys we allocate two key cache slot
6893147Sxc151355  * pairs so that we can setup separate TX and RX MIC keys.  Note
6903147Sxc151355  * that the MIC key for a TKIP key at slot i is assumed by the
6913147Sxc151355  * hardware to be at slot i+64.  This limits TKIP keys to the first
6923147Sxc151355  * 64 entries.
6933147Sxc151355  */
6943147Sxc151355 /* ARGSUSED */
6953147Sxc151355 int
6963147Sxc151355 ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k,
6973147Sxc151355     ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
6983147Sxc151355 {
6994126Szf162725 	ath_t *asc = (ath_t *)ic;
7004126Szf162725 
7014126Szf162725 	/*
7024126Szf162725 	 * We allocate two pair for TKIP when using the h/w to do
7034126Szf162725 	 * the MIC.  For everything else, including software crypto,
7044126Szf162725 	 * we allocate a single entry.  Note that s/w crypto requires
7054126Szf162725 	 * a pass-through slot on the 5211 and 5212.  The 5210 does
7064126Szf162725 	 * not support pass-through cache entries and we map all
7074126Szf162725 	 * those requests to slot 0.
7084126Szf162725 	 */
7094126Szf162725 	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
7104126Szf162725 		return (key_alloc_single(asc, keyix, rxkeyix));
7114126Szf162725 	} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
7124126Szf162725 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) {
7134126Szf162725 		return (key_alloc_2pair(asc, keyix, rxkeyix));
7144126Szf162725 	} else {
7154126Szf162725 		return (key_alloc_single(asc, keyix, rxkeyix));
7164126Szf162725 	}
7174126Szf162725 }
7184126Szf162725 
7194126Szf162725 /*
7204126Szf162725  * Delete an entry in the key cache allocated by ath_key_alloc.
7214126Szf162725  */
7224126Szf162725 int
7234126Szf162725 ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k)
7244126Szf162725 {
7254126Szf162725 	ath_t *asc = (ath_t *)ic;
7264126Szf162725 	struct ath_hal *ah = asc->asc_ah;
7274126Szf162725 	const struct ieee80211_cipher *cip = k->wk_cipher;
7284126Szf162725 	ieee80211_keyix keyix = k->wk_keyix;
7294126Szf162725 
7304126Szf162725 	ATH_DEBUG((ATH_DBG_AUX, "ath_key_delete:"
7314126Szf162725 	    " delete key %u ic_cipher=0x%x\n", keyix, cip->ic_cipher));
7324126Szf162725 
7334126Szf162725 	ATH_HAL_KEYRESET(ah, keyix);
7344126Szf162725 	/*
7354126Szf162725 	 * Handle split tx/rx keying required for TKIP with h/w MIC.
7364126Szf162725 	 */
7374126Szf162725 	if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
7384126Szf162725 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic)
7394126Szf162725 		ATH_HAL_KEYRESET(ah, keyix+32);		/* RX key */
7404126Szf162725 
7414126Szf162725 	if (keyix >= IEEE80211_WEP_NKID) {
7424126Szf162725 		/*
7434126Szf162725 		 * Don't touch keymap entries for global keys so
7444126Szf162725 		 * they are never considered for dynamic allocation.
7454126Szf162725 		 */
7464126Szf162725 		clrbit(asc->asc_keymap, keyix);
7474126Szf162725 		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
7484126Szf162725 		    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
7494126Szf162725 		    asc->asc_splitmic) {
7504126Szf162725 			clrbit(asc->asc_keymap, keyix+64);	/* TX key MIC */
7514126Szf162725 			clrbit(asc->asc_keymap, keyix+32);	/* RX key */
7524126Szf162725 			clrbit(asc->asc_keymap, keyix+32+64);	/* RX key MIC */
7534126Szf162725 		}
7544126Szf162725 	}
7553147Sxc151355 	return (1);
7563147Sxc151355 }
7571000Sxc151355 
7584126Szf162725 static void
7594126Szf162725 ath_keyprint(const char *tag, uint_t ix,
7604126Szf162725     const HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
7613147Sxc151355 {
7624126Szf162725 	static const char *ciphers[] = {
7634126Szf162725 		"WEP",
7644126Szf162725 		"AES-OCB",
7654126Szf162725 		"AES-CCM",
7664126Szf162725 		"CKIP",
7674126Szf162725 		"TKIP",
7684126Szf162725 		"CLR",
7694126Szf162725 	};
7704126Szf162725 	int i, n;
7714126Szf162725 	char buf[MAX_IEEE80211STR], buft[32];
7724126Szf162725 
7734126Szf162725 	(void) snprintf(buf, sizeof (buf), "%s: [%02u] %s ",
7744126Szf162725 	    tag, ix, ciphers[hk->kv_type]);
7754126Szf162725 	for (i = 0, n = hk->kv_len; i < n; i++) {
7764126Szf162725 		(void) snprintf(buft, sizeof (buft), "%02x", hk->kv_val[i]);
7774126Szf162725 		(void) strlcat(buf, buft, sizeof (buf));
7784126Szf162725 	}
7794126Szf162725 	(void) snprintf(buft, sizeof (buft), " mac %s",
7804126Szf162725 	    ieee80211_macaddr_sprintf(mac));
7814126Szf162725 	(void) strlcat(buf, buft, sizeof (buf));
7824126Szf162725 	if (hk->kv_type == HAL_CIPHER_TKIP) {
7834126Szf162725 		(void) snprintf(buft, sizeof (buft), " mic ");
7844126Szf162725 		(void) strlcat(buf, buft, sizeof (buf));
7854126Szf162725 		for (i = 0; i < sizeof (hk->kv_mic); i++) {
7864126Szf162725 			(void) snprintf(buft, sizeof (buft), "%02x",
7874126Szf162725 			    hk->kv_mic[i]);
7884126Szf162725 			(void) strlcat(buf, buft, sizeof (buf));
7894126Szf162725 		}
7904126Szf162725 	}
7914126Szf162725 	ATH_DEBUG((ATH_DBG_AUX, "%s", buf));
7924126Szf162725 }
7933147Sxc151355 
7944126Szf162725 /*
7954126Szf162725  * Set a TKIP key into the hardware.  This handles the
7964126Szf162725  * potential distribution of key state to multiple key
7974126Szf162725  * cache slots for TKIP.
7984126Szf162725  */
7994126Szf162725 static int
8004126Szf162725 ath_keyset_tkip(ath_t *asc, const struct ieee80211_key *k,
8014126Szf162725 	HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
8024126Szf162725 {
8034126Szf162725 #define	IEEE80211_KEY_XR	(IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
8044126Szf162725 	static const uint8_t zerobssid[IEEE80211_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
8054126Szf162725 	struct ath_hal *ah = asc->asc_ah;
8064126Szf162725 
8074126Szf162725 	ASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP);
8084126Szf162725 	if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
8094126Szf162725 		/*
8104126Szf162725 		 * TX key goes at first index, RX key at +32.
8114126Szf162725 		 * The hal handles the MIC keys at index+64.
8124126Szf162725 		 */
8134126Szf162725 		(void) memcpy(hk->kv_mic, k->wk_txmic, sizeof (hk->kv_mic));
8144126Szf162725 		ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid);
8154126Szf162725 		if (!ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid))
8164126Szf162725 			return (0);
8174126Szf162725 
8184126Szf162725 		(void) memcpy(hk->kv_mic, k->wk_rxmic, sizeof (hk->kv_mic));
8194126Szf162725 		ath_keyprint("ath_keyset_tkip:", k->wk_keyix+32, hk, mac);
8204126Szf162725 		return (ATH_HAL_KEYSET(ah, k->wk_keyix+32, hk, mac));
8214126Szf162725 	} else if (k->wk_flags & IEEE80211_KEY_XR) {
8224126Szf162725 		/*
8234126Szf162725 		 * TX/RX key goes at first index.
8244126Szf162725 		 * The hal handles the MIC keys are index+64.
8254126Szf162725 		 */
8264126Szf162725 		(void) memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
8274126Szf162725 		    k->wk_txmic : k->wk_rxmic, sizeof (hk->kv_mic));
8284126Szf162725 		ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid);
8294126Szf162725 		return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid));
8304126Szf162725 	}
8314126Szf162725 	return (0);
8324126Szf162725 #undef IEEE80211_KEY_XR
8333147Sxc151355 }
8341000Sxc151355 
8351000Sxc151355 /*
8363147Sxc151355  * Set the key cache contents for the specified key.  Key cache
8373147Sxc151355  * slot(s) must already have been allocated by ath_key_alloc.
8383147Sxc151355  */
8393147Sxc151355 int
8403147Sxc151355 ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
8413147Sxc151355     const uint8_t mac[IEEE80211_ADDR_LEN])
8423147Sxc151355 {
8433147Sxc151355 	static const uint8_t ciphermap[] = {
8443147Sxc151355 		HAL_CIPHER_WEP,		/* IEEE80211_CIPHER_WEP */
8453147Sxc151355 		HAL_CIPHER_TKIP,	/* IEEE80211_CIPHER_TKIP */
8463147Sxc151355 		HAL_CIPHER_AES_OCB,	/* IEEE80211_CIPHER_AES_OCB */
8473147Sxc151355 		HAL_CIPHER_AES_CCM,	/* IEEE80211_CIPHER_AES_CCM */
8483147Sxc151355 		HAL_CIPHER_CKIP,	/* IEEE80211_CIPHER_CKIP */
8493147Sxc151355 		HAL_CIPHER_CLR,		/* IEEE80211_CIPHER_NONE */
8503147Sxc151355 	};
8513147Sxc151355 	ath_t *asc = (ath_t *)ic;
8523147Sxc151355 	struct ath_hal *ah = asc->asc_ah;
8533147Sxc151355 	const struct ieee80211_cipher *cip = k->wk_cipher;
8543147Sxc151355 	HAL_KEYVAL hk;
8553147Sxc151355 
8563147Sxc151355 	bzero(&hk, sizeof (hk));
8573147Sxc151355 	/*
8583147Sxc151355 	 * Software crypto uses a "clear key" so non-crypto
8593147Sxc151355 	 * state kept in the key cache are maintainedd so that
8603147Sxc151355 	 * rx frames have an entry to match.
8613147Sxc151355 	 */
8623147Sxc151355 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
8633147Sxc151355 		ASSERT(cip->ic_cipher < ATH_N(ciphermap));
8643147Sxc151355 		hk.kv_type = ciphermap[cip->ic_cipher];
8653147Sxc151355 		hk.kv_len = k->wk_keylen;
8663147Sxc151355 		bcopy(k->wk_key, hk.kv_val, k->wk_keylen);
8673147Sxc151355 	} else {
8683147Sxc151355 		hk.kv_type = HAL_CIPHER_CLR;
8693147Sxc151355 	}
8703147Sxc151355 
8714126Szf162725 	if (hk.kv_type == HAL_CIPHER_TKIP &&
8724126Szf162725 	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
8734126Szf162725 	    asc->asc_splitmic) {
8744126Szf162725 		return (ath_keyset_tkip(asc, k, &hk, mac));
8754126Szf162725 	} else {
8764126Szf162725 		ath_keyprint("ath_keyset:", k->wk_keyix, &hk, mac);
8774126Szf162725 		return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac));
8784126Szf162725 	}
8793147Sxc151355 }
8803147Sxc151355 
8813147Sxc151355 /*
8823147Sxc151355  * Enable/Disable short slot timing
8831000Sxc151355  */
8841000Sxc151355 void
8853147Sxc151355 ath_set_shortslot(ieee80211com_t *ic, int onoff)
8861000Sxc151355 {
8873147Sxc151355 	struct ath_hal *ah = ((ath_t *)ic)->asc_ah;
8881000Sxc151355 
8893147Sxc151355 	if (onoff)
8903147Sxc151355 		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9);
8913147Sxc151355 	else
8923147Sxc151355 		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20);
8931000Sxc151355 }
8941000Sxc151355 
8953147Sxc151355 int
8963147Sxc151355 ath_reset(ieee80211com_t *ic)
8971000Sxc151355 {
8983147Sxc151355 	ath_t *asc = (ath_t *)ic;
8991000Sxc151355 	struct ath_hal *ah = asc->asc_ah;
9003147Sxc151355 	struct ieee80211_channel *ch;
9011000Sxc151355 	HAL_STATUS status;
9021000Sxc151355 
9031000Sxc151355 	/*
9041000Sxc151355 	 * Convert to a HAL channel description with the flags
9051000Sxc151355 	 * constrained to reflect the current operating mode.
9061000Sxc151355 	 */
9073147Sxc151355 	ch = ic->ic_curchan;
9083147Sxc151355 	asc->asc_curchan.channel = ch->ich_freq;
9093147Sxc151355 	asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch);
9101000Sxc151355 
9111000Sxc151355 	ATH_HAL_INTRSET(ah, 0);		/* disable interrupts */
9121000Sxc151355 	ath_draintxq(asc);		/* stop xmit side */
9133147Sxc151355 	if (ATH_IS_RUNNING(asc)) {
9141000Sxc151355 		ath_stoprecv(asc);		/* stop recv side */
9153147Sxc151355 		/* indicate channel change so we do a full reset */
9166235Sxc151355 		if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
9176235Sxc151355 		    &asc->asc_curchan, AH_TRUE, &status)) {
9183147Sxc151355 			ath_problem("ath: ath_reset(): "
9196235Sxc151355 			    "resetting hardware failed, '%s' (HAL status %u)\n",
9206235Sxc151355 			    ath_get_hal_status_desc(status), status);
9213147Sxc151355 		}
9223147Sxc151355 		ath_chan_change(asc, ch);
9231000Sxc151355 	}
9243147Sxc151355 	if (ATH_IS_RUNNING(asc)) {
9251000Sxc151355 		if (ath_startrecv(asc) != 0)	/* restart recv */
9261000Sxc151355 			ath_problem("ath: ath_reset(): "
9271000Sxc151355 			    "starting receiving logic failed\n");
9283147Sxc151355 		if (ic->ic_state == IEEE80211_S_RUN) {
9291000Sxc151355 			ath_beacon_config(asc);	/* restart beacons */
9301000Sxc151355 		}
9311000Sxc151355 		ATH_HAL_INTRSET(ah, asc->asc_imask);
9321000Sxc151355 	}
9333147Sxc151355 	return (0);
9341000Sxc151355 }
935