ath9k: Cleanup beacon logic
authorSujith Manoharan <c_manoha@qca.qualcomm.com>
Tue, 17 Jul 2012 11:45:56 +0000 (17:15 +0530)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 17 Jul 2012 19:11:38 +0000 (15:11 -0400)
* The beaconing status routine is not required, since in
  multi-VIF cases the HW beacon parameters should not be
  re-configured.

* Remove SC_OP_TSF_RESET - when a beaconing interface comes
  up the first time, the TSF has to be reset.

* Simplify ath9k_allow_beacon_config().

* Handle setting/clearing the SWBA interrupt properly.

* Remove the TSF mangling in IBSS mode, it is not required.

* General code cleanup.

Signed-off-by: Sujith Manoharan <c_manoha@qca.qualcomm.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/recv.c

index 9dd8fbb847fdf25679735b09f1f2c19f711e5189..4cce997d686791b1e726d46150ef42da3bc2022e 100644 (file)
@@ -389,6 +389,7 @@ struct ath_beacon_config {
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
+       bool enable_beacon;
 };
 
 struct ath_beacon {
@@ -415,11 +416,13 @@ struct ath_beacon {
 };
 
 void ath_beacon_tasklet(unsigned long data);
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
+                        u32 changed);
 void ath9k_beacon_assign_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 void ath9k_beacon_remove_slot(struct ath_softc *sc, struct ieee80211_vif *vif);
 int ath_beaconq_config(struct ath_softc *sc);
-void ath_set_beacon(struct ath_softc *sc);
+void ath9k_set_beacon(struct ath_softc *sc);
 void ath9k_set_beaconing_status(struct ath_softc *sc, bool status);
 
 /*******************/
@@ -622,7 +625,6 @@ enum sc_op_flags {
        SC_OP_INVALID,
        SC_OP_BEACONS,
        SC_OP_RXFLUSH,
-       SC_OP_TSF_RESET,
        SC_OP_ANI_RUN,
        SC_OP_PRIM_STA_VIF,
        SC_OP_HW_RESET,
index 351ded55c798640121202ba442c31edfbb62b143..a79ec4572c2f06a6f66dd6afb90062458bd9e61d 100644 (file)
@@ -315,7 +315,6 @@ void ath_beacon_tasklet(unsigned long data)
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
                        ath_dbg(common, BSTUCK, "beacon is officially stuck\n");
                        sc->beacon.bmisscnt = 0;
-                       set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
                        ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
                }
 
@@ -401,21 +400,16 @@ void ath_beacon_tasklet(unsigned long data)
        }
 }
 
-static void ath9k_beacon_init(struct ath_softc *sc,
-                             u32 next_beacon,
-                             u32 beacon_period)
+static void ath9k_beacon_init(struct ath_softc *sc, u32 nexttbtt, u32 intval)
 {
-       if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
-               ath9k_ps_wakeup(sc);
-               ath9k_hw_reset_tsf(sc->sc_ah);
-       }
-
-       ath9k_hw_beaconinit(sc->sc_ah, next_beacon, beacon_period);
+       struct ath_hw *ah = sc->sc_ah;
 
-       if (test_bit(SC_OP_TSF_RESET, &sc->sc_flags)) {
-               ath9k_ps_restore(sc);
-               clear_bit(SC_OP_TSF_RESET, &sc->sc_flags);
-       }
+       ath9k_hw_disable_interrupts(ah);
+       ath9k_hw_reset_tsf(ah);
+       ath9k_hw_beaconinit(ah, nexttbtt, intval);
+       sc->beacon.bmisscnt = 0;
+       ath9k_hw_set_interrupts(ah);
+       ath9k_hw_enable_interrupts(ah);
 }
 
 /*
@@ -423,32 +417,28 @@ static void ath9k_beacon_init(struct ath_softc *sc,
  * burst together.  For the former arrange for the SWBA to be delivered for each
  * slot. Slots that are not occupied will generate nothing.
  */
