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