ath_aux.c revision 6990:d24af98bb8ea
1/*
2 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * Copyright (c) 2002-2004 Sam Leffler, Errno Consulting
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer,
15 * without modification.
16 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
17 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
18 * redistribution must be conditioned upon including a substantially
19 * similar Disclaimer requirement for further binary redistribution.
20 * 3. Neither the names of the above-listed copyright holders nor the names
21 * of any contributors may be used to endorse or promote products derived
22 * from this software without specific prior written permission.
23 *
24 * NO WARRANTY
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
28 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
29 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
30 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
33 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGES.
36 */
37
38#pragma ident	"%Z%%M%	%I%	%E% SMI"
39
40#include <sys/param.h>
41#include <sys/types.h>
42#include <sys/signal.h>
43#include <sys/stream.h>
44#include <sys/termio.h>
45#include <sys/errno.h>
46#include <sys/file.h>
47#include <sys/cmn_err.h>
48#include <sys/stropts.h>
49#include <sys/strsubr.h>
50#include <sys/strtty.h>
51#include <sys/kbio.h>
52#include <sys/cred.h>
53#include <sys/stat.h>
54#include <sys/consdev.h>
55#include <sys/kmem.h>
56#include <sys/modctl.h>
57#include <sys/ddi.h>
58#include <sys/sunddi.h>
59#include <sys/pci.h>
60#include <sys/errno.h>
61#include <sys/gld.h>
62#include <sys/dlpi.h>
63#include <sys/ethernet.h>
64#include <sys/list.h>
65#include <sys/byteorder.h>
66#include <sys/strsun.h>
67#include <inet/common.h>
68#include <inet/nd.h>
69#include <inet/mi.h>
70#include <inet/wifi_ioctl.h>
71#include "ath_hal.h"
72#include "ath_impl.h"
73
74static const char *acnames[] = {
75	"WME_AC_BE",
76	"WME_AC_BK",
77	"WME_AC_VI",
78	"WME_AC_VO",
79	"WME_UPSD"
80};
81
82extern void ath_setup_desc(ath_t *asc, struct ath_buf *bf);
83
84
85const char *
86ath_get_hal_status_desc(HAL_STATUS status)
87{
88	static const char *hal_status_desc[] = {
89	    "No error",
90	    "No hardware present or device not yet supported",
91	    "Memory allocation failed",
92	    "Hardware didn't respond as expected",
93	    "EEPROM magic number invalid",
94	    "EEPROM version invalid",
95	    "EEPROM unreadable",
96	    "EEPROM checksum invalid",
97	    "EEPROM read problem",
98	    "EEPROM mac address invalid",
99	    "EEPROM size not supported",
100	    "Attempt to change write-locked EEPROM",
101	    "Invalid parameter to function",
102	    "Hardware revision not supported",
103	    "Hardware self-test failed",
104	    "Operation incomplete"
105	};
106
107	if (status >= 0 && status < sizeof (hal_status_desc)/sizeof (char *))
108		return (hal_status_desc[status]);
109	else
110		return ("");
111}
112
113uint32_t
114ath_calcrxfilter(ath_t *asc)
115{
116	ieee80211com_t *ic = (ieee80211com_t *)asc;
117	struct ath_hal *ah = asc->asc_ah;
118	uint32_t rfilt;
119
120	rfilt = (ATH_HAL_GETRXFILTER(ah) & HAL_RX_FILTER_PHYERR)
121	    | HAL_RX_FILTER_UCAST | HAL_RX_FILTER_BCAST | HAL_RX_FILTER_MCAST;
122	if (ic->ic_opmode != IEEE80211_M_STA)
123		rfilt |= HAL_RX_FILTER_PROBEREQ;
124	if (ic->ic_opmode != IEEE80211_M_HOSTAP && asc->asc_promisc)
125		rfilt |= HAL_RX_FILTER_PROM;	/* promiscuous */
126	if (ic->ic_opmode == IEEE80211_M_STA ||
127	    ic->ic_opmode == IEEE80211_M_IBSS ||
128	    ic->ic_state == IEEE80211_S_SCAN)
129		rfilt |= HAL_RX_FILTER_BEACON;
130	return (rfilt);
131}
132
133static int
134ath_set_data_queue(ath_t *asc, int ac, int haltype)
135{
136	HAL_TXQ_INFO qi;
137	int qnum;
138	struct ath_hal *ah = asc->asc_ah;
139	struct ath_txq *txq;
140
141	if (ac >= ATH_N(asc->asc_ac2q)) {
142		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
143		    "ac %u out of range, max %u!\n",
144		    ac, ATH_N(asc->asc_ac2q)));
145		return (1);
146	}
147	(void) memset(&qi, 0, sizeof (qi));
148	qi.tqi_subtype = haltype;
149	/*
150	 * Enable interrupts only for EOL and DESC conditions.
151	 * We mark tx descriptors to receive a DESC interrupt
152	 * when a tx queue gets deep; otherwise waiting for the
153	 * EOL to reap descriptors.  Note that this is done to
154	 * reduce interrupt load and this only defers reaping
155	 * descriptors, never transmitting frames.  Aside from
156	 * reducing interrupts this also permits more concurrency.
157	 * The only potential downside is if the tx queue backs
158	 * up in which case the top half of the kernel may backup
159	 * due to a lack of tx descriptors.
160	 */
161	qi.tqi_qflags = HAL_TXQ_TXEOLINT_ENABLE | HAL_TXQ_TXDESCINT_ENABLE;
162	qnum = ATH_HAL_SETUPTXQUEUE(ah, HAL_TX_QUEUE_DATA, &qi);
163	if (qnum == -1) {
164		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
165		    "Unable to setup hardware queue for %s traffic!\n",
166		    acnames[ac]));
167		return (1);
168	}
169	if (qnum >= ATH_N(asc->asc_txq)) {
170		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_set_data_queue(): "
171		    "hal qnum %u out of range, max %u!\n",
172		    qnum, ATH_N(asc->asc_txq)));
173		return (1);
174	}
175	if (!ATH_TXQ_SETUP(asc, qnum)) {
176		txq = &asc->asc_txq[qnum];
177		txq->axq_qnum = qnum;
178		txq->axq_depth = 0;
179		txq->axq_intrcnt = 0;
180		txq->axq_link = NULL;
181		list_create(&txq->axq_list, sizeof (struct ath_buf),
182		    offsetof(struct ath_buf, bf_node));
183		mutex_init(&txq->axq_lock, NULL, MUTEX_DRIVER, NULL);
184		asc->asc_txqsetup |= 1<<qnum;
185	}
186	asc->asc_ac2q[ac] = &asc->asc_txq[qnum];
187	return (0);
188}
189
190int
191ath_txq_setup(ath_t *asc)
192{
193	if (ath_set_data_queue(asc, WME_AC_BE, HAL_WME_AC_BK) ||
194	    ath_set_data_queue(asc, WME_AC_BK, HAL_WME_AC_BE) ||
195	    ath_set_data_queue(asc, WME_AC_VI, HAL_WME_AC_VI) ||
196	    ath_set_data_queue(asc, WME_AC_VO, HAL_WME_AC_VO)) {
197		return (1);
198	}
199
200	return (0);
201}
202
203void
204ath_txq_cleanup(ath_t *asc)
205{
206	int i;
207
208	mutex_destroy(&asc->asc_txbuflock);
209	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
210		if (ATH_TXQ_SETUP(asc, i)) {
211			struct ath_txq *txq = &asc->asc_txq[i];
212
213			ATH_HAL_RELEASETXQUEUE(asc->asc_ah, txq->axq_qnum);
214			mutex_destroy(&txq->axq_lock);
215			asc->asc_txqsetup &= ~(1 << txq->axq_qnum);
216		}
217	}
218}
219
220void
221ath_setcurmode(ath_t *asc, enum ieee80211_phymode mode)
222{
223	const HAL_RATE_TABLE *rt;
224	int i;
225
226	for (i = 0; i < sizeof (asc->asc_rixmap); i++)
227		asc->asc_rixmap[i] = 0xff;
228
229	rt = asc->asc_rates[mode];
230	ASSERT(rt != NULL);
231
232	for (i = 0; i < rt->rateCount; i++)
233		asc->asc_rixmap[rt->info[i].dot11Rate & IEEE80211_RATE_VAL] = i;
234
235	asc->asc_currates = rt;
236	asc->asc_curmode = mode;
237}
238
239/* Set correct parameters for a certain mode */
240void
241ath_mode_init(ath_t *asc)
242{
243	ieee80211com_t *ic = (ieee80211com_t *)asc;
244	struct ath_hal *ah = asc->asc_ah;
245	uint32_t rfilt;
246
247	/* configure rx filter */
248	rfilt = ath_calcrxfilter(asc);
249	ATH_HAL_SETRXFILTER(ah, rfilt);
250	ATH_HAL_SETOPMODE(ah);
251	ATH_HAL_SETMCASTFILTER(ah, asc->asc_mcast_hash[0],
252	    asc->asc_mcast_hash[1]);
253	ATH_DEBUG((ATH_DBG_AUX, "ath: ath_mode_init(): "
254	    "mode =%d RX filter 0x%x, MC filter %08x:%08x\n",
255	    ic->ic_opmode, rfilt,
256	    asc->asc_mcast_hash[0], asc->asc_mcast_hash[1]));
257}
258
259/*
260 * Disable the receive h/w in preparation for a reset.
261 */
262void
263ath_stoprecv(ath_t *asc)
264{
265	ATH_HAL_STOPPCURECV(asc->asc_ah);	/* disable PCU */
266	ATH_HAL_SETRXFILTER(asc->asc_ah, 0);	/* clear recv filter */
267	ATH_HAL_STOPDMARECV(asc->asc_ah);	/* disable DMA engine */
268	drv_usecwait(3000);
269
270	ATH_DEBUG((ATH_DBG_AUX, "ath: ath_stoprecv(): rx queue %p, link %p\n",
271	    ATH_HAL_GETRXBUF(asc->asc_ah), asc->asc_rxlink));
272	asc->asc_rxlink = NULL;
273}
274
275uint32_t
276ath_chan2flags(ieee80211com_t *isc, struct ieee80211_channel *chan)
277{
278	static const uint32_t modeflags[] = {
279	    0,				/* IEEE80211_MODE_AUTO */
280	    CHANNEL_A,			/* IEEE80211_MODE_11A */
281	    CHANNEL_B,			/* IEEE80211_MODE_11B */
282	    CHANNEL_PUREG,		/* IEEE80211_MODE_11G */
283	    0,				/* IEEE80211_MODE_FH */
284	    CHANNEL_108A,		/* IEEE80211_MODE_TURBO_A */
285	    CHANNEL_108G		/* IEEE80211_MODE_TURBO_G */
286	};
287	return (modeflags[ieee80211_chan2mode(isc, chan)]);
288}
289
290
291int
292ath_getchannels(ath_t *asc, uint32_t cc, HAL_BOOL outdoor, HAL_BOOL xchanmode)
293{
294	ieee80211com_t *ic = (ieee80211com_t *)asc;
295	struct ath_hal *ah = asc->asc_ah;
296	HAL_CHANNEL *chans;
297	int i, ix;
298	uint32_t nchan;
299
300	chans = (HAL_CHANNEL *)
301	    kmem_zalloc(IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL), KM_SLEEP);
302
303	if (!ath_hal_init_channels(ah, chans, IEEE80211_CHAN_MAX, &nchan,
304	    NULL, 0, NULL, cc, HAL_MODE_ALL, outdoor, xchanmode)) {
305		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
306		    "unable to get channel list\n"));
307		kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
308		return (EINVAL);
309	}
310
311	/*
312	 * Convert HAL channels to ieee80211 ones and insert
313	 * them in the table according to their channel number.
314	 */
315	for (i = 0; i < nchan; i++) {
316		HAL_CHANNEL *c = &chans[i];
317		uint16_t flags;
318		ix = ath_hal_mhz2ieee(ah, c->channel, c->channelFlags);
319		if (ix > IEEE80211_CHAN_MAX) {
320			ATH_DEBUG((ATH_DBG_AUX, "ath: ath_getchannels(): "
321			    "bad hal channel %d (%u/%x) ignored\n",
322			    ix, c->channel, c->channelFlags));
323			continue;
324		}
325		/* NB: flags are known to be compatible */
326		if (ix < 0) {
327			/*
328			 * can't handle frequency <2400MHz (negative
329			 * channels) right now
330			 */
331			ATH_DEBUG((ATH_DBG_AUX, "ath:ath_getchannels(): "
332			    "hal channel %d (%u/%x) "
333			    "cannot be handled, ignored\n",
334			    ix, c->channel, c->channelFlags));
335			continue;
336		}
337		/*
338		 * Calculate net80211 flags; most are compatible
339		 * but some need massaging.  Note the static turbo
340		 * conversion can be removed once net80211 is updated
341		 * to understand static vs. dynamic turbo.
342		 */
343		flags = c->channelFlags & CHANNEL_COMPAT;
344		if (c->channelFlags & CHANNEL_STURBO)
345			flags |= IEEE80211_CHAN_TURBO;
346		if (ic->ic_sup_channels[ix].ich_freq == 0) {
347			ic->ic_sup_channels[ix].ich_freq = c->channel;
348			ic->ic_sup_channels[ix].ich_flags = flags;
349		} else {
350			/* channels overlap; e.g. 11g and 11b */
351			ic->ic_sup_channels[ix].ich_flags |= flags;
352		}
353		if ((c->channelFlags & CHANNEL_G) == CHANNEL_G)
354			asc->asc_have11g = 1;
355	}
356	kmem_free(chans, IEEE80211_CHAN_MAX * sizeof (HAL_CHANNEL));
357	return (0);
358}
359
360static void
361ath_drainq(ath_t *asc, struct ath_txq *txq)
362{
363	struct ath_buf *bf;
364
365	/*
366	 * This assumes output has been stopped.
367	 */
368	for (;;) {
369		mutex_enter(&txq->axq_lock);
370		bf = list_head(&txq->axq_list);
371		if (bf == NULL) {
372			txq->axq_link = NULL;
373			mutex_exit(&txq->axq_lock);
374			break;
375		}
376		list_remove(&txq->axq_list, bf);
377		mutex_exit(&txq->axq_lock);
378		bf->bf_in = NULL;
379		mutex_enter(&asc->asc_txbuflock);
380		list_insert_tail(&asc->asc_txbuf_list, bf);
381		mutex_exit(&asc->asc_txbuflock);
382	}
383}
384
385
386/*
387 * Drain the transmit queues and reclaim resources.
388 */
389void
390ath_draintxq(ath_t *asc)
391{
392	struct ath_hal *ah = asc->asc_ah;
393	struct ath_txq *txq;
394	int i;
395
396	if (!asc->asc_invalid) {
397		for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
398			if (ATH_TXQ_SETUP(asc, i)) {
399				txq = &asc->asc_txq[i];
400				(void) ATH_HAL_STOPTXDMA(ah, txq->axq_qnum);
401			}
402		}
403	}
404	for (i = 0; i < HAL_NUM_TX_QUEUES; i++) {
405		if (ATH_TXQ_SETUP(asc, i)) {
406			ath_drainq(asc, &asc->asc_txq[i]);
407		}
408	}
409}
410
411
412/* Enable the receive h/w following a reset */
413int
414ath_startrecv(ath_t *asc)
415{
416	struct ath_buf *bf;
417
418	asc->asc_rxlink = NULL;
419
420	bf = list_head(&asc->asc_rxbuf_list);
421	while (bf != NULL) {
422		ath_setup_desc(asc, bf);
423		bf = list_next(&asc->asc_rxbuf_list, bf);
424	}
425
426	bf = list_head(&asc->asc_rxbuf_list);
427	ATH_HAL_PUTRXBUF(asc->asc_ah, bf->bf_daddr);
428	ATH_HAL_RXENA(asc->asc_ah);		/* enable recv descriptors */
429	ath_mode_init(asc);			/* set filters, etc. */
430	ATH_HAL_STARTPCURECV(asc->asc_ah);	/* re-enable PCU/DMA engine */
431	return (0);
432}
433
434/*
435 * Update internal state after a channel change.
436 */
437void
438ath_chan_change(ath_t *asc, struct ieee80211_channel *chan)
439{
440	struct ieee80211com *ic = &asc->asc_isc;
441	enum ieee80211_phymode mode;
442
443	/*
444	 * Change channels and update the h/w rate map
445	 * if we're switching; e.g. 11a to 11b/g.
446	 */
447	mode = ieee80211_chan2mode(ic, chan);
448	if (mode != asc->asc_curmode)
449		ath_setcurmode(asc, mode);
450}
451
452/*
453 * Set/change channels.  If the channel is really being changed,
454 * it's done by resetting the chip.  To accomplish this we must
455 * first cleanup any pending DMA.
456 */
457int
458ath_chan_set(ath_t *asc, struct ieee80211_channel *chan)
459{
460	struct ath_hal *ah = asc->asc_ah;
461	ieee80211com_t *ic = &asc->asc_isc;
462
463	if (chan != ic->ic_ibss_chan) {
464		HAL_STATUS status;
465		HAL_CHANNEL hchan;
466
467		/*
468		 * To switch channels clear any pending DMA operations;
469		 * wait long enough for the RX fifo to drain, reset the
470		 * hardware at the new frequency, and then re-enable
471		 * the relevant bits of the h/w.
472		 */
473		ATH_HAL_INTRSET(ah, 0);		/* disable interrupts */
474		ath_draintxq(asc);		/* clear pending tx frames */
475		ath_stoprecv(asc);		/* turn off frame recv */
476		/*
477		 * Convert to a HAL channel description with
478		 * the flags constrained to reflect the current
479		 * operating mode.
480		 */
481		hchan.channel = chan->ich_freq;
482		hchan.channelFlags = ath_chan2flags(ic, chan);
483		if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
484		    &hchan, AH_TRUE, &status)) {
485			ATH_DEBUG((ATH_DBG_AUX, "ath: ath_chan_set():"
486			    "unable to reset channel %u (%uMhz)\n"
487			    "flags 0x%x: '%s' (HAL status %u)\n",
488			    ieee80211_chan2ieee(ic, chan), hchan.channel,
489			    hchan.channelFlags,
490			    ath_get_hal_status_desc(status), status));
491			return (EIO);
492		}
493		asc->asc_curchan = hchan;
494
495		/*
496		 * Re-enable rx framework.
497		 */
498		if (ath_startrecv(asc) != 0) {
499			ath_problem("ath: ath_chan_set(): "
500			    "restarting receiving logic failed\n");
501			return (EIO);
502		}
503
504		/*
505		 * Change channels and update the h/w rate map
506		 * if we're switching; e.g. 11a to 11b/g.
507		 */
508		ic->ic_ibss_chan = chan;
509		ath_chan_change(asc, chan);
510		/*
511		 * Re-enable interrupts.
512		 */
513		ATH_HAL_INTRSET(ah, asc->asc_imask);
514	}
515	return (0);
516}
517
518
519/*
520 * Configure the beacon and sleep timers.
521 *
522 * When operating as an AP this resets the TSF and sets
523 * up the hardware to notify us when we need to issue beacons.
524 *
525 * When operating in station mode this sets up the beacon
526 * timers according to the timestamp of the last received
527 * beacon and the current TSF, configures PCF and DTIM
528 * handling, programs the sleep registers so the hardware
529 * will wakeup in time to receive beacons, and configures
530 * the beacon miss handling so we'll receive a BMISS
531 * interrupt when we stop seeing beacons from the AP
532 * we've associated with.
533 */
534void
535ath_beacon_config(ath_t *asc)
536{
537	struct ath_hal *ah = asc->asc_ah;
538	ieee80211com_t *ic = (ieee80211com_t *)asc;
539	struct ieee80211_node *in = ic->ic_bss;
540	uint32_t nexttbtt;
541
542	nexttbtt = (ATH_LE_READ_4(in->in_tstamp.data + 4) << 22) |
543	    (ATH_LE_READ_4(in->in_tstamp.data) >> 10);
544	nexttbtt += in->in_intval;
545	if (ic->ic_opmode != IEEE80211_M_HOSTAP) {
546		HAL_BEACON_STATE bs;
547
548		/* NB: no PCF support right now */
549		bzero(&bs, sizeof (bs));
550		bs.bs_intval = in->in_intval;
551		bs.bs_nexttbtt = nexttbtt;
552		bs.bs_dtimperiod = bs.bs_intval;
553		bs.bs_nextdtim = nexttbtt;
554
555		/*
556		 * Setup the number of consecutive beacons to miss
557		 * before taking a BMISS interrupt.
558		 * Note that we clamp the result to at most 10 beacons.
559		 */
560		bs.bs_bmissthreshold = ic->ic_bmissthreshold;
561		if (bs.bs_bmissthreshold > 10)
562			bs.bs_bmissthreshold = 10;
563		else if (bs.bs_bmissthreshold < 1)
564			bs.bs_bmissthreshold = 1;
565		/*
566		 * Calculate sleep duration.  The configuration is
567		 * given in ms.  We insure a multiple of the beacon
568		 * period is used.  Also, if the sleep duration is
569		 * greater than the DTIM period then it makes senses
570		 * to make it a multiple of that.
571		 */
572		bs.bs_sleepduration =
573		    roundup((100 * 1000) / 1024, bs.bs_intval);
574		if (bs.bs_sleepduration > bs.bs_dtimperiod)
575			bs.bs_sleepduration =
576			    roundup(bs.bs_sleepduration, bs.bs_dtimperiod);
577
578
579		ATH_DEBUG((ATH_DBG_AUX, "ath: ath_beacon_config(): "
580		    "intval %u nexttbtt %u dtim %u"
581		    " nextdtim %u bmiss %u sleep %u\n",
582		    bs.bs_intval,
583		    bs.bs_nexttbtt,
584		    bs.bs_dtimperiod,
585		    bs.bs_nextdtim,
586		    bs.bs_bmissthreshold,
587		    bs.bs_sleepduration));
588		ATH_HAL_INTRSET(ah, 0);
589		/*
590		 * Reset our tsf so the hardware will update the
591		 * tsf register to reflect timestamps found in
592		 * received beacons.
593		 */
594		ATH_HAL_RESETTSF(ah);
595		ATH_HAL_BEACONTIMERS(ah, &bs);
596		asc->asc_imask |= HAL_INT_BMISS;
597		ATH_HAL_INTRSET(ah, asc->asc_imask);
598	} else {
599		ATH_HAL_INTRSET(ah, 0);
600		ATH_HAL_BEACONINIT(ah, nexttbtt, in->in_intval);
601		asc->asc_imask |= HAL_INT_SWBA;	/* beacon prepare */
602		ATH_HAL_INTRSET(ah, asc->asc_imask);
603	}
604}
605
606/*
607 * Allocate tx/rx key slots for TKIP.  We allocate two slots for
608 * each key, one for decrypt/encrypt and the other for the MIC.
609 */
610static int
611key_alloc_2pair(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
612{
613	uint16_t i, keyix;
614
615	ASSERT(asc->asc_splitmic);
616	for (i = 0; i < ATH_N(asc->asc_keymap)/4; i++) {
617		uint8_t b = asc->asc_keymap[i];
618		if (b != 0xff) {
619			/*
620			 * One or more slots in this byte are free.
621			 */
622			keyix = i*NBBY;
623			while (b & 1) {
624		again:
625				keyix++;
626				b >>= 1;
627			}
628			/* XXX IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV */
629			if (isset(asc->asc_keymap, keyix+32) ||
630			    isset(asc->asc_keymap, keyix+64) ||
631			    isset(asc->asc_keymap, keyix+32+64)) {
632				/* full pair unavailable */
633				if (keyix == (i+1)*NBBY) {
634					/* no slots were appropriate, advance */
635					continue;
636				}
637				goto again;
638			}
639			setbit(asc->asc_keymap, keyix);
640			setbit(asc->asc_keymap, keyix+64);
641			setbit(asc->asc_keymap, keyix+32);
642			setbit(asc->asc_keymap, keyix+32+64);
643			ATH_DEBUG((ATH_DBG_AUX,
644			    "key_alloc_2pair: key pair %u,%u %u,%u\n",
645			    keyix, keyix+64,
646			    keyix+32, keyix+32+64));
647			*txkeyix = *rxkeyix = keyix;
648			return (1);
649		}
650	}
651	ATH_DEBUG((ATH_DBG_AUX, "key_alloc_2pair:"
652	    " out of pair space\n"));
653	return (0);
654}
655/*
656 * Allocate a single key cache slot.
657 */
658static int
659key_alloc_single(ath_t *asc, ieee80211_keyix *txkeyix, ieee80211_keyix *rxkeyix)
660{
661	uint16_t i, keyix;
662
663	/* try i,i+32,i+64,i+32+64 to minimize key pair conflicts */
664	for (i = 0; i < ATH_N(asc->asc_keymap); i++) {
665		uint8_t b = asc->asc_keymap[i];
666
667		if (b != 0xff) {
668			/*
669			 * One or more slots are free.
670			 */
671			keyix = i*NBBY;
672			while (b & 1)
673				keyix++, b >>= 1;
674			setbit(asc->asc_keymap, keyix);
675			ATH_DEBUG((ATH_DBG_AUX, "key_alloc_single:"
676			    " key %u\n", keyix));
677			*txkeyix = *rxkeyix = keyix;
678			return (1);
679		}
680	}
681	return (0);
682}
683
684/*
685 * Allocate one or more key cache slots for a unicast key.  The
686 * key itself is needed only to identify the cipher.  For hardware
687 * TKIP with split cipher+MIC keys we allocate two key cache slot
688 * pairs so that we can setup separate TX and RX MIC keys.  Note
689 * that the MIC key for a TKIP key at slot i is assumed by the
690 * hardware to be at slot i+64.  This limits TKIP keys to the first
691 * 64 entries.
692 */
693/* ARGSUSED */
694int
695ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k,
696    ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
697{
698	ath_t *asc = (ath_t *)ic;
699
700	/*
701	 * We allocate two pair for TKIP when using the h/w to do
702	 * the MIC.  For everything else, including software crypto,
703	 * we allocate a single entry.  Note that s/w crypto requires
704	 * a pass-through slot on the 5211 and 5212.  The 5210 does
705	 * not support pass-through cache entries and we map all
706	 * those requests to slot 0.
707	 */
708	if (k->wk_flags & IEEE80211_KEY_SWCRYPT) {
709		return (key_alloc_single(asc, keyix, rxkeyix));
710	} else if (k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP &&
711	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic) {
712		return (key_alloc_2pair(asc, keyix, rxkeyix));
713	} else {
714		return (key_alloc_single(asc, keyix, rxkeyix));
715	}
716}
717
718/*
719 * Delete an entry in the key cache allocated by ath_key_alloc.
720 */
721int
722ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k)
723{
724	ath_t *asc = (ath_t *)ic;
725	struct ath_hal *ah = asc->asc_ah;
726	const struct ieee80211_cipher *cip = k->wk_cipher;
727	ieee80211_keyix keyix = k->wk_keyix;
728
729	ATH_DEBUG((ATH_DBG_AUX, "ath_key_delete:"
730	    " delete key %u ic_cipher=0x%x\n", keyix, cip->ic_cipher));
731
732	ATH_HAL_KEYRESET(ah, keyix);
733	/*
734	 * Handle split tx/rx keying required for TKIP with h/w MIC.
735	 */
736	if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
737	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 && asc->asc_splitmic)
738		ATH_HAL_KEYRESET(ah, keyix+32);		/* RX key */
739
740	if (keyix >= IEEE80211_WEP_NKID) {
741		/*
742		 * Don't touch keymap entries for global keys so
743		 * they are never considered for dynamic allocation.
744		 */
745		clrbit(asc->asc_keymap, keyix);
746		if (cip->ic_cipher == IEEE80211_CIPHER_TKIP &&
747		    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
748		    asc->asc_splitmic) {
749			clrbit(asc->asc_keymap, keyix+64);	/* TX key MIC */
750			clrbit(asc->asc_keymap, keyix+32);	/* RX key */
751			clrbit(asc->asc_keymap, keyix+32+64);	/* RX key MIC */
752		}
753	}
754	return (1);
755}
756
757static void
758ath_keyprint(const char *tag, uint_t ix,
759    const HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
760{
761	static const char *ciphers[] = {
762		"WEP",
763		"AES-OCB",
764		"AES-CCM",
765		"CKIP",
766		"TKIP",
767		"CLR",
768	};
769	int i, n;
770	char buf[MAX_IEEE80211STR], buft[32];
771
772	(void) snprintf(buf, sizeof (buf), "%s: [%02u] %s ",
773	    tag, ix, ciphers[hk->kv_type]);
774	for (i = 0, n = hk->kv_len; i < n; i++) {
775		(void) snprintf(buft, sizeof (buft), "%02x", hk->kv_val[i]);
776		(void) strlcat(buf, buft, sizeof (buf));
777	}
778	(void) snprintf(buft, sizeof (buft), " mac %s",
779	    ieee80211_macaddr_sprintf(mac));
780	(void) strlcat(buf, buft, sizeof (buf));
781	if (hk->kv_type == HAL_CIPHER_TKIP) {
782		(void) snprintf(buft, sizeof (buft), " mic ");
783		(void) strlcat(buf, buft, sizeof (buf));
784		for (i = 0; i < sizeof (hk->kv_mic); i++) {
785			(void) snprintf(buft, sizeof (buft), "%02x",
786			    hk->kv_mic[i]);
787			(void) strlcat(buf, buft, sizeof (buf));
788		}
789	}
790	ATH_DEBUG((ATH_DBG_AUX, "%s", buf));
791}
792
793/*
794 * Set a TKIP key into the hardware.  This handles the
795 * potential distribution of key state to multiple key
796 * cache slots for TKIP.
797 */
798static int
799ath_keyset_tkip(ath_t *asc, const struct ieee80211_key *k,
800	HAL_KEYVAL *hk, const uint8_t mac[IEEE80211_ADDR_LEN])
801{
802#define	IEEE80211_KEY_XR	(IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV)
803	static const uint8_t zerobssid[IEEE80211_ADDR_LEN] = {0, 0, 0, 0, 0, 0};
804	struct ath_hal *ah = asc->asc_ah;
805
806	ASSERT(k->wk_cipher->ic_cipher == IEEE80211_CIPHER_TKIP);
807	if ((k->wk_flags & IEEE80211_KEY_XR) == IEEE80211_KEY_XR) {
808		/*
809		 * TX key goes at first index, RX key at +32.
810		 * The hal handles the MIC keys at index+64.
811		 */
812		(void) memcpy(hk->kv_mic, k->wk_txmic, sizeof (hk->kv_mic));
813		ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid);
814		if (!ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid))
815			return (0);
816
817		(void) memcpy(hk->kv_mic, k->wk_rxmic, sizeof (hk->kv_mic));
818		ath_keyprint("ath_keyset_tkip:", k->wk_keyix+32, hk, mac);
819		return (ATH_HAL_KEYSET(ah, k->wk_keyix+32, hk, mac));
820	} else if (k->wk_flags & IEEE80211_KEY_XR) {
821		/*
822		 * TX/RX key goes at first index.
823		 * The hal handles the MIC keys are index+64.
824		 */
825		(void) memcpy(hk->kv_mic, k->wk_flags & IEEE80211_KEY_XMIT ?
826		    k->wk_txmic : k->wk_rxmic, sizeof (hk->kv_mic));
827		ath_keyprint("ath_keyset_tkip:", k->wk_keyix, hk, zerobssid);
828		return (ATH_HAL_KEYSET(ah, k->wk_keyix, hk, zerobssid));
829	}
830	return (0);
831#undef IEEE80211_KEY_XR
832}
833
834/*
835 * Set the key cache contents for the specified key.  Key cache
836 * slot(s) must already have been allocated by ath_key_alloc.
837 */
838int
839ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
840    const uint8_t mac[IEEE80211_ADDR_LEN])
841{
842	static const uint8_t ciphermap[] = {
843		HAL_CIPHER_WEP,		/* IEEE80211_CIPHER_WEP */
844		HAL_CIPHER_TKIP,	/* IEEE80211_CIPHER_TKIP */
845		HAL_CIPHER_AES_OCB,	/* IEEE80211_CIPHER_AES_OCB */
846		HAL_CIPHER_AES_CCM,	/* IEEE80211_CIPHER_AES_CCM */
847		HAL_CIPHER_CKIP,	/* IEEE80211_CIPHER_CKIP */
848		HAL_CIPHER_CLR,		/* IEEE80211_CIPHER_NONE */
849	};
850	ath_t *asc = (ath_t *)ic;
851	struct ath_hal *ah = asc->asc_ah;
852	const struct ieee80211_cipher *cip = k->wk_cipher;
853	HAL_KEYVAL hk;
854
855	bzero(&hk, sizeof (hk));
856	/*
857	 * Software crypto uses a "clear key" so non-crypto
858	 * state kept in the key cache are maintainedd so that
859	 * rx frames have an entry to match.
860	 */
861	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
862		ASSERT(cip->ic_cipher < ATH_N(ciphermap));
863		hk.kv_type = ciphermap[cip->ic_cipher];
864		hk.kv_len = k->wk_keylen;
865		bcopy(k->wk_key, hk.kv_val, k->wk_keylen);
866	} else {
867		hk.kv_type = HAL_CIPHER_CLR;
868	}
869
870	if (hk.kv_type == HAL_CIPHER_TKIP &&
871	    (k->wk_flags & IEEE80211_KEY_SWMIC) == 0 &&
872	    asc->asc_splitmic) {
873		return (ath_keyset_tkip(asc, k, &hk, mac));
874	} else {
875		ath_keyprint("ath_keyset:", k->wk_keyix, &hk, mac);
876		return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac));
877	}
878}
879
880/*
881 * Enable/Disable short slot timing
882 */
883void
884ath_set_shortslot(ieee80211com_t *ic, int onoff)
885{
886	struct ath_hal *ah = ((ath_t *)ic)->asc_ah;
887
888	if (onoff)
889		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9);
890	else
891		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20);
892}
893
894int
895ath_reset(ieee80211com_t *ic)
896{
897	ath_t *asc = (ath_t *)ic;
898	struct ath_hal *ah = asc->asc_ah;
899	struct ieee80211_channel *ch;
900	HAL_STATUS status;
901
902	/*
903	 * Convert to a HAL channel description with the flags
904	 * constrained to reflect the current operating mode.
905	 */
906	ch = ic->ic_curchan;
907	asc->asc_curchan.channel = ch->ich_freq;
908	asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch);
909
910	ATH_HAL_INTRSET(ah, 0);		/* disable interrupts */
911	ath_draintxq(asc);		/* stop xmit side */
912	if (ATH_IS_RUNNING(asc)) {
913		ath_stoprecv(asc);		/* stop recv side */
914		/* indicate channel change so we do a full reset */
915		if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode,
916		    &asc->asc_curchan, AH_TRUE, &status)) {
917			ath_problem("ath: ath_reset(): "
918			    "resetting hardware failed, '%s' (HAL status %u)\n",
919			    ath_get_hal_status_desc(status), status);
920		}
921		ath_chan_change(asc, ch);
922	}
923	if (ATH_IS_RUNNING(asc)) {
924		if (ath_startrecv(asc) != 0)	/* restart recv */
925			ath_problem("ath: ath_reset(): "
926			    "starting receiving logic failed\n");
927		if (ic->ic_state == IEEE80211_S_RUN) {
928			ath_beacon_config(asc);	/* restart beacons */
929		}
930		ATH_HAL_INTRSET(ah, asc->asc_imask);
931	}
932	return (0);
933}
934