-static void ath_beacon_config_ap(struct ath_softc *sc,
-                                struct ath_beacon_config *conf)
+static void ath9k_beacon_config_ap(struct ath_softc *sc,
+                                  struct ath_beacon_config *conf)
 {
        struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
        u32 nexttbtt, intval;
 
        /* NB: the beacon interval is kept internally in TU's */
        intval = TU_TO_USEC(conf->beacon_interval);
-       intval /= ATH_BCBUF;    /* for staggered beacons */
+       intval /= ATH_BCBUF;
        nexttbtt = intval;
 
-       /*
-        * In AP mode we enable the beacon timers and SWBA interrupts to
-        * prepare beacon frames.
-        */
-       ah->imask |= ATH9K_INT_SWBA;
-       ath_beaconq_config(sc);
+       if (conf->enable_beacon)
+               ah->imask |= ATH9K_INT_SWBA;
+       else
+               ah->imask &= ~ATH9K_INT_SWBA;
 
-       /* Set the computed AP beacon timers */
+       ath_dbg(common, BEACON, "AP nexttbtt: %u intval: %u conf_intval: %u\n",
+               nexttbtt, intval, conf->beacon_interval);
 
-       ath9k_hw_disable_interrupts(ah);
-       set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
+       ath_beaconq_config(sc);
        ath9k_beacon_init(sc, nexttbtt, intval);
-       sc->beacon.bmisscnt = 0;
-       ath9k_hw_set_interrupts(ah);
-       ath9k_hw_enable_interrupts(ah);
 }
 
 /*
@@ -459,8 +449,8 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
  * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
  * we've associated with.
  */
-static void ath_beacon_config_sta(struct ath_softc *sc,
-                                 struct ath_beacon_config *conf)
+static void ath9k_beacon_config_sta(struct ath_softc *sc,
+                                   struct ath_beacon_config *conf)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -579,97 +569,66 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
        ath9k_hw_enable_interrupts(ah);
 }
 
-static void ath_beacon_config_adhoc(struct ath_softc *sc,
-                                   struct ath_beacon_config *conf)
+static void ath9k_beacon_config_adhoc(struct ath_softc *sc,
+                                     struct ath_beacon_config *conf)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 tsf, intval, nexttbtt;
+       u32 intval, nexttbtt;
 
        ath9k_reset_beacon_status(sc);
-       if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
-               ath9k_hw_settsf64(ah, sc->beacon.bc_tstamp);
 
        intval = TU_TO_USEC(conf->beacon_interval);
-       tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
-       nexttbtt = tsf + intval;
+       nexttbtt = intval;
 
-       ath_dbg(common, BEACON, "IBSS nexttbtt %u intval %u (%u)\n",
-               nexttbtt, intval, conf->beacon_interval);
+       if (conf->enable_beacon)
+               ah->imask |= ATH9K_INT_SWBA;
+       else
+               ah->imask &= ~ATH9K_INT_SWBA;
 
-       /*
-        * In IBSS mode enable the beacon timers but only enable SWBA interrupts
-        * if we need to manually prepare beacon frames.  Otherwise we use a
-        * self-linked tx descriptor and let the hardware deal with things.
-        */
-       ah->imask |= ATH9K_INT_SWBA;
+       ath_dbg(common, BEACON, "IBSS nexttbtt: %u intval: %u conf_intval: %u\n",
+               nexttbtt, intval, conf->beacon_interval);
 
        ath_beaconq_config(sc);
-
-       /* Set the computed ADHOC beacon timers */
-
-       ath9k_hw_disable_interrupts(ah);
        ath9k_beacon_init(sc, nexttbtt, intval);
-       sc->beacon.bmisscnt = 0;
-
-       ath9k_hw_set_interrupts(ah);
-       ath9k_hw_enable_interrupts(ah);
 }
 
