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