diff options
author | Andrei Otcheretianski <andrei.otcheretianski@intel.com> | 2014-11-10 04:10:11 -0500 |
---|---|---|
committer | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2014-11-24 01:30:29 -0500 |
commit | 7ef0aab66b317ff4d818966b2104c900c7126ec8 (patch) | |
tree | 14e643acbf19c1a9146c56e9a4f76417374ccb17 /drivers/net/wireless/iwlwifi | |
parent | 6fd1fb63abeb78fd7fe30f08f478732ad601702c (diff) |
iwlwifi: mvm: Handle failed beacon transmissions during CSA
The spec requires to decrement the CSA counters based on TBTT,
regardless if the beacon was actually transmitted. Previously, the fw
would send beacon notifications only for successfully transmitted
beacons. This behavior resulted in inaccurate CSA countdown. In order
to address this issue, the fw was changed to send beacon
notifications also for not transmitted beacons. Such notifications
have TX_STATUS_INTERNAL_ABORT (0x92).
Don't start the CSA countdown before first successfully transmitted
beacon, in order to guarantee that the CSA is announced for a
required period.
Signed-off-by: Andrei Otcheretianski <andrei.otcheretianski@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | 21 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mac80211.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/mvm/mvm.h | 3 |
3 files changed, 29 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c index a1dc9b86c2d1..0cb79bc06781 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c | |||
@@ -1263,17 +1263,25 @@ int iwl_mvm_mac_ctxt_remove(struct iwl_mvm *mvm, struct ieee80211_vif *vif) | |||
1263 | } | 1263 | } |
1264 | 1264 | ||
1265 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, | 1265 | static void iwl_mvm_csa_count_down(struct iwl_mvm *mvm, |
1266 | struct ieee80211_vif *csa_vif, u32 gp2) | 1266 | struct ieee80211_vif *csa_vif, u32 gp2, |
1267 | bool tx_success) | ||
1267 | { | 1268 | { |
1268 | struct iwl_mvm_vif *mvmvif = | 1269 | struct iwl_mvm_vif *mvmvif = |
1269 | iwl_mvm_vif_from_mac80211(csa_vif); | 1270 | iwl_mvm_vif_from_mac80211(csa_vif); |
1270 | 1271 | ||
1272 | /* Don't start to countdown from a failed beacon */ | ||
1273 | if (!tx_success && !mvmvif->csa_countdown) | ||
1274 | return; | ||
1275 | |||
1276 | mvmvif->csa_countdown = true; | ||
1277 | |||
1271 | if (!ieee80211_csa_is_complete(csa_vif)) { | 1278 | if (!ieee80211_csa_is_complete(csa_vif)) { |
1272 | int c = ieee80211_csa_update_counter(csa_vif); | 1279 | int c = ieee80211_csa_update_counter(csa_vif); |
1273 | 1280 | ||
1274 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); | 1281 | iwl_mvm_mac_ctxt_beacon_changed(mvm, csa_vif); |
1275 | if (csa_vif->p2p && | 1282 | if (csa_vif->p2p && |
1276 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2) { | 1283 | !iwl_mvm_te_scheduled(&mvmvif->time_event_data) && gp2 && |
1284 | tx_success) { | ||
1277 | u32 rel_time = (c + 1) * | 1285 | u32 rel_time = (c + 1) * |
1278 | csa_vif->bss_conf.beacon_int - | 1286 | csa_vif->bss_conf.beacon_int - |
1279 | IWL_MVM_CHANNEL_SWITCH_TIME_GO; | 1287 | IWL_MVM_CHANNEL_SWITCH_TIME_GO; |
@@ -1300,6 +1308,7 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1300 | struct ieee80211_vif *csa_vif; | 1308 | struct ieee80211_vif *csa_vif; |
1301 | struct ieee80211_vif *tx_blocked_vif; | 1309 | struct ieee80211_vif *tx_blocked_vif; |
1302 | u64 tsf; | 1310 | u64 tsf; |
1311 | u16 status; | ||
1303 | 1312 | ||
1304 | lockdep_assert_held(&mvm->mutex); | 1313 | lockdep_assert_held(&mvm->mutex); |
1305 | 1314 | ||
@@ -1316,18 +1325,18 @@ int iwl_mvm_rx_beacon_notif(struct iwl_mvm *mvm, | |||
1316 | tsf = le64_to_cpu(beacon->tsf); | 1325 | tsf = le64_to_cpu(beacon->tsf); |
1317 | } | 1326 | } |
1318 | 1327 | ||
1328 | status = le16_to_cpu(beacon_notify_hdr->status.status) & TX_STATUS_MSK; | ||
1319 | IWL_DEBUG_RX(mvm, | 1329 | IWL_DEBUG_RX(mvm, |
1320 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", | 1330 | "beacon status %#x retries:%d tsf:0x%16llX gp2:0x%X rate:%d\n", |
1321 | le16_to_cpu(beacon_notify_hdr->status.status) & | 1331 | status, beacon_notify_hdr->failure_frame, tsf, |
1322 | TX_STATUS_MSK, | ||
1323 | beacon_notify_hdr->failure_frame, tsf, | ||
1324 | mvm->ap_last_beacon_gp2, | 1332 | mvm->ap_last_beacon_gp2, |
1325 | le32_to_cpu(beacon_notify_hdr->initial_rate)); | 1333 | le32_to_cpu(beacon_notify_hdr->initial_rate)); |
1326 | 1334 | ||
1327 | csa_vif = rcu_dereference_protected(mvm->csa_vif, | 1335 | csa_vif = rcu_dereference_protected(mvm->csa_vif, |
1328 | lockdep_is_held(&mvm->mutex)); | 1336 | lockdep_is_held(&mvm->mutex)); |
1329 | if (unlikely(csa_vif && csa_vif->csa_active)) | 1337 | if (unlikely(csa_vif && csa_vif->csa_active)) |
1330 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2); | 1338 | iwl_mvm_csa_count_down(mvm, csa_vif, mvm->ap_last_beacon_gp2, |
1339 | (status == TX_STATUS_SUCCESS)); | ||
1331 | 1340 | ||
1332 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, | 1341 | tx_blocked_vif = rcu_dereference_protected(mvm->csa_tx_blocked_vif, |
1333 | lockdep_is_held(&mvm->mutex)); | 1342 | lockdep_is_held(&mvm->mutex)); |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c index 1d556173fcb6..6098eafcf13a 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c +++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c | |||
@@ -2909,6 +2909,8 @@ static void __iwl_mvm_unassign_vif_chanctx(struct iwl_mvm *mvm, | |||
2909 | if (!vif->csa_active || !mvmvif->ap_ibss_active) | 2909 | if (!vif->csa_active || !mvmvif->ap_ibss_active) |
2910 | goto out; | 2910 | goto out; |
2911 | 2911 | ||
2912 | mvmvif->csa_countdown = false; | ||
2913 | |||
2912 | /* Set CS bit on all the stations */ | 2914 | /* Set CS bit on all the stations */ |
2913 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); | 2915 | iwl_mvm_modify_all_sta_disable_tx(mvm, mvmvif, true); |
2914 | 2916 | ||
@@ -3164,6 +3166,7 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | |||
3164 | { | 3166 | { |
3165 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); | 3167 | struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); |
3166 | struct ieee80211_vif *csa_vif; | 3168 | struct ieee80211_vif *csa_vif; |
3169 | struct iwl_mvm_vif *mvmvif; | ||
3167 | int ret; | 3170 | int ret; |
3168 | 3171 | ||
3169 | mutex_lock(&mvm->mutex); | 3172 | mutex_lock(&mvm->mutex); |
@@ -3183,6 +3186,14 @@ static int iwl_mvm_pre_channel_switch(struct ieee80211_hw *hw, | |||
3183 | } | 3186 | } |
3184 | 3187 | ||
3185 | rcu_assign_pointer(mvm->csa_vif, vif); | 3188 | rcu_assign_pointer(mvm->csa_vif, vif); |
3189 | |||
3190 | mvmvif = iwl_mvm_vif_from_mac80211(vif); | ||
3191 | if (WARN_ONCE(mvmvif->csa_countdown, | ||
3192 | "Previous CSA countdown didn't complete")) { | ||
3193 | ret = -EBUSY; | ||
3194 | goto out_unlock; | ||
3195 | } | ||
3196 | |||
3186 | break; | 3197 | break; |
3187 | default: | 3198 | default: |
3188 | break; | 3199 | break; |
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h index 44625adae1c5..2c54c522b8c6 100644 --- a/drivers/net/wireless/iwlwifi/mvm/mvm.h +++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h | |||
@@ -399,6 +399,9 @@ struct iwl_mvm_vif { | |||
399 | 399 | ||
400 | /* FW identified misbehaving AP */ | 400 | /* FW identified misbehaving AP */ |
401 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; | 401 | u8 uapsd_misbehaving_bssid[ETH_ALEN]; |
402 | |||
403 | /* Indicates that CSA countdown may be started */ | ||
404 | bool csa_countdown; | ||
402 | }; | 405 | }; |
403 | 406 | ||
404 | static inline struct iwl_mvm_vif * | 407 | static inline struct iwl_mvm_vif * |