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