Commit 74dd1764 authored by Sara Sharon's avatar Sara Sharon Committed by Luca Coelho

iwlwifi: mvm: loosen nssn comparison to reorder buffer head

Up till now, the reorder buffer uses standard spec based comparison
when comparing the buffer status to NSSN. This indeed works for the
regular case, since we shouldn't cross the 2048 boundary without
getting a frame release notification.
However, this is problematic due to packet filtering that may be
performed by the FW while we are in d0i3. Theoretically we may
filter over 2048 packets, and then the check of the NSSN will get
incorrect.
Change the comparison to always trust nssn unless it is 64 or less
frames behind the head - which might happen due to a timeout.
This new comparison is to be used only when comparing reorder buffer
head with nssn, and not when comparing the packet SN to nssn or
reorder buffer head.
Put this in a separate commit as the logic is a bit tricky and
stands for its own commit message.
Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent 7ef3dd26
...@@ -395,6 +395,18 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask, ...@@ -395,6 +395,18 @@ int iwl_mvm_notify_rx_queue(struct iwl_mvm *mvm, u32 rxq_mask,
return ret; return ret;
} }
/*
* Returns true if sn2 - buffer_size < sn1 < sn2.
* To be used only in order to compare reorder buffer head with NSSN.
* We fully trust NSSN unless it is behind us due to reorder timeout.
* Reorder timeout can only bring us up to buffer_size SNs ahead of NSSN.
*/
static bool iwl_mvm_is_sn_less(u16 sn1, u16 sn2, u16 buffer_size)
{
return ieee80211_sn_less(sn1, sn2) &&
!ieee80211_sn_less(sn1, sn2 - buffer_size);
}
#define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10) #define RX_REORDER_BUF_TIMEOUT_MQ (HZ / 10)
static void iwl_mvm_release_frames(struct iwl_mvm *mvm, static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
...@@ -408,10 +420,10 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm, ...@@ -408,10 +420,10 @@ static void iwl_mvm_release_frames(struct iwl_mvm *mvm,
lockdep_assert_held(&reorder_buf->lock); lockdep_assert_held(&reorder_buf->lock);
/* ignore nssn smaller than head sn - this can happen due to timeout */ /* ignore nssn smaller than head sn - this can happen due to timeout */
if (ieee80211_sn_less(nssn, ssn)) if (iwl_mvm_is_sn_less(nssn, ssn, reorder_buf->buf_size))
return; return;
while (ieee80211_sn_less(ssn, nssn)) { while (iwl_mvm_is_sn_less(ssn, nssn, reorder_buf->buf_size)) {
int index = ssn % reorder_buf->buf_size; int index = ssn % reorder_buf->buf_size;
struct sk_buff_head *skb_list = &reorder_buf->entries[index]; struct sk_buff_head *skb_list = &reorder_buf->entries[index];
struct sk_buff *skb; struct sk_buff *skb;
...@@ -625,7 +637,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -625,7 +637,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
* rest of the function will take of storing it and releasing up to the * rest of the function will take of storing it and releasing up to the
* nssn * nssn
*/ */
if (!ieee80211_sn_less(nssn, buffer->head_sn + buffer->buf_size)) { if (!iwl_mvm_is_sn_less(nssn, buffer->head_sn + buffer->buf_size,
buffer->buf_size)) {
u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn; u16 min_sn = ieee80211_sn_less(sn, nssn) ? sn : nssn;
iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn); iwl_mvm_release_frames(mvm, sta, napi, buffer, min_sn);
...@@ -637,7 +650,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -637,7 +650,8 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
/* release immediately if allowed by nssn and no stored frames */ /* release immediately if allowed by nssn and no stored frames */
if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) { if (!buffer->num_stored && ieee80211_sn_less(sn, nssn)) {
if (ieee80211_sn_less(buffer->head_sn, nssn)) if (iwl_mvm_is_sn_less(buffer->head_sn, nssn,
buffer->buf_size))
buffer->head_sn = nssn; buffer->head_sn = nssn;
/* No need to update AMSDU last SN - we are moving the head */ /* No need to update AMSDU last SN - we are moving the head */
spin_unlock_bh(&buffer->lock); spin_unlock_bh(&buffer->lock);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment