summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2016-02-28 20:28:17 +0200
committerLuca Coelho <luciano.coelho@intel.com>2016-05-10 22:14:42 +0300
commit0690405fef290c3ae9bf466d603731b2ba478053 (patch)
tree025cb08d77df59cce0a5aafb139922c1e4298c6e /drivers/net/wireless/intel/iwlwifi/mvm/sta.c
parentb915c10174fb7df533b7928046129c8f626cca42 (diff)
downloadlinux-0690405fef290c3ae9bf466d603731b2ba478053.tar.gz
linux-0690405fef290c3ae9bf466d603731b2ba478053.tar.bz2
linux-0690405fef290c3ae9bf466d603731b2ba478053.zip
iwlwifi: mvm: add reorder timeout per frame
Add a timer in order to release expired frames from the reorder buffer. This is needed since some APs do not retransmit frames to fill in the reorder holes and in TCP it results with a complete stall of traffic. This has a few side effects on the general design: The nssn may not reflect the the head of the reorder buffer. This situation is valid, and packets with SN lower than the reorder buffer head will be dropped. Another side effect is that since the reorder timer might expire we need to lock the reorder buffer. This however is fine since the locking is only inside a single reorder buffer between RX path and reorder timeout and there is no outside contention. Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/sta.c')
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c23
1 files changed, 22 insertions, 1 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index 2b839114a60f..e7f1da56d82d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -1189,8 +1189,11 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm,
struct iwl_mvm_reorder_buffer *reorder_buf =
&data->reorder_buf[i];
- if (likely(!reorder_buf->num_stored))
+ spin_lock_bh(&reorder_buf->lock);
+ if (likely(!reorder_buf->num_stored)) {
+ spin_unlock_bh(&reorder_buf->lock);
continue;
+ }
/*
* This shouldn't happen in regular DELBA since the internal
@@ -1201,6 +1204,17 @@ static void iwl_mvm_free_reorder(struct iwl_mvm *mvm,
for (j = 0; j < reorder_buf->buf_size; j++)
__skb_queue_purge(&reorder_buf->entries[j]);
+ /*
+ * Prevent timer re-arm. This prevents a very far fetched case
+ * where we timed out on the notification. There may be prior
+ * RX frames pending in the RX queue before the notification
+ * that might get processed between now and the actual deletion
+ * and we would re-arm the timer although we are deleting the
+ * reorder buffer.
+ */
+ reorder_buf->removed = true;
+ spin_unlock_bh(&reorder_buf->lock);
+ del_timer_sync(&reorder_buf->reorder_timer);
}
}
@@ -1219,6 +1233,13 @@ static void iwl_mvm_init_reorder_buffer(struct iwl_mvm *mvm,
reorder_buf->num_stored = 0;
reorder_buf->head_sn = ssn;
reorder_buf->buf_size = buf_size;
+ /* rx reorder timer */
+ reorder_buf->reorder_timer.function =
+ iwl_mvm_reorder_timer_expired;
+ reorder_buf->reorder_timer.data = (unsigned long)reorder_buf;
+ init_timer(&reorder_buf->reorder_timer);
+ spin_lock_init(&reorder_buf->lock);
+ reorder_buf->mvm = mvm;
reorder_buf->queue = i;
reorder_buf->sta_id = sta_id;
for (j = 0; j < reorder_buf->buf_size; j++)