]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/net/wireless/ath/ath9k/main.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
[karo-tx-linux.git] / drivers / net / wireless / ath / ath9k / main.c
index 709301f88dcd26210a18db4d6eb1f8e230905608..20a2fbc1e34ff27a00a3d6de2739da45181bf32f 100644 (file)
@@ -312,17 +312,91 @@ out:
  * by reseting the chip.  To accomplish this we must first cleanup any pending
  * DMA, then restart stuff.
 */
-static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
-                   struct ath9k_channel *hchan)
+static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef)
 {
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_common *common = ath9k_hw_common(ah);
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath9k_channel *hchan;
+       struct ieee80211_channel *chan = chandef->chan;
+       unsigned long flags;
+       bool offchannel;
+       int pos = chan->hw_value;
+       int old_pos = -1;
        int r;
 
        if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return -EIO;
 
+       offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL);
+
+       if (ah->curchan)
+               old_pos = ah->curchan - &ah->channels[0];
+
+       ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
+               chan->center_freq, chandef->width);
+
+       /* update survey stats for the old channel before switching */
+       spin_lock_irqsave(&common->cc_lock, flags);
+       ath_update_survey_stats(sc);
+       spin_unlock_irqrestore(&common->cc_lock, flags);
+
+       ath9k_cmn_get_channel(hw, ah, chandef);
+
+       /*
+        * If the operating channel changes, change the survey in-use flags
+        * along with it.
+        * Reset the survey data for the new channel, unless we're switching
+        * back to the operating channel from an off-channel operation.
+        */
+       if (!offchannel && sc->cur_survey != &sc->survey[pos]) {
+               if (sc->cur_survey)
+                       sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
+
+               sc->cur_survey = &sc->survey[pos];
+
+               memset(sc->cur_survey, 0, sizeof(struct survey_info));
+               sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
+       } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
+               memset(&sc->survey[pos], 0, sizeof(struct survey_info));
+       }
+
+       hchan = &sc->sc_ah->channels[pos];
        r = ath_reset_internal(sc, hchan);
+       if (r)
+               return r;
 
-       return r;
+       /*
+        * The most recent snapshot of channel->noisefloor for the old
+        * channel is only available after the hardware reset. Copy it to
+        * the survey stats now.
+        */
+       if (old_pos >= 0)
+               ath_update_survey_nf(sc, old_pos);
+
+       /*
+        * Enable radar pulse detection if on a DFS channel. Spectral
+        * scanning and radar detection can not be used concurrently.
+        */
+       if (hw->conf.radar_enabled) {
+               u32 rxfilter;
+
+               /* set HW specific DFS configuration */
+               ath9k_hw_set_radar_params(ah);
+               rxfilter = ath9k_hw_getrxfilter(ah);
+               rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
+                               ATH9K_RX_FILTER_PHYERR;
+               ath9k_hw_setrxfilter(ah, rxfilter);
+               ath_dbg(common, DFS, "DFS enabled at freq %d\n",
+                       chan->center_freq);
+       } else {
+               /* perform spectral scan if requested. */
+               if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
+                       sc->spectral_mode == SPECTRAL_CHANSCAN)
+                       ath9k_spectral_scan_trigger(hw);
+       }
+
+       return 0;
 }
 
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
@@ -372,6 +446,13 @@ void ath9k_tasklet(unsigned long data)
                        type = RESET_TYPE_BB_WATCHDOG;
 
                ath9k_queue_reset(sc, type);
+
+               /*
+                * Increment the ref. counter here so that
+                * interrupts are enabled in the reset routine.
+                */
+               atomic_inc(&ah->intr_ref_cnt);
+               ath_dbg(common, ANY, "FATAL: Skipping interrupts\n");
                goto out;
        }
 
@@ -410,10 +491,9 @@ void ath9k_tasklet(unsigned long data)
 
        ath9k_btcoex_handle_interrupt(sc, status);
 
-out:
        /* re-enable hardware interrupt */
        ath9k_hw_enable_interrupts(ah);