-static bool ath9k_allow_beacon_config(struct ath_softc *sc,
-                                     struct ieee80211_vif *vif)
+bool ath9k_allow_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
 {
-       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
 
-       /*
-        * Can not have different beacon interval on multiple
-        * AP interface case
-        */
-       if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
-           (sc->nbcnvifs > 1) &&
-           (vif->type == NL80211_IFTYPE_AP) &&
-           (cur_conf->beacon_interval != bss_conf->beacon_int)) {
-               ath_dbg(common, CONFIG,
-                       "Changing beacon interval of multiple AP interfaces !\n");
-               return false;
-       }
-       /*
-        * Can not configure station vif's beacon config
-        * while on AP opmode
-        */
-       if ((sc->sc_ah->opmode == NL80211_IFTYPE_AP) &&
-           (vif->type != NL80211_IFTYPE_AP)) {
-               ath_dbg(common, CONFIG,
-                       "STA vif's beacon not allowed on AP mode\n");
-               return false;
+       if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
+               if ((vif->type != NL80211_IFTYPE_AP) ||
+                   (sc->nbcnvifs > 1)) {
+                       ath_dbg(common, CONFIG,
+                               "An AP interface is already present !\n");
+                       return false;
+               }
        }
-       /*
-        * Do not allow beacon config if HW was already configured
-        * with another STA vif
-        */
-       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
-           (vif->type == NL80211_IFTYPE_STATION) &&
-           test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
-           !avp->primary_sta_vif) {
-               ath_dbg(common, CONFIG,
-                       "Beacon already configured for a station interface\n");
-               return false;
+
+       if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
+               if ((vif->type == NL80211_IFTYPE_STATION) &&
+                   test_bit(SC_OP_BEACONS, &sc->sc_flags) &&
+                   !avp->primary_sta_vif) {
+                       ath_dbg(common, CONFIG,
+                               "Beacon already configured for a station interface\n");
+                       return false;
+               }
        }
+
        return true;
 }
 
-void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+static void ath9k_cache_beacon_config(struct ath_softc *sc,
+                                     struct ieee80211_bss_conf *bss_conf)
 {
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
-       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
 
-       if (!ath9k_allow_beacon_config(sc, vif))
-               return;
+       ath_dbg(common, BEACON,
+               "Caching beacon data for BSS: %pM\n", bss_conf->bssid);
 
-       /* Setup the beacon configuration parameters */
        cur_conf->beacon_interval = bss_conf->beacon_int;
        cur_conf->dtim_period = bss_conf->dtim_period;
        cur_conf->listen_interval = 1;
@@ -694,73 +653,62 @@ void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
        if (cur_conf->dtim_period == 0)
                cur_conf->dtim_period = 1;
 
-       ath_set_beacon(sc);
 }
 
