ath9k: change beacon allocation to prefer the first beacon slot
[safe/jmp/linux-2.6] / drivers / net / wireless / ath / ath9k / beacon.c
index 1660ef1..77face7 100644 (file)
@@ -62,7 +62,7 @@ int ath_beaconq_config(struct ath_softc *sc)
  *  Beacons are always sent out at the lowest rate, and are not retried.
 */
 static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
-                            struct ath_buf *bf)
+                            struct ath_buf *bf, int rateidx)
 {
        struct sk_buff *skb = bf->bf_mpdu;
        struct ath_hw *ah = sc->sc_ah;
@@ -93,12 +93,10 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
                antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
        }
 
-       ds->ds_data = bf->bf_buf_addr;
-
        sband = &sc->sbands[common->hw->conf.channel->band];
-       rate = sband->bitrates[0].hw_value;
+       rate = sband->bitrates[rateidx].hw_value;
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-               rate |= sband->bitrates[0].hw_value_short;
+               rate |= sband->bitrates[rateidx].hw_value_short;
 
        ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
                               ATH9K_PKT_TYPE_BEACON,
@@ -109,7 +107,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
 
        /* NB: beacon's BufLen must be a multiple of 4 bytes */
        ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
-                           true, true, ds);
+                           true, true, ds, bf->bf_buf_addr,
+                           sc->beacon.beaconq);
 
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
        series[0].Tries = 1;
@@ -206,7 +205,7 @@ static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
                }
        }
 
-       ath_beacon_setup(sc, avp, bf);
+       ath_beacon_setup(sc, avp, bf, info->control.rates[0].idx);
 
        while (skb) {
                ath_tx_cabq(hw, skb);
@@ -237,7 +236,7 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc,
        bf = avp->av_bcbuf;
        skb = bf->bf_mpdu;
 
-       ath_beacon_setup(sc, avp, bf);
+       ath_beacon_setup(sc, avp, bf, 0);
 
        /* NB: caller is known to have already stopped tx dma */
        ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr);
@@ -275,17 +274,11 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
                        avp->av_bslot = 0;
                        for (slot = 0; slot < ATH_BCBUF; slot++)
                                if (sc->beacon.bslot[slot] == NULL) {
-                                       /*
-                                        * XXX hack, space out slots to better
-                                        * deal with misses
-                                        */
-                                       if (slot+1 < ATH_BCBUF &&
-                                           sc->beacon.bslot[slot+1] == NULL) {
-                                               avp->av_bslot = slot+1;
-                                               break;
-                                       }
                                        avp->av_bslot = slot;
+
                                        /* NB: keep looking for a double slot */
+                                       if (slot == 0 || !sc->beacon.bslot[slot-1])
+                                               break;
                                }
                        BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
                        sc->beacon.bslot[avp->av_bslot] = vif;
@@ -480,7 +473,8 @@ void ath_beacon_tasklet(unsigned long data)
                sc->beacon.updateslot = COMMIT; /* commit next beacon */
                sc->beacon.slotupdate = slot;
        } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) {
-               ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime);
+               ah->slottime = sc->beacon.slottime;
+               ath9k_hw_init_global_settings(ah);
                sc->beacon.updateslot = OK;
        }
        if (bfaddr != 0) {
@@ -523,33 +517,31 @@ static void ath9k_beacon_init(struct ath_softc *sc,
 static void ath_beacon_config_ap(struct ath_softc *sc,
                                 struct ath_beacon_config *conf)
 {
+       struct ath_hw *ah = sc->sc_ah;
        u32 nexttbtt, intval;
 
-       /* Configure the timers only when the TSF has to be reset */
-
-       if (!(sc->sc_flags & SC_OP_TSF_RESET))
-               return;
-
        /* NB: the beacon interval is kept internally in TU's */
        intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
        intval /= ATH_BCBUF;    /* for staggered beacons */
        nexttbtt = intval;
-       intval |= ATH9K_BEACON_RESET_TSF;
+
+       if (sc->sc_flags & SC_OP_TSF_RESET)
+               intval |= ATH9K_BEACON_RESET_TSF;
 
        /*
         * In AP mode we enable the beacon timers and SWBA interrupts to
         * prepare beacon frames.
         */
        intval |= ATH9K_BEACON_ENA;
-       sc->imask |= ATH9K_INT_SWBA;
+       ah->imask |= ATH9K_INT_SWBA;
        ath_beaconq_config(sc);
 
        /* Set the computed AP beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Clear the reset TSF flag, so that subsequent beacon updation
           will not reset the HW TSF. */
@@ -568,7 +560,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
 static void ath_beacon_config_sta(struct ath_softc *sc,
                                  struct ath_beacon_config *conf)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        struct ath9k_beacon_state bs;
        int dtimperiod, dtimcount, sleepduration;
        int cfpperiod, cfpcount;
@@ -576,6 +569,13 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
        u64 tsf;
        int num_beacons, offset, dtim_dec_count, cfp_dec_count;
 
+       /* No need to configure beacon if we are not associated */
+       if (!common->curaid) {
+               ath_print(common, ATH_DBG_BEACON,
+                        "STA is not yet associated..skipping beacon config\n");
+               return;
+       }
+
        memset(&bs, 0, sizeof(bs));
        intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
 
@@ -600,7 +600,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
         * Pull nexttbtt forward to reflect the current
         * TSF and calculate dtim+cfp state for the result.
         */
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
 
        num_beacons = tsftu / intval + 1;
@@ -673,17 +673,18 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
 
        /* Set the computed STA beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
-       ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
-       sc->imask |= ATH9K_INT_BMISS;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, 0);
+       ath9k_hw_set_sta_beacon_timers(ah, &bs);
+       ah->imask |= ATH9K_INT_BMISS;
+       ath9k_hw_set_interrupts(ah, ah->imask);
 }
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
                                    struct ath_beacon_config *conf,
                                    struct ieee80211_vif *vif)
 {
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        u64 tsf;
        u32 tsftu, intval, nexttbtt;
 
@@ -698,7 +699,7 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         else if (intval)
                 nexttbtt = roundup(nexttbtt, intval);
 
-       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
        do {
                nexttbtt += intval;
@@ -714,20 +715,20 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
         * self-linked tx descriptor and let the hardware deal with things.
         */
        intval |= ATH9K_BEACON_ENA;
-       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-               sc->imask |= ATH9K_INT_SWBA;
+       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
+               ah->imask |= ATH9K_INT_SWBA;
 
        ath_beaconq_config(sc);
 
        /* Set the computed ADHOC beacon timers */
 
-       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_interrupts(ah, 0);
        ath9k_beacon_init(sc, nexttbtt, intval);
        sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+       ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* FIXME: Handle properly when vif is NULL */
-       if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+       if (vif && ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
                ath_beacon_start_adhoc(sc, vif);
 }
 
@@ -738,7 +739,6 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
        enum nl80211_iftype iftype;
 
        /* Setup the beacon configuration parameters */
-
        if (vif) {
                struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;