]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
iwlwifi: mvm: give client MACs time to synchronise during restart
authorJohannes Berg <johannes.berg@intel.com>
Fri, 3 May 2013 09:16:15 +0000 (11:16 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 2 Oct 2013 16:00:34 +0000 (18:00 +0200)
When firmware restart happens, the timers are obviously reset and
the new firmware has no synchronisation with the AP as we program
timings to the pre-restart values. The firmware should attempt to
synchronise by itself, but in multi-channel scenarios this isn't
easy, particularly since it has to try to keep service quality up
for other MACs.

To make it more reliable, give each client MAC some time to catch
beacons when restarting or resuming. Service quality was impacted
anyway (or in resume doesn't really matter much.)

Reviewed-by: Moshe Island <moshe.island@intel.com>
Reviewed-by: Ilan Peer <ilan.peer@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h

index 3261730181fa53c548d9e9061501c36f1cdc9673..77166520bc019619bb14a2a20f129929813dfc76 100644 (file)
@@ -803,6 +803,27 @@ static void iwl_mvm_bss_info_changed_station(struct iwl_mvm *mvm,
                                return;
                        }
                        iwl_mvm_configure_mcast_filter(mvm, vif);
+
+                       if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+                                    &mvm->status)) {
+                               /*
+                                * If we're restarting then the firmware will
+                                * obviously have lost synchronisation with
+                                * the AP. It will attempt to synchronise by
+                                * itself, but we can make it more reliable by
+                                * scheduling a session protection time event.
+                                *
+                                * The firmware needs to receive a beacon to
+                                * catch up with synchronisation, use 110% of
+                                * the beacon interval.
+                                *
+                                * Set a large maximum delay to allow for more
+                                * than a single interface.
+                                */
+                               u32 dur = (11 * vif->bss_conf.beacon_int) / 10;
+                               iwl_mvm_protect_session(mvm, vif, dur, dur,
+                                                       5 * dur);
+                       }
                } else if (mvmvif->ap_sta_id != IWL_MVM_STATION_COUNT) {
                        /* remove AP station now that the MAC is unassoc */
                        ret = iwl_mvm_rm_sta_id(mvm, vif, mvmvif->ap_sta_id);
@@ -1170,7 +1191,7 @@ static void iwl_mvm_mac_mgd_prepare_tx(struct ieee80211_hw *hw,
 
        mutex_lock(&mvm->mutex);
        /* Try really hard to protect the session and hear a beacon */
-       iwl_mvm_protect_session(mvm, vif, duration, min_duration);
+       iwl_mvm_protect_session(mvm, vif, duration, min_duration, 500);
        mutex_unlock(&mvm->mutex);
 }
 
index 76a3c177e100ab28660ac9433fe5c26edc5a79e8..33cf56fdfc41f86b8bb517a8824740bdbb71a896 100644 (file)
@@ -387,7 +387,8 @@ static int iwl_mvm_time_event_send_add(struct iwl_mvm *mvm,
 
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                             struct ieee80211_vif *vif,
-                            u32 duration, u32 min_duration)
+                            u32 duration, u32 min_duration,
+                            u32 max_delay)
 {
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
        struct iwl_mvm_time_event_data *te_data = &mvmvif->time_event_data;
@@ -426,7 +427,7 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                cpu_to_le32(iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG));
 
        time_cmd.max_frags = TE_V2_FRAG_NONE;
-       time_cmd.max_delay = cpu_to_le32(500);
+       time_cmd.max_delay = cpu_to_le32(max_delay);
        /* TODO: why do we need to interval = bi if it is not periodic? */
        time_cmd.interval = cpu_to_le32(1);
        time_cmd.duration = cpu_to_le32(duration);
index f86c51065ed3afe1e860f8fb15d50cc1f6eaef9b..d9c8d6cfa2db0c4a44a58b0ec2bc0eaf6fca94cc 100644 (file)
  * @duration: the duration of the session in TU.
  * @min_duration: will start a new session if the current session will end
  *     in less than min_duration.
+ * @max_delay: maximum delay before starting the time event (in TU)
  *
  * This function can be used to start a session protection which means that the
  * fw will stay on the channel for %duration_ms milliseconds. This function
  */
 void iwl_mvm_protect_session(struct iwl_mvm *mvm,
                             struct ieee80211_vif *vif,
-                            u32 duration, u32 min_duration);
+                            u32 duration, u32 min_duration,
+                            u32 max_delay);
 
 /**
  * iwl_mvm_stop_session_protection - cancel the session protection.