diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/beacon.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/beacon.c | 445 |
1 files changed, 275 insertions, 170 deletions
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c index 4d4b22d52dfd..d4d8ceced89b 100644 --- a/drivers/net/wireless/ath/ath9k/beacon.c +++ b/drivers/net/wireless/ath/ath9k/beacon.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) 2008-2009 Atheros Communications Inc. | 2 | * Copyright (c) 2008-2011 Atheros Communications Inc. |
3 | * | 3 | * |
4 | * Permission to use, copy, modify, and/or distribute this software for any | 4 | * Permission to use, copy, modify, and/or distribute this software for any |
5 | * purpose with or without fee is hereby granted, provided that the above | 5 | * purpose with or without fee is hereby granted, provided that the above |
@@ -18,6 +18,12 @@ | |||
18 | 18 | ||
19 | #define FUDGE 2 | 19 | #define FUDGE 2 |
20 | 20 | ||
21 | static void ath9k_reset_beacon_status(struct ath_softc *sc) | ||
22 | { | ||
23 | sc->beacon.tx_processed = false; | ||
24 | sc->beacon.tx_last = false; | ||
25 | } | ||
26 | |||
21 | /* | 27 | /* |
22 | * This function will modify certain transmit queue properties depending on | 28 | * This function will modify certain transmit queue properties depending on |
23 | * the operating mode of the station (AP or AdHoc). Parameters are AIFS | 29 | * the operating mode of the station (AP or AdHoc). Parameters are AIFS |
@@ -28,7 +34,7 @@ int ath_beaconq_config(struct ath_softc *sc) | |||
28 | struct ath_hw *ah = sc->sc_ah; | 34 | struct ath_hw *ah = sc->sc_ah; |
29 | struct ath_common *common = ath9k_hw_common(ah); | 35 | struct ath_common *common = ath9k_hw_common(ah); |
30 | struct ath9k_tx_queue_info qi, qi_be; | 36 | struct ath9k_tx_queue_info qi, qi_be; |
31 | int qnum; | 37 | struct ath_txq *txq; |
32 | 38 | ||
33 | ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); | 39 | ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); |
34 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { | 40 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) { |
@@ -38,16 +44,16 @@ int ath_beaconq_config(struct ath_softc *sc) | |||
38 | qi.tqi_cwmax = 0; | 44 | qi.tqi_cwmax = 0; |
39 | } else { | 45 | } else { |
40 | /* Adhoc mode; important thing is to use 2x cwmin. */ | 46 | /* Adhoc mode; important thing is to use 2x cwmin. */ |
41 | qnum = sc->tx.hwq_map[WME_AC_BE]; | 47 | txq = sc->tx.txq_map[WME_AC_BE]; |
42 | ath9k_hw_get_txq_props(ah, qnum, &qi_be); | 48 | ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be); |
43 | qi.tqi_aifs = qi_be.tqi_aifs; | 49 | qi.tqi_aifs = qi_be.tqi_aifs; |
44 | qi.tqi_cwmin = 4*qi_be.tqi_cwmin; | 50 | qi.tqi_cwmin = 4*qi_be.tqi_cwmin; |
45 | qi.tqi_cwmax = qi_be.tqi_cwmax; | 51 | qi.tqi_cwmax = qi_be.tqi_cwmax; |
46 | } | 52 | } |
47 | 53 | ||
48 | if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { | 54 | if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { |
49 | ath_print(common, ATH_DBG_FATAL, | 55 | ath_err(common, |
50 | "Unable to update h/w beacon queue parameters\n"); | 56 | "Unable to update h/w beacon queue parameters\n"); |
51 | return 0; | 57 | return 0; |
52 | } else { | 58 | } else { |
53 | ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); | 59 | ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); |
@@ -57,8 +63,8 @@ int ath_beaconq_config(struct ath_softc *sc) | |||
57 | 63 | ||
58 | /* | 64 | /* |
59 | * Associates the beacon frame buffer with a transmit descriptor. Will set | 65 | * Associates the beacon frame buffer with a transmit descriptor. Will set |
60 | * up all required antenna switch parameters, rate codes, and channel flags. | 66 | * up rate codes, and channel flags. Beacons are always sent out at the |
61 | * Beacons are always sent out at the lowest rate, and are not retried. | 67 | * lowest rate, and are not retried. |
62 | */ | 68 | */ |
63 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | 69 | static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, |
64 | struct ath_buf *bf, int rateidx) | 70 | struct ath_buf *bf, int rateidx) |
@@ -68,20 +74,16 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
68 | struct ath_common *common = ath9k_hw_common(ah); | 74 | struct ath_common *common = ath9k_hw_common(ah); |
69 | struct ath_desc *ds; | 75 | struct ath_desc *ds; |
70 | struct ath9k_11n_rate_series series[4]; | 76 | struct ath9k_11n_rate_series series[4]; |
71 | int flags, antenna, ctsrate = 0, ctsduration = 0; | 77 | int flags, ctsrate = 0, ctsduration = 0; |
72 | struct ieee80211_supported_band *sband; | 78 | struct ieee80211_supported_band *sband; |
73 | u8 rate = 0; | 79 | u8 rate = 0; |
74 | 80 | ||
81 | ath9k_reset_beacon_status(sc); | ||
82 | |||
75 | ds = bf->bf_desc; | 83 | ds = bf->bf_desc; |
76 | flags = ATH9K_TXDESC_NOACK; | 84 | flags = ATH9K_TXDESC_NOACK; |
77 | 85 | ||
78 | ds->ds_link = 0; | 86 | ds->ds_link = 0; |
79 | /* | ||
80 | * Switch antenna every beacon. | ||
81 | * Should only switch every beacon period, not for every SWBA | ||
82 | * XXX assumes two antennae | ||
83 | */ | ||
84 | antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1); | ||
85 | 87 | ||
86 | sband = &sc->sbands[common->hw->conf.channel->band]; | 88 | sband = &sc->sbands[common->hw->conf.channel->band]; |
87 | rate = sband->bitrates[rateidx].hw_value; | 89 | rate = sband->bitrates[rateidx].hw_value; |
@@ -103,17 +105,35 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp, | |||
103 | memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); | 105 | memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); |
104 | series[0].Tries = 1; | 106 | series[0].Tries = 1; |
105 | series[0].Rate = rate; | 107 | series[0].Rate = rate; |
106 | series[0].ChSel = common->tx_chainmask; | 108 | series[0].ChSel = ath_txchainmask_reduction(sc, |
109 | common->tx_chainmask, series[0].Rate); | ||
107 | series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; | 110 | series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0; |
108 | ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, | 111 | ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration, |
109 | series, 4, 0); | 112 | series, 4, 0); |
110 | } | 113 | } |
111 | 114 | ||
115 | static void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb) | ||
116 | { | ||
117 | struct ath_softc *sc = hw->priv; | ||
118 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
119 | struct ath_tx_control txctl; | ||
120 | |||
121 | memset(&txctl, 0, sizeof(struct ath_tx_control)); | ||
122 | txctl.txq = sc->beacon.cabq; | ||
123 | |||
124 | ath_dbg(common, ATH_DBG_XMIT, | ||
125 | "transmitting CABQ packet, skb: %p\n", skb); | ||
126 | |||
127 | if (ath_tx_start(hw, skb, &txctl) != 0) { | ||
128 | ath_dbg(common, ATH_DBG_XMIT, "CABQ TX failed\n"); | ||
129 | dev_kfree_skb_any(skb); | ||
130 | } | ||
131 | } | ||
132 | |||
112 | static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | 133 | static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, |
113 | struct ieee80211_vif *vif) | 134 | struct ieee80211_vif *vif) |
114 | { | 135 | { |
115 | struct ath_wiphy *aphy = hw->priv; | 136 | struct ath_softc *sc = hw->priv; |
116 | struct ath_softc *sc = aphy->sc; | ||
117 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 137 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
118 | struct ath_buf *bf; | 138 | struct ath_buf *bf; |
119 | struct ath_vif *avp; | 139 | struct ath_vif *avp; |
@@ -122,13 +142,12 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
122 | struct ieee80211_tx_info *info; | 142 | struct ieee80211_tx_info *info; |
123 | int cabq_depth; | 143 | int cabq_depth; |
124 | 144 | ||
125 | if (aphy->state != ATH_WIPHY_ACTIVE) | 145 | ath9k_reset_beacon_status(sc); |
126 | return NULL; | ||
127 | 146 | ||
128 | avp = (void *)vif->drv_priv; | 147 | avp = (void *)vif->drv_priv; |
129 | cabq = sc->beacon.cabq; | 148 | cabq = sc->beacon.cabq; |
130 | 149 | ||
131 | if (avp->av_bcbuf == NULL) | 150 | if ((avp->av_bcbuf == NULL) || !avp->is_bslot_active) |
132 | return NULL; | 151 | return NULL; |
133 | 152 | ||
134 | /* Release the old beacon first */ | 153 | /* Release the old beacon first */ |
@@ -136,9 +155,10 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
136 | bf = avp->av_bcbuf; | 155 | bf = avp->av_bcbuf; |
137 | skb = bf->bf_mpdu; | 156 | skb = bf->bf_mpdu; |
138 | if (skb) { | 157 | if (skb) { |
139 | dma_unmap_single(sc->dev, bf->bf_dmacontext, | 158 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
140 | skb->len, DMA_TO_DEVICE); | 159 | skb->len, DMA_TO_DEVICE); |
141 | dev_kfree_skb_any(skb); | 160 | dev_kfree_skb_any(skb); |
161 | bf->bf_buf_addr = 0; | ||
142 | } | 162 | } |
143 | 163 | ||
144 | /* Get a new beacon from mac80211 */ | 164 | /* Get a new beacon from mac80211 */ |
@@ -162,14 +182,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
162 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); | 182 | hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); |
163 | } | 183 | } |
164 | 184 | ||
165 | bf->bf_buf_addr = bf->bf_dmacontext = | 185 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, |
166 | dma_map_single(sc->dev, skb->data, | 186 | skb->len, DMA_TO_DEVICE); |
167 | skb->len, DMA_TO_DEVICE); | ||
168 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { | 187 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { |
169 | dev_kfree_skb_any(skb); | 188 | dev_kfree_skb_any(skb); |
170 | bf->bf_mpdu = NULL; | 189 | bf->bf_mpdu = NULL; |
171 | ath_print(common, ATH_DBG_FATAL, | 190 | bf->bf_buf_addr = 0; |
172 | "dma_mapping_error on beaconing\n"); | 191 | ath_err(common, "dma_mapping_error on beaconing\n"); |
173 | return NULL; | 192 | return NULL; |
174 | } | 193 | } |
175 | 194 | ||
@@ -189,8 +208,8 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
189 | 208 | ||
190 | if (skb && cabq_depth) { | 209 | if (skb && cabq_depth) { |
191 | if (sc->nvifs > 1) { | 210 | if (sc->nvifs > 1) { |
192 | ath_print(common, ATH_DBG_BEACON, | 211 | ath_dbg(common, ATH_DBG_BEACON, |
193 | "Flushing previous cabq traffic\n"); | 212 | "Flushing previous cabq traffic\n"); |
194 | ath_draintxq(sc, cabq, false); | 213 | ath_draintxq(sc, cabq, false); |
195 | } | 214 | } |
196 | } | 215 | } |
@@ -205,13 +224,13 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw, | |||
205 | return bf; | 224 | return bf; |
206 | } | 225 | } |
207 | 226 | ||
208 | int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | 227 | int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) |
209 | { | 228 | { |
210 | struct ath_softc *sc = aphy->sc; | ||
211 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 229 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
212 | struct ath_vif *avp; | 230 | struct ath_vif *avp; |
213 | struct ath_buf *bf; | 231 | struct ath_buf *bf; |
214 | struct sk_buff *skb; | 232 | struct sk_buff *skb; |
233 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
215 | __le64 tstamp; | 234 | __le64 tstamp; |
216 | 235 | ||
217 | avp = (void *)vif->drv_priv; | 236 | avp = (void *)vif->drv_priv; |
@@ -224,9 +243,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
224 | struct ath_buf, list); | 243 | struct ath_buf, list); |
225 | list_del(&avp->av_bcbuf->list); | 244 | list_del(&avp->av_bcbuf->list); |
226 | 245 | ||
227 | if (sc->sc_ah->opmode == NL80211_IFTYPE_AP || | 246 | if (ath9k_uses_beacons(vif->type)) { |
228 | sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC || | ||
229 | sc->sc_ah->opmode == NL80211_IFTYPE_MESH_POINT) { | ||
230 | int slot; | 247 | int slot; |
231 | /* | 248 | /* |
232 | * Assign the vif to a beacon xmit slot. As | 249 | * Assign the vif to a beacon xmit slot. As |
@@ -236,6 +253,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
236 | for (slot = 0; slot < ATH_BCBUF; slot++) | 253 | for (slot = 0; slot < ATH_BCBUF; slot++) |
237 | if (sc->beacon.bslot[slot] == NULL) { | 254 | if (sc->beacon.bslot[slot] == NULL) { |
238 | avp->av_bslot = slot; | 255 | avp->av_bslot = slot; |
256 | avp->is_bslot_active = false; | ||
239 | 257 | ||
240 | /* NB: keep looking for a double slot */ | 258 | /* NB: keep looking for a double slot */ |
241 | if (slot == 0 || !sc->beacon.bslot[slot-1]) | 259 | if (slot == 0 || !sc->beacon.bslot[slot-1]) |
@@ -243,7 +261,6 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
243 | } | 261 | } |
244 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); | 262 | BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL); |
245 | sc->beacon.bslot[avp->av_bslot] = vif; | 263 | sc->beacon.bslot[avp->av_bslot] = vif; |
246 | sc->beacon.bslot_aphy[avp->av_bslot] = aphy; | ||
247 | sc->nbcnvifs++; | 264 | sc->nbcnvifs++; |
248 | } | 265 | } |
249 | } | 266 | } |
@@ -252,27 +269,26 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
252 | bf = avp->av_bcbuf; | 269 | bf = avp->av_bcbuf; |
253 | if (bf->bf_mpdu != NULL) { | 270 | if (bf->bf_mpdu != NULL) { |
254 | skb = bf->bf_mpdu; | 271 | skb = bf->bf_mpdu; |
255 | dma_unmap_single(sc->dev, bf->bf_dmacontext, | 272 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
256 | skb->len, DMA_TO_DEVICE); | 273 | skb->len, DMA_TO_DEVICE); |
257 | dev_kfree_skb_any(skb); | 274 | dev_kfree_skb_any(skb); |
258 | bf->bf_mpdu = NULL; | 275 | bf->bf_mpdu = NULL; |
276 | bf->bf_buf_addr = 0; | ||
259 | } | 277 | } |
260 | 278 | ||
261 | /* NB: the beacon data buffer must be 32-bit aligned. */ | 279 | /* NB: the beacon data buffer must be 32-bit aligned. */ |
262 | skb = ieee80211_beacon_get(sc->hw, vif); | 280 | skb = ieee80211_beacon_get(sc->hw, vif); |
263 | if (skb == NULL) { | 281 | if (skb == NULL) |
264 | ath_print(common, ATH_DBG_BEACON, "cannot get skb\n"); | ||
265 | return -ENOMEM; | 282 | return -ENOMEM; |
266 | } | ||
267 | 283 | ||
268 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; | 284 | tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; |
269 | sc->beacon.bc_tstamp = le64_to_cpu(tstamp); | 285 | sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp); |
270 | /* Calculate a TSF adjustment factor required for staggered beacons. */ | 286 | /* Calculate a TSF adjustment factor required for staggered beacons. */ |
271 | if (avp->av_bslot > 0) { | 287 | if (avp->av_bslot > 0) { |
272 | u64 tsfadjust; | 288 | u64 tsfadjust; |
273 | int intval; | 289 | int intval; |
274 | 290 | ||
275 | intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; | 291 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; |
276 | 292 | ||
277 | /* | 293 | /* |
278 | * Calculate the TSF offset for this beacon slot, i.e., the | 294 | * Calculate the TSF offset for this beacon slot, i.e., the |
@@ -282,13 +298,12 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
282 | * adjustment. Other slots are adjusted to get the timestamp | 298 | * adjustment. Other slots are adjusted to get the timestamp |
283 | * close to the TBTT for the BSS. | 299 | * close to the TBTT for the BSS. |
284 | */ | 300 | */ |
285 | tsfadjust = intval * avp->av_bslot / ATH_BCBUF; | 301 | tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF; |
286 | avp->tsf_adjust = cpu_to_le64(TU_TO_USEC(tsfadjust)); | 302 | avp->tsf_adjust = cpu_to_le64(tsfadjust); |
287 | 303 | ||
288 | ath_print(common, ATH_DBG_BEACON, | 304 | ath_dbg(common, ATH_DBG_BEACON, |
289 | "stagger beacons, bslot %d intval " | 305 | "stagger beacons, bslot %d intval %u tsfadjust %llu\n", |
290 | "%u tsfadjust %llu\n", | 306 | avp->av_bslot, intval, (unsigned long long)tsfadjust); |
291 | avp->av_bslot, intval, (unsigned long long)tsfadjust); | ||
292 | 307 | ||
293 | ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = | 308 | ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = |
294 | avp->tsf_adjust; | 309 | avp->tsf_adjust; |
@@ -296,16 +311,16 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif) | |||
296 | avp->tsf_adjust = cpu_to_le64(0); | 311 | avp->tsf_adjust = cpu_to_le64(0); |
297 | 312 | ||
298 | bf->bf_mpdu = skb; | 313 | bf->bf_mpdu = skb; |
299 | bf->bf_buf_addr = bf->bf_dmacontext = | 314 | bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, |
300 | dma_map_single(sc->dev, skb->data, | 315 | skb->len, DMA_TO_DEVICE); |
301 | skb->len, DMA_TO_DEVICE); | ||
302 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { | 316 | if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { |
303 | dev_kfree_skb_any(skb); | 317 | dev_kfree_skb_any(skb); |
304 | bf->bf_mpdu = NULL; | 318 | bf->bf_mpdu = NULL; |
305 | ath_print(common, ATH_DBG_FATAL, | 319 | bf->bf_buf_addr = 0; |
306 | "dma_mapping_error on beacon alloc\n"); | 320 | ath_err(common, "dma_mapping_error on beacon alloc\n"); |
307 | return -ENOMEM; | 321 | return -ENOMEM; |
308 | } | 322 | } |
323 | avp->is_bslot_active = true; | ||
309 | 324 | ||
310 | return 0; | 325 | return 0; |
311 | } | 326 | } |
@@ -315,19 +330,21 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) | |||
315 | if (avp->av_bcbuf != NULL) { | 330 | if (avp->av_bcbuf != NULL) { |
316 | struct ath_buf *bf; | 331 | struct ath_buf *bf; |
317 | 332 | ||
333 | avp->is_bslot_active = false; | ||
318 | if (avp->av_bslot != -1) { | 334 | if (avp->av_bslot != -1) { |
319 | sc->beacon.bslot[avp->av_bslot] = NULL; | 335 | sc->beacon.bslot[avp->av_bslot] = NULL; |
320 | sc->beacon.bslot_aphy[avp->av_bslot] = NULL; | ||
321 | sc->nbcnvifs--; | 336 | sc->nbcnvifs--; |
337 | avp->av_bslot = -1; | ||
322 | } | 338 | } |
323 | 339 | ||
324 | bf = avp->av_bcbuf; | 340 | bf = avp->av_bcbuf; |
325 | if (bf->bf_mpdu != NULL) { | 341 | if (bf->bf_mpdu != NULL) { |
326 | struct sk_buff *skb = bf->bf_mpdu; | 342 | struct sk_buff *skb = bf->bf_mpdu; |
327 | dma_unmap_single(sc->dev, bf->bf_dmacontext, | 343 | dma_unmap_single(sc->dev, bf->bf_buf_addr, |
328 | skb->len, DMA_TO_DEVICE); | 344 | skb->len, DMA_TO_DEVICE); |
329 | dev_kfree_skb_any(skb); | 345 | dev_kfree_skb_any(skb); |
330 | bf->bf_mpdu = NULL; | 346 | bf->bf_mpdu = NULL; |
347 | bf->bf_buf_addr = 0; | ||
331 | } | 348 | } |
332 | list_add_tail(&bf->list, &sc->beacon.bbuf); | 349 | list_add_tail(&bf->list, &sc->beacon.bbuf); |
333 | 350 | ||
@@ -338,15 +355,13 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp) | |||
338 | void ath_beacon_tasklet(unsigned long data) | 355 | void ath_beacon_tasklet(unsigned long data) |
339 | { | 356 | { |
340 | struct ath_softc *sc = (struct ath_softc *)data; | 357 | struct ath_softc *sc = (struct ath_softc *)data; |
358 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
341 | struct ath_hw *ah = sc->sc_ah; | 359 | struct ath_hw *ah = sc->sc_ah; |
342 | struct ath_common *common = ath9k_hw_common(ah); | 360 | struct ath_common *common = ath9k_hw_common(ah); |
343 | struct ath_buf *bf = NULL; | 361 | struct ath_buf *bf = NULL; |
344 | struct ieee80211_vif *vif; | 362 | struct ieee80211_vif *vif; |
345 | struct ath_wiphy *aphy; | ||
346 | int slot; | 363 | int slot; |
347 | u32 bfaddr, bc = 0, tsftu; | 364 | u32 bfaddr, bc = 0; |
348 | u64 tsf; | ||
349 | u16 intval; | ||
350 | 365 | ||
351 | /* | 366 | /* |
352 | * Check if the previous beacon has gone out. If | 367 | * Check if the previous beacon has gone out. If |
@@ -358,60 +373,65 @@ void ath_beacon_tasklet(unsigned long data) | |||
358 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { | 373 | if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { |
359 | sc->beacon.bmisscnt++; | 374 | sc->beacon.bmisscnt++; |
360 | 375 | ||
361 | if (sc->beacon.bmisscnt < BSTUCK_THRESH) { | 376 | if (sc->beacon.bmisscnt < BSTUCK_THRESH * sc->nbcnvifs) { |
362 | ath_print(common, ATH_DBG_BEACON, | 377 | ath_dbg(common, ATH_DBG_BSTUCK, |
363 | "missed %u consecutive beacons\n", | 378 | "missed %u consecutive beacons\n", |
364 | sc->beacon.bmisscnt); | 379 | sc->beacon.bmisscnt); |
380 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); | ||
381 | if (sc->beacon.bmisscnt > 3) | ||
382 | ath9k_hw_bstuck_nfcal(ah); | ||
365 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { | 383 | } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { |
366 | ath_print(common, ATH_DBG_BEACON, | 384 | ath_dbg(common, ATH_DBG_BSTUCK, |
367 | "beacon is officially stuck\n"); | 385 | "beacon is officially stuck\n"); |
368 | sc->sc_flags |= SC_OP_TSF_RESET; | 386 | sc->sc_flags |= SC_OP_TSF_RESET; |
369 | ath_reset(sc, false); | 387 | ath_reset(sc, true); |
370 | } | 388 | } |
371 | 389 | ||
372 | return; | 390 | return; |
373 | } | 391 | } |
374 | 392 | ||
375 | if (sc->beacon.bmisscnt != 0) { | ||
376 | ath_print(common, ATH_DBG_BEACON, | ||
377 | "resume beacon xmit after %u misses\n", | ||
378 | sc->beacon.bmisscnt); | ||
379 | sc->beacon.bmisscnt = 0; | ||
380 | } | ||
381 | |||
382 | /* | 393 | /* |
383 | * Generate beacon frames. we are sending frames | 394 | * Generate beacon frames. we are sending frames |
384 | * staggered so calculate the slot for this frame based | 395 | * staggered so calculate the slot for this frame based |
385 | * on the tsf to safeguard against missing an swba. | 396 | * on the tsf to safeguard against missing an swba. |
386 | */ | 397 | */ |
387 | 398 | ||
388 | intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL; | ||
389 | 399 | ||
390 | tsf = ath9k_hw_gettsf64(ah); | 400 | if (ah->opmode == NL80211_IFTYPE_AP) { |
391 | tsftu = TSF_TO_TU(tsf>>32, tsf); | 401 | u16 intval; |
392 | slot = ((tsftu % intval) * ATH_BCBUF) / intval; | 402 | u32 tsftu; |
393 | /* | 403 | u64 tsf; |
394 | * Reverse the slot order to get slot 0 on the TBTT offset that does | 404 | |
395 | * not require TSF adjustment and other slots adding | 405 | intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; |
396 | * slot/ATH_BCBUF * beacon_int to timestamp. For example, with | 406 | tsf = ath9k_hw_gettsf64(ah); |
397 | * ATH_BCBUF = 4, we process beacon slots as follows: 3 2 1 0 3 2 1 .. | 407 | tsf += TU_TO_USEC(ah->config.sw_beacon_response_time); |
398 | * and slot 0 is at correct offset to TBTT. | 408 | tsftu = TSF_TO_TU((tsf * ATH_BCBUF) >>32, tsf * ATH_BCBUF); |
399 | */ | 409 | slot = (tsftu % (intval * ATH_BCBUF)) / intval; |
400 | slot = ATH_BCBUF - slot - 1; | 410 | vif = sc->beacon.bslot[slot]; |
401 | vif = sc->beacon.bslot[slot]; | 411 | |
402 | aphy = sc->beacon.bslot_aphy[slot]; | 412 | ath_dbg(common, ATH_DBG_BEACON, |
413 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | ||
414 | slot, tsf, tsftu / ATH_BCBUF, intval, vif); | ||
415 | } else { | ||
416 | slot = 0; | ||
417 | vif = sc->beacon.bslot[slot]; | ||
418 | } | ||
403 | 419 | ||
404 | ath_print(common, ATH_DBG_BEACON, | ||
405 | "slot %d [tsf %llu tsftu %u intval %u] vif %p\n", | ||
406 | slot, tsf, tsftu, intval, vif); | ||
407 | 420 | ||
408 | bfaddr = 0; | 421 | bfaddr = 0; |
409 | if (vif) { | 422 | if (vif) { |
410 | bf = ath_beacon_generate(aphy->hw, vif); | 423 | bf = ath_beacon_generate(sc->hw, vif); |
411 | if (bf != NULL) { | 424 | if (bf != NULL) { |
412 | bfaddr = bf->bf_daddr; | 425 | bfaddr = bf->bf_daddr; |
413 | bc = 1; | 426 | bc = 1; |
414 | } | 427 | } |
428 | |||
429 | if (sc->beacon.bmisscnt != 0) { | ||
430 | ath_dbg(common, ATH_DBG_BSTUCK, | ||
431 | "resume beacon xmit after %u misses\n", | ||
432 | sc->beacon.bmisscnt); | ||
433 | sc->beacon.bmisscnt = 0; | ||
434 | } | ||
415 | } | 435 | } |
416 | 436 | ||
417 | /* | 437 | /* |
@@ -439,16 +459,6 @@ void ath_beacon_tasklet(unsigned long data) | |||
439 | sc->beacon.updateslot = OK; | 459 | sc->beacon.updateslot = OK; |
440 | } | 460 | } |
441 | if (bfaddr != 0) { | 461 | if (bfaddr != 0) { |
442 | /* | ||
443 | * Stop any current dma and put the new frame(s) on the queue. | ||
444 | * This should never fail since we check above that no frames | ||
445 | * are still pending on the queue. | ||
446 | */ | ||
447 | if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { | ||
448 | ath_print(common, ATH_DBG_FATAL, | ||
449 | "beacon queue %u did not stop?\n", sc->beacon.beaconq); | ||
450 | } | ||
451 | |||
452 | /* NB: cabq traffic should already be queued and primed */ | 462 | /* NB: cabq traffic should already be queued and primed */ |
453 | ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); | 463 | ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); |
454 | ath9k_hw_txstart(ah, sc->beacon.beaconq); | 464 | ath9k_hw_txstart(ah, sc->beacon.beaconq); |
@@ -461,13 +471,17 @@ static void ath9k_beacon_init(struct ath_softc *sc, | |||
461 | u32 next_beacon, | 471 | u32 next_beacon, |
462 | u32 beacon_period) | 472 | u32 beacon_period) |
463 | { | 473 | { |
464 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 474 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
465 | ath9k_ps_wakeup(sc); | 475 | ath9k_ps_wakeup(sc); |
476 | ath9k_hw_reset_tsf(sc->sc_ah); | ||
477 | } | ||
466 | 478 | ||
467 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); | 479 | ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period); |
468 | 480 | ||
469 | if (beacon_period & ATH9K_BEACON_RESET_TSF) | 481 | if (sc->sc_flags & SC_OP_TSF_RESET) { |
470 | ath9k_ps_restore(sc); | 482 | ath9k_ps_restore(sc); |
483 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
484 | } | ||
471 | } | 485 | } |
472 | 486 | ||
473 | /* | 487 | /* |
@@ -482,32 +496,23 @@ static void ath_beacon_config_ap(struct ath_softc *sc, | |||
482 | u32 nexttbtt, intval; | 496 | u32 nexttbtt, intval; |
483 | 497 | ||
484 | /* NB: the beacon interval is kept internally in TU's */ | 498 | /* NB: the beacon interval is kept internally in TU's */ |
485 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | 499 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
486 | intval /= ATH_BCBUF; /* for staggered beacons */ | 500 | intval /= ATH_BCBUF; /* for staggered beacons */ |
487 | nexttbtt = intval; | 501 | nexttbtt = intval; |
488 | 502 | ||
489 | if (sc->sc_flags & SC_OP_TSF_RESET) | ||
490 | intval |= ATH9K_BEACON_RESET_TSF; | ||
491 | |||
492 | /* | 503 | /* |
493 | * In AP mode we enable the beacon timers and SWBA interrupts to | 504 | * In AP mode we enable the beacon timers and SWBA interrupts to |
494 | * prepare beacon frames. | 505 | * prepare beacon frames. |
495 | */ | 506 | */ |
496 | intval |= ATH9K_BEACON_ENA; | ||
497 | ah->imask |= ATH9K_INT_SWBA; | 507 | ah->imask |= ATH9K_INT_SWBA; |
498 | ath_beaconq_config(sc); | 508 | ath_beaconq_config(sc); |
499 | 509 | ||
500 | /* Set the computed AP beacon timers */ | 510 | /* Set the computed AP beacon timers */ |
501 | 511 | ||
502 | ath9k_hw_set_interrupts(ah, 0); | 512 | ath9k_hw_disable_interrupts(ah); |
503 | ath9k_beacon_init(sc, nexttbtt, intval); | 513 | ath9k_beacon_init(sc, nexttbtt, intval); |
504 | sc->beacon.bmisscnt = 0; | 514 | sc->beacon.bmisscnt = 0; |
505 | ath9k_hw_set_interrupts(ah, ah->imask); | 515 | ath9k_hw_set_interrupts(ah, ah->imask); |
506 | |||
507 | /* Clear the reset TSF flag, so that subsequent beacon updation | ||
508 | will not reset the HW TSF. */ | ||
509 | |||
510 | sc->sc_flags &= ~SC_OP_TSF_RESET; | ||
511 | } | 516 | } |
512 | 517 | ||
513 | /* | 518 | /* |
@@ -532,8 +537,8 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
532 | 537 | ||
533 | /* No need to configure beacon if we are not associated */ | 538 | /* No need to configure beacon if we are not associated */ |
534 | if (!common->curaid) { | 539 | if (!common->curaid) { |
535 | ath_print(common, ATH_DBG_BEACON, | 540 | ath_dbg(common, ATH_DBG_BEACON, |
536 | "STA is not yet associated..skipping beacon config\n"); | 541 | "STA is not yet associated..skipping beacon config\n"); |
537 | return; | 542 | return; |
538 | } | 543 | } |
539 | 544 | ||
@@ -545,8 +550,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
545 | * last beacon we received (which may be none). | 550 | * last beacon we received (which may be none). |
546 | */ | 551 | */ |
547 | dtimperiod = conf->dtim_period; | 552 | dtimperiod = conf->dtim_period; |
548 | if (dtimperiod <= 0) /* NB: 0 if not known */ | ||
549 | dtimperiod = 1; | ||
550 | dtimcount = conf->dtim_count; | 553 | dtimcount = conf->dtim_count; |
551 | if (dtimcount >= dtimperiod) /* NB: sanity check */ | 554 | if (dtimcount >= dtimperiod) /* NB: sanity check */ |
552 | dtimcount = 0; | 555 | dtimcount = 0; |
@@ -554,8 +557,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
554 | cfpcount = 0; | 557 | cfpcount = 0; |
555 | 558 | ||
556 | sleepduration = conf->listen_interval * intval; | 559 | sleepduration = conf->listen_interval * intval; |
557 | if (sleepduration <= 0) | ||
558 | sleepduration = intval; | ||
559 | 560 | ||
560 | /* | 561 | /* |
561 | * Pull nexttbtt forward to reflect the current | 562 | * Pull nexttbtt forward to reflect the current |
@@ -626,89 +627,135 @@ static void ath_beacon_config_sta(struct ath_softc *sc, | |||
626 | /* TSF out of range threshold fixed at 1 second */ | 627 | /* TSF out of range threshold fixed at 1 second */ |
627 | bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; | 628 | bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD; |
628 | 629 | ||
629 | ath_print(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); | 630 | ath_dbg(common, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu); |
630 | ath_print(common, ATH_DBG_BEACON, | 631 | ath_dbg(common, ATH_DBG_BEACON, |
631 | "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", | 632 | "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n", |
632 | bs.bs_bmissthreshold, bs.bs_sleepduration, | 633 | bs.bs_bmissthreshold, bs.bs_sleepduration, |
633 | bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); | 634 | bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext); |
634 | 635 | ||
635 | /* Set the computed STA beacon timers */ | 636 | /* Set the computed STA beacon timers */ |
636 | 637 | ||
637 | ath9k_hw_set_interrupts(ah, 0); | 638 | ath9k_hw_disable_interrupts(ah); |
638 | ath9k_hw_set_sta_beacon_timers(ah, &bs); | 639 | ath9k_hw_set_sta_beacon_timers(ah, &bs); |
639 | ah->imask |= ATH9K_INT_BMISS; | 640 | ah->imask |= ATH9K_INT_BMISS; |
640 | ath9k_hw_set_interrupts(ah, ah->imask); | 641 | |
642 | /* | ||
643 | * If the beacon config is called beacause of TSFOOR, | ||
644 | * Interrupts will be enabled back at the end of ath9k_tasklet | ||
645 | */ | ||
646 | if (!(sc->ps_flags & PS_TSFOOR_SYNC)) | ||
647 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
641 | } | 648 | } |
642 | 649 | ||
643 | static void ath_beacon_config_adhoc(struct ath_softc *sc, | 650 | static void ath_beacon_config_adhoc(struct ath_softc *sc, |
644 | struct ath_beacon_config *conf, | 651 | struct ath_beacon_config *conf) |
645 | struct ieee80211_vif *vif) | ||
646 | { | 652 | { |
647 | struct ath_hw *ah = sc->sc_ah; | 653 | struct ath_hw *ah = sc->sc_ah; |
648 | struct ath_common *common = ath9k_hw_common(ah); | 654 | struct ath_common *common = ath9k_hw_common(ah); |
649 | u64 tsf; | 655 | u32 tsf, delta, intval, nexttbtt; |
650 | u32 tsftu, intval, nexttbtt; | ||
651 | |||
652 | intval = conf->beacon_interval & ATH9K_BEACON_PERIOD; | ||
653 | |||
654 | 656 | ||
655 | /* Pull nexttbtt forward to reflect the current TSF */ | 657 | ath9k_reset_beacon_status(sc); |
656 | 658 | ||
657 | nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); | 659 | tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE); |
658 | if (nexttbtt == 0) | 660 | intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD); |
659 | nexttbtt = intval; | ||
660 | else if (intval) | ||
661 | nexttbtt = roundup(nexttbtt, intval); | ||
662 | 661 | ||
663 | tsf = ath9k_hw_gettsf64(ah); | 662 | if (!sc->beacon.bc_tstamp) |
664 | tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE; | 663 | nexttbtt = tsf + intval; |
665 | do { | 664 | else { |
666 | nexttbtt += intval; | 665 | if (tsf > sc->beacon.bc_tstamp) |
667 | } while (nexttbtt < tsftu); | 666 | delta = (tsf - sc->beacon.bc_tstamp); |
667 | else | ||
668 | delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp)); | ||
669 | nexttbtt = tsf + intval - (delta % intval); | ||
670 | } | ||
668 | 671 | ||
669 | ath_print(common, ATH_DBG_BEACON, | 672 | ath_dbg(common, ATH_DBG_BEACON, |
670 | "IBSS nexttbtt %u intval %u (%u)\n", | 673 | "IBSS nexttbtt %u intval %u (%u)\n", |
671 | nexttbtt, intval, conf->beacon_interval); | 674 | nexttbtt, intval, conf->beacon_interval); |
672 | 675 | ||
673 | /* | 676 | /* |
674 | * In IBSS mode enable the beacon timers but only enable SWBA interrupts | 677 | * In IBSS mode enable the beacon timers but only enable SWBA interrupts |
675 | * if we need to manually prepare beacon frames. Otherwise we use a | 678 | * if we need to manually prepare beacon frames. Otherwise we use a |
676 | * self-linked tx descriptor and let the hardware deal with things. | 679 | * self-linked tx descriptor and let the hardware deal with things. |
677 | */ | 680 | */ |
678 | intval |= ATH9K_BEACON_ENA; | ||
679 | ah->imask |= ATH9K_INT_SWBA; | 681 | ah->imask |= ATH9K_INT_SWBA; |
680 | 682 | ||
681 | ath_beaconq_config(sc); | 683 | ath_beaconq_config(sc); |
682 | 684 | ||
683 | /* Set the computed ADHOC beacon timers */ | 685 | /* Set the computed ADHOC beacon timers */ |
684 | 686 | ||
685 | ath9k_hw_set_interrupts(ah, 0); | 687 | ath9k_hw_disable_interrupts(ah); |
686 | ath9k_beacon_init(sc, nexttbtt, intval); | 688 | ath9k_beacon_init(sc, nexttbtt, intval); |
687 | sc->beacon.bmisscnt = 0; | 689 | sc->beacon.bmisscnt = 0; |
688 | ath9k_hw_set_interrupts(ah, ah->imask); | 690 | /* |
691 | * If the beacon config is called beacause of TSFOOR, | ||
692 | * Interrupts will be enabled back at the end of ath9k_tasklet | ||
693 | */ | ||
694 | if (!(sc->ps_flags & PS_TSFOOR_SYNC)) | ||
695 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
689 | } | 696 | } |
690 | 697 | ||
691 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | 698 | static bool ath9k_allow_beacon_config(struct ath_softc *sc, |
699 | struct ieee80211_vif *vif) | ||
692 | { | 700 | { |
693 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | 701 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; |
694 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 702 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
695 | enum nl80211_iftype iftype; | 703 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
704 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
696 | 705 | ||
697 | /* Setup the beacon configuration parameters */ | 706 | /* |
698 | if (vif) { | 707 | * Can not have different beacon interval on multiple |
699 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 708 | * AP interface case |
709 | */ | ||
710 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && | ||
711 | (sc->nbcnvifs > 1) && | ||
712 | (vif->type == NL80211_IFTYPE_AP) && | ||
713 | (cur_conf->beacon_interval != bss_conf->beacon_int)) { | ||
714 | ath_dbg(common, ATH_DBG_CONFIG, | ||
715 | "Changing beacon interval of multiple \ | ||
716 | AP interfaces !\n"); | ||
717 | return false; | ||
718 | } | ||
719 | /* | ||
720 | * Can not configure station vif's beacon config | ||
721 | * while on AP opmode | ||
722 | */ | ||
723 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) && | ||
724 | (vif->type != NL80211_IFTYPE_AP)) { | ||
725 | ath_dbg(common, ATH_DBG_CONFIG, | ||
726 | "STA vif's beacon not allowed on AP mode\n"); | ||
727 | return false; | ||
728 | } | ||
729 | /* | ||
730 | * Do not allow beacon config if HW was already configured | ||
731 | * with another STA vif | ||
732 | */ | ||
733 | if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) && | ||
734 | (vif->type == NL80211_IFTYPE_STATION) && | ||
735 | (sc->sc_flags & SC_OP_BEACONS) && | ||
736 | !avp->primary_sta_vif) { | ||
737 | ath_dbg(common, ATH_DBG_CONFIG, | ||
738 | "Beacon already configured for a station interface\n"); | ||
739 | return false; | ||
740 | } | ||
741 | return true; | ||
742 | } | ||
700 | 743 | ||
701 | iftype = vif->type; | 744 | void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) |
745 | { | ||
746 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
747 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
702 | 748 | ||
703 | cur_conf->beacon_interval = bss_conf->beacon_int; | 749 | if (!ath9k_allow_beacon_config(sc, vif)) |
704 | cur_conf->dtim_period = bss_conf->dtim_period; | 750 | return; |
705 | cur_conf->listen_interval = 1; | 751 | |
706 | cur_conf->dtim_count = 1; | 752 | /* Setup the beacon configuration parameters */ |
707 | cur_conf->bmiss_timeout = | 753 | cur_conf->beacon_interval = bss_conf->beacon_int; |
708 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | 754 | cur_conf->dtim_period = bss_conf->dtim_period; |
709 | } else { | 755 | cur_conf->listen_interval = 1; |
710 | iftype = sc->sc_ah->opmode; | 756 | cur_conf->dtim_count = 1; |
711 | } | 757 | cur_conf->bmiss_timeout = |
758 | ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval; | ||
712 | 759 | ||
713 | /* | 760 | /* |
714 | * It looks like mac80211 may end up using beacon interval of zero in | 761 | * It looks like mac80211 may end up using beacon interval of zero in |
@@ -719,22 +766,80 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif) | |||
719 | if (cur_conf->beacon_interval == 0) | 766 | if (cur_conf->beacon_interval == 0) |
720 | cur_conf->beacon_interval = 100; | 767 | cur_conf->beacon_interval = 100; |
721 | 768 | ||
722 | switch (iftype) { | 769 | /* |
770 | * We don't parse dtim period from mac80211 during the driver | ||
771 | * initialization as it breaks association with hidden-ssid | ||
772 | * AP and it causes latency in roaming | ||
773 | */ | ||
774 | if (cur_conf->dtim_period == 0) | ||
775 | cur_conf->dtim_period = 1; | ||
776 | |||
777 | ath_set_beacon(sc); | ||
778 | } | ||
779 | |||
780 | static bool ath_has_valid_bslot(struct ath_softc *sc) | ||
781 | { | ||
782 | struct ath_vif *avp; | ||
783 | int slot; | ||
784 | bool found = false; | ||
785 | |||
786 | for (slot = 0; slot < ATH_BCBUF; slot++) { | ||
787 | if (sc->beacon.bslot[slot]) { | ||
788 | avp = (void *)sc->beacon.bslot[slot]->drv_priv; | ||
789 | if (avp->is_bslot_active) { | ||
790 | found = true; | ||
791 | break; | ||
792 | } | ||
793 | } | ||
794 | } | ||
795 | return found; | ||
796 | } | ||
797 | |||
798 | |||
799 | void ath_set_beacon(struct ath_softc *sc) | ||
800 | { | ||
801 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
802 | struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf; | ||
803 | |||
804 | switch (sc->sc_ah->opmode) { | ||
723 | case NL80211_IFTYPE_AP: | 805 | case NL80211_IFTYPE_AP: |
724 | ath_beacon_config_ap(sc, cur_conf); | 806 | if (ath_has_valid_bslot(sc)) |
807 | ath_beacon_config_ap(sc, cur_conf); | ||
725 | break; | 808 | break; |
726 | case NL80211_IFTYPE_ADHOC: | 809 | case NL80211_IFTYPE_ADHOC: |
727 | case NL80211_IFTYPE_MESH_POINT: | 810 | case NL80211_IFTYPE_MESH_POINT: |
728 | ath_beacon_config_adhoc(sc, cur_conf, vif); | 811 | ath_beacon_config_adhoc(sc, cur_conf); |
729 | break; | 812 | break; |
730 | case NL80211_IFTYPE_STATION: | 813 | case NL80211_IFTYPE_STATION: |
731 | ath_beacon_config_sta(sc, cur_conf); | 814 | ath_beacon_config_sta(sc, cur_conf); |
732 | break; | 815 | break; |
733 | default: | 816 | default: |
734 | ath_print(common, ATH_DBG_CONFIG, | 817 | ath_dbg(common, ATH_DBG_CONFIG, |
735 | "Unsupported beaconing mode\n"); | 818 | "Unsupported beaconing mode\n"); |
736 | return; | 819 | return; |
737 | } | 820 | } |
738 | 821 | ||
739 | sc->sc_flags |= SC_OP_BEACONS; | 822 | sc->sc_flags |= SC_OP_BEACONS; |
740 | } | 823 | } |
824 | |||
825 | void ath9k_set_beaconing_status(struct ath_softc *sc, bool status) | ||
826 | { | ||
827 | struct ath_hw *ah = sc->sc_ah; | ||
828 | |||
829 | if (!ath_has_valid_bslot(sc)) | ||
830 | return; | ||
831 | |||
832 | ath9k_ps_wakeup(sc); | ||
833 | if (status) { | ||
834 | /* Re-enable beaconing */ | ||
835 | ah->imask |= ATH9K_INT_SWBA; | ||
836 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
837 | } else { | ||
838 | /* Disable SWBA interrupt */ | ||
839 | ah->imask &= ~ATH9K_INT_SWBA; | ||
840 | ath9k_hw_set_interrupts(ah, ah->imask); | ||
841 | tasklet_kill(&sc->bcon_tasklet); | ||
842 | ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq); | ||
843 | } | ||
844 | ath9k_ps_restore(sc); | ||
845 | } | ||