Commit 0968fbfa authored by Johannes Berg's avatar Johannes Berg Committed by Luca Coelho

iwlwifi: mvm: drop BA sessions on too many old-SN frames

Certain APs (I think a certain Broadcom model) interact badly with our
full state BA bitmap handling, and if triggered badly with many powersave
transitions they keep sending frames from before the window, which our
hardware then doesn't appear to ACK (to them) since it has moved on and
is sending ACKs for higher SNs now.

Try to detect this situation and if this keeps happening, disable the
aggregation session.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarLuca Coelho <luciano.coelho@intel.com>
parent f005fd88
...@@ -153,5 +153,6 @@ ...@@ -153,5 +153,6 @@
#define IWL_MVM_FTM_INITIATOR_DYNACK true #define IWL_MVM_FTM_INITIATOR_DYNACK true
#define IWL_MVM_D3_DEBUG false #define IWL_MVM_D3_DEBUG false
#define IWL_MVM_USE_TWT false #define IWL_MVM_USE_TWT false
#define IWL_MVM_AMPDU_CONSEC_DROPS_DELBA 10
#endif /* __MVM_CONSTANTS_H */ #endif /* __MVM_CONSTANTS_H */
...@@ -661,6 +661,12 @@ struct iwl_mvm_tcm { ...@@ -661,6 +661,12 @@ struct iwl_mvm_tcm {
* @valid: reordering is valid for this queue * @valid: reordering is valid for this queue
* @lock: protect reorder buffer internal state * @lock: protect reorder buffer internal state
* @mvm: mvm pointer, needed for frame timer context * @mvm: mvm pointer, needed for frame timer context
* @consec_oldsn_drops: consecutive drops due to old SN
* @consec_oldsn_ampdu_gp2: A-MPDU GP2 timestamp to track
* when to apply old SN consecutive drop workaround
* @consec_oldsn_prev_drop: track whether or not an MPDU
* that was single/part of the previous A-MPDU was
* dropped due to old SN
*/ */
struct iwl_mvm_reorder_buffer { struct iwl_mvm_reorder_buffer {
u16 head_sn; u16 head_sn;
...@@ -674,6 +680,9 @@ struct iwl_mvm_reorder_buffer { ...@@ -674,6 +680,9 @@ struct iwl_mvm_reorder_buffer {
bool valid; bool valid;
spinlock_t lock; spinlock_t lock;
struct iwl_mvm *mvm; struct iwl_mvm *mvm;
unsigned int consec_oldsn_drops;
u32 consec_oldsn_ampdu_gp2;
unsigned int consec_oldsn_prev_drop:1;
} ____cacheline_aligned_in_smp; } ____cacheline_aligned_in_smp;
/** /**
......
...@@ -781,6 +781,55 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi, ...@@ -781,6 +781,55 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct napi_struct *napi,
wake_up(&mvm->rx_sync_waitq); wake_up(&mvm->rx_sync_waitq);
} }
static void iwl_mvm_oldsn_workaround(struct iwl_mvm *mvm,
struct ieee80211_sta *sta, int tid,
struct iwl_mvm_reorder_buffer *buffer,
u32 reorder, u32 gp2, int queue)
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
if (gp2 != buffer->consec_oldsn_ampdu_gp2) {
/* we have a new (A-)MPDU ... */
/*
* reset counter to 0 if we didn't have any oldsn in
* the last A-MPDU (as detected by GP2 being identical)
*/
if (!buffer->consec_oldsn_prev_drop)
buffer->consec_oldsn_drops = 0;
/* either way, update our tracking state */
buffer->consec_oldsn_ampdu_gp2 = gp2;
} else if (buffer->consec_oldsn_prev_drop) {
/*
* tracking state didn't change, and we had an old SN
* indication before - do nothing in this case, we
* already noted this one down and are waiting for the
* next A-MPDU (by GP2)
*/
return;
}
/* return unless this MPDU has old SN */
if (!(reorder & IWL_RX_MPDU_REORDER_BA_OLD_SN))
return;
/* update state */
buffer->consec_oldsn_prev_drop = 1;
buffer->consec_oldsn_drops++;
/* if limit is reached, send del BA and reset state */
if (buffer->consec_oldsn_drops == IWL_MVM_AMPDU_CONSEC_DROPS_DELBA) {
IWL_WARN(mvm,
"reached %d old SN frames from %pM on queue %d, stopping BA session on TID %d\n",
IWL_MVM_AMPDU_CONSEC_DROPS_DELBA,
sta->addr, queue, tid);
ieee80211_stop_rx_ba_session(mvmsta->vif, BIT(tid), sta->addr);
buffer->consec_oldsn_prev_drop = 0;
buffer->consec_oldsn_drops = 0;
}
}
/* /*
* Returns true if the MPDU was buffered\dropped, false if it should be passed * Returns true if the MPDU was buffered\dropped, false if it should be passed
* to upper layer. * to upper layer.
...@@ -792,6 +841,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -792,6 +841,7 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
struct sk_buff *skb, struct sk_buff *skb,
struct iwl_rx_mpdu_desc *desc) struct iwl_rx_mpdu_desc *desc)
{ {
struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb); struct ieee80211_hdr *hdr = iwl_mvm_skb_get_hdr(skb);
struct iwl_mvm_sta *mvm_sta; struct iwl_mvm_sta *mvm_sta;
struct iwl_mvm_baid_data *baid_data; struct iwl_mvm_baid_data *baid_data;
...@@ -894,6 +944,9 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm, ...@@ -894,6 +944,9 @@ static bool iwl_mvm_reorder(struct iwl_mvm *mvm,
min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC); min_sn, IWL_MVM_RELEASE_SEND_RSS_SYNC);
} }
iwl_mvm_oldsn_workaround(mvm, sta, tid, buffer, reorder,
rx_status->device_timestamp, queue);
/* drop any oudated packets */ /* drop any oudated packets */
if (ieee80211_sn_less(sn, buffer->head_sn)) if (ieee80211_sn_less(sn, buffer->head_sn))
goto drop; goto drop;
......
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