-
+out:
        spin_unlock(&sc->sc_pcu_lock);
        ath9k_ps_restore(sc);
 }
@@ -594,7 +674,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
        ath9k_ps_wakeup(sc);
        mutex_lock(&sc->mutex);
 
-       init_channel = ath9k_cmn_get_curchannel(hw, ah);
+       init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
 
        /* Reset SERDES registers */
        ath9k_hw_configpcipowersave(ah, false);
@@ -797,7 +877,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        }
 
        if (!ah->curchan)
-               ah->curchan = ath9k_cmn_get_curchannel(hw, ah);
+               ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef);
 
        ath9k_hw_reset(ah, ah->curchan, ah->caldata, false);
        ath9k_hw_phy_disable(ah);
@@ -816,7 +896,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
        ath_dbg(common, CONFIG, "Driver halt\n");
 }
 
-bool ath9k_uses_beacons(int type)
+static bool ath9k_uses_beacons(int type)
 {
        switch (type) {
        case NL80211_IFTYPE_AP:
@@ -1201,81 +1281,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
        }
 
        if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) {
-               struct ieee80211_channel *curchan = hw->conf.chandef.chan;
-               int pos = curchan->hw_value;
-               int old_pos = -1;
-               unsigned long flags;
-
-               if (ah->curchan)
-                       old_pos = ah->curchan - &ah->channels[0];
-
-               ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n",
-                       curchan->center_freq, hw->conf.chandef.width);
-
-               /* update survey stats for the old channel before switching */
-               spin_lock_irqsave(&common->cc_lock, flags);
-               ath_update_survey_stats(sc);
-               spin_unlock_irqrestore(&common->cc_lock, flags);
-
-               ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos],
-                                         &conf->chandef);
-
-               /*
-                * If the operating channel changes, change the survey in-use flags
-                * along with it.
-                * Reset the survey data for the new channel, unless we're switching
-                * back to the operating channel from an off-channel operation.
-                */
-               if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
-                   sc->cur_survey != &sc->survey[pos]) {
-
-                       if (sc->cur_survey)
-                               sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE;
-
-                       sc->cur_survey = &sc->survey[pos];
-
-                       memset(sc->cur_survey, 0, sizeof(struct survey_info));
-                       sc->cur_survey->filled |= SURVEY_INFO_IN_USE;
-               } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) {
-                       memset(&sc->survey[pos], 0, sizeof(struct survey_info));
-               }
-
-               if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
+               if (ath_set_channel(sc, &hw->conf.chandef) < 0) {
                        ath_err(common, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
                        ath9k_ps_restore(sc);
                        return -EINVAL;
                }
-
-               /*
-                * The most recent snapshot of channel->noisefloor for the old
-                * channel is only available after the hardware reset. Copy it to
-                * the survey stats now.
-                */
-               if (old_pos >= 0)
-                       ath_update_survey_nf(sc, old_pos);
-
-               /*
-                * Enable radar pulse detection if on a DFS channel. Spectral
-                * scanning and radar detection can not be used concurrently.
-                */
-               if (hw->conf.radar_enabled) {
-                       u32 rxfilter;
-
-                       /* set HW specific DFS configuration */
-                       ath9k_hw_set_radar_params(ah);
-                       rxfilter = ath9k_hw_getrxfilter(ah);
-                       rxfilter |= ATH9K_RX_FILTER_PHYRADAR |
-                                   ATH9K_RX_FILTER_PHYERR;
-                       ath9k_hw_setrxfilter(ah, rxfilter);
-                       ath_dbg(common, DFS, "DFS enabled at freq %d\n",
-                               curchan->center_freq);
-               } else {
-                       /* perform spectral scan if requested. */
-                       if (test_bit(SC_OP_SCANNING, &sc->sc_flags) &&
-                           sc->spectral_mode == SPECTRAL_CHANSCAN)
-                               ath9k_spectral_scan_trigger(hw);
-               }
        }
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {