ath9k: Use ath_chanctx_check_active properly
[cascardo/linux.git] / drivers / net / wireless / ath / ath9k / channel.c
index ceb3ce8..08bb14c 100644 (file)
@@ -101,6 +101,69 @@ static int ath_set_channel(struct ath_softc *sc)
        return 0;
 }
 
+void ath_chanctx_init(struct ath_softc *sc)
+{
+       struct ath_chanctx *ctx;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *chan;
+       int i, j;
+
+       sband = &common->sbands[IEEE80211_BAND_2GHZ];
+       if (!sband->n_channels)
+               sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+       chan = &sband->channels[0];
+       for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
+               ctx = &sc->chanctx[i];
+               cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+               INIT_LIST_HEAD(&ctx->vifs);
+               ctx->txpower = ATH_TXPOWER_MAX;
+               for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
+                       INIT_LIST_HEAD(&ctx->acq[j]);
+       }
+}
+
+void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
+                            struct cfg80211_chan_def *chandef)
+{
+       bool cur_chan;
+
+       spin_lock_bh(&sc->chan_lock);
+       if (chandef)
+               memcpy(&ctx->chandef, chandef, sizeof(*chandef));
+       cur_chan = sc->cur_chan == ctx;
+       spin_unlock_bh(&sc->chan_lock);
+
+       if (!cur_chan)
+               return;
+
+       ath_set_channel(sc);
+}
+
+#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
+
+/**********************************************************/
+/* Functions to handle the channel context state machine. */
+/**********************************************************/
+
+static const char *offchannel_state_string(enum ath_offchannel_state state)
+{
+#define case_rtn_string(val) case val: return #val
+
+       switch (state) {
+               case_rtn_string(ATH_OFFCHANNEL_IDLE);
+               case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
+               case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
+               case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_START);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
+               case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
+       default:
+               return "unknown";
+       }
+}
+
 void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -139,55 +202,11 @@ void ath_chanctx_check_active(struct ath_softc *sc, struct ath_chanctx *ctx)
        }
        if (test_and_set_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags))
                return;
-       ath_chanctx_event(sc, NULL, ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
-}
 
