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