xref: /illumos-gate/usr/src/uts/common/io/arn/arn_beacon.c (revision fd7c5980)
1dd1de374Slin wang - Sun Microsystems - Beijing China /*
2c0c93480Slin wang - Sun Microsystems - Beijing China  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
3dd1de374Slin wang - Sun Microsystems - Beijing China  * Use is subject to license terms.
4dd1de374Slin wang - Sun Microsystems - Beijing China  */
5dd1de374Slin wang - Sun Microsystems - Beijing China 
6dd1de374Slin wang - Sun Microsystems - Beijing China /*
7dd1de374Slin wang - Sun Microsystems - Beijing China  * Copyright (c) 2008 Atheros Communications Inc.
8dd1de374Slin wang - Sun Microsystems - Beijing China  *
9dd1de374Slin wang - Sun Microsystems - Beijing China  * Permission to use, copy, modify, and/or distribute this software for any
10dd1de374Slin wang - Sun Microsystems - Beijing China  * purpose with or without fee is hereby granted, provided that the above
11dd1de374Slin wang - Sun Microsystems - Beijing China  * copyright notice and this permission notice appear in all copies.
12dd1de374Slin wang - Sun Microsystems - Beijing China  *
13dd1de374Slin wang - Sun Microsystems - Beijing China  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14dd1de374Slin wang - Sun Microsystems - Beijing China  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15dd1de374Slin wang - Sun Microsystems - Beijing China  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16dd1de374Slin wang - Sun Microsystems - Beijing China  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17dd1de374Slin wang - Sun Microsystems - Beijing China  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18dd1de374Slin wang - Sun Microsystems - Beijing China  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19dd1de374Slin wang - Sun Microsystems - Beijing China  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20dd1de374Slin wang - Sun Microsystems - Beijing China  */
21dd1de374Slin wang - Sun Microsystems - Beijing China 
22dd1de374Slin wang - Sun Microsystems - Beijing China #include <sys/param.h>
23dd1de374Slin wang - Sun Microsystems - Beijing China #include <sys/strsun.h>
24dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/common.h>
25dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/nd.h>
26dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/mi.h>
27dd1de374Slin wang - Sun Microsystems - Beijing China #include <inet/wifi_ioctl.h>
28dd1de374Slin wang - Sun Microsystems - Beijing China 
29dd1de374Slin wang - Sun Microsystems - Beijing China #include "arn_core.h"
30dd1de374Slin wang - Sun Microsystems - Beijing China 
31dd1de374Slin wang - Sun Microsystems - Beijing China /*
32dd1de374Slin wang - Sun Microsystems - Beijing China  * Associates the beacon frame buffer with a transmit descriptor.  Will set
33dd1de374Slin wang - Sun Microsystems - Beijing China  * up all required antenna switch parameters, rate codes, and channel flags.
34dd1de374Slin wang - Sun Microsystems - Beijing China  * Beacons are always sent out at the lowest rate, and are not retried.
35dd1de374Slin wang - Sun Microsystems - Beijing China  */
36c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_IBSS
37dd1de374Slin wang - Sun Microsystems - Beijing China static void
arn_beacon_setup(struct arn_softc * sc,struct ath_buf * bf)38dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_setup(struct arn_softc *sc, struct ath_buf *bf)
39dd1de374Slin wang - Sun Microsystems - Beijing China {
40dd1de374Slin wang - Sun Microsystems - Beijing China #define	USE_SHPREAMBLE(_ic) \
41dd1de374Slin wang - Sun Microsystems - Beijing China 	(((_ic)->ic_flags & (IEEE80211_F_SHPREAMBLE | IEEE80211_F_USEBARKER))\
42dd1de374Slin wang - Sun Microsystems - Beijing China 	    == IEEE80211_F_SHPREAMBLE)
43dd1de374Slin wang - Sun Microsystems - Beijing China 	mblk_t *mp = bf->bf_m;
44dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_hal *ah = sc->sc_ah;
45dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_desc *ds;
46dd1de374Slin wang - Sun Microsystems - Beijing China 	/* LINTED E_FUNC_SET_NOT_USED */
47dd1de374Slin wang - Sun Microsystems - Beijing China 	int flags, antenna = 0;
48dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_rate_table *rt;
49dd1de374Slin wang - Sun Microsystems - Beijing China 	uint8_t rix, rate;
50dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath9k_11n_rate_series series[4];
51dd1de374Slin wang - Sun Microsystems - Beijing China 	int ctsrate = 0;
52dd1de374Slin wang - Sun Microsystems - Beijing China 	int ctsduration = 0;
53dd1de374Slin wang - Sun Microsystems - Beijing China 
54dd1de374Slin wang - Sun Microsystems - Beijing China 	/* set up descriptors */
55dd1de374Slin wang - Sun Microsystems - Beijing China 	ds = bf->bf_desc;
56dd1de374Slin wang - Sun Microsystems - Beijing China 
57dd1de374Slin wang - Sun Microsystems - Beijing China 	flags = ATH9K_TXDESC_NOACK;
58dd1de374Slin wang - Sun Microsystems - Beijing China 	if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS &&
59dd1de374Slin wang - Sun Microsystems - Beijing China 	    (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) {
60dd1de374Slin wang - Sun Microsystems - Beijing China 		ds->ds_link = bf->bf_daddr;	/* self-linked */
61dd1de374Slin wang - Sun Microsystems - Beijing China 		flags |= ATH9K_TXDESC_VEOL;
62dd1de374Slin wang - Sun Microsystems - Beijing China 		/*
63dd1de374Slin wang - Sun Microsystems - Beijing China 		 * Let hardware handle antenna switching.
64dd1de374Slin wang - Sun Microsystems - Beijing China 		 */
65dd1de374Slin wang - Sun Microsystems - Beijing China 		antenna = 0;
66dd1de374Slin wang - Sun Microsystems - Beijing China 	} else {
67dd1de374Slin wang - Sun Microsystems - Beijing China 		ds->ds_link = 0;
68dd1de374Slin wang - Sun Microsystems - Beijing China 		/*
69dd1de374Slin wang - Sun Microsystems - Beijing China 		 * Switch antenna every 4 beacons.
70dd1de374Slin wang - Sun Microsystems - Beijing China 		 * NB: assumes two antenna
71dd1de374Slin wang - Sun Microsystems - Beijing China 		 */
72dd1de374Slin wang - Sun Microsystems - Beijing China 		antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1);
73dd1de374Slin wang - Sun Microsystems - Beijing China 	}
74dd1de374Slin wang - Sun Microsystems - Beijing China 
75dd1de374Slin wang - Sun Microsystems - Beijing China 	ds->ds_data = bf->bf_dma.cookie.dmac_address;
76dd1de374Slin wang - Sun Microsystems - Beijing China 	/*
77dd1de374Slin wang - Sun Microsystems - Beijing China 	 * Calculate rate code.
78dd1de374Slin wang - Sun Microsystems - Beijing China 	 * XXX everything at min xmit rate
79dd1de374Slin wang - Sun Microsystems - Beijing China 	 */
80dd1de374Slin wang - Sun Microsystems - Beijing China 	rix = 0;
81dd1de374Slin wang - Sun Microsystems - Beijing China 	rt = sc->hw_rate_table[sc->sc_curmode];
82dd1de374Slin wang - Sun Microsystems - Beijing China 	rate = rt->info[rix].ratecode;
83dd1de374Slin wang - Sun Microsystems - Beijing China 	if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
84dd1de374Slin wang - Sun Microsystems - Beijing China 		rate |= rt->info[rix].short_preamble;
85dd1de374Slin wang - Sun Microsystems - Beijing China 
86dd1de374Slin wang - Sun Microsystems - Beijing China 	ath9k_hw_set11n_txdesc(ah, ds,
87dd1de374Slin wang - Sun Microsystems - Beijing China 	    MBLKL(mp) + IEEE80211_CRC_LEN, /* frame length */
88dd1de374Slin wang - Sun Microsystems - Beijing China 	    ATH9K_PKT_TYPE_BEACON,	/* Atheros packet type */
89dd1de374Slin wang - Sun Microsystems - Beijing China 	    MAX_RATE_POWER,		/* FIXME */
90dd1de374Slin wang - Sun Microsystems - Beijing China 	    ATH9K_TXKEYIX_INVALID,	/* no encryption */
91dd1de374Slin wang - Sun Microsystems - Beijing China 	    ATH9K_KEY_TYPE_CLEAR,	/* no encryption */
92dd1de374Slin wang - Sun Microsystems - Beijing China 	    flags);			/* no ack, veol for beacons */
93dd1de374Slin wang - Sun Microsystems - Beijing China 
94dd1de374Slin wang - Sun Microsystems - Beijing China 	/* NB: beacon's BufLen must be a multiple of 4 bytes */
95dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_filltxdesc(ah, ds,
96dd1de374Slin wang - Sun Microsystems - Beijing China 	    roundup(MBLKL(mp), 4),	/* buffer length */
97dd1de374Slin wang - Sun Microsystems - Beijing China 	    B_TRUE,			/* first segment */
98dd1de374Slin wang - Sun Microsystems - Beijing China 	    B_TRUE,			/* last segment */
99dd1de374Slin wang - Sun Microsystems - Beijing China 	    ds);			/* first descriptor */
100dd1de374Slin wang - Sun Microsystems - Beijing China 
101dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) memset(series, 0, sizeof (struct ath9k_11n_rate_series) * 4);
102dd1de374Slin wang - Sun Microsystems - Beijing China 	series[0].Tries = 1;
103dd1de374Slin wang - Sun Microsystems - Beijing China 	series[0].Rate = rate;
104dd1de374Slin wang - Sun Microsystems - Beijing China 	series[0].ChSel = sc->sc_tx_chainmask;
105dd1de374Slin wang - Sun Microsystems - Beijing China 	series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
106dd1de374Slin wang - Sun Microsystems - Beijing China 	ath9k_hw_set11n_ratescenario(ah, ds, ds, 0,
107dd1de374Slin wang - Sun Microsystems - Beijing China 	    ctsrate, ctsduration, series, 4, 0);
108dd1de374Slin wang - Sun Microsystems - Beijing China #undef	USE_SHPREAMBLE
109dd1de374Slin wang - Sun Microsystems - Beijing China }
110c0c93480Slin wang - Sun Microsystems - Beijing China #endif
111dd1de374Slin wang - Sun Microsystems - Beijing China 
112dd1de374Slin wang - Sun Microsystems - Beijing China /*
113dd1de374Slin wang - Sun Microsystems - Beijing China  * Startup beacon transmission for adhoc mode when they are sent entirely
114dd1de374Slin wang - Sun Microsystems - Beijing China  * by the hardware using the self-linked descriptor + veol trick.
115dd1de374Slin wang - Sun Microsystems - Beijing China  */
116c0c93480Slin wang - Sun Microsystems - Beijing China #ifdef ARN_IBSS
117dd1de374Slin wang - Sun Microsystems - Beijing China static void
arn_beacon_start_adhoc(struct arn_softc * sc)118dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_start_adhoc(struct arn_softc *sc)
119dd1de374Slin wang - Sun Microsystems - Beijing China {
120dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_buf *bf = list_head(&sc->sc_bcbuf_list);
121dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ieee80211_node *in = bf->bf_in;
122dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ieee80211com *ic = in->in_ic;
123dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_hal *ah = sc->sc_ah;
124dd1de374Slin wang - Sun Microsystems - Beijing China 	mblk_t *mp;
125dd1de374Slin wang - Sun Microsystems - Beijing China 
126dd1de374Slin wang - Sun Microsystems - Beijing China 	mp = bf->bf_m;
127dd1de374Slin wang - Sun Microsystems - Beijing China 	if (ieee80211_beacon_update(ic, bf->bf_in, &sc->asc_boff, mp, 0))
128dd1de374Slin wang - Sun Microsystems - Beijing China 		bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp));
129dd1de374Slin wang - Sun Microsystems - Beijing China 
130dd1de374Slin wang - Sun Microsystems - Beijing China 	/* Construct tx descriptor. */
131dd1de374Slin wang - Sun Microsystems - Beijing China 	arn_beacon_setup(sc, bf);
132dd1de374Slin wang - Sun Microsystems - Beijing China 
133dd1de374Slin wang - Sun Microsystems - Beijing China 	/*
134dd1de374Slin wang - Sun Microsystems - Beijing China 	 * Stop any current dma and put the new frame on the queue.
135dd1de374Slin wang - Sun Microsystems - Beijing China 	 * This should never fail since we check above that no frames
136dd1de374Slin wang - Sun Microsystems - Beijing China 	 * are still pending on the queue.
137dd1de374Slin wang - Sun Microsystems - Beijing China 	 */
138dd1de374Slin wang - Sun Microsystems - Beijing China 	if (!ath9k_hw_stoptxdma(ah, sc->sc_beaconq)) {
139dd1de374Slin wang - Sun Microsystems - Beijing China 		arn_problem("ath: beacon queue %d did not stop?\n",
140dd1de374Slin wang - Sun Microsystems - Beijing China 		    sc->sc_beaconq);
141dd1de374Slin wang - Sun Microsystems - Beijing China 	}
142dd1de374Slin wang - Sun Microsystems - Beijing China 	ARN_DMA_SYNC(bf->bf_dma, DDI_DMA_SYNC_FORDEV);
143dd1de374Slin wang - Sun Microsystems - Beijing China 
144dd1de374Slin wang - Sun Microsystems - Beijing China 	/* NB: caller is known to have already stopped tx dma */
145dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_puttxbuf(ah, sc->sc_beaconq, bf->bf_daddr);
146dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_txstart(ah, sc->sc_beaconq);
147dd1de374Slin wang - Sun Microsystems - Beijing China 
148dd1de374Slin wang - Sun Microsystems - Beijing China 	ARN_DBG((ARN_DBG_BEACON, "arn: arn_bstuck_process(): "
149dd1de374Slin wang - Sun Microsystems - Beijing China 	    "TXDP%u = %llx (%p)\n", sc->sc_beaconq,
150dd1de374Slin wang - Sun Microsystems - Beijing China 	    ito64(bf->bf_daddr), bf->bf_desc));
151dd1de374Slin wang - Sun Microsystems - Beijing China }
152c0c93480Slin wang - Sun Microsystems - Beijing China #endif /* ARN_IBSS */
153dd1de374Slin wang - Sun Microsystems - Beijing China 
154dd1de374Slin wang - Sun Microsystems - Beijing China uint32_t
arn_beaconq_setup(struct ath_hal * ah)155dd1de374Slin wang - Sun Microsystems - Beijing China arn_beaconq_setup(struct ath_hal *ah)
156dd1de374Slin wang - Sun Microsystems - Beijing China {
157dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath9k_tx_queue_info qi;
158dd1de374Slin wang - Sun Microsystems - Beijing China 
159dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) memset(&qi, 0, sizeof (qi));
160dd1de374Slin wang - Sun Microsystems - Beijing China 	qi.tqi_aifs = 1;
161dd1de374Slin wang - Sun Microsystems - Beijing China 	qi.tqi_cwmin = 0;
162dd1de374Slin wang - Sun Microsystems - Beijing China 	qi.tqi_cwmax = 0;
163dd1de374Slin wang - Sun Microsystems - Beijing China 	/* NB: don't enable any interrupts */
164dd1de374Slin wang - Sun Microsystems - Beijing China 	return (ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi));
165dd1de374Slin wang - Sun Microsystems - Beijing China }
166dd1de374Slin wang - Sun Microsystems - Beijing China 
167dd1de374Slin wang - Sun Microsystems - Beijing China int
arn_beacon_alloc(struct arn_softc * sc,struct ieee80211_node * in)168dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_alloc(struct arn_softc *sc, struct ieee80211_node *in)
169dd1de374Slin wang - Sun Microsystems - Beijing China {
170dd1de374Slin wang - Sun Microsystems - Beijing China 	ieee80211com_t	*ic = in->in_ic;
171dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_buf *bf;
172dd1de374Slin wang - Sun Microsystems - Beijing China 	mblk_t *mp;
173dd1de374Slin wang - Sun Microsystems - Beijing China 
174dd1de374Slin wang - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_bcbuflock);
175dd1de374Slin wang - Sun Microsystems - Beijing China 	bf = list_head(&sc->sc_bcbuf_list);
176dd1de374Slin wang - Sun Microsystems - Beijing China 	if (bf == NULL) {
177dd1de374Slin wang - Sun Microsystems - Beijing China 		arn_problem("arn: arn_beacon_alloc():"
178dd1de374Slin wang - Sun Microsystems - Beijing China 		    "no dma buffers");
179dd1de374Slin wang - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_bcbuflock);
180dd1de374Slin wang - Sun Microsystems - Beijing China 		return (ENOMEM);
181dd1de374Slin wang - Sun Microsystems - Beijing China 	}
182dd1de374Slin wang - Sun Microsystems - Beijing China 
183dd1de374Slin wang - Sun Microsystems - Beijing China 	mp = ieee80211_beacon_alloc(ic, in, &sc->asc_boff);
184dd1de374Slin wang - Sun Microsystems - Beijing China 	if (mp == NULL) {
185dd1de374Slin wang - Sun Microsystems - Beijing China 		arn_problem("ath: arn_beacon_alloc():"
186dd1de374Slin wang - Sun Microsystems - Beijing China 		    "cannot get mbuf\n");
187dd1de374Slin wang - Sun Microsystems - Beijing China 		mutex_exit(&sc->sc_bcbuflock);
188dd1de374Slin wang - Sun Microsystems - Beijing China 		return (ENOMEM);
189dd1de374Slin wang - Sun Microsystems - Beijing China 	}
190dd1de374Slin wang - Sun Microsystems - Beijing China 	ASSERT(mp->b_cont == NULL);
191dd1de374Slin wang - Sun Microsystems - Beijing China 	bf->bf_m = mp;
192dd1de374Slin wang - Sun Microsystems - Beijing China 	bcopy(mp->b_rptr, bf->bf_dma.mem_va, MBLKL(mp));
193dd1de374Slin wang - Sun Microsystems - Beijing China 	bf->bf_in = ieee80211_ref_node(in);
194dd1de374Slin wang - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_bcbuflock);
195dd1de374Slin wang - Sun Microsystems - Beijing China 
196dd1de374Slin wang - Sun Microsystems - Beijing China 	return (0);
197dd1de374Slin wang - Sun Microsystems - Beijing China }
198dd1de374Slin wang - Sun Microsystems - Beijing China 
199dd1de374Slin wang - Sun Microsystems - Beijing China 
200dd1de374Slin wang - Sun Microsystems - Beijing China void
arn_beacon_return(struct arn_softc * sc)201dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_return(struct arn_softc *sc)
202dd1de374Slin wang - Sun Microsystems - Beijing China {
203dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_buf *bf;
204dd1de374Slin wang - Sun Microsystems - Beijing China 
205dd1de374Slin wang - Sun Microsystems - Beijing China 	mutex_enter(&sc->sc_bcbuflock);
206dd1de374Slin wang - Sun Microsystems - Beijing China 	bf = list_head(&sc->sc_bcbuf_list);
207dd1de374Slin wang - Sun Microsystems - Beijing China 	while (bf != NULL) {
208dd1de374Slin wang - Sun Microsystems - Beijing China 		if (bf->bf_m != NULL) {
209dd1de374Slin wang - Sun Microsystems - Beijing China 			freemsg(bf->bf_m);
210dd1de374Slin wang - Sun Microsystems - Beijing China 			bf->bf_m = NULL;
211dd1de374Slin wang - Sun Microsystems - Beijing China 		}
212dd1de374Slin wang - Sun Microsystems - Beijing China 		if (bf->bf_in != NULL) {
213dd1de374Slin wang - Sun Microsystems - Beijing China 			ieee80211_free_node(bf->bf_in);
214dd1de374Slin wang - Sun Microsystems - Beijing China 			bf->bf_in = NULL;
215dd1de374Slin wang - Sun Microsystems - Beijing China 		}
216dd1de374Slin wang - Sun Microsystems - Beijing China 		bf = list_next(&sc->sc_bcbuf_list, bf);
217dd1de374Slin wang - Sun Microsystems - Beijing China 	}
218dd1de374Slin wang - Sun Microsystems - Beijing China 	mutex_exit(&sc->sc_bcbuflock);
219dd1de374Slin wang - Sun Microsystems - Beijing China }
220dd1de374Slin wang - Sun Microsystems - Beijing China 
221dd1de374Slin wang - Sun Microsystems - Beijing China void
arn_beacon_config(struct arn_softc * sc)222dd1de374Slin wang - Sun Microsystems - Beijing China arn_beacon_config(struct arn_softc *sc)
223dd1de374Slin wang - Sun Microsystems - Beijing China {
224dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ath_beacon_config conf;
225dd1de374Slin wang - Sun Microsystems - Beijing China 	ieee80211com_t *ic = (ieee80211com_t *)sc;
226dd1de374Slin wang - Sun Microsystems - Beijing China 	struct ieee80211_node *in = ic->ic_bss;
2273ae945c3Slin wang - Sun Microsystems - Beijing China 
228c0c93480Slin wang - Sun Microsystems - Beijing China 	/* New added */
2293ae945c3Slin wang - Sun Microsystems - Beijing China 	struct ath9k_beacon_state bs;
2303ae945c3Slin wang - Sun Microsystems - Beijing China 	int dtimperiod, dtimcount, sleepduration;
2313ae945c3Slin wang - Sun Microsystems - Beijing China 	int cfpperiod, cfpcount;
2323ae945c3Slin wang - Sun Microsystems - Beijing China 	uint32_t nexttbtt = 0, intval, tsftu;
2333ae945c3Slin wang - Sun Microsystems - Beijing China 	uint64_t tsf;
234dd1de374Slin wang - Sun Microsystems - Beijing China 
235dd1de374Slin wang - Sun Microsystems - Beijing China 	(void) memset(&conf, 0, sizeof (struct ath_beacon_config));
236dd1de374Slin wang - Sun Microsystems - Beijing China 
237dd1de374Slin wang - Sun Microsystems - Beijing China 	/* XXX fix me */
238dd1de374Slin wang - Sun Microsystems - Beijing China 	conf.beacon_interval = in->in_intval ?
239dd1de374Slin wang - Sun Microsystems - Beijing China 	    in->in_intval : ATH_DEFAULT_BINTVAL;
240c0c93480Slin wang - Sun Microsystems - Beijing China 	ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config():"
241c0c93480Slin wang - Sun Microsystems - Beijing China 	    "conf.beacon_interval = %d\n", conf.beacon_interval));
242dd1de374Slin wang - Sun Microsystems - Beijing China 	conf.listen_interval = 1;
243dd1de374Slin wang - Sun Microsystems - Beijing China 	conf.dtim_period = conf.beacon_interval;
244dd1de374Slin wang - Sun Microsystems - Beijing China 	conf.dtim_count = 1;
245dd1de374Slin wang - Sun Microsystems - Beijing China 	conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
246dd1de374Slin wang - Sun Microsystems - Beijing China 
2473ae945c3Slin wang - Sun Microsystems - Beijing China 	(void) memset(&bs, 0, sizeof (bs));
2483ae945c3Slin wang - Sun Microsystems - Beijing China 	intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
249dd1de374Slin wang - Sun Microsystems - Beijing China 
2503ae945c3Slin wang - Sun Microsystems - Beijing China 	/*
2513ae945c3Slin wang - Sun Microsystems - Beijing China 	 * Setup dtim and cfp parameters according to
2523ae945c3Slin wang - Sun Microsystems - Beijing China 	 * last beacon we received (which may be none).
2533ae945c3Slin wang - Sun Microsystems - Beijing China 	 */
2543ae945c3Slin wang - Sun Microsystems - Beijing China 	dtimperiod = conf.dtim_period;
2553ae945c3Slin wang - Sun Microsystems - Beijing China 	if (dtimperiod <= 0)		/* NB: 0 if not known */
2563ae945c3Slin wang - Sun Microsystems - Beijing China 		dtimperiod = 1;
2573ae945c3Slin wang - Sun Microsystems - Beijing China 	dtimcount = conf.dtim_count;
2583ae945c3Slin wang - Sun Microsystems - Beijing China 	if (dtimcount >= dtimperiod)	/* NB: sanity check */
2593ae945c3Slin wang - Sun Microsystems - Beijing China 		dtimcount = 0;
2603ae945c3Slin wang - Sun Microsystems - Beijing China 	cfpperiod = 1;			/* NB: no PCF support yet */
2613ae945c3Slin wang - Sun Microsystems - Beijing China 	cfpcount = 0;
2623ae945c3Slin wang - Sun Microsystems - Beijing China 
2633ae945c3Slin wang - Sun Microsystems - Beijing China 	sleepduration = conf.listen_interval * intval;
2643ae945c3Slin wang - Sun Microsystems - Beijing China 	if (sleepduration <= 0)
2653ae945c3Slin wang - Sun Microsystems - Beijing China 		sleepduration = intval;
2663ae945c3Slin wang - Sun Microsystems - Beijing China 
2673ae945c3Slin wang - Sun Microsystems - Beijing China 	/*
2683ae945c3Slin wang - Sun Microsystems - Beijing China 	 * Pull nexttbtt forward to reflect the current
2693ae945c3Slin wang - Sun Microsystems - Beijing China 	 * TSF and calculate dtim+cfp state for the result.
2703ae945c3Slin wang - Sun Microsystems - Beijing China 	 */
2713ae945c3Slin wang - Sun Microsystems - Beijing China 	tsf = ath9k_hw_gettsf64(sc->sc_ah);
2723ae945c3Slin wang - Sun Microsystems - Beijing China 	tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
2733ae945c3Slin wang - Sun Microsystems - Beijing China 	do {
2743ae945c3Slin wang - Sun Microsystems - Beijing China 		nexttbtt += intval;
2753ae945c3Slin wang - Sun Microsystems - Beijing China 		if (--dtimcount < 0) {
2763ae945c3Slin wang - Sun Microsystems - Beijing China 			dtimcount = dtimperiod - 1;
2773ae945c3Slin wang - Sun Microsystems - Beijing China 			if (--cfpcount < 0)
2783ae945c3Slin wang - Sun Microsystems - Beijing China 				cfpcount = cfpperiod - 1;
2793ae945c3Slin wang - Sun Microsystems - Beijing China 		}
2803ae945c3Slin wang - Sun Microsystems - Beijing China 	} while (nexttbtt < tsftu);
2813ae945c3Slin wang - Sun Microsystems - Beijing China 
2823ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_intval = intval;
2833ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_nexttbtt = nexttbtt;
2843ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_dtimperiod = dtimperiod*intval;
2853ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
2863ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
2873ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
2883ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_cfpmaxduration = 0;
2893ae945c3Slin wang - Sun Microsystems - Beijing China 
2903ae945c3Slin wang - Sun Microsystems - Beijing China 	/*
2913ae945c3Slin wang - Sun Microsystems - Beijing China 	 * Calculate the number of consecutive beacons to miss* before taking
2923ae945c3Slin wang - Sun Microsystems - Beijing China 	 * a BMISS interrupt. The configuration is specified in TU so we only
293c0c93480Slin wang - Sun Microsystems - Beijing China 	 * need calculate based	on the beacon interval.  Note that we clamp the
2943ae945c3Slin wang - Sun Microsystems - Beijing China 	 * result to at most 15 beacons.
2953ae945c3Slin wang - Sun Microsystems - Beijing China 	 */
2963ae945c3Slin wang - Sun Microsystems - Beijing China 	if (sleepduration > intval) {
2973ae945c3Slin wang - Sun Microsystems - Beijing China 		bs.bs_bmissthreshold = conf.listen_interval *
298*fd7c5980SRichard Lowe 		    ATH_DEFAULT_BMISS_LIMIT / 2;
299dd1de374Slin wang - Sun Microsystems - Beijing China 	} else {
3003ae945c3Slin wang - Sun Microsystems - Beijing China 		bs.bs_bmissthreshold = DIV_ROUND_UP(conf.bmiss_timeout, intval);
3013ae945c3Slin wang - Sun Microsystems - Beijing China 		if (bs.bs_bmissthreshold > 15)
3023ae945c3Slin wang - Sun Microsystems - Beijing China 			bs.bs_bmissthreshold = 15;
3033ae945c3Slin wang - Sun Microsystems - Beijing China 		else if (bs.bs_bmissthreshold == 0)
3043ae945c3Slin wang - Sun Microsystems - Beijing China 			bs.bs_bmissthreshold = 1;
305dd1de374Slin wang - Sun Microsystems - Beijing China 	}
306dd1de374Slin wang - Sun Microsystems - Beijing China 
3073ae945c3Slin wang - Sun Microsystems - Beijing China 	/*
3083ae945c3Slin wang - Sun Microsystems - Beijing China 	 * Calculate sleep duration. The configuration is given in ms.
3093ae945c3Slin wang - Sun Microsystems - Beijing China 	 * We ensure a multiple of the beacon period is used. Also, if the sleep
3103ae945c3Slin wang - Sun Microsystems - Beijing China 	 * duration is greater than the DTIM period then it makes senses
3113ae945c3Slin wang - Sun Microsystems - Beijing China 	 * to make it a multiple of that.
3123ae945c3Slin wang - Sun Microsystems - Beijing China 	 *
3133ae945c3Slin wang - Sun Microsystems - Beijing China 	 * XXX fixed at 100ms
3143ae945c3Slin wang - Sun Microsystems - Beijing China 	 */
315dd1de374Slin wang - Sun Microsystems - Beijing China 
3163ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
3173ae945c3Slin wang - Sun Microsystems - Beijing China 	if (bs.bs_sleepduration > bs.bs_dtimperiod)
3183ae945c3Slin wang - Sun Microsystems - Beijing China 		bs.bs_sleepduration = bs.bs_dtimperiod;
319dd1de374Slin wang - Sun Microsystems - Beijing China 
3203ae945c3Slin wang - Sun Microsystems - Beijing China 	/* TSF out of range threshold fixed at 1 second */
3213ae945c3Slin wang - Sun Microsystems - Beijing China 	bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
322dd1de374Slin wang - Sun Microsystems - Beijing China 
3233ae945c3Slin wang - Sun Microsystems - Beijing China 	ARN_DBG((ARN_DBG_BEACON, "arn: arn_beacon_config(): "
324c0c93480Slin wang - Sun Microsystems - Beijing China 	    "tsf %llu "
325c0c93480Slin wang - Sun Microsystems - Beijing China 	    "tsf:tu %u "
326c0c93480Slin wang - Sun Microsystems - Beijing China 	    "intval %u "
327c0c93480Slin wang - Sun Microsystems - Beijing China 	    "nexttbtt %u "
328c0c93480Slin wang - Sun Microsystems - Beijing China 	    "dtim %u "
329c0c93480Slin wang - Sun Microsystems - Beijing China 	    "nextdtim %u "
330c0c93480Slin wang - Sun Microsystems - Beijing China 	    "bmiss %u "
331c0c93480Slin wang - Sun Microsystems - Beijing China 	    "sleep %u "
332c0c93480Slin wang - Sun Microsystems - Beijing China 	    "cfp:period %u "
333c0c93480Slin wang - Sun Microsystems - Beijing China 	    "maxdur %u "
334c0c93480Slin wang - Sun Microsystems - Beijing China 	    "next %u "
335c0c93480Slin wang - Sun Microsystems - Beijing China 	    "timoffset %u\n",
336c0c93480Slin wang - Sun Microsystems - Beijing China 	    (unsigned long long)tsf, tsftu,
337c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_intval,
338c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_nexttbtt,
339c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_dtimperiod,
340c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_nextdtim,
341c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_bmissthreshold,
342c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_sleepduration,
343c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_cfpperiod,
344c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_cfpmaxduration,
345c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_cfpnext,
346c0c93480Slin wang - Sun Microsystems - Beijing China 	    bs.bs_timoffset));
347dd1de374Slin wang - Sun Microsystems - Beijing China 
3483ae945c3Slin wang - Sun Microsystems - Beijing China 	/* Set the computed STA beacon timers */
349dd1de374Slin wang - Sun Microsystems - Beijing China 
3503ae945c3Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_set_interrupts(sc->sc_ah, 0);
3513ae945c3Slin wang - Sun Microsystems - Beijing China 	ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
3523ae945c3Slin wang - Sun Microsystems - Beijing China 	sc->sc_imask |= ATH9K_INT_BMISS;
3533ae945c3Slin wang - Sun Microsystems - Beijing China 	(void) ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask);
354dd1de374Slin wang - Sun Microsystems - Beijing China }
355dd1de374Slin wang - Sun Microsystems - Beijing China 
356dd1de374Slin wang - Sun Microsystems - Beijing China void
ath_beacon_sync(struct arn_softc * sc)357dd1de374Slin wang - Sun Microsystems - Beijing China ath_beacon_sync(struct arn_softc *sc)
358dd1de374Slin wang - Sun Microsystems - Beijing China {
359dd1de374Slin wang - Sun Microsystems - Beijing China 	/*
360dd1de374Slin wang - Sun Microsystems - Beijing China 	 * Resync beacon timers using the tsf of the
361dd1de374Slin wang - Sun Microsystems - Beijing China 	 * beacon frame we just received.
362dd1de374Slin wang - Sun Microsystems - Beijing China 	 */
363dd1de374Slin wang - Sun Microsystems - Beijing China 	arn_beacon_config(sc);
364dd1de374Slin wang - Sun Microsystems - Beijing China 	sc->sc_flags |= SC_OP_BEACONS;
365dd1de374Slin wang - Sun Microsystems - Beijing China }
366dd1de374Slin wang - Sun Microsystems - Beijing China 
367dd1de374Slin wang - Sun Microsystems - Beijing China void
arn_bmiss_proc(void * arg)368dd1de374Slin wang - Sun Microsystems - Beijing China arn_bmiss_proc(void *arg)
369dd1de374Slin wang - Sun Microsystems - Beijing China {
370dd1de374Slin wang - Sun Microsystems - Beijing China 	struct arn_softc *sc = (struct arn_softc *)arg;
371dd1de374Slin wang - Sun Microsystems - Beijing China 	ieee80211com_t *ic = (ieee80211com_t *)sc;
372dd1de374Slin wang - Sun Microsystems - Beijing China 	uint64_t tsf, lastrx;
373dd1de374Slin wang - Sun Microsystems - Beijing China 	uint_t  bmisstimeout;
374dd1de374Slin wang - Sun Microsystems - Beijing China 
375dd1de374Slin wang - Sun Microsystems - Beijing China 	if (ic->ic_opmode != IEEE80211_M_STA ||
376dd1de374Slin wang - Sun Microsystems - Beijing China 	    ic->ic_state != IEEE80211_S_RUN) {
377dd1de374Slin wang - Sun Microsystems - Beijing China 		return;
378dd1de374Slin wang - Sun Microsystems - Beijing China 	}
379dd1de374Slin wang - Sun Microsystems - Beijing China 
380dd1de374Slin wang - Sun Microsystems - Beijing China 	ARN_LOCK(sc);
381dd1de374Slin wang - Sun Microsystems - Beijing China 	lastrx = sc->sc_lastrx;
382dd1de374Slin wang - Sun Microsystems - Beijing China 	tsf = ath9k_hw_gettsf64(sc->sc_ah);
383dd1de374Slin wang - Sun Microsystems - Beijing China 	bmisstimeout = ic->ic_bmissthreshold * ic->ic_bss->in_intval * 1024;
384dd1de374Slin wang - Sun Microsystems - Beijing China 
385dd1de374Slin wang - Sun Microsystems - Beijing China 	ARN_DBG((ARN_DBG_BEACON, "arn_bmiss_proc():"
386dd1de374Slin wang - Sun Microsystems - Beijing China 	    " tsf %llu, lastrx %llu (%lld), bmiss %u\n",
387dd1de374Slin wang - Sun Microsystems - Beijing China 	    (unsigned long long)tsf, (unsigned long long)sc->sc_lastrx,
388dd1de374Slin wang - Sun Microsystems - Beijing China 	    (long long)(tsf - lastrx), bmisstimeout));
389dd1de374Slin wang - Sun Microsystems - Beijing China 	ARN_UNLOCK(sc);
390dd1de374Slin wang - Sun Microsystems - Beijing China 
391dd1de374Slin wang - Sun Microsystems - Beijing China 	/* temp workaround */
392c0c93480Slin wang - Sun Microsystems - Beijing China 	if ((tsf - lastrx) > bmisstimeout)
393dd1de374Slin wang - Sun Microsystems - Beijing China 		ieee80211_beacon_miss(ic);
394dd1de374Slin wang - Sun Microsystems - Beijing China }
395