diff options
author | Eliad Peller <eliad@wizery.com> | 2013-12-05 10:19:39 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-02-03 15:23:41 -0500 |
commit | 37577fe2499a4d83c39910702959832baf589bab (patch) | |
tree | d97c34db553b0793ba44ab24ef35bb8525a1d8ce | |
parent | b77f06d9eccb2edb1ef78c30eb6d38632ed4f196 (diff) |
iwlwifi: mvm: get status on D0i3 exit
Schedule work to query the wakeup reasons, and
disconnect in some cases (e.g. beacon loss).
Signed-off-by: Eliad Peller <eliadx.peller@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 4 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/ops.c | 79 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/sta.c | 4 |
4 files changed, 88 insertions, 4 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 827510ea7eab..59b5b7a80d12 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -547,6 +547,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm) | |||
547 | iwl_mvm_cleanup_iterator, mvm); | 547 | iwl_mvm_cleanup_iterator, mvm); |
548 | 548 | ||
549 | mvm->p2p_device_vif = NULL; | 549 | mvm->p2p_device_vif = NULL; |
550 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
550 | 551 | ||
551 | iwl_mvm_reset_phy_ctxts(mvm); | 552 | iwl_mvm_reset_phy_ctxts(mvm); |
552 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); | 553 | memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); |
@@ -602,6 +603,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw) | |||
602 | { | 603 | { |
603 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 604 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
604 | 605 | ||
606 | flush_work(&mvm->d0i3_exit_work); | ||
605 | flush_work(&mvm->async_handlers_wk); | 607 | flush_work(&mvm->async_handlers_wk); |
606 | 608 | ||
607 | mutex_lock(&mvm->mutex); | 609 | mutex_lock(&mvm->mutex); |
@@ -1216,6 +1218,9 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm, | |||
1216 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); | 1218 | ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id); |
1217 | if (ret) | 1219 | if (ret) |
1218 | IWL_ERR(mvm, "failed to remove AP station\n"); | 1220 | IWL_ERR(mvm, "failed to remove AP station\n"); |
1221 | |||
1222 | if (mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) | ||
1223 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
1219 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 1224 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
1220 | /* remove quota for this interface */ | 1225 | /* remove quota for this interface */ |
1221 | ret = iwl_mvm_update_quotas(mvm, NULL); | 1226 | ret = iwl_mvm_update_quotas(mvm, NULL); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index fe3896ca16e7..f3966078935c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -577,6 +577,10 @@ struct iwl_mvm { | |||
577 | #endif | 577 | #endif |
578 | #endif | 578 | #endif |
579 | 579 | ||
580 | /* d0i3 */ | ||
581 | u8 d0i3_ap_sta_id; | ||
582 | struct work_struct d0i3_exit_work; | ||
583 | |||
580 | /* BT-Coex */ | 584 | /* BT-Coex */ |
581 | u8 bt_kill_msk; | 585 | u8 bt_kill_msk; |
582 | struct iwl_bt_coex_profile_notif last_bt_notif; | 586 | struct iwl_bt_coex_profile_notif last_bt_notif; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c index 12b81ca91954..4b7fa7a55c1c 100644 --- a/drivers/net/wireless/iwlwifi/mvm/ops.c +++ b/drivers/net/wireless/iwlwifi/mvm/ops.c | |||
@@ -326,6 +326,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = { | |||
326 | 326 | ||
327 | /* this forward declaration can avoid to export the function */ | 327 | /* this forward declaration can avoid to export the function */ |
328 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk); | 328 | static void iwl_mvm_async_handlers_wk(struct work_struct *wk); |
329 | static void iwl_mvm_d0i3_exit_work(struct work_struct *wk); | ||
329 | 330 | ||
330 | static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) | 331 | static u32 calc_min_backoff(struct iwl_trans *trans, const struct iwl_cfg *cfg) |
331 | { | 332 | { |
@@ -404,6 +405,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg, | |||
404 | INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); | 405 | INIT_WORK(&mvm->async_handlers_wk, iwl_mvm_async_handlers_wk); |
405 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); | 406 | INIT_WORK(&mvm->roc_done_wk, iwl_mvm_roc_done_wk); |
406 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); | 407 | INIT_WORK(&mvm->sta_drained_wk, iwl_mvm_sta_drained_wk); |
408 | INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work); | ||
407 | 409 | ||
408 | SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); | 410 | SET_IEEE80211_DEV(mvm->hw, mvm->trans->dev); |
409 | 411 | ||
@@ -819,10 +821,18 @@ static void iwl_mvm_cmd_queue_full(struct iwl_op_mode *op_mode) | |||
819 | iwl_mvm_nic_restart(mvm); | 821 | iwl_mvm_nic_restart(mvm); |
820 | } | 822 | } |
821 | 823 | ||
824 | struct iwl_d0i3_iter_data { | ||
825 | struct iwl_mvm *mvm; | ||
826 | u8 ap_sta_id; | ||
827 | u8 vif_count; | ||
828 | }; | ||
829 | |||
822 | static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, | 830 | static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, |
823 | struct ieee80211_vif *vif) | 831 | struct ieee80211_vif *vif) |
824 | { | 832 | { |
825 | struct iwl_mvm *mvm = _data; | 833 | struct iwl_d0i3_iter_data *data = _data; |
834 | struct iwl_mvm *mvm = data->mvm; | ||
835 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
826 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; | 836 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; |
827 | 837 | ||
828 | IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr); | 838 | IWL_DEBUG_RPM(mvm, "entering D0i3 - vif %pM\n", vif->addr); |
@@ -838,6 +848,8 @@ static void iwl_mvm_enter_d0i3_iterator(void *_data, u8 *mac, | |||
838 | * reconfigure them (we might want to use different | 848 | * reconfigure them (we might want to use different |
839 | * params later on, though). | 849 | * params later on, though). |
840 | */ | 850 | */ |
851 | data->ap_sta_id = mvmvif->ap_sta_id; | ||
852 | data->vif_count++; | ||
841 | } | 853 | } |
842 | 854 | ||
843 | static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | 855 | static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) |
@@ -845,6 +857,9 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
845 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 857 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
846 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; | 858 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE; |
847 | int ret; | 859 | int ret; |
860 | struct iwl_d0i3_iter_data d0i3_iter_data = { | ||
861 | .mvm = mvm, | ||
862 | }; | ||
848 | struct iwl_wowlan_config_cmd wowlan_config_cmd = { | 863 | struct iwl_wowlan_config_cmd wowlan_config_cmd = { |
849 | .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | | 864 | .wakeup_filter = cpu_to_le32(IWL_WOWLAN_WAKEUP_RX_FRAME | |
850 | IWL_WOWLAN_WAKEUP_BEACON_MISS | | 865 | IWL_WOWLAN_WAKEUP_BEACON_MISS | |
@@ -860,7 +875,13 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode) | |||
860 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 875 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
861 | IEEE80211_IFACE_ITER_NORMAL, | 876 | IEEE80211_IFACE_ITER_NORMAL, |
862 | iwl_mvm_enter_d0i3_iterator, | 877 | iwl_mvm_enter_d0i3_iterator, |
863 | mvm); | 878 | &d0i3_iter_data); |
879 | if (d0i3_iter_data.vif_count == 1) { | ||
880 | mvm->d0i3_ap_sta_id = d0i3_iter_data.ap_sta_id; | ||
881 | } else { | ||
882 | WARN_ON_ONCE(d0i3_iter_data.vif_count > 1); | ||
883 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
884 | } | ||
864 | 885 | ||
865 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, | 886 | ret = iwl_mvm_send_cmd_pdu(mvm, WOWLAN_CONFIGURATION, flags, |
866 | sizeof(wowlan_config_cmd), | 887 | sizeof(wowlan_config_cmd), |
@@ -887,6 +908,54 @@ static void iwl_mvm_exit_d0i3_iterator(void *_data, u8 *mac, | |||
887 | iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); | 908 | iwl_mvm_update_d0i3_power_mode(mvm, vif, false, flags); |
888 | } | 909 | } |
889 | 910 | ||
911 | static void iwl_mvm_d0i3_disconnect_iter(void *data, u8 *mac, | ||
912 | struct ieee80211_vif *vif) | ||
913 | { | ||
914 | struct iwl_mvm *mvm = data; | ||
915 | struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
916 | |||
917 | if (vif->type == NL80211_IFTYPE_STATION && vif->bss_conf.assoc && | ||
918 | mvm->d0i3_ap_sta_id == mvmvif->ap_sta_id) | ||
919 | ieee80211_connection_loss(vif); | ||
920 | } | ||
921 | |||
922 | static void iwl_mvm_d0i3_exit_work(struct work_struct *wk) | ||
923 | { | ||
924 | struct iwl_mvm *mvm = container_of(wk, struct iwl_mvm, d0i3_exit_work); | ||
925 | struct iwl_host_cmd get_status_cmd = { | ||
926 | .id = WOWLAN_GET_STATUSES, | ||
927 | .flags = CMD_SYNC | CMD_HIGH_PRIO | CMD_WANT_SKB, | ||
928 | }; | ||
929 | struct iwl_wowlan_status_v6 *status; | ||
930 | int ret; | ||
931 | u32 disconnection_reasons, wakeup_reasons; | ||
932 | |||
933 | mutex_lock(&mvm->mutex); | ||
934 | ret = iwl_mvm_send_cmd(mvm, &get_status_cmd); | ||
935 | if (ret) | ||
936 | goto out; | ||
937 | |||
938 | if (!get_status_cmd.resp_pkt) | ||
939 | goto out; | ||
940 | |||
941 | status = (void *)get_status_cmd.resp_pkt->data; | ||
942 | wakeup_reasons = le32_to_cpu(status->wakeup_reasons); | ||
943 | |||
944 | IWL_DEBUG_RPM(mvm, "wakeup reasons: 0x%x\n", wakeup_reasons); | ||
945 | |||
946 | disconnection_reasons = | ||
947 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_MISSED_BEACON | | ||
948 | IWL_WOWLAN_WAKEUP_BY_DISCONNECTION_ON_DEAUTH; | ||
949 | if (wakeup_reasons & disconnection_reasons) | ||
950 | ieee80211_iterate_active_interfaces( | ||
951 | mvm->hw, IEEE80211_IFACE_ITER_NORMAL, | ||
952 | iwl_mvm_d0i3_disconnect_iter, mvm); | ||
953 | |||
954 | iwl_free_resp(&get_status_cmd); | ||
955 | out: | ||
956 | mutex_unlock(&mvm->mutex); | ||
957 | } | ||
958 | |||
890 | static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) | 959 | static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) |
891 | { | 960 | { |
892 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); | 961 | struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode); |
@@ -898,13 +967,15 @@ static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode) | |||
898 | 967 | ||
899 | ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); | 968 | ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); |
900 | if (ret) | 969 | if (ret) |
901 | return ret; | 970 | goto out; |
902 | 971 | ||
903 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, | 972 | ieee80211_iterate_active_interfaces_atomic(mvm->hw, |
904 | IEEE80211_IFACE_ITER_NORMAL, | 973 | IEEE80211_IFACE_ITER_NORMAL, |
905 | iwl_mvm_exit_d0i3_iterator, | 974 | iwl_mvm_exit_d0i3_iterator, |
906 | mvm); | 975 | mvm); |
907 | return 0; | 976 | out: |
977 | schedule_work(&mvm->d0i3_exit_work); | ||
978 | return ret; | ||
908 | } | 979 | } |
909 | 980 | ||
910 | static const struct iwl_op_mode_ops iwl_mvm_ops = { | 981 | static const struct iwl_op_mode_ops iwl_mvm_ops = { |
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c index af94f75c3999..fb416c5d4a63 100644 --- a/drivers/net/wireless/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/iwlwifi/mvm/sta.c | |||
@@ -522,6 +522,10 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm, | |||
522 | 522 | ||
523 | /* unassoc - go ahead - remove the AP STA now */ | 523 | /* unassoc - go ahead - remove the AP STA now */ |
524 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; | 524 | mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT; |
525 | |||
526 | /* clear d0i3_ap_sta_id if no longer relevant */ | ||
527 | if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id) | ||
528 | mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT; | ||
525 | } | 529 | } |
526 | 530 | ||
527 | /* | 531 | /* |