Merge commit 'origin/master' into next
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / beacon.c
index eb4759f..3639a2e 100644 (file)
@@ -63,7 +63,7 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        struct ath_hw *ah = sc->sc_ah;
        struct ath_desc *ds;
        struct ath9k_11n_rate_series series[4];
-       struct ath_rate_table *rt;
+       const struct ath_rate_table *rt;
        int flags, antenna, ctsrate = 0, ctsduration = 0;
        u8 rate;
 
@@ -320,8 +320,7 @@ int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
                u64 tsfadjust;
                int intval;
 
-               intval = sc->hw->conf.beacon_int ?
-                       sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
+               intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 
                /*
                 * Calculate the TSF offset for this beacon slot, i.e., the
@@ -412,6 +411,7 @@ void ath_beacon_tasklet(unsigned long data)
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
                        DPRINTF(sc, ATH_DBG_BEACON,
                                "beacon is officially stuck\n");
+                       sc->sc_flags |= SC_OP_TSF_RESET;
                        ath_reset(sc, false);
                }
 
@@ -431,8 +431,7 @@ void ath_beacon_tasklet(unsigned long data)
         * on the tsf to safeguard against missing an swba.
         */
 
-       intval = sc->hw->conf.beacon_int ?
-               sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
+       intval = sc->beacon_interval ? : ATH_DEFAULT_BINTVAL;
 
        tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf);
@@ -509,8 +508,7 @@ void ath_beacon_tasklet(unsigned long data)
  * slot. Slots that are not occupied will generate nothing.
  */
 static void ath_beacon_config_ap(struct ath_softc *sc,
-                                struct ath_beacon_config *conf,
-                                struct ath_vif *avp)
+                                struct ath_beacon_config *conf)
 {
        u32 nexttbtt, intval;
 
@@ -555,14 +553,14 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
  * we've associated with.
  */
 static void ath_beacon_config_sta(struct ath_softc *sc,
-                                 struct ath_beacon_config *conf,
-                                 struct ath_vif *avp)
+                                 struct ath_beacon_config *conf)
 {
        struct ath9k_beacon_state bs;
        int dtimperiod, dtimcount, sleepduration;
        int cfpperiod, cfpcount;
        u32 nexttbtt = 0, intval, tsftu;
        u64 tsf;
+       int num_beacons, offset, dtim_dec_count, cfp_dec_count;
 
        memset(&bs, 0, sizeof(bs));
        intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
@@ -590,14 +588,27 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
         */
        tsf = ath9k_hw_gettsf64(sc->sc_ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
-       do {
+
+       num_beacons = tsftu / intval + 1;
+       offset = tsftu % intval;
+       nexttbtt = tsftu - offset;
+       if (offset)
                nexttbtt += intval;
-               if (--dtimcount < 0) {
-                       dtimcount = dtimperiod - 1;
-                       if (--cfpcount < 0)
-                               cfpcount = cfpperiod - 1;
-               }
-       } while (nexttbtt < tsftu);
+
+       /* DTIM Beacon every dtimperiod Beacon */
+       dtim_dec_count = num_beacons % dtimperiod;
+       /* CFP every cfpperiod DTIM Beacon */
+       cfp_dec_count = (num_beacons / dtimperiod) % cfpperiod;
+       if (dtim_dec_count)
+               cfp_dec_count++;
+
+       dtimcount -= dtim_dec_count;
+       if (dtimcount < 0)
+               dtimcount += dtimperiod;
+
+       cfpcount -= cfp_dec_count;
+       if (cfpcount < 0)
+               cfpcount += cfpperiod;
 
        bs.bs_intval = intval;
        bs.bs_nexttbtt = nexttbtt;
@@ -656,7 +667,6 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
 
 static void ath_beacon_config_adhoc(struct ath_softc *sc,
                                    struct ath_beacon_config *conf,
-                                   struct ath_vif *avp,
                                    struct ieee80211_vif *vif)
 {
        u64 tsf;
@@ -664,6 +674,14 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
 
        intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
 
+       /*
+        * It looks like mac80211 may end up using beacon interval of zero in
+        * some cases (at least for mesh point). Avoid getting into an
+        * infinite loop by using a bit safer value instead..
+        */
+       if (intval == 0)
+               intval = 100;
+
        /* Pull nexttbtt forward to reflect the current TSF */
 
        nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
@@ -700,44 +718,50 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
        sc->beacon.bmisscnt = 0;
        ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+       /* FIXME: Handle properly when vif is NULL */
+       if (vif && sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
                ath_beacon_start_adhoc(sc, vif);
 }
 
 void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
 {
-       struct ath_beacon_config conf;
+       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
+       enum nl80211_iftype iftype;
 
        /* Setup the beacon configuration parameters */
 
-       memset(&conf, 0, sizeof(struct ath_beacon_config));
-       conf.beacon_interval = sc->hw->conf.beacon_int ?
-               sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
-       conf.listen_interval = 1;
-       conf.dtim_period = conf.beacon_interval;
-       conf.dtim_count = 1;
-       conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
-
        if (vif) {
-               struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
-
-               switch(avp->av_opmode) {
-               case NL80211_IFTYPE_AP:
-                       ath_beacon_config_ap(sc, &conf, avp);
-                       break;
-               case NL80211_IFTYPE_ADHOC:
-               case NL80211_IFTYPE_MESH_POINT:
-                       ath_beacon_config_adhoc(sc, &conf, avp, vif);
-                       break;
-               case NL80211_IFTYPE_STATION:
-                       ath_beacon_config_sta(sc, &conf, avp);
-                       break;
-               default:
-                       DPRINTF(sc, ATH_DBG_CONFIG,
-                               "Unsupported beaconing mode\n");
-                       return;
-               }
+               struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+
+               iftype = vif->type;
 
-               sc->sc_flags |= SC_OP_BEACONS;
+               cur_conf->beacon_interval = bss_conf->beacon_int;
+               cur_conf->dtim_period = bss_conf->dtim_period;
+               cur_conf->listen_interval = 1;
+               cur_conf->dtim_count = 1;
+               cur_conf->bmiss_timeout =
+                       ATH_DEFAULT_BMISS_LIMIT * cur_conf->beacon_interval;
+       } else {
+               iftype = sc->sc_ah->opmode;
        }
+
+
+       switch (iftype) {
+       case NL80211_IFTYPE_AP:
+               ath_beacon_config_ap(sc, cur_conf);
+               break;
+       case NL80211_IFTYPE_ADHOC:
+       case NL80211_IFTYPE_MESH_POINT:
+               ath_beacon_config_adhoc(sc, cur_conf, vif);
+               break;
+       case NL80211_IFTYPE_STATION:
+               ath_beacon_config_sta(sc, cur_conf);
+               break;
+       default:
+               DPRINTF(sc, ATH_DBG_CONFIG,
+                       "Unsupported beaconing mode\n");
+               return;
+       }
+
+       sc->sc_flags |= SC_OP_BEACONS;
 }