diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 156 |
1 files changed, 139 insertions, 17 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index b8b76dd2c11e..c8de50fa6378 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -51,13 +51,11 @@ static void ath_cache_conf_rate(struct ath_softc *sc, | |||
51 | static void ath_update_txpow(struct ath_softc *sc) | 51 | static void ath_update_txpow(struct ath_softc *sc) |
52 | { | 52 | { |
53 | struct ath_hw *ah = sc->sc_ah; | 53 | struct ath_hw *ah = sc->sc_ah; |
54 | u32 txpow; | ||
55 | 54 | ||
56 | if (sc->curtxpow != sc->config.txpowlimit) { | 55 | if (sc->curtxpow != sc->config.txpowlimit) { |
57 | ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); | 56 | ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit); |
58 | /* read back in case value is clamped */ | 57 | /* read back in case value is clamped */ |
59 | ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); | 58 | sc->curtxpow = ath9k_hw_regulatory(ah)->power_limit; |
60 | sc->curtxpow = txpow; | ||
61 | } | 59 | } |
62 | } | 60 | } |
63 | 61 | ||
@@ -232,6 +230,113 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw, | |||
232 | return r; | 230 | return r; |
233 | } | 231 | } |
234 | 232 | ||
233 | static void ath_paprd_activate(struct ath_softc *sc) | ||
234 | { | ||
235 | struct ath_hw *ah = sc->sc_ah; | ||
236 | int chain; | ||
237 | |||
238 | if (!ah->curchan->paprd_done) | ||
239 | return; | ||
240 | |||
241 | ath9k_ps_wakeup(sc); | ||
242 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
243 | if (!(ah->caps.tx_chainmask & BIT(chain))) | ||
244 | continue; | ||
245 | |||
246 | ar9003_paprd_populate_single_table(ah, ah->curchan, chain); | ||
247 | } | ||
248 | |||
249 | ar9003_paprd_enable(ah, true); | ||
250 | ath9k_ps_restore(sc); | ||
251 | } | ||
252 | |||
253 | void ath_paprd_calibrate(struct work_struct *work) | ||
254 | { | ||
255 | struct ath_softc *sc = container_of(work, struct ath_softc, paprd_work); | ||
256 | struct ieee80211_hw *hw = sc->hw; | ||
257 | struct ath_hw *ah = sc->sc_ah; | ||
258 | struct ieee80211_hdr *hdr; | ||
259 | struct sk_buff *skb = NULL; | ||
260 | struct ieee80211_tx_info *tx_info; | ||
261 | int band = hw->conf.channel->band; | ||
262 | struct ieee80211_supported_band *sband = &sc->sbands[band]; | ||
263 | struct ath_tx_control txctl; | ||
264 | int qnum, ftype; | ||
265 | int chain_ok = 0; | ||
266 | int chain; | ||
267 | int len = 1800; | ||
268 | int time_left; | ||
269 | int i; | ||
270 | |||
271 | ath9k_ps_wakeup(sc); | ||
272 | skb = alloc_skb(len, GFP_KERNEL); | ||
273 | if (!skb) | ||
274 | return; | ||
275 | |||
276 | tx_info = IEEE80211_SKB_CB(skb); | ||
277 | |||
278 | skb_put(skb, len); | ||
279 | memset(skb->data, 0, len); | ||
280 | hdr = (struct ieee80211_hdr *)skb->data; | ||
281 | ftype = IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC; | ||
282 | hdr->frame_control = cpu_to_le16(ftype); | ||
283 | hdr->duration_id = 10; | ||
284 | memcpy(hdr->addr1, hw->wiphy->perm_addr, ETH_ALEN); | ||
285 | memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN); | ||
286 | memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN); | ||
287 | |||
288 | memset(&txctl, 0, sizeof(txctl)); | ||
289 | qnum = sc->tx.hwq_map[WME_AC_BE]; | ||
290 | txctl.txq = &sc->tx.txq[qnum]; | ||
291 | |||
292 | ar9003_paprd_init_table(ah); | ||
293 | for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) { | ||
294 | if (!(ah->caps.tx_chainmask & BIT(chain))) | ||
295 | continue; | ||
296 | |||
297 | chain_ok = 0; | ||
298 | memset(tx_info, 0, sizeof(*tx_info)); | ||
299 | tx_info->band = band; | ||
300 | |||
301 | for (i = 0; i < 4; i++) { | ||
302 | tx_info->control.rates[i].idx = sband->n_bitrates - 1; | ||
303 | tx_info->control.rates[i].count = 6; | ||
304 | } | ||
305 | |||
306 | init_completion(&sc->paprd_complete); | ||
307 | ar9003_paprd_setup_gain_table(ah, chain); | ||
308 | txctl.paprd = BIT(chain); | ||
309 | if (ath_tx_start(hw, skb, &txctl) != 0) | ||
310 | break; | ||
311 | |||
312 | time_left = wait_for_completion_timeout(&sc->paprd_complete, | ||
313 | 100); | ||
314 | if (!time_left) { | ||
315 | ath_print(ath9k_hw_common(ah), ATH_DBG_CALIBRATE, | ||
316 | "Timeout waiting for paprd training on " | ||
317 | "TX chain %d\n", | ||
318 | chain); | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | if (!ar9003_paprd_is_done(ah)) | ||
323 | break; | ||
324 | |||
325 | if (ar9003_paprd_create_curve(ah, ah->curchan, chain) != 0) | ||
326 | break; | ||
327 | |||
328 | chain_ok = 1; | ||
329 | } | ||
330 | kfree_skb(skb); | ||
331 | |||
332 | if (chain_ok) { | ||
333 | ah->curchan->paprd_done = true; | ||
334 | ath_paprd_activate(sc); | ||
335 | } | ||
336 | |||
337 | ath9k_ps_restore(sc); | ||
338 | } | ||
339 | |||
235 | /* | 340 | /* |
236 | * This routine performs the periodic noise floor calibration function | 341 | * This routine performs the periodic noise floor calibration function |
237 | * that is used to adjust and optimize the chip performance. This | 342 | * that is used to adjust and optimize the chip performance. This |
@@ -285,7 +390,8 @@ void ath_ani_calibrate(unsigned long data) | |||
285 | } | 390 | } |
286 | 391 | ||
287 | /* Verify whether we must check ANI */ | 392 | /* Verify whether we must check ANI */ |
288 | if ((timestamp - common->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) { | 393 | if ((timestamp - common->ani.checkani_timer) >= |
394 | ah->config.ani_poll_interval) { | ||
289 | aniflag = true; | 395 | aniflag = true; |
290 | common->ani.checkani_timer = timestamp; | 396 | common->ani.checkani_timer = timestamp; |
291 | } | 397 | } |
@@ -326,15 +432,24 @@ set_timer: | |||
326 | */ | 432 | */ |
327 | cal_interval = ATH_LONG_CALINTERVAL; | 433 | cal_interval = ATH_LONG_CALINTERVAL; |
328 | if (sc->sc_ah->config.enable_ani) | 434 | if (sc->sc_ah->config.enable_ani) |
329 | cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); | 435 | cal_interval = min(cal_interval, |
436 | (u32)ah->config.ani_poll_interval); | ||
330 | if (!common->ani.caldone) | 437 | if (!common->ani.caldone) |
331 | cal_interval = min(cal_interval, (u32)short_cal_interval); | 438 | cal_interval = min(cal_interval, (u32)short_cal_interval); |
332 | 439 | ||
333 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); | 440 | mod_timer(&common->ani.timer, jiffies + msecs_to_jiffies(cal_interval)); |
441 | if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_PAPRD) && | ||
442 | !(sc->sc_flags & SC_OP_SCANNING)) { | ||
443 | if (!sc->sc_ah->curchan->paprd_done) | ||
444 | ieee80211_queue_work(sc->hw, &sc->paprd_work); | ||
445 | else | ||
446 | ath_paprd_activate(sc); | ||
447 | } | ||
334 | } | 448 | } |
335 | 449 | ||
336 | static void ath_start_ani(struct ath_common *common) | 450 | static void ath_start_ani(struct ath_common *common) |
337 | { | 451 | { |
452 | struct ath_hw *ah = common->ah; | ||
338 | unsigned long timestamp = jiffies_to_msecs(jiffies); | 453 | unsigned long timestamp = jiffies_to_msecs(jiffies); |
339 | 454 | ||
340 | common->ani.longcal_timer = timestamp; | 455 | common->ani.longcal_timer = timestamp; |
@@ -342,7 +457,8 @@ static void ath_start_ani(struct ath_common *common) | |||
342 | common->ani.checkani_timer = timestamp; | 457 | common->ani.checkani_timer = timestamp; |
343 | 458 | ||
344 | mod_timer(&common->ani.timer, | 459 | mod_timer(&common->ani.timer, |
345 | jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); | 460 | jiffies + |
461 | msecs_to_jiffies((u32)ah->config.ani_poll_interval)); | ||
346 | } | 462 | } |
347 | 463 | ||
348 | /* | 464 | /* |
@@ -804,25 +920,25 @@ int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
804 | return r; | 920 | return r; |
805 | } | 921 | } |
806 | 922 | ||
807 | int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) | 923 | static int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) |
808 | { | 924 | { |
809 | int qnum; | 925 | int qnum; |
810 | 926 | ||
811 | switch (queue) { | 927 | switch (queue) { |
812 | case 0: | 928 | case 0: |
813 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; | 929 | qnum = sc->tx.hwq_map[WME_AC_VO]; |
814 | break; | 930 | break; |
815 | case 1: | 931 | case 1: |
816 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; | 932 | qnum = sc->tx.hwq_map[WME_AC_VI]; |
817 | break; | 933 | break; |
818 | case 2: | 934 | case 2: |
819 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; | 935 | qnum = sc->tx.hwq_map[WME_AC_BE]; |
820 | break; | 936 | break; |
821 | case 3: | 937 | case 3: |
822 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; | 938 | qnum = sc->tx.hwq_map[WME_AC_BK]; |
823 | break; | 939 | break; |
824 | default: | 940 | default: |
825 | qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; | 941 | qnum = sc->tx.hwq_map[WME_AC_BE]; |
826 | break; | 942 | break; |
827 | } | 943 | } |
828 | 944 | ||
@@ -834,16 +950,16 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) | |||
834 | int qnum; | 950 | int qnum; |
835 | 951 | ||
836 | switch (queue) { | 952 | switch (queue) { |
837 | case ATH9K_WME_AC_VO: | 953 | case WME_AC_VO: |
838 | qnum = 0; | 954 | qnum = 0; |
839 | break; | 955 | break; |
840 | case ATH9K_WME_AC_VI: | 956 | case WME_AC_VI: |
841 | qnum = 1; | 957 | qnum = 1; |
842 | break; | 958 | break; |
843 | case ATH9K_WME_AC_BE: | 959 | case WME_AC_BE: |
844 | qnum = 2; | 960 | qnum = 2; |
845 | break; | 961 | break; |
846 | case ATH9K_WME_AC_BK: | 962 | case WME_AC_BK: |
847 | qnum = 3; | 963 | qnum = 3; |
848 | break; | 964 | break; |
849 | default: | 965 | default: |
@@ -1127,6 +1243,7 @@ static void ath9k_stop(struct ieee80211_hw *hw) | |||
1127 | 1243 | ||
1128 | cancel_delayed_work_sync(&sc->ath_led_blink_work); | 1244 | cancel_delayed_work_sync(&sc->ath_led_blink_work); |
1129 | cancel_delayed_work_sync(&sc->tx_complete_work); | 1245 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1246 | cancel_work_sync(&sc->paprd_work); | ||
1130 | 1247 | ||
1131 | if (!sc->num_sec_wiphy) { | 1248 | if (!sc->num_sec_wiphy) { |
1132 | cancel_delayed_work_sync(&sc->wiphy_work); | 1249 | cancel_delayed_work_sync(&sc->wiphy_work); |
@@ -1555,7 +1672,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue, | |||
1555 | ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); | 1672 | ath_print(common, ATH_DBG_FATAL, "TXQ Update failed\n"); |
1556 | 1673 | ||
1557 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) | 1674 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) |
1558 | if ((qnum == sc->tx.hwq_map[ATH9K_WME_AC_BE]) && !ret) | 1675 | if ((qnum == sc->tx.hwq_map[WME_AC_BE]) && !ret) |
1559 | ath_beaconq_config(sc); | 1676 | ath_beaconq_config(sc); |
1560 | 1677 | ||
1561 | mutex_unlock(&sc->mutex); | 1678 | mutex_unlock(&sc->mutex); |
@@ -1769,6 +1886,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1769 | struct ath_softc *sc = aphy->sc; | 1886 | struct ath_softc *sc = aphy->sc; |
1770 | int ret = 0; | 1887 | int ret = 0; |
1771 | 1888 | ||
1889 | local_bh_disable(); | ||
1890 | |||
1772 | switch (action) { | 1891 | switch (action) { |
1773 | case IEEE80211_AMPDU_RX_START: | 1892 | case IEEE80211_AMPDU_RX_START: |
1774 | if (!(sc->sc_flags & SC_OP_RXAGGR)) | 1893 | if (!(sc->sc_flags & SC_OP_RXAGGR)) |
@@ -1798,6 +1917,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, | |||
1798 | "Unknown AMPDU action\n"); | 1917 | "Unknown AMPDU action\n"); |
1799 | } | 1918 | } |
1800 | 1919 | ||
1920 | local_bh_enable(); | ||
1921 | |||
1801 | return ret; | 1922 | return ret; |
1802 | } | 1923 | } |
1803 | 1924 | ||
@@ -1842,6 +1963,7 @@ static void ath9k_sw_scan_start(struct ieee80211_hw *hw) | |||
1842 | ath9k_wiphy_pause_all_forced(sc, aphy); | 1963 | ath9k_wiphy_pause_all_forced(sc, aphy); |
1843 | sc->sc_flags |= SC_OP_SCANNING; | 1964 | sc->sc_flags |= SC_OP_SCANNING; |
1844 | del_timer_sync(&common->ani.timer); | 1965 | del_timer_sync(&common->ani.timer); |
1966 | cancel_work_sync(&sc->paprd_work); | ||
1845 | cancel_delayed_work_sync(&sc->tx_complete_work); | 1967 | cancel_delayed_work_sync(&sc->tx_complete_work); |
1846 | mutex_unlock(&sc->mutex); | 1968 | mutex_unlock(&sc->mutex); |
1847 | } | 1969 | } |