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