diff options
author | John W. Linville <linville@tuxdriver.com> | 2013-10-17 14:02:07 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2013-10-17 14:02:07 -0400 |
commit | 9f96da4dd2ccf685b506a21104cb13b1aadd907a (patch) | |
tree | 5d9eff61123f096e2434a9d36e6fdbd4cc5c6292 /drivers/net/wireless/ath/ath9k/main.c | |
parent | ccdbb6e96beca362db876d820ac1e560ff6d9579 (diff) | |
parent | b6b561c31d51db3dec0cb55412a5d7a1a2397521 (diff) |
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next into for-davem
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 157 |
1 files changed, 81 insertions, 76 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index cdb3b1e10b95..c42b55c1face 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -302,17 +302,91 @@ out: | |||
302 | * by reseting the chip. To accomplish this we must first cleanup any pending | 302 | * by reseting the chip. To accomplish this we must first cleanup any pending |
303 | * DMA, then restart stuff. | 303 | * DMA, then restart stuff. |
304 | */ | 304 | */ |
305 | static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | 305 | static int ath_set_channel(struct ath_softc *sc, struct cfg80211_chan_def *chandef) |
306 | struct ath9k_channel *hchan) | ||
307 | { | 306 | { |
307 | struct ath_hw *ah = sc->sc_ah; | ||
308 | struct ath_common *common = ath9k_hw_common(ah); | ||
309 | struct ieee80211_hw *hw = sc->hw; | ||
310 | struct ath9k_channel *hchan; | ||
311 | struct ieee80211_channel *chan = chandef->chan; | ||
312 | unsigned long flags; | ||
313 | bool offchannel; | ||
314 | int pos = chan->hw_value; | ||
315 | int old_pos = -1; | ||
308 | int r; | 316 | int r; |
309 | 317 | ||
310 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) | 318 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) |
311 | return -EIO; | 319 | return -EIO; |
312 | 320 | ||
321 | offchannel = !!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL); | ||
322 | |||
323 | if (ah->curchan) | ||
324 | old_pos = ah->curchan - &ah->channels[0]; | ||
325 | |||
326 | ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", | ||
327 | chan->center_freq, chandef->width); | ||
328 | |||
329 | /* update survey stats for the old channel before switching */ | ||
330 | spin_lock_irqsave(&common->cc_lock, flags); | ||
331 | ath_update_survey_stats(sc); | ||
332 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
333 | |||
334 | ath9k_cmn_get_channel(hw, ah, chandef); | ||
335 | |||
336 | /* | ||
337 | * If the operating channel changes, change the survey in-use flags | ||
338 | * along with it. | ||
339 | * Reset the survey data for the new channel, unless we're switching | ||
340 | * back to the operating channel from an off-channel operation. | ||
341 | */ | ||
342 | if (!offchannel && sc->cur_survey != &sc->survey[pos]) { | ||
343 | if (sc->cur_survey) | ||
344 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; | ||
345 | |||
346 | sc->cur_survey = &sc->survey[pos]; | ||
347 | |||
348 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); | ||
349 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; | ||
350 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { | ||
351 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); | ||
352 | } | ||
353 | |||
354 | hchan = &sc->sc_ah->channels[pos]; | ||
313 | r = ath_reset_internal(sc, hchan); | 355 | r = ath_reset_internal(sc, hchan); |
356 | if (r) | ||
357 | return r; | ||
314 | 358 | ||
315 | return r; | 359 | /* |
360 | * The most recent snapshot of channel->noisefloor for the old | ||
361 | * channel is only available after the hardware reset. Copy it to | ||
362 | * the survey stats now. | ||
363 | */ | ||
364 | if (old_pos >= 0) | ||
365 | ath_update_survey_nf(sc, old_pos); | ||
366 | |||
367 | /* | ||
368 | * Enable radar pulse detection if on a DFS channel. Spectral | ||
369 | * scanning and radar detection can not be used concurrently. | ||
370 | */ | ||
371 | if (hw->conf.radar_enabled) { | ||
372 | u32 rxfilter; | ||
373 | |||
374 | /* set HW specific DFS configuration */ | ||
375 | ath9k_hw_set_radar_params(ah); | ||
376 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
377 | rxfilter |= ATH9K_RX_FILTER_PHYRADAR | | ||
378 | ATH9K_RX_FILTER_PHYERR; | ||
379 | ath9k_hw_setrxfilter(ah, rxfilter); | ||
380 | ath_dbg(common, DFS, "DFS enabled at freq %d\n", | ||
381 | chan->center_freq); | ||
382 | } else { | ||
383 | /* perform spectral scan if requested. */ | ||
384 | if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && | ||
385 | sc->spectral_mode == SPECTRAL_CHANSCAN) | ||
386 | ath9k_spectral_scan_trigger(hw); | ||
387 | } | ||
388 | |||
389 | return 0; | ||
316 | } | 390 | } |
317 | 391 | ||
318 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, | 392 | static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta, |
@@ -601,7 +675,7 @@ static int ath9k_start(struct ieee80211_hw *hw) | |||
601 | ath9k_ps_wakeup(sc); | 675 | ath9k_ps_wakeup(sc); |
602 | mutex_lock(&sc->mutex); | 676 | mutex_lock(&sc->mutex); |
603 | 677 | ||
604 | init_channel = ath9k_cmn_get_curchannel(hw, ah); | 678 | init_channel = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); |
605 | 679 | ||
606 | /* Reset SERDES registers */ | 680 | /* Reset SERDES registers */ |
607 | ath9k_hw_configpcipowersave(ah, false); | 681 | ath9k_hw_configpcipowersave(ah, false); |
@@ -804,7 +878,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
804 | } | 878 | } |
805 | 879 | ||
806 | if (!ah->curchan) | 880 | if (!ah->curchan) |
807 | ah->curchan = ath9k_cmn_get_curchannel(hw, ah); | 881 | ah->curchan = ath9k_cmn_get_channel(hw, ah, &hw->conf.chandef); |
808 | 882 | ||
809 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); | 883 | ath9k_hw_reset(ah, ah->curchan, ah->caldata, false); |
810 | ath9k_hw_phy_disable(ah); | 884 | ath9k_hw_phy_disable(ah); |
@@ -823,7 +897,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
823 | ath_dbg(common, CONFIG, "Driver halt\n"); | 897 | ath_dbg(common, CONFIG, "Driver halt\n"); |
824 | } | 898 | } |
825 | 899 | ||
826 | bool ath9k_uses_beacons(int type) | 900 | static bool ath9k_uses_beacons(int type) |
827 | { | 901 | { |
828 | switch (type) { | 902 | switch (type) { |
829 | case NL80211_IFTYPE_AP: | 903 | case NL80211_IFTYPE_AP: |
@@ -1208,81 +1282,12 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed) | |||
1208 | } | 1282 | } |
1209 | 1283 | ||
1210 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { | 1284 | if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) || reset_channel) { |
1211 | struct ieee80211_channel *curchan = hw->conf.chandef.chan; | 1285 | if (ath_set_channel(sc, &hw->conf.chandef) < 0) { |
1212 | int pos = curchan->hw_value; | ||
1213 | int old_pos = -1; | ||
1214 | unsigned long flags; | ||
1215 | |||
1216 | if (ah->curchan) | ||
1217 | old_pos = ah->curchan - &ah->channels[0]; | ||
1218 | |||
1219 | ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", | ||
1220 | curchan->center_freq, hw->conf.chandef.width); | ||
1221 | |||
1222 | /* update survey stats for the old channel before switching */ | ||
1223 | spin_lock_irqsave(&common->cc_lock, flags); | ||
1224 | ath_update_survey_stats(sc); | ||
1225 | spin_unlock_irqrestore(&common->cc_lock, flags); | ||
1226 | |||
1227 | ath9k_cmn_update_ichannel(&sc->sc_ah->channels[pos], | ||
1228 | &conf->chandef); | ||
1229 | |||
1230 | /* | ||
1231 | * If the operating channel changes, change the survey in-use flags | ||
1232 | * along with it. | ||
1233 | * Reset the survey data for the new channel, unless we're switching | ||
1234 | * back to the operating channel from an off-channel operation. | ||
1235 | */ | ||
1236 | if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) && | ||
1237 | sc->cur_survey != &sc->survey[pos]) { | ||
1238 | |||
1239 | if (sc->cur_survey) | ||
1240 | sc->cur_survey->filled &= ~SURVEY_INFO_IN_USE; | ||
1241 | |||
1242 | sc->cur_survey = &sc->survey[pos]; | ||
1243 | |||
1244 | memset(sc->cur_survey, 0, sizeof(struct survey_info)); | ||
1245 | sc->cur_survey->filled |= SURVEY_INFO_IN_USE; | ||
1246 | } else if (!(sc->survey[pos].filled & SURVEY_INFO_IN_USE)) { | ||
1247 | memset(&sc->survey[pos], 0, sizeof(struct survey_info)); | ||
1248 | } | ||
1249 | |||
1250 | if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) { | ||
1251 | ath_err(common, "Unable to set channel\n"); | 1286 | ath_err(common, "Unable to set channel\n"); |
1252 | mutex_unlock(&sc->mutex); | 1287 | mutex_unlock(&sc->mutex); |
1253 | ath9k_ps_restore(sc); | 1288 | ath9k_ps_restore(sc); |
1254 | return -EINVAL; | 1289 | return -EINVAL; |
1255 | } | 1290 | } |
1256 | |||
1257 | /* | ||
1258 | * The most recent snapshot of channel->noisefloor for the old | ||
1259 | * channel is only available after the hardware reset. Copy it to | ||
1260 | * the survey stats now. | ||
1261 | */ | ||
1262 | if (old_pos >= 0) | ||
1263 | ath_update_survey_nf(sc, old_pos); | ||
1264 | |||
1265 | /* | ||
1266 | * Enable radar pulse detection if on a DFS channel. Spectral | ||
1267 | * scanning and radar detection can not be used concurrently. | ||
1268 | */ | ||
1269 | if (hw->conf.radar_enabled) { | ||
1270 | u32 rxfilter; | ||
1271 | |||
1272 | /* set HW specific DFS configuration */ | ||
1273 | ath9k_hw_set_radar_params(ah); | ||
1274 | rxfilter = ath9k_hw_getrxfilter(ah); | ||
1275 | rxfilter |= ATH9K_RX_FILTER_PHYRADAR | | ||
1276 | ATH9K_RX_FILTER_PHYERR; | ||
1277 | ath9k_hw_setrxfilter(ah, rxfilter); | ||
1278 | ath_dbg(common, DFS, "DFS enabled at freq %d\n", | ||
1279 | curchan->center_freq); | ||
1280 | } else { | ||
1281 | /* perform spectral scan if requested. */ | ||
1282 | if (test_bit(SC_OP_SCANNING, &sc->sc_flags) && | ||
1283 | sc->spectral_mode == SPECTRAL_CHANSCAN) | ||
1284 | ath9k_spectral_scan_trigger(hw); | ||
1285 | } | ||
1286 | } | 1291 | } |
1287 | 1292 | ||
1288 | if (changed & IEEE80211_CONF_CHANGE_POWER) { | 1293 | if (changed & IEEE80211_CONF_CHANGE_POWER) { |