aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/beacon.c141
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c48
3 files changed, 47 insertions, 146 deletions
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 3e7a5726652..9dd8fbb847f 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -416,8 +416,8 @@ struct ath_beacon {
416 416
417void ath_beacon_tasklet(unsigned long data); 417void ath_beacon_tasklet(unsigned long data);
418void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif); 418void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
419int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif); 419void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
420void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp); 420void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
421int ath_beaconq_config(struct ath_softc *sc); 421int ath_beaconq_config(struct ath_softc *sc);
422void ath_set_beacon(struct ath_softc *sc); 422void ath_set_beacon(struct ath_softc *sc);
423void ath9k_set_beaconing_status(struct ath_softc *sc, bool status); 423void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
diff --git a/drivers/net/wireless/ath/ath9k/beacon.c b/drivers/net/wireless/ath/ath9k/beacon.c
index 40775da8941..d35700287d6 100644
--- a/drivers/net/wireless/ath/ath9k/beacon.c
+++ b/drivers/net/wireless/ath/ath9k/beacon.c
@@ -222,132 +222,57 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
222 return bf; 222 return bf;
223} 223}
224 224
225int ath_beacon_alloc(struct ath_softc *sc, struct ieee80211_vif *vif) 225void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
226{ 226{
227 struct ath_common *common = ath9k_hw_common(sc->sc_ah); 227 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
228 struct ath_vif *avp; 228 struct ath_vif *avp = (void *)vif->drv_priv;
229 struct ath_buf *bf; 229 int slot;
230 struct sk_buff *skb;
231 struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
232 __le64 tstamp;
233 230
234 avp = (void *)vif->drv_priv; 231 avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list);
232 list_del(&avp->av_bcbuf->list);
235 233
236 /* Allocate a beacon descriptor if we haven't done so. */ 234 for (slot = 0; slot < ATH_BCBUF; slot++) {
237 if (!avp->av_bcbuf) { 235 if (sc->beacon.bslot[slot] == NULL) {
238 /* Allocate beacon state for hostap/ibss. We know 236 avp->av_bslot = slot;
239 * a buffer is available. */ 237 avp->is_bslot_active = false;
240 avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, 238 break;
241 struct ath_buf, list);
242 list_del(&avp->av_bcbuf->list);
243
244 if (ath9k_uses_beacons(vif->type)) {
245 int slot;
246 /*
247 * Assign the vif to a beacon xmit slot. As
248 * above, this cannot fail to find one.
249 */
250 avp->av_bslot = 0;
251 for (slot = 0; slot < ATH_BCBUF; slot++)
252 if (sc->beacon.bslot[slot] == NULL) {
253 avp->av_bslot = slot;
254 avp->is_bslot_active = false;
255
256 /* NB: keep looking for a double slot */
257 if (slot == 0 || !sc->beacon.bslot[slot-1])
258 break;
259 }
260 BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
261 sc->beacon.bslot[avp->av_bslot] = vif;
262 sc->nbcnvifs++;
263 } 239 }
264 } 240 }
265 241
266 /* release the previous beacon frame, if it already exists. */ 242 sc->beacon.bslot[avp->av_bslot] = vif;
267 bf = avp->av_bcbuf; 243 sc->nbcnvifs++;
268 if (bf->bf_mpdu != NULL) {
269 skb = bf->bf_mpdu;
270 dma_unmap_single(sc->dev, bf->bf_buf_addr,
271 skb->len, DMA_TO_DEVICE);
272 dev_kfree_skb_any(skb);
273 bf->bf_mpdu = NULL;
274 bf->bf_buf_addr = 0;
275 }
276
277 /* NB: the beacon data buffer must be 32-bit aligned. */
278 skb = ieee80211_beacon_get(sc->hw, vif);
279 if (skb == NULL)
280 return -ENOMEM;
281
282 tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
283 sc->beacon.bc_tstamp = (u32) le64_to_cpu(tstamp);
284 /* Calculate a TSF adjustment factor required for staggered beacons. */
285 if (avp->av_bslot > 0) {
286 u64 tsfadjust;
287 int intval;
288 244
289 intval = cur_conf->beacon_interval ? : ATH_DEFAULT_BINTVAL; 245 ath_dbg(common, CONFIG, "Added interface at beacon slot: %d\n",
246 avp->av_bslot);
247}
290 248
291 /* 249void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif)
292 * Calculate the TSF offset for this beacon slot, i.e., the 250{
293 * number of usecs that need to be added to the timestamp field 251 struct ath_common *common = ath9k_hw_common(sc->sc_ah);
294 * in Beacon and Probe Response frames. Beacon slot 0 is 252 struct ath_vif *avp = (void *)vif->drv_priv;
295 * processed at the correct offset, so it does not require TSF 253 struct ath_buf *bf = avp->av_bcbuf;
296 * adjustment. Other slots are adjusted to get the timestamp
297 * close to the TBTT for the BSS.
298 */
299 tsfadjust = TU_TO_USEC(intval * avp->av_bslot) / ATH_BCBUF;
300 avp->tsf_adjust = cpu_to_le64(tsfadjust);
301 254
302 ath_dbg(common, BEACON, 255 ath_dbg(common, CONFIG, "Removing interface at beacon slot: %d\n",
303 "stagger beacons, bslot %d intval %u tsfadjust %llu\n", 256 avp->av_bslot);
304 avp->av_bslot, intval, (unsigned long long)tsfadjust);
305 257
306 ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp = 258 tasklet_disable(&sc->bcon_tasklet);
307 avp->tsf_adjust;
308 } else
309 avp->tsf_adjust = cpu_to_le64(0);
310 259
311 bf->bf_mpdu = skb; 260 if (bf && bf->bf_mpdu) {
312 bf->bf_buf_addr = dma_map_single(sc->dev, skb->data, 261 struct sk_buff *skb = bf->bf_mpdu;
313 skb->len, DMA_TO_DEVICE); 262 dma_unmap_single(sc->dev, bf->bf_buf_addr,
314 if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) { 263 skb->len, DMA_TO_DEVICE);
315 dev_kfree_skb_any(skb); 264 dev_kfree_skb_any(skb);
316 bf->bf_mpdu = NULL; 265 bf->bf_mpdu = NULL;
317 bf->bf_buf_addr = 0; 266 bf->bf_buf_addr = 0;
318 ath_err(common, "dma_mapping_error on beacon alloc\n");
319 return -ENOMEM;
320 } 267 }
321 avp->is_bslot_active = true;
322
323 return 0;
324}
325
326void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
327{
328 if (avp->av_bcbuf != NULL) {
329 struct ath_buf *bf;
330
331 avp->is_bslot_active = false;
332 if (avp->av_bslot != -1) {
333 sc->beacon.bslot[avp->av_bslot] = NULL;
334 sc->nbcnvifs--;
335 avp->av_bslot = -1;
336 }
337 268
338 bf = avp->av_bcbuf; 269 avp->av_bcbuf = NULL;
339 if (bf->bf_mpdu != NULL) { 270 avp->is_bslot_active = false;
340 struct sk_buff *skb = bf->bf_mpdu; 271 sc->beacon.bslot[avp->av_bslot] = NULL;
341 dma_unmap_single(sc->dev, bf->bf_buf_addr, 272 sc->nbcnvifs--;
342 skb->len, DMA_TO_DEVICE); 273 list_add_tail(&bf->list, &sc->beacon.bbuf);
343 dev_kfree_skb_any(skb);
344 bf->bf_mpdu = NULL;
345 bf->bf_buf_addr = 0;
346 }
347 list_add_tail(&bf->list, &sc->beacon.bbuf);
348 274
349 avp->av_bcbuf = NULL; 275 tasklet_enable(&sc->bcon_tasklet);
350 }
351} 276}
352 277
353void ath_beacon_tasklet(unsigned long data) 278void ath_beacon_tasklet(unsigned long data)
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index a07f69c1e9e..f7d92e0ba4d 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -852,16 +852,6 @@ bool ath9k_uses_beacons(int type)
852 } 852 }
853} 853}
854 854
855static void ath9k_reclaim_beacon(struct ath_softc *sc,
856 struct ieee80211_vif *vif)
857{
858 struct ath_vif *avp = (void *)vif->drv_priv;
859
860 ath9k_set_beaconing_status(sc, false);
861 ath_beacon_return(sc, avp);
862 ath9k_set_beaconing_status(sc, true);
863}
864
865static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) 855static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
866{ 856{
867 struct ath9k_vif_iter_data *iter_data = data; 857 struct ath9k_vif_iter_data *iter_data = data;
@@ -977,22 +967,6 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
977 } 967 }
978} 968}
979 969
980/* Called with sc->mutex held, vif counts set up properly. */
981static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw,
982 struct ieee80211_vif *vif)
983{
984 struct ath_softc *sc = hw->priv;
985
986 ath9k_calculate_summary_state(hw, vif);
987
988 if (ath9k_uses_beacons(vif->type)) {
989 /* Reserve a beacon slot for the vif */
990 ath9k_set_beaconing_status(sc, false);
991 ath_beacon_alloc(sc, vif);
992 ath9k_set_beaconing_status(sc, true);
993 }
994}
995
996static int ath9k_add_interface(struct ieee80211_hw *hw, 970static int ath9k_add_interface(struct ieee80211_hw *hw,
997 struct ieee80211_vif *vif) 971 struct ieee80211_vif *vif)
998{ 972{
@@ -1032,7 +1006,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
1032 1006
1033 sc->nvifs++; 1007 sc->nvifs++;
1034 1008
1035 ath9k_do_vif_add_setup(hw, vif); 1009 ath9k_calculate_summary_state(hw, vif);
1010 if (ath9k_uses_beacons(vif->type))
1011 ath9k_beacon_assign_slot(sc, vif);
1012
1036out: 1013out:
1037 mutex_unlock(&sc->mutex); 1014 mutex_unlock(&sc->mutex);
1038 ath9k_ps_restore(sc); 1015 ath9k_ps_restore(sc);
@@ -1049,6 +1026,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
1049 int ret = 0; 1026 int ret = 0;
1050 1027
1051 ath_dbg(common, CONFIG, "Change Interface\n"); 1028 ath_dbg(common, CONFIG, "Change Interface\n");
1029
1052 mutex_lock(&sc->mutex); 1030 mutex_lock(&sc->mutex);
1053 ath9k_ps_wakeup(sc); 1031 ath9k_ps_wakeup(sc);
1054 1032
@@ -1061,15 +1039,16 @@ static int ath9k_change_interface(struct ieee80211_hw *hw,
1061 } 1039 }
1062 } 1040 }
1063 1041
1064 /* Clean up old vif stuff */
1065 if (ath9k_uses_beacons(vif->type)) 1042 if (ath9k_uses_beacons(vif->type))
1066 ath9k_reclaim_beacon(sc, vif); 1043 ath9k_beacon_remove_slot(sc, vif);
1067 1044
1068 /* Add new settings */
1069 vif->type = new_type; 1045 vif->type = new_type;
1070 vif->p2p = p2p; 1046 vif->p2p = p2p;
1071 1047
1072 ath9k_do_vif_add_setup(hw, vif); 1048 ath9k_calculate_summary_state(hw, vif);
1049 if (ath9k_uses_beacons(vif->type))
1050 ath9k_beacon_assign_slot(sc, vif);
1051
1073out: 1052out:
1074 ath9k_ps_restore(sc); 1053 ath9k_ps_restore(sc);
1075 mutex_unlock(&sc->mutex); 1054 mutex_unlock(&sc->mutex);
@@ -1089,9 +1068,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
1089 1068
1090 sc->nvifs--; 1069 sc->nvifs--;
1091 1070
1092 /* Reclaim beacon resources */
1093 if (ath9k_uses_beacons(vif->type)) 1071 if (ath9k_uses_beacons(vif->type))
1094 ath9k_reclaim_beacon(sc, vif); 1072 ath9k_beacon_remove_slot(sc, vif);
1095 1073
1096 ath9k_calculate_summary_state(hw, NULL); 1074 ath9k_calculate_summary_state(hw, NULL);
1097 1075
@@ -1610,9 +1588,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
1610 (changed & BSS_CHANGED_BEACON_ENABLED) || 1588 (changed & BSS_CHANGED_BEACON_ENABLED) ||
1611 (changed & BSS_CHANGED_BEACON_INT))) { 1589 (changed & BSS_CHANGED_BEACON_INT))) {
1612 ath9k_set_beaconing_status(sc, false); 1590 ath9k_set_beaconing_status(sc, false);
1613 if (bss_conf->enable_beacon) 1591 if (!bss_conf->enable_beacon)
1614 ath_beacon_alloc(sc, vif);
1615 else
1616 avp->is_bslot_active = false; 1592 avp->is_bslot_active = false;
1617 ath_beacon_config(sc, vif); 1593 ath_beacon_config(sc, vif);
1618 ath9k_set_beaconing_status(sc, true); 1594 ath9k_set_beaconing_status(sc, true);