-void ath_chanctx_init(struct ath_softc *sc)
-{
-       struct ath_chanctx *ctx;
-       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *chan;
-       int i, j;
-
-       sband = &common->sbands[IEEE80211_BAND_2GHZ];
-       if (!sband->n_channels)
-               sband = &common->sbands[IEEE80211_BAND_5GHZ];
-
-       chan = &sband->channels[0];
-       for (i = 0; i < ATH9K_NUM_CHANCTX; i++) {
-               ctx = &sc->chanctx[i];
-               cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
-               INIT_LIST_HEAD(&ctx->vifs);
-               ctx->txpower = ATH_TXPOWER_MAX;
-               for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
-                       INIT_LIST_HEAD(&ctx->acq[j]);
+       if (ath9k_is_chanctx_enabled()) {
+               ath_chanctx_event(sc, NULL,
+                                 ATH_CHANCTX_EVENT_ENABLE_MULTICHANNEL);
        }
-       ctx = &sc->offchannel.chan;
-       cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
-       INIT_LIST_HEAD(&ctx->vifs);
-       ctx->txpower = ATH_TXPOWER_MAX;
-       for (j = 0; j < ARRAY_SIZE(ctx->acq); j++)
-               INIT_LIST_HEAD(&ctx->acq[j]);
-       sc->offchannel.chan.offchannel = true;
-
-}
-
-void ath_chanctx_set_channel(struct ath_softc *sc, struct ath_chanctx *ctx,
-                            struct cfg80211_chan_def *chandef)
-{
-       bool cur_chan;
-
-       spin_lock_bh(&sc->chan_lock);
-       if (chandef)
-               memcpy(&ctx->chandef, chandef, sizeof(*chandef));
-       cur_chan = sc->cur_chan == ctx;
-       spin_unlock_bh(&sc->chan_lock);
-
-       if (!cur_chan)
-               return;
-
-       ath_set_channel(sc);
 }
 
 static struct ath_chanctx *
@@ -440,23 +459,18 @@ void ath_chanctx_event(struct ath_softc *sc, struct ieee80211_vif *vif,
        spin_unlock_bh(&sc->chan_lock);
 }
 
-#ifdef CONFIG_ATH9K_CHANNEL_CONTEXT
-
-static const char *offchannel_state_string(enum ath_offchannel_state state)
+void ath_chanctx_beacon_sent_ev(struct ath_softc *sc,
+                               enum ath_chanctx_event ev)
 {
-#define case_rtn_string(val) case val: return #val
+       if (sc->sched.beacon_pending)
+               ath_chanctx_event(sc, NULL, ev);
+}
 
-       switch (state) {
-               case_rtn_string(ATH_OFFCHANNEL_IDLE);
-               case_rtn_string(ATH_OFFCHANNEL_PROBE_SEND);
-               case_rtn_string(ATH_OFFCHANNEL_PROBE_WAIT);
-               case_rtn_string(ATH_OFFCHANNEL_SUSPEND);
-               case_rtn_string(ATH_OFFCHANNEL_ROC_START);
-               case_rtn_string(ATH_OFFCHANNEL_ROC_WAIT);
-               case_rtn_string(ATH_OFFCHANNEL_ROC_DONE);
-       default:
-               return "unknown";
-       }
+void ath_chanctx_beacon_recv_ev(struct ath_softc *sc, u32 ts,
+                               enum ath_chanctx_event ev)
+{
+       sc->sched.next_tbtt = ts;
+       ath_chanctx_event(sc, NULL, ev);
 }
 
 static int ath_scan_channel_duration(struct ath_softc *sc,
@@ -920,6 +934,31 @@ static void ath_chanctx_work(struct work_struct *work)
        mutex_unlock(&sc->mutex);
 }
 
+void ath9k_offchannel_init(struct ath_softc *sc)
+{
+       struct ath_chanctx *ctx;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *chan;
+       int i;
+
+       sband = &common->sbands[IEEE80211_BAND_2GHZ];
+       if (!sband->n_channels)
+               sband = &common->sbands[IEEE80211_BAND_5GHZ];
+
+       chan = &sband->channels[0];
+
+       ctx = &sc->offchannel.chan;
+       INIT_LIST_HEAD(&ctx->vifs);
+       ctx->txpower = ATH_TXPOWER_MAX;
+       cfg80211_chandef_create(&ctx->chandef, chan, NL80211_CHAN_HT20);
+
+       for (i = 0; i < ARRAY_SIZE(ctx->acq); i++)
+               INIT_LIST_HEAD(&ctx->acq[i]);
+
+       sc->offchannel.chan.offchannel = true;
+}
+
 void ath9k_init_channel_context(struct ath_softc *sc)
 {
        INIT_WORK(&sc->chanctx_work, ath_chanctx_work);
@@ -940,6 +979,28 @@ bool ath9k_is_chanctx_enabled(void)
        return (ath9k_use_chanctx == 1);
 }
 
+/********************/
+/* Queue management */
+/********************/
+
+void ath9k_chanctx_wake_queues(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       int i;
+
+       if (sc->cur_chan == &sc->offchannel.chan) {
+               ieee80211_wake_queue(sc->hw,
+                                    sc->hw->offchannel_tx_hw_queue);
+       } else {
+               for (i = 0; i < IEEE80211_NUM_ACS; i++)
+                       ieee80211_wake_queue(sc->hw,
+                                            sc->cur_chan->hw_queue_base + i);
+       }
+
+       if (ah->opmode == NL80211_IFTYPE_AP)
+               ieee80211_wake_queue(sc->hw, sc->hw->queues - 2);
+}
+
 /*****************/
 /* P2P Powersave */
 /*****************/