diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/d3.c')
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 70 |
1 files changed, 49 insertions, 21 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c index d3e21d95cece..78572ef89b26 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/d3.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/d3.c | |||
@@ -7,6 +7,7 @@ | |||
7 | * | 7 | * |
8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 8 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
9 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | 9 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
10 | * Copyright(c) 2016 Intel Deutschland GmbH | ||
10 | * | 11 | * |
11 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of version 2 of the GNU General Public License as | 13 | * it under the terms of version 2 of the GNU General Public License as |
@@ -33,6 +34,7 @@ | |||
33 | * | 34 | * |
34 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. | 35 | * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. |
35 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH | 36 | * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH |
37 | * Copyright(c) 2016 Intel Deutschland GmbH | ||
36 | * All rights reserved. | 38 | * All rights reserved. |
37 | * | 39 | * |
38 | * Redistribution and use in source and binary forms, with or without | 40 | * Redistribution and use in source and binary forms, with or without |
@@ -1023,14 +1025,18 @@ iwl_mvm_wowlan_config(struct iwl_mvm *mvm, | |||
1023 | struct ieee80211_sta *ap_sta) | 1025 | struct ieee80211_sta *ap_sta) |
1024 | { | 1026 | { |
1025 | int ret; | 1027 | int ret; |
1028 | bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, | ||
1029 | IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); | ||
1026 | 1030 | ||
1027 | ret = iwl_mvm_switch_to_d3(mvm); | 1031 | if (!unified_image) { |
1028 | if (ret) | 1032 | ret = iwl_mvm_switch_to_d3(mvm); |
1029 | return ret; | 1033 | if (ret) |
1034 | return ret; | ||
1030 | 1035 | ||
1031 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); | 1036 | ret = iwl_mvm_d3_reprogram(mvm, vif, ap_sta); |
1032 | if (ret) | 1037 | if (ret) |
1033 | return ret; | 1038 | return ret; |
1039 | } | ||
1034 | 1040 | ||
1035 | if (!iwlwifi_mod_params.sw_crypto) { | 1041 | if (!iwlwifi_mod_params.sw_crypto) { |
1036 | /* | 1042 | /* |
@@ -1072,10 +1078,14 @@ iwl_mvm_netdetect_config(struct iwl_mvm *mvm, | |||
1072 | { | 1078 | { |
1073 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; | 1079 | struct iwl_wowlan_config_cmd wowlan_config_cmd = {}; |
1074 | int ret; | 1080 | int ret; |
1081 | bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, | ||
1082 | IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); | ||
1075 | 1083 | ||
1076 | ret = iwl_mvm_switch_to_d3(mvm); | 1084 | if (!unified_image) { |
1077 | if (ret) | 1085 | ret = iwl_mvm_switch_to_d3(mvm); |
1078 | return ret; | 1086 | if (ret) |
1087 | return ret; | ||
1088 | } | ||
1079 | 1089 | ||
1080 | /* rfkill release can be either for wowlan or netdetect */ | 1090 | /* rfkill release can be either for wowlan or netdetect */ |
1081 | if (wowlan->rfkill_release) | 1091 | if (wowlan->rfkill_release) |
@@ -1151,6 +1161,8 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1151 | }; | 1161 | }; |
1152 | int ret; | 1162 | int ret; |
1153 | int len __maybe_unused; | 1163 | int len __maybe_unused; |
1164 | bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, | ||
1165 | IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); | ||
1154 | 1166 | ||
1155 | if (!wowlan) { | 1167 | if (!wowlan) { |
1156 | /* | 1168 | /* |
@@ -1236,7 +1248,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw, | |||
1236 | 1248 | ||
1237 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 1249 | clear_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
1238 | 1250 | ||
1239 | iwl_trans_d3_suspend(mvm->trans, test); | 1251 | iwl_trans_d3_suspend(mvm->trans, test, !unified_image); |
1240 | out: | 1252 | out: |
1241 | if (ret < 0) { | 1253 | if (ret < 0) { |
1242 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | 1254 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); |
@@ -1299,7 +1311,7 @@ int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan) | |||
1299 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); | 1311 | __set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags); |
1300 | mutex_unlock(&mvm->d0i3_suspend_mutex); | 1312 | mutex_unlock(&mvm->d0i3_suspend_mutex); |
1301 | 1313 | ||
1302 | iwl_trans_d3_suspend(trans, false); | 1314 | iwl_trans_d3_suspend(trans, false, false); |
1303 | 1315 | ||
1304 | return 0; | 1316 | return 0; |
1305 | } | 1317 | } |
@@ -2041,9 +2053,14 @@ static void iwl_mvm_d3_disconnect_iter(void *data, u8 *mac, | |||
2041 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | 2053 | static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) |
2042 | { | 2054 | { |
2043 | struct ieee80211_vif *vif = NULL; | 2055 | struct ieee80211_vif *vif = NULL; |
2044 | int ret; | 2056 | int ret = 1; |
2045 | enum iwl_d3_status d3_status; | 2057 | enum iwl_d3_status d3_status; |
2046 | bool keep = false; | 2058 | bool keep = false; |
2059 | bool unified_image = fw_has_capa(&mvm->fw->ucode_capa, | ||
2060 | IWL_UCODE_TLV_CAPA_CNSLDTD_D3_D0_IMG); | ||
2061 | |||
2062 | u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE | | ||
2063 | CMD_WAKE_UP_TRANS; | ||
2047 | 2064 | ||
2048 | mutex_lock(&mvm->mutex); | 2065 | mutex_lock(&mvm->mutex); |
2049 | 2066 | ||
@@ -2052,7 +2069,7 @@ static int __iwl_mvm_resume(struct iwl_mvm *mvm, bool test) | |||
2052 | if (IS_ERR_OR_NULL(vif)) | 2069 | if (IS_ERR_OR_NULL(vif)) |
2053 | goto err; | 2070 | goto err; |
2054 | 2071 | ||
2055 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test); | 2072 | ret = iwl_trans_d3_resume(mvm->trans, &d3_status, test, !unified_image); |
2056 | if (ret) | 2073 | if (ret) |
2057 | goto err; | 2074 | goto err; |
2058 | 2075 | ||
@@ -2095,17 +2112,28 @@ out_iterate: | |||
2095 | iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); | 2112 | iwl_mvm_d3_disconnect_iter, keep ? vif : NULL); |
2096 | 2113 | ||
2097 | out: | 2114 | out: |
2098 | /* return 1 to reconfigure the device */ | 2115 | if (unified_image && !ret) { |
2116 | ret = iwl_mvm_send_cmd_pdu(mvm, D0I3_END_CMD, flags, 0, NULL); | ||
2117 | if (!ret) /* D3 ended successfully - no need to reset device */ | ||
2118 | return 0; | ||
2119 | } | ||
2120 | |||
2121 | /* | ||
2122 | * Reconfigure the device in one of the following cases: | ||
2123 | * 1. We are not using a unified image | ||
2124 | * 2. We are using a unified image but had an error while exiting D3 | ||
2125 | */ | ||
2099 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); | 2126 | set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status); |
2100 | set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); | 2127 | set_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status); |
2101 | 2128 | /* | |
2102 | /* We always return 1, which causes mac80211 to do a reconfig | 2129 | * When switching images we return 1, which causes mac80211 |
2103 | * with IEEE80211_RECONFIG_TYPE_RESTART. This type of | 2130 | * to do a reconfig with IEEE80211_RECONFIG_TYPE_RESTART. |
2104 | * reconfig calls iwl_mvm_restart_complete(), where we unref | 2131 | * This type of reconfig calls iwl_mvm_restart_complete(), |
2105 | * the IWL_MVM_REF_UCODE_DOWN, so we need to take the | 2132 | * where we unref the IWL_MVM_REF_UCODE_DOWN, so we need |
2106 | * reference here. | 2133 | * to take the reference here. |
2107 | */ | 2134 | */ |
2108 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); | 2135 | iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN); |
2136 | |||
2109 | return 1; | 2137 | return 1; |
2110 | } | 2138 | } |
2111 | 2139 | ||
@@ -2122,7 +2150,7 @@ static int iwl_mvm_resume_d0i3(struct iwl_mvm *mvm) | |||
2122 | enum iwl_d3_status d3_status; | 2150 | enum iwl_d3_status d3_status; |
2123 | struct iwl_trans *trans = mvm->trans; | 2151 | struct iwl_trans *trans = mvm->trans; |
2124 | 2152 | ||
2125 | iwl_trans_d3_resume(trans, &d3_status, false); | 2153 | iwl_trans_d3_resume(trans, &d3_status, false, false); |
2126 | 2154 | ||
2127 | /* | 2155 | /* |
2128 | * make sure to clear D0I3_DEFER_WAKEUP before | 2156 | * make sure to clear D0I3_DEFER_WAKEUP before |