diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/main.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/main.c | 691 |
1 files changed, 515 insertions, 176 deletions
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c index 248e5b24acfa..6049d8b82855 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c | |||
@@ -19,6 +19,9 @@ | |||
19 | #include "ath9k.h" | 19 | #include "ath9k.h" |
20 | #include "btcoex.h" | 20 | #include "btcoex.h" |
21 | 21 | ||
22 | static void ath9k_set_assoc_state(struct ath_softc *sc, | ||
23 | struct ieee80211_vif *vif); | ||
24 | |||
22 | u8 ath9k_parse_mpdudensity(u8 mpdudensity) | 25 | u8 ath9k_parse_mpdudensity(u8 mpdudensity) |
23 | { | 26 | { |
24 | /* | 27 | /* |
@@ -167,8 +170,6 @@ static void ath_cancel_work(struct ath_softc *sc) | |||
167 | 170 | ||
168 | static void ath_restart_work(struct ath_softc *sc) | 171 | static void ath_restart_work(struct ath_softc *sc) |
169 | { | 172 | { |
170 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | ||
171 | |||
172 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); | 173 | ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0); |
173 | 174 | ||
174 | if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || | 175 | if (AR_SREV_9340(sc->sc_ah) || AR_SREV_9485(sc->sc_ah) || |
@@ -177,21 +178,18 @@ static void ath_restart_work(struct ath_softc *sc) | |||
177 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); | 178 | msecs_to_jiffies(ATH_PLL_WORK_INTERVAL)); |
178 | 179 | ||
179 | ath_start_rx_poll(sc, 3); | 180 | ath_start_rx_poll(sc, 3); |
180 | 181 | ath_start_ani(sc); | |
181 | if (!common->disable_ani) | ||
182 | ath_start_ani(common); | ||
183 | } | 182 | } |
184 | 183 | ||
185 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) | 184 | static bool ath_prepare_reset(struct ath_softc *sc, bool retry_tx, bool flush) |
186 | { | 185 | { |
187 | struct ath_hw *ah = sc->sc_ah; | 186 | struct ath_hw *ah = sc->sc_ah; |
188 | struct ath_common *common = ath9k_hw_common(ah); | ||
189 | bool ret = true; | 187 | bool ret = true; |
190 | 188 | ||
191 | ieee80211_stop_queues(sc->hw); | 189 | ieee80211_stop_queues(sc->hw); |
192 | 190 | ||
193 | sc->hw_busy_count = 0; | 191 | sc->hw_busy_count = 0; |
194 | del_timer_sync(&common->ani.timer); | 192 | ath_stop_ani(sc); |
195 | del_timer_sync(&sc->rx_poll_timer); | 193 | del_timer_sync(&sc->rx_poll_timer); |
196 | 194 | ||
197 | ath9k_debug_samp_bb_mac(sc); | 195 | ath9k_debug_samp_bb_mac(sc); |
@@ -236,7 +234,7 @@ static bool ath_complete_reset(struct ath_softc *sc, bool start) | |||
236 | if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) | 234 | if (!test_bit(SC_OP_BEACONS, &sc->sc_flags)) |
237 | goto work; | 235 | goto work; |
238 | 236 | ||
239 | ath_set_beacon(sc); | 237 | ath9k_set_beacon(sc); |
240 | 238 | ||
241 | if (ah->opmode == NL80211_IFTYPE_STATION && | 239 | if (ah->opmode == NL80211_IFTYPE_STATION && |
242 | test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { | 240 | test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { |
@@ -365,6 +363,7 @@ void ath9k_tasklet(unsigned long data) | |||
365 | struct ath_softc *sc = (struct ath_softc *)data; | 363 | struct ath_softc *sc = (struct ath_softc *)data; |
366 | struct ath_hw *ah = sc->sc_ah; | 364 | struct ath_hw *ah = sc->sc_ah; |
367 | struct ath_common *common = ath9k_hw_common(ah); | 365 | struct ath_common *common = ath9k_hw_common(ah); |
366 | enum ath_reset_type type; | ||
368 | unsigned long flags; | 367 | unsigned long flags; |
369 | u32 status = sc->intrstatus; | 368 | u32 status = sc->intrstatus; |
370 | u32 rxmask; | 369 | u32 rxmask; |
@@ -374,18 +373,13 @@ void ath9k_tasklet(unsigned long data) | |||
374 | 373 | ||
375 | if ((status & ATH9K_INT_FATAL) || | 374 | if ((status & ATH9K_INT_FATAL) || |
376 | (status & ATH9K_INT_BB_WATCHDOG)) { | 375 | (status & ATH9K_INT_BB_WATCHDOG)) { |
377 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
378 | enum ath_reset_type type; | ||
379 | 376 | ||
380 | if (status & ATH9K_INT_FATAL) | 377 | if (status & ATH9K_INT_FATAL) |
381 | type = RESET_TYPE_FATAL_INT; | 378 | type = RESET_TYPE_FATAL_INT; |
382 | else | 379 | else |
383 | type = RESET_TYPE_BB_WATCHDOG; | 380 | type = RESET_TYPE_BB_WATCHDOG; |
384 | 381 | ||
385 | RESET_STAT_INC(sc, type); | 382 | ath9k_queue_reset(sc, type); |
386 | #endif | ||
387 | set_bit(SC_OP_HW_RESET, &sc->sc_flags); | ||
388 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
389 | goto out; | 383 | goto out; |
390 | } | 384 | } |
391 | 385 | ||
@@ -493,6 +487,17 @@ irqreturn_t ath_isr(int irq, void *dev) | |||
493 | if (status & SCHED_INTR) | 487 | if (status & SCHED_INTR) |
494 | sched = true; | 488 | sched = true; |
495 | 489 | ||
490 | #ifdef CONFIG_PM_SLEEP | ||
491 | if (status & ATH9K_INT_BMISS) { | ||
492 | if (atomic_read(&sc->wow_sleep_proc_intr) == 0) { | ||
493 | ath_dbg(common, ANY, "during WoW we got a BMISS\n"); | ||
494 | atomic_inc(&sc->wow_got_bmiss_intr); | ||
495 | atomic_dec(&sc->wow_sleep_proc_intr); | ||
496 | } | ||
497 | ath_dbg(common, INTERRUPT, "beacon miss interrupt\n"); | ||
498 | } | ||
499 | #endif | ||
500 | |||
496 | /* | 501 | /* |
497 | * If a FATAL or RXORN interrupt is received, we have to reset the | 502 | * If a FATAL or RXORN interrupt is received, we have to reset the |
498 | * chip immediately. | 503 | * chip immediately. |
@@ -575,6 +580,15 @@ static int ath_reset(struct ath_softc *sc, bool retry_tx) | |||
575 | return r; | 580 | return r; |
576 | } | 581 | } |
577 | 582 | ||
583 | void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type) | ||
584 | { | ||
585 | #ifdef CONFIG_ATH9K_DEBUGFS | ||
586 | RESET_STAT_INC(sc, type); | ||
587 | #endif | ||
588 | set_bit(SC_OP_HW_RESET, &sc->sc_flags); | ||
589 | ieee80211_queue_work(sc->hw, &sc->hw_reset_work); | ||
590 | } | ||
591 | |||
578 | void ath_reset_work(struct work_struct *work) | 592 | void ath_reset_work(struct work_struct *work) |
579 | { | 593 | { |
580 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); | 594 | struct ath_softc *sc = container_of(work, struct ath_softc, hw_reset_work); |
@@ -841,16 +855,6 @@ bool ath9k_uses_beacons(int type) | |||
841 | } | 855 | } |
842 | } | 856 | } |
843 | 857 | ||
844 | static void ath9k_reclaim_beacon(struct ath_softc *sc, | ||
845 | struct ieee80211_vif *vif) | ||
846 | { | ||
847 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
848 | |||
849 | ath9k_set_beaconing_status(sc, false); | ||
850 | ath_beacon_return(sc, avp); | ||
851 | ath9k_set_beaconing_status(sc, true); | ||
852 | } | ||
853 | |||
854 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 858 | static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
855 | { | 859 | { |
856 | struct ath9k_vif_iter_data *iter_data = data; | 860 | struct ath9k_vif_iter_data *iter_data = data; |
@@ -882,6 +886,18 @@ static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | |||
882 | } | 886 | } |
883 | } | 887 | } |
884 | 888 | ||
889 | static void ath9k_sta_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | ||
890 | { | ||
891 | struct ath_softc *sc = data; | ||
892 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
893 | |||
894 | if (vif->type != NL80211_IFTYPE_STATION) | ||
895 | return; | ||
896 | |||
897 | if (avp->primary_sta_vif) | ||
898 | ath9k_set_assoc_state(sc, vif); | ||
899 | } | ||
900 | |||
885 | /* Called with sc->mutex held. */ | 901 | /* Called with sc->mutex held. */ |
886 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, | 902 | void ath9k_calculate_iter_data(struct ieee80211_hw *hw, |
887 | struct ieee80211_vif *vif, | 903 | struct ieee80211_vif *vif, |
@@ -915,21 +931,18 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
915 | struct ath_hw *ah = sc->sc_ah; | 931 | struct ath_hw *ah = sc->sc_ah; |
916 | struct ath_common *common = ath9k_hw_common(ah); | 932 | struct ath_common *common = ath9k_hw_common(ah); |
917 | struct ath9k_vif_iter_data iter_data; | 933 | struct ath9k_vif_iter_data iter_data; |
934 | enum nl80211_iftype old_opmode = ah->opmode; | ||
918 | 935 | ||
919 | ath9k_calculate_iter_data(hw, vif, &iter_data); | 936 | ath9k_calculate_iter_data(hw, vif, &iter_data); |
920 | 937 | ||
921 | /* Set BSSID mask. */ | ||
922 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); | 938 | memcpy(common->bssidmask, iter_data.mask, ETH_ALEN); |
923 | ath_hw_setbssidmask(common); | 939 | ath_hw_setbssidmask(common); |
924 | 940 | ||
925 | /* Set op-mode & TSF */ | ||
926 | if (iter_data.naps > 0) { | 941 | if (iter_data.naps > 0) { |
927 | ath9k_hw_set_tsfadjust(ah, 1); | 942 | ath9k_hw_set_tsfadjust(ah, true); |
928 | set_bit(SC_OP_TSF_RESET, &sc->sc_flags); | ||
929 | ah->opmode = NL80211_IFTYPE_AP; | 943 | ah->opmode = NL80211_IFTYPE_AP; |
930 | } else { | 944 | } else { |
931 | ath9k_hw_set_tsfadjust(ah, 0); | 945 | ath9k_hw_set_tsfadjust(ah, false); |
932 | clear_bit(SC_OP_TSF_RESET, &sc->sc_flags); | ||
933 | 946 | ||
934 | if (iter_data.nmeshes) | 947 | if (iter_data.nmeshes) |
935 | ah->opmode = NL80211_IFTYPE_MESH_POINT; | 948 | ah->opmode = NL80211_IFTYPE_MESH_POINT; |
@@ -941,9 +954,8 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
941 | ah->opmode = NL80211_IFTYPE_STATION; | 954 | ah->opmode = NL80211_IFTYPE_STATION; |
942 | } | 955 | } |
943 | 956 | ||
944 | /* | 957 | ath9k_hw_setopmode(ah); |
945 | * Enable MIB interrupts when there are hardware phy counters. | 958 | |
946 | */ | ||
947 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) | 959 | if ((iter_data.nstations + iter_data.nadhocs + iter_data.nmeshes) > 0) |
948 | ah->imask |= ATH9K_INT_TSFOOR; | 960 | ah->imask |= ATH9K_INT_TSFOOR; |
949 | else | 961 | else |
@@ -951,34 +963,15 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw, | |||
951 | 963 | ||
952 | ath9k_hw_set_interrupts(ah); | 964 | ath9k_hw_set_interrupts(ah); |
953 | 965 | ||
954 | /* Set up ANI */ | 966 | /* |
955 | if (iter_data.naps > 0) { | 967 | * If we are changing the opmode to STATION, |
956 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | 968 | * a beacon sync needs to be done. |
957 | 969 | */ | |
958 | if (!common->disable_ani) { | 970 | if (ah->opmode == NL80211_IFTYPE_STATION && |
959 | set_bit(SC_OP_ANI_RUN, &sc->sc_flags); | 971 | old_opmode == NL80211_IFTYPE_AP && |
960 | ath_start_ani(common); | 972 | test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { |
961 | } | 973 | ieee80211_iterate_active_interfaces_atomic(sc->hw, |
962 | 974 | ath9k_sta_vif_iter, sc); | |
963 | } else { | ||
964 | clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); | ||
965 | del_timer_sync(&common->ani.timer); | ||
966 | } | ||
967 | } | ||
968 | |||
969 | /* Called with sc->mutex held, vif counts set up properly. */ | ||
970 | static void ath9k_do_vif_add_setup(struct ieee80211_hw *hw, | ||
971 | struct ieee80211_vif *vif) | ||
972 | { | ||
973 | struct ath_softc *sc = hw->priv; | ||
974 | |||
975 | ath9k_calculate_summary_state(hw, vif); | ||
976 | |||
977 | if (ath9k_uses_beacons(vif->type)) { | ||
978 | /* Reserve a beacon slot for the vif */ | ||
979 | ath9k_set_beaconing_status(sc, false); | ||
980 | ath_beacon_alloc(sc, vif); | ||
981 | ath9k_set_beaconing_status(sc, true); | ||
982 | } | 975 | } |
983 | } | 976 | } |
984 | 977 | ||
@@ -1021,7 +1014,10 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, | |||
1021 | 1014 | ||
1022 | sc->nvifs++; | 1015 | sc->nvifs++; |
1023 | 1016 | ||
1024 | ath9k_do_vif_add_setup(hw, vif); | 1017 | ath9k_calculate_summary_state(hw, vif); |
1018 | if (ath9k_uses_beacons(vif->type)) | ||
1019 | ath9k_beacon_assign_slot(sc, vif); | ||
1020 | |||
1025 | out: | 1021 | out: |
1026 | mutex_unlock(&sc->mutex); | 1022 | mutex_unlock(&sc->mutex); |
1027 | ath9k_ps_restore(sc); | 1023 | ath9k_ps_restore(sc); |
@@ -1038,6 +1034,7 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
1038 | int ret = 0; | 1034 | int ret = 0; |
1039 | 1035 | ||
1040 | ath_dbg(common, CONFIG, "Change Interface\n"); | 1036 | ath_dbg(common, CONFIG, "Change Interface\n"); |
1037 | |||
1041 | mutex_lock(&sc->mutex); | 1038 | mutex_lock(&sc->mutex); |
1042 | ath9k_ps_wakeup(sc); | 1039 | ath9k_ps_wakeup(sc); |
1043 | 1040 | ||
@@ -1050,15 +1047,16 @@ static int ath9k_change_interface(struct ieee80211_hw *hw, | |||
1050 | } | 1047 | } |
1051 | } | 1048 | } |
1052 | 1049 | ||
1053 | /* Clean up old vif stuff */ | ||
1054 | if (ath9k_uses_beacons(vif->type)) | 1050 | if (ath9k_uses_beacons(vif->type)) |
1055 | ath9k_reclaim_beacon(sc, vif); | 1051 | ath9k_beacon_remove_slot(sc, vif); |
1056 | 1052 | ||
1057 | /* Add new settings */ | ||
1058 | vif->type = new_type; | 1053 | vif->type = new_type; |
1059 | vif->p2p = p2p; | 1054 | vif->p2p = p2p; |
1060 | 1055 | ||
1061 | ath9k_do_vif_add_setup(hw, vif); | 1056 | ath9k_calculate_summary_state(hw, vif); |
1057 | if (ath9k_uses_beacons(vif->type)) | ||
1058 | ath9k_beacon_assign_slot(sc, vif); | ||
1059 | |||
1062 | out: | 1060 | out: |
1063 | ath9k_ps_restore(sc); | 1061 | ath9k_ps_restore(sc); |
1064 | mutex_unlock(&sc->mutex); | 1062 | mutex_unlock(&sc->mutex); |
@@ -1078,9 +1076,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, | |||
1078 | 1076 | ||
1079 | sc->nvifs--; | 1077 | sc->nvifs--; |
1080 | 1078 | ||
1081 | /* Reclaim beacon resources */ | ||
1082 | if (ath9k_uses_beacons(vif->type)) | 1079 | if (ath9k_uses_beacons(vif->type)) |
1083 | ath9k_reclaim_beacon(sc, vif); | 1080 | ath9k_beacon_remove_slot(sc, vif); |
1084 | 1081 | ||
1085 | ath9k_calculate_summary_state(hw, NULL); | 1082 | ath9k_calculate_summary_state(hw, NULL); |
1086 | 1083 | ||
@@ -1377,21 +1374,18 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, | |||
1377 | qi.tqi_aifs = params->aifs; | 1374 | qi.tqi_aifs = params->aifs; |
1378 | qi.tqi_cwmin = params->cw_min; | 1375 | qi.tqi_cwmin = params->cw_min; |
1379 | qi.tqi_cwmax = params->cw_max; | 1376 | qi.tqi_cwmax = params->cw_max; |
1380 | qi.tqi_burstTime = params->txop; | 1377 | qi.tqi_burstTime = params->txop * 32; |
1381 | 1378 | ||
1382 | ath_dbg(common, CONFIG, | 1379 | ath_dbg(common, CONFIG, |
1383 | "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", | 1380 | "Configure tx [queue/halq] [%d/%d], aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", |
1384 | queue, txq->axq_qnum, params->aifs, params->cw_min, | 1381 | queue, txq->axq_qnum, params->aifs, params->cw_min, |
1385 | params->cw_max, params->txop); | 1382 | params->cw_max, params->txop); |
1386 | 1383 | ||
1384 | ath_update_max_aggr_framelen(sc, queue, qi.tqi_burstTime); | ||
1387 | ret = ath_txq_update(sc, txq->axq_qnum, &qi); | 1385 | ret = ath_txq_update(sc, txq->axq_qnum, &qi); |
1388 | if (ret) | 1386 | if (ret) |
1389 | ath_err(common, "TXQ Update failed\n"); | 1387 | ath_err(common, "TXQ Update failed\n"); |
1390 | 1388 | ||
1391 | if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) | ||
1392 | if (queue == WME_AC_BE && !ret) | ||
1393 | ath_beaconq_config(sc); | ||
1394 | |||
1395 | mutex_unlock(&sc->mutex); | 1389 | mutex_unlock(&sc->mutex); |
1396 | ath9k_ps_restore(sc); | 1390 | ath9k_ps_restore(sc); |
1397 | 1391 | ||
@@ -1460,86 +1454,53 @@ static int ath9k_set_key(struct ieee80211_hw *hw, | |||
1460 | 1454 | ||
1461 | return ret; | 1455 | return ret; |
1462 | } | 1456 | } |
1463 | static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif) | 1457 | |
1458 | static void ath9k_set_assoc_state(struct ath_softc *sc, | ||
1459 | struct ieee80211_vif *vif) | ||
1464 | { | 1460 | { |
1465 | struct ath_softc *sc = data; | ||
1466 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1461 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); |
1467 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
1468 | struct ath_vif *avp = (void *)vif->drv_priv; | 1462 | struct ath_vif *avp = (void *)vif->drv_priv; |
1463 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | ||
1469 | unsigned long flags; | 1464 | unsigned long flags; |
1465 | |||
1466 | set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); | ||
1467 | avp->primary_sta_vif = true; | ||
1468 | |||
1470 | /* | 1469 | /* |
1471 | * Skip iteration if primary station vif's bss info | 1470 | * Set the AID, BSSID and do beacon-sync only when |
1472 | * was not changed | 1471 | * the HW opmode is STATION. |
1472 | * | ||
1473 | * But the primary bit is set above in any case. | ||
1473 | */ | 1474 | */ |
1474 | if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) | 1475 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) |
1475 | return; | 1476 | return; |
1476 | 1477 | ||
1477 | if (bss_conf->assoc) { | 1478 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); |
1478 | set_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); | 1479 | common->curaid = bss_conf->aid; |
1479 | avp->primary_sta_vif = true; | 1480 | ath9k_hw_write_associd(sc->sc_ah); |
1480 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | ||
1481 | common->curaid = bss_conf->aid; | ||
1482 | ath9k_hw_write_associd(sc->sc_ah); | ||
1483 | ath_dbg(common, CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", | ||
1484 | bss_conf->aid, common->curbssid); | ||
1485 | ath_beacon_config(sc, vif); | ||
1486 | /* | ||
1487 | * Request a re-configuration of Beacon related timers | ||
1488 | * on the receipt of the first Beacon frame (i.e., | ||
1489 | * after time sync with the AP). | ||
1490 | */ | ||
1491 | spin_lock_irqsave(&sc->sc_pm_lock, flags); | ||
1492 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; | ||
1493 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); | ||
1494 | |||
1495 | /* Reset rssi stats */ | ||
1496 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; | ||
1497 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
1498 | 1481 | ||
1499 | ath_start_rx_poll(sc, 3); | 1482 | sc->last_rssi = ATH_RSSI_DUMMY_MARKER; |
1483 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
1500 | 1484 | ||
1501 | if (!common->disable_ani) { | 1485 | spin_lock_irqsave(&sc->sc_pm_lock, flags); |
1502 | set_bit(SC_OP_ANI_RUN, &sc->sc_flags); | 1486 | sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON; |
1503 | ath_start_ani(common); | 1487 | spin_unlock_irqrestore(&sc->sc_pm_lock, flags); |
1504 | } | ||
1505 | 1488 | ||
1506 | } | 1489 | ath_dbg(common, CONFIG, |
1490 | "Primary Station interface: %pM, BSSID: %pM\n", | ||
1491 | vif->addr, common->curbssid); | ||
1507 | } | 1492 | } |
1508 | 1493 | ||
1509 | static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif) | 1494 | static void ath9k_bss_assoc_iter(void *data, u8 *mac, struct ieee80211_vif *vif) |
1510 | { | 1495 | { |
1511 | struct ath_common *common = ath9k_hw_common(sc->sc_ah); | 1496 | struct ath_softc *sc = data; |
1512 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; | 1497 | struct ieee80211_bss_conf *bss_conf = &vif->bss_conf; |
1513 | struct ath_vif *avp = (void *)vif->drv_priv; | ||
1514 | 1498 | ||
1515 | if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION) | 1499 | if (test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) |
1516 | return; | 1500 | return; |
1517 | 1501 | ||
1518 | /* Reconfigure bss info */ | 1502 | if (bss_conf->assoc) |
1519 | if (avp->primary_sta_vif && !bss_conf->assoc) { | 1503 | ath9k_set_assoc_state(sc, vif); |
1520 | ath_dbg(common, CONFIG, "Bss Info DISASSOC %d, bssid %pM\n", | ||
1521 | common->curaid, common->curbssid); | ||
1522 | clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); | ||
1523 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
1524 | avp->primary_sta_vif = false; | ||
1525 | memset(common->curbssid, 0, ETH_ALEN); | ||
1526 | common->curaid = 0; | ||
1527 | } | ||
1528 | |||
1529 | ieee80211_iterate_active_interfaces_atomic( | ||
1530 | sc->hw, ath9k_bss_iter, sc); | ||
1531 | |||
1532 | /* | ||
1533 | * None of station vifs are associated. | ||
1534 | * Clear bssid & aid | ||
1535 | */ | ||
1536 | if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { | ||
1537 | ath9k_hw_write_associd(sc->sc_ah); | ||
1538 | clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); | ||
1539 | del_timer_sync(&common->ani.timer); | ||
1540 | del_timer_sync(&sc->rx_poll_timer); | ||
1541 | memset(&sc->caldata, 0, sizeof(sc->caldata)); | ||
1542 | } | ||
1543 | } | 1504 | } |
1544 | 1505 | ||
1545 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | 1506 | static void ath9k_bss_info_changed(struct ieee80211_hw *hw, |
@@ -1547,6 +1508,11 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1547 | struct ieee80211_bss_conf *bss_conf, | 1508 | struct ieee80211_bss_conf *bss_conf, |
1548 | u32 changed) | 1509 | u32 changed) |
1549 | { | 1510 | { |
1511 | #define CHECK_ANI \ | ||
1512 | (BSS_CHANGED_ASSOC | \ | ||
1513 | BSS_CHANGED_IBSS | \ | ||
1514 | BSS_CHANGED_BEACON_ENABLED) | ||
1515 | |||
1550 | struct ath_softc *sc = hw->priv; | 1516 | struct ath_softc *sc = hw->priv; |
1551 | struct ath_hw *ah = sc->sc_ah; | 1517 | struct ath_hw *ah = sc->sc_ah; |
1552 | struct ath_common *common = ath9k_hw_common(ah); | 1518 | struct ath_common *common = ath9k_hw_common(ah); |
@@ -1557,53 +1523,41 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1557 | mutex_lock(&sc->mutex); | 1523 | mutex_lock(&sc->mutex); |
1558 | 1524 | ||
1559 | if (changed & BSS_CHANGED_ASSOC) { | 1525 | if (changed & BSS_CHANGED_ASSOC) { |
1560 | ath9k_config_bss(sc, vif); | 1526 | ath_dbg(common, CONFIG, "BSSID %pM Changed ASSOC %d\n", |
1527 | bss_conf->bssid, bss_conf->assoc); | ||
1561 | 1528 | ||
1562 | ath_dbg(common, CONFIG, "BSSID: %pM aid: 0x%x\n", | 1529 | if (avp->primary_sta_vif && !bss_conf->assoc) { |
1563 | common->curbssid, common->curaid); | 1530 | clear_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags); |
1531 | avp->primary_sta_vif = false; | ||
1532 | |||
1533 | if (ah->opmode == NL80211_IFTYPE_STATION) | ||
1534 | clear_bit(SC_OP_BEACONS, &sc->sc_flags); | ||
1535 | } | ||
1536 | |||
1537 | ieee80211_iterate_active_interfaces_atomic(sc->hw, | ||
1538 | ath9k_bss_assoc_iter, sc); | ||
1539 | |||
1540 | if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) && | ||
1541 | ah->opmode == NL80211_IFTYPE_STATION) { | ||
1542 | memset(common->curbssid, 0, ETH_ALEN); | ||
1543 | common->curaid = 0; | ||
1544 | ath9k_hw_write_associd(sc->sc_ah); | ||
1545 | } | ||
1564 | } | 1546 | } |
1565 | 1547 | ||
1566 | if (changed & BSS_CHANGED_IBSS) { | 1548 | if (changed & BSS_CHANGED_IBSS) { |
1567 | /* There can be only one vif available */ | ||
1568 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); | 1549 | memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN); |
1569 | common->curaid = bss_conf->aid; | 1550 | common->curaid = bss_conf->aid; |
1570 | ath9k_hw_write_associd(sc->sc_ah); | 1551 | ath9k_hw_write_associd(sc->sc_ah); |
1571 | |||
1572 | if (bss_conf->ibss_joined) { | ||
1573 | sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER; | ||
1574 | |||
1575 | if (!common->disable_ani) { | ||
1576 | set_bit(SC_OP_ANI_RUN, &sc->sc_flags); | ||
1577 | ath_start_ani(common); | ||
1578 | } | ||
1579 | |||
1580 | } else { | ||
1581 | clear_bit(SC_OP_ANI_RUN, &sc->sc_flags); | ||
1582 | del_timer_sync(&common->ani.timer); | ||
1583 | del_timer_sync(&sc->rx_poll_timer); | ||
1584 | } | ||
1585 | } | 1552 | } |
1586 | 1553 | ||
1587 | /* | 1554 | if ((changed & BSS_CHANGED_BEACON_ENABLED) || |
1588 | * In case of AP mode, the HW TSF has to be reset | 1555 | (changed & BSS_CHANGED_BEACON_INT)) { |
1589 | * when the beacon interval changes. | 1556 | if (ah->opmode == NL80211_IFTYPE_AP && |
1590 | */ | 1557 | bss_conf->enable_beacon) |
1591 | if ((changed & BSS_CHANGED_BEACON_INT) && | 1558 | ath9k_set_tsfadjust(sc, vif); |
1592 | (vif->type == NL80211_IFTYPE_AP)) | 1559 | if (ath9k_allow_beacon_config(sc, vif)) |
1593 | set_bit(SC_OP_TSF_RESET, &sc->sc_flags); | 1560 | ath9k_beacon_config(sc, vif, changed); |
1594 | |||
1595 | /* Configure beaconing (AP, IBSS, MESH) */ | ||
1596 | if (ath9k_uses_beacons(vif->type) && | ||
1597 | ((changed & BSS_CHANGED_BEACON) || | ||
1598 | (changed & BSS_CHANGED_BEACON_ENABLED) || | ||
1599 | (changed & BSS_CHANGED_BEACON_INT))) { | ||
1600 | ath9k_set_beaconing_status(sc, false); | ||
1601 | if (bss_conf->enable_beacon) | ||
1602 | ath_beacon_alloc(sc, vif); | ||
1603 | else | ||
1604 | avp->is_bslot_active = false; | ||
1605 | ath_beacon_config(sc, vif); | ||
1606 | ath9k_set_beaconing_status(sc, true); | ||
1607 | } | 1561 | } |
1608 | 1562 | ||
1609 | if (changed & BSS_CHANGED_ERP_SLOT) { | 1563 | if (changed & BSS_CHANGED_ERP_SLOT) { |
@@ -1625,8 +1579,13 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, | |||
1625 | } | 1579 | } |
1626 | } | 1580 | } |
1627 | 1581 | ||
1582 | if (changed & CHECK_ANI) | ||
1583 | ath_check_ani(sc); | ||
1584 | |||
1628 | mutex_unlock(&sc->mutex); | 1585 | mutex_unlock(&sc->mutex); |
1629 | ath9k_ps_restore(sc); | 1586 | ath9k_ps_restore(sc); |
1587 | |||
1588 | #undef CHECK_ANI | ||
1630 | } | 1589 | } |
1631 | 1590 | ||
1632 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) | 1591 | static u64 ath9k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif) |
@@ -1855,10 +1814,11 @@ static int ath9k_tx_last_beacon(struct ieee80211_hw *hw) | |||
1855 | if (!vif) | 1814 | if (!vif) |
1856 | return 0; | 1815 | return 0; |
1857 | 1816 | ||
1858 | avp = (void *)vif->drv_priv; | 1817 | if (!vif->bss_conf.enable_beacon) |
1859 | if (!avp->is_bslot_active) | ||
1860 | return 0; | 1818 | return 0; |
1861 | 1819 | ||
1820 | avp = (void *)vif->drv_priv; | ||
1821 | |||
1862 | if (!sc->beacon.tx_processed && !edma) { | 1822 | if (!sc->beacon.tx_processed && !edma) { |
1863 | tasklet_disable(&sc->bcon_tasklet); | 1823 | tasklet_disable(&sc->bcon_tasklet); |
1864 | 1824 | ||
@@ -1912,12 +1872,29 @@ static u32 fill_chainmask(u32 cap, u32 new) | |||
1912 | return filled; | 1872 | return filled; |
1913 | } | 1873 | } |
1914 | 1874 | ||
1875 | static bool validate_antenna_mask(struct ath_hw *ah, u32 val) | ||
1876 | { | ||
1877 | switch (val & 0x7) { | ||
1878 | case 0x1: | ||
1879 | case 0x3: | ||
1880 | case 0x7: | ||
1881 | return true; | ||
1882 | case 0x2: | ||
1883 | return (ah->caps.rx_chainmask == 1); | ||
1884 | default: | ||
1885 | return false; | ||
1886 | } | ||
1887 | } | ||
1888 | |||
1915 | static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) | 1889 | static int ath9k_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) |
1916 | { | 1890 | { |
1917 | struct ath_softc *sc = hw->priv; | 1891 | struct ath_softc *sc = hw->priv; |
1918 | struct ath_hw *ah = sc->sc_ah; | 1892 | struct ath_hw *ah = sc->sc_ah; |
1919 | 1893 | ||
1920 | if (!rx_ant || !tx_ant) | 1894 | if (ah->caps.rx_chainmask != 1) |
1895 | rx_ant |= tx_ant; | ||
1896 | |||
1897 | if (!validate_antenna_mask(ah, rx_ant) || !tx_ant) | ||
1921 | return -EINVAL; | 1898 | return -EINVAL; |
1922 | 1899 | ||
1923 | sc->ant_rx = rx_ant; | 1900 | sc->ant_rx = rx_ant; |
@@ -2075,6 +2052,362 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw, | |||
2075 | #endif | 2052 | #endif |
2076 | 2053 | ||
2077 | 2054 | ||
2055 | #ifdef CONFIG_PM_SLEEP | ||
2056 | |||
2057 | static void ath9k_wow_map_triggers(struct ath_softc *sc, | ||
2058 | struct cfg80211_wowlan *wowlan, | ||
2059 | u32 *wow_triggers) | ||
2060 | { | ||
2061 | if (wowlan->disconnect) | ||
2062 | *wow_triggers |= AH_WOW_LINK_CHANGE | | ||
2063 | AH_WOW_BEACON_MISS; | ||
2064 | if (wowlan->magic_pkt) | ||
2065 | *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN; | ||
2066 | |||
2067 | if (wowlan->n_patterns) | ||
2068 | *wow_triggers |= AH_WOW_USER_PATTERN_EN; | ||
2069 | |||
2070 | sc->wow_enabled = *wow_triggers; | ||
2071 | |||
2072 | } | ||
2073 | |||
2074 | static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc) | ||
2075 | { | ||
2076 | struct ath_hw *ah = sc->sc_ah; | ||
2077 | struct ath_common *common = ath9k_hw_common(ah); | ||
2078 | struct ath9k_hw_capabilities *pcaps = &ah->caps; | ||
2079 | int pattern_count = 0; | ||
2080 | int i, byte_cnt; | ||
2081 | u8 dis_deauth_pattern[MAX_PATTERN_SIZE]; | ||
2082 | u8 dis_deauth_mask[MAX_PATTERN_SIZE]; | ||
2083 | |||
2084 | memset(dis_deauth_pattern, 0, MAX_PATTERN_SIZE); | ||
2085 | memset(dis_deauth_mask, 0, MAX_PATTERN_SIZE); | ||
2086 | |||
2087 | /* | ||
2088 | * Create Dissassociate / Deauthenticate packet filter | ||
2089 | * | ||
2090 | * 2 bytes 2 byte 6 bytes 6 bytes 6 bytes | ||
2091 | * +--------------+----------+---------+--------+--------+---- | ||
2092 | * + Frame Control+ Duration + DA + SA + BSSID + | ||
2093 | * +--------------+----------+---------+--------+--------+---- | ||
2094 | * | ||
2095 | * The above is the management frame format for disassociate/ | ||
2096 | * deauthenticate pattern, from this we need to match the first byte | ||
2097 | * of 'Frame Control' and DA, SA, and BSSID fields | ||
2098 | * (skipping 2nd byte of FC and Duration feild. | ||
2099 | * | ||
2100 | * Disassociate pattern | ||
2101 | * -------------------- | ||
2102 | * Frame control = 00 00 1010 | ||
2103 | * DA, SA, BSSID = x:x:x:x:x:x | ||
2104 | * Pattern will be A0000000 | x:x:x:x:x:x | x:x:x:x:x:x | ||
2105 | * | x:x:x:x:x:x -- 22 bytes | ||
2106 | * | ||
2107 | * Deauthenticate pattern | ||
2108 | * ---------------------- | ||
2109 | * Frame control = 00 00 1100 | ||
2110 | * DA, SA, BSSID = x:x:x:x:x:x | ||
2111 | * Pattern will be C0000000 | x:x:x:x:x:x | x:x:x:x:x:x | ||
2112 | * | x:x:x:x:x:x -- 22 bytes | ||
2113 | */ | ||
2114 | |||
2115 | /* Create Disassociate Pattern first */ | ||
2116 | |||
2117 | byte_cnt = 0; | ||
2118 | |||
2119 | /* Fill out the mask with all FF's */ | ||
2120 | |||
2121 | for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++) | ||
2122 | dis_deauth_mask[i] = 0xff; | ||
2123 | |||
2124 | /* copy the first byte of frame control field */ | ||
2125 | dis_deauth_pattern[byte_cnt] = 0xa0; | ||
2126 | byte_cnt++; | ||
2127 | |||
2128 | /* skip 2nd byte of frame control and Duration field */ | ||
2129 | byte_cnt += 3; | ||
2130 | |||
2131 | /* | ||
2132 | * need not match the destination mac address, it can be a broadcast | ||
2133 | * mac address or an unicast to this station | ||
2134 | */ | ||
2135 | byte_cnt += 6; | ||
2136 | |||
2137 | /* copy the source mac address */ | ||
2138 | memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); | ||
2139 | |||
2140 | byte_cnt += 6; | ||
2141 | |||
2142 | /* copy the bssid, its same as the source mac address */ | ||
2143 | |||
2144 | memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN); | ||
2145 | |||
2146 | /* Create Disassociate pattern mask */ | ||
2147 | |||
2148 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_EXACT) { | ||
2149 | |||
2150 | if (pcaps->hw_caps & ATH9K_HW_WOW_PATTERN_MATCH_DWORD) { | ||
2151 | /* | ||
2152 | * for AR9280, because of hardware limitation, the | ||
2153 | * first 4 bytes have to be matched for all patterns. | ||
2154 | * the mask for disassociation and de-auth pattern | ||
2155 | * matching need to enable the first 4 bytes. | ||
2156 | * also the duration field needs to be filled. | ||
2157 | */ | ||
2158 | dis_deauth_mask[0] = 0xf0; | ||
2159 | |||
2160 | /* | ||
2161 | * fill in duration field | ||
2162 | FIXME: what is the exact value ? | ||
2163 | */ | ||
2164 | dis_deauth_pattern[2] = 0xff; | ||
2165 | dis_deauth_pattern[3] = 0xff; | ||
2166 | } else { | ||
2167 | dis_deauth_mask[0] = 0xfe; | ||
2168 | } | ||
2169 | |||
2170 | dis_deauth_mask[1] = 0x03; | ||
2171 | dis_deauth_mask[2] = 0xc0; | ||
2172 | } else { | ||
2173 | dis_deauth_mask[0] = 0xef; | ||
2174 | dis_deauth_mask[1] = 0x3f; | ||
2175 | dis_deauth_mask[2] = 0x00; | ||
2176 | dis_deauth_mask[3] = 0xfc; | ||
2177 | } | ||
2178 | |||
2179 | ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n"); | ||
2180 | |||
2181 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, | ||
2182 | pattern_count, byte_cnt); | ||
2183 | |||
2184 | pattern_count++; | ||
2185 | /* | ||
2186 | * for de-authenticate pattern, only the first byte of the frame | ||
2187 | * control field gets changed from 0xA0 to 0xC0 | ||
2188 | */ | ||
2189 | dis_deauth_pattern[0] = 0xC0; | ||
2190 | |||
2191 | ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask, | ||
2192 | pattern_count, byte_cnt); | ||
2193 | |||
2194 | } | ||
2195 | |||
2196 | static void ath9k_wow_add_pattern(struct ath_softc *sc, | ||
2197 | struct cfg80211_wowlan *wowlan) | ||
2198 | { | ||
2199 | struct ath_hw *ah = sc->sc_ah; | ||
2200 | struct ath9k_wow_pattern *wow_pattern = NULL; | ||
2201 | struct cfg80211_wowlan_trig_pkt_pattern *patterns = wowlan->patterns; | ||
2202 | int mask_len; | ||
2203 | s8 i = 0; | ||
2204 | |||
2205 | if (!wowlan->n_patterns) | ||
2206 | return; | ||
2207 | |||
2208 | /* | ||
2209 | * Add the new user configured patterns | ||
2210 | */ | ||
2211 | for (i = 0; i < wowlan->n_patterns; i++) { | ||
2212 | |||
2213 | wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL); | ||
2214 | |||
2215 | if (!wow_pattern) | ||
2216 | return; | ||
2217 | |||
2218 | /* | ||
2219 | * TODO: convert the generic user space pattern to | ||
2220 | * appropriate chip specific/802.11 pattern. | ||
2221 | */ | ||
2222 | |||
2223 | mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8); | ||
2224 | memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE); | ||
2225 | memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE); | ||
2226 | memcpy(wow_pattern->pattern_bytes, patterns[i].pattern, | ||
2227 | patterns[i].pattern_len); | ||
2228 | memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len); | ||
2229 | wow_pattern->pattern_len = patterns[i].pattern_len; | ||
2230 | |||
2231 | /* | ||
2232 | * just need to take care of deauth and disssoc pattern, | ||
2233 | * make sure we don't overwrite them. | ||
2234 | */ | ||
2235 | |||
2236 | ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes, | ||
2237 | wow_pattern->mask_bytes, | ||
2238 | i + 2, | ||
2239 | wow_pattern->pattern_len); | ||
2240 | kfree(wow_pattern); | ||
2241 | |||
2242 | } | ||
2243 | |||
2244 | } | ||
2245 | |||
2246 | static int ath9k_suspend(struct ieee80211_hw *hw, | ||
2247 | struct cfg80211_wowlan *wowlan) | ||
2248 | { | ||
2249 | struct ath_softc *sc = hw->priv; | ||
2250 | struct ath_hw *ah = sc->sc_ah; | ||
2251 | struct ath_common *common = ath9k_hw_common(ah); | ||
2252 | u32 wow_triggers_enabled = 0; | ||
2253 | int ret = 0; | ||
2254 | |||
2255 | mutex_lock(&sc->mutex); | ||
2256 | |||
2257 | ath_cancel_work(sc); | ||
2258 | del_timer_sync(&common->ani.timer); | ||
2259 | del_timer_sync(&sc->rx_poll_timer); | ||
2260 | |||
2261 | if (test_bit(SC_OP_INVALID, &sc->sc_flags)) { | ||
2262 | ath_dbg(common, ANY, "Device not present\n"); | ||
2263 | ret = -EINVAL; | ||
2264 | goto fail_wow; | ||
2265 | } | ||
2266 | |||
2267 | if (WARN_ON(!wowlan)) { | ||
2268 | ath_dbg(common, WOW, "None of the WoW triggers enabled\n"); | ||
2269 | ret = -EINVAL; | ||
2270 | goto fail_wow; | ||
2271 | } | ||
2272 | |||
2273 | if (!device_can_wakeup(sc->dev)) { | ||
2274 | ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n"); | ||
2275 | ret = 1; | ||
2276 | goto fail_wow; | ||
2277 | } | ||
2278 | |||
2279 | /* | ||
2280 | * none of the sta vifs are associated | ||
2281 | * and we are not currently handling multivif | ||
2282 | * cases, for instance we have to seperately | ||
2283 | * configure 'keep alive frame' for each | ||
2284 | * STA. | ||
2285 | */ | ||
2286 | |||
2287 | if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) { | ||
2288 | ath_dbg(common, WOW, "None of the STA vifs are associated\n"); | ||
2289 | ret = 1; | ||
2290 | goto fail_wow; | ||
2291 | } | ||
2292 | |||
2293 | if (sc->nvifs > 1) { | ||
2294 | ath_dbg(common, WOW, "WoW for multivif is not yet supported\n"); | ||
2295 | ret = 1; | ||
2296 | goto fail_wow; | ||
2297 | } | ||
2298 | |||
2299 | ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled); | ||
2300 | |||
2301 | ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n", | ||
2302 | wow_triggers_enabled); | ||
2303 | |||
2304 | ath9k_ps_wakeup(sc); | ||
2305 | |||
2306 | ath9k_stop_btcoex(sc); | ||
2307 | |||
2308 | /* | ||
2309 | * Enable wake up on recieving disassoc/deauth | ||
2310 | * frame by default. | ||
2311 | */ | ||
2312 | ath9k_wow_add_disassoc_deauth_pattern(sc); | ||
2313 | |||
2314 | if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN) | ||
2315 | ath9k_wow_add_pattern(sc, wowlan); | ||
2316 | |||
2317 | spin_lock_bh(&sc->sc_pcu_lock); | ||
2318 | /* | ||
2319 | * To avoid false wake, we enable beacon miss interrupt only | ||
2320 | * when we go to sleep. We save the current interrupt mask | ||
2321 | * so we can restore it after the system wakes up | ||
2322 | */ | ||
2323 | sc->wow_intr_before_sleep = ah->imask; | ||
2324 | ah->imask &= ~ATH9K_INT_GLOBAL; | ||
2325 | ath9k_hw_disable_interrupts(ah); | ||
2326 | ah->imask = ATH9K_INT_BMISS | ATH9K_INT_GLOBAL; | ||
2327 | ath9k_hw_set_interrupts(ah); | ||
2328 | ath9k_hw_enable_interrupts(ah); | ||
2329 | |||
2330 | spin_unlock_bh(&sc->sc_pcu_lock); | ||
2331 | |||
2332 | /* | ||
2333 | * we can now sync irq and kill any running tasklets, since we already | ||
2334 | * disabled interrupts and not holding a spin lock | ||
2335 | */ | ||
2336 | synchronize_irq(sc->irq); | ||
2337 | tasklet_kill(&sc->intr_tq); | ||
2338 | |||
2339 | ath9k_hw_wow_enable(ah, wow_triggers_enabled); | ||
2340 | |||
2341 | ath9k_ps_restore(sc); | ||
2342 | ath_dbg(common, ANY, "WoW enabled in ath9k\n"); | ||
2343 | atomic_inc(&sc->wow_sleep_proc_intr); | ||
2344 | |||
2345 | fail_wow: | ||
2346 | mutex_unlock(&sc->mutex); | ||
2347 | return ret; | ||
2348 | } | ||
2349 | |||
2350 | static int ath9k_resume(struct ieee80211_hw *hw) | ||
2351 | { | ||
2352 | struct ath_softc *sc = hw->priv; | ||
2353 | struct ath_hw *ah = sc->sc_ah; | ||
2354 | struct ath_common *common = ath9k_hw_common(ah); | ||
2355 | u32 wow_status; | ||
2356 | |||
2357 | mutex_lock(&sc->mutex); | ||
2358 | |||
2359 | ath9k_ps_wakeup(sc); | ||
2360 | |||
2361 | spin_lock_bh(&sc->sc_pcu_lock); | ||
2362 | |||
2363 | ath9k_hw_disable_interrupts(ah); | ||
2364 | ah->imask = sc->wow_intr_before_sleep; | ||
2365 | ath9k_hw_set_interrupts(ah); | ||
2366 | ath9k_hw_enable_interrupts(ah); | ||
2367 | |||
2368 | spin_unlock_bh(&sc->sc_pcu_lock); | ||
2369 | |||
2370 | wow_status = ath9k_hw_wow_wakeup(ah); | ||
2371 | |||
2372 | if (atomic_read(&sc->wow_got_bmiss_intr) == 0) { | ||
2373 | /* | ||
2374 | * some devices may not pick beacon miss | ||
2375 | * as the reason they woke up so we add | ||
2376 | * that here for that shortcoming. | ||
2377 | */ | ||
2378 | wow_status |= AH_WOW_BEACON_MISS; | ||
2379 | atomic_dec(&sc->wow_got_bmiss_intr); | ||
2380 | ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n"); | ||
2381 | } | ||
2382 | |||
2383 | atomic_dec(&sc->wow_sleep_proc_intr); | ||
2384 | |||
2385 | if (wow_status) { | ||
2386 | ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n", | ||
2387 | ath9k_hw_wow_event_to_string(wow_status), wow_status); | ||
2388 | } | ||
2389 | |||
2390 | ath_restart_work(sc); | ||
2391 | ath9k_start_btcoex(sc); | ||
2392 | |||
2393 | ath9k_ps_restore(sc); | ||
2394 | mutex_unlock(&sc->mutex); | ||
2395 | |||
2396 | return 0; | ||
2397 | } | ||
2398 | |||
2399 | static void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled) | ||
2400 | { | ||
2401 | struct ath_softc *sc = hw->priv; | ||
2402 | |||
2403 | mutex_lock(&sc->mutex); | ||
2404 | device_init_wakeup(sc->dev, 1); | ||
2405 | device_set_wakeup_enable(sc->dev, enabled); | ||
2406 | mutex_unlock(&sc->mutex); | ||
2407 | } | ||
2408 | |||
2409 | #endif | ||
2410 | |||
2078 | struct ieee80211_ops ath9k_ops = { | 2411 | struct ieee80211_ops ath9k_ops = { |
2079 | .tx = ath9k_tx, | 2412 | .tx = ath9k_tx, |
2080 | .start = ath9k_start, | 2413 | .start = ath9k_start, |
@@ -2104,6 +2437,12 @@ struct ieee80211_ops ath9k_ops = { | |||
2104 | .set_antenna = ath9k_set_antenna, | 2437 | .set_antenna = ath9k_set_antenna, |
2105 | .get_antenna = ath9k_get_antenna, | 2438 | .get_antenna = ath9k_get_antenna, |
2106 | 2439 | ||
2440 | #ifdef CONFIG_PM_SLEEP | ||
2441 | .suspend = ath9k_suspend, | ||
2442 | .resume = ath9k_resume, | ||
2443 | .set_wakeup = ath9k_set_wakeup, | ||
2444 | #endif | ||
2445 | |||
2107 | #ifdef CONFIG_ATH9K_DEBUGFS | 2446 | #ifdef CONFIG_ATH9K_DEBUGFS |
2108 | .get_et_sset_count = ath9k_get_et_sset_count, | 2447 | .get_et_sset_count = ath9k_get_et_sset_count, |
2109 | .get_et_stats = ath9k_get_et_stats, | 2448 | .get_et_stats = ath9k_get_et_stats, |