xref: /illumos-gate/usr/src/uts/common/io/ath/ath_aux.c (revision b0fe7b8fa79924061f3bdf7f240ea116c2c0b704)
1 /*
2  * Copyright 2006 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 one or more key cache slots for a unicast key.  The
577  * key itself is needed only to identify the cipher.  For hardware
578  * TKIP with split cipher+MIC keys we allocate two key cache slot
579  * pairs so that we can setup separate TX and RX MIC keys.  Note
580  * that the MIC key for a TKIP key at slot i is assumed by the
581  * hardware to be at slot i+64.  This limits TKIP keys to the first
582  * 64 entries.
583  */
584 /* ARGSUSED */
585 int
586 ath_key_alloc(ieee80211com_t *ic, const struct ieee80211_key *k,
587     ieee80211_keyix *keyix, ieee80211_keyix *rxkeyix)
588 {
589 	*keyix = *rxkeyix = 0;
590 	return (1);
591 }
592 
593 int
594 ath_key_delete(ieee80211com_t *ic, const struct ieee80211_key *k)
595 {
596 	struct ath_hal *ah = ((ath_t *)ic)->asc_ah;
597 
598 	ATH_HAL_KEYRESET(ah, k->wk_keyix);
599 	return (1);
600 }
601 
602 /*
603  * Set the key cache contents for the specified key.  Key cache
604  * slot(s) must already have been allocated by ath_key_alloc.
605  */
606 int
607 ath_key_set(ieee80211com_t *ic, const struct ieee80211_key *k,
608     const uint8_t mac[IEEE80211_ADDR_LEN])
609 {
610 	static const uint8_t ciphermap[] = {
611 		HAL_CIPHER_WEP,		/* IEEE80211_CIPHER_WEP */
612 		HAL_CIPHER_TKIP,	/* IEEE80211_CIPHER_TKIP */
613 		HAL_CIPHER_AES_OCB,	/* IEEE80211_CIPHER_AES_OCB */
614 		HAL_CIPHER_AES_CCM,	/* IEEE80211_CIPHER_AES_CCM */
615 		(uint8_t)-1,		/* 4 is not allocated */
616 		HAL_CIPHER_CKIP,	/* IEEE80211_CIPHER_CKIP */
617 		HAL_CIPHER_CLR,		/* IEEE80211_CIPHER_NONE */
618 	};
619 	ath_t *asc = (ath_t *)ic;
620 	struct ath_hal *ah = asc->asc_ah;
621 	const struct ieee80211_cipher *cip = k->wk_cipher;
622 	HAL_KEYVAL hk;
623 
624 	bzero(&hk, sizeof (hk));
625 	/*
626 	 * Software crypto uses a "clear key" so non-crypto
627 	 * state kept in the key cache are maintainedd so that
628 	 * rx frames have an entry to match.
629 	 */
630 	if ((k->wk_flags & IEEE80211_KEY_SWCRYPT) == 0) {
631 		ASSERT(cip->ic_cipher < ATH_N(ciphermap));
632 		hk.kv_type = ciphermap[cip->ic_cipher];
633 		hk.kv_len = k->wk_keylen;
634 		bcopy(k->wk_key, hk.kv_val, k->wk_keylen);
635 	} else {
636 		hk.kv_type = HAL_CIPHER_CLR;
637 	}
638 
639 	return (ATH_HAL_KEYSET(ah, k->wk_keyix, &hk, mac));
640 }
641 
642 /*
643  * Enable/Disable short slot timing
644  */
645 void
646 ath_set_shortslot(ieee80211com_t *ic, int onoff)
647 {
648 	struct ath_hal *ah = ((ath_t *)ic)->asc_ah;
649 
650 	if (onoff)
651 		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_9);
652 	else
653 		ATH_HAL_SETSLOTTIME(ah, HAL_SLOT_TIME_20);
654 }
655 
656 int
657 ath_reset(ieee80211com_t *ic)
658 {
659 	ath_t *asc = (ath_t *)ic;
660 	struct ath_hal *ah = asc->asc_ah;
661 	struct ieee80211_channel *ch;
662 	HAL_STATUS status;
663 	HAL_CHANNEL hchan;
664 
665 	/*
666 	 * Convert to a HAL channel description with the flags
667 	 * constrained to reflect the current operating mode.
668 	 */
669 	ch = ic->ic_curchan;
670 	asc->asc_curchan.channel = ch->ich_freq;
671 	asc->asc_curchan.channelFlags = ath_chan2flags(ic, ch);
672 
673 	ATH_HAL_INTRSET(ah, 0);		/* disable interrupts */
674 	ath_draintxq(asc);		/* stop xmit side */
675 	if (ATH_IS_RUNNING(asc)) {
676 		ath_stoprecv(asc);		/* stop recv side */
677 		/* indicate channel change so we do a full reset */
678 		if (!ATH_HAL_RESET(ah, (HAL_OPMODE)ic->ic_opmode, &hchan,
679 		    AH_TRUE, &status)) {
680 			ath_problem("ath: ath_reset(): "
681 			    "resetting hardware failed, HAL status %u\n",
682 			    status);
683 		}
684 		ath_chan_change(asc, ch);
685 	}
686 	if (ATH_IS_RUNNING(asc)) {
687 		if (ath_startrecv(asc) != 0)	/* restart recv */
688 			ath_problem("ath: ath_reset(): "
689 			    "starting receiving logic failed\n");
690 		if (ic->ic_state == IEEE80211_S_RUN) {
691 			ath_beacon_config(asc);	/* restart beacons */
692 		}
693 		ATH_HAL_INTRSET(ah, asc->asc_imask);
694 	}
695 	return (0);
696 }
697