-static bool ath_has_valid_bslot(struct ath_softc *sc)
+void ath9k_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif,
+                        u32 changed)
 {
-       struct ath_vif *avp;
-       int slot;
-       bool found = false;
+       struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
+       struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
 
-       for (slot = 0; slot < ATH_BCBUF; slot++) {
-               if (sc->beacon.bslot[slot]) {
-                       avp = (void *)sc->beacon.bslot[slot]->drv_priv;
-                       if (avp->is_bslot_active) {
-                               found = true;
-                               break;
+       if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
+               ath9k_cache_beacon_config(sc, bss_conf);
+               ath9k_set_beacon(sc);
+               set_bit(SC_OP_BEACONS, &sc->sc_flags);
+       } else {
+               /*
+                * Take care of multiple interfaces when
+                * enabling/disabling SWBA.
+                */
+               if (changed & BSS_CHANGED_BEACON_ENABLED) {
+                       if (!bss_conf->enable_beacon &&
+                           (sc->nbcnvifs <= 1)) {
+                               cur_conf->enable_beacon = false;
+                       } else if (bss_conf->enable_beacon) {
+                               cur_conf->enable_beacon = true;
+                               ath9k_cache_beacon_config(sc, bss_conf);
                        }
                }
+
+               if (cur_conf->beacon_interval) {
+                       ath9k_set_beacon(sc);
+
+                       if (cur_conf->enable_beacon)
+                               set_bit(SC_OP_BEACONS, &sc->sc_flags);
+                       else
+                               clear_bit(SC_OP_BEACONS, &sc->sc_flags);
+               }
        }
-       return found;
 }
 
-
-void ath_set_beacon(struct ath_softc *sc)
+void ath9k_set_beacon(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_beacon_config *cur_conf = &sc->cur_beacon_conf;
 
        switch (sc->sc_ah->opmode) {
        case NL80211_IFTYPE_AP:
-               if (ath_has_valid_bslot(sc))
-                       ath_beacon_config_ap(sc, cur_conf);
+               ath9k_beacon_config_ap(sc, cur_conf);
                break;
        case NL80211_IFTYPE_ADHOC:
        case NL80211_IFTYPE_MESH_POINT:
-               ath_beacon_config_adhoc(sc, cur_conf);
+               ath9k_beacon_config_adhoc(sc, cur_conf);
                break;
        case NL80211_IFTYPE_STATION:
-               ath_beacon_config_sta(sc, cur_conf);
+               ath9k_beacon_config_sta(sc, cur_conf);
                break;
        default:
                ath_dbg(common, CONFIG, "Unsupported beaconing mode\n");
                return;
        }
-
-       set_bit(SC_OP_BEACONS, &sc->sc_flags);
-}
-
-void ath9k_set_beaconing_status(struct ath_softc *sc, bool status)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       if (!ath_has_valid_bslot(sc)) {
-               clear_bit(SC_OP_BEACONS, &sc->sc_flags);
-               return;
-       }
-
-       ath9k_ps_wakeup(sc);
-       if (status) {
-               /* Re-enable beaconing */
-               ah->imask |= ATH9K_INT_SWBA;
-               ath9k_hw_set_interrupts(ah);
-       } else {
-               /* Disable SWBA interrupt */
-               ah->imask &= ~ATH9K_INT_SWBA;
-               ath9k_hw_set_interrupts(ah);
-               tasklet_kill(&sc->bcon_tasklet);
-               ath9k_hw_stop_dma_queue(ah, sc->beacon.beaconq);
-       }
-       ath9k_ps_restore(sc);
 }
index 2a155ce2d46172f57dc25a5f22d7e1b36485b2ad..e411189abd7dc2e0bd343629c8abee7523ef4ec7 100644 (file)
@@ -236,7 +236,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start)
                if (!test_bit(SC_OP_BEACONS, &sc->sc_flags))
                        goto work;
 
-               ath_set_beacon(sc);
+               ath9k_set_beacon(sc);
 
                if (ah->opmode == NL80211_IFTYPE_STATION &&
                    test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
@@ -1533,24 +1533,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                }
        }
 
-       /*
-        * In case of AP mode, the HW TSF has to be reset
-        * when the beacon interval changes.
-        */
-       if ((changed & BSS_CHANGED_BEACON_INT) &&
-           (vif->type == NL80211_IFTYPE_AP))
-               set_bit(SC_OP_TSF_RESET, &sc->sc_flags);
-
-       /* Configure beaconing (AP, IBSS, MESH) */
-       if (ath9k_uses_beacons(vif->type) &&
-           ((changed & BSS_CHANGED_BEACON) ||
-            (changed & BSS_CHANGED_BEACON_ENABLED) ||
-            (changed & BSS_CHANGED_BEACON_INT))) {
-               ath9k_set_beaconing_status(sc, false);
-               if (!bss_conf->enable_beacon)
-                       avp->is_bslot_active = false;
-               ath_beacon_config(sc, vif);
-               ath9k_set_beaconing_status(sc, true);
+       if ((changed & BSS_CHANGED_BEACON_ENABLED) ||
+           (changed & BSS_CHANGED_BEACON_INT)) {
+               if (ath9k_allow_beacon_config(sc, vif))
+                       ath9k_beacon_config(sc, vif, changed);
        }
 
        if (changed & BSS_CHANGED_ERP_SLOT) {
index 11f3703a420a930fce50434403a365a0562ddd2f..12aca02228c22e9c8f5c62db20687c03f5992959 100644 (file)
@@ -553,7 +553,7 @@ static void ath_rx_ps_beacon(struct ath_softc *sc, struct sk_buff *skb)
                sc->ps_flags &= ~PS_BEACON_SYNC;
                ath_dbg(common, PS,
                        "Reconfigure Beacon timers based on timestamp from the AP\n");
-               ath_set_beacon(sc);
+               ath9k_set_beacon(sc);
        }
 
        if (ath_beacon_dtim_pending_cab(skb)) {