aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDaniel Halperin <dhalperi@cs.washington.edu>2010-05-24 21:41:30 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-06-06 02:21:00 -0400
commit02cd8dee6e10d6ab7161a3c6f36a60f8894fafdd (patch)
treeceb933589fc9a7cc2a2b84e5118deb63e1adb243 /drivers
parent18ab9f1ea615a1beae2ef3364e732a990e02d9ea (diff)
iwlwifi: parse block ack responses correctly
Compressed BlockAck frames store the ACKs/NACKs in a 64-bit bitmap that starts at the sequence number of the first frame sent in the aggregated batch. Note that this is a selective ACKnowledgement following selective retransmission; e.g., if frames 1,4-5 in a batch are ACKed then the next transmission will include frames 2-3,6-10 (7 frames). In this latter case, the Compressed BlockAck will not have all meaningful information in the low order bits -- the semantically meaningful bits of the BA will be 0x1f3 (where the low-order frame is seq 2). The driver code originally just looked at the lower (in this case, 7) bits of the BlockAck. In this case, the lower 7 bits of 0x1f3 => only 5 packets, maximum, could ever be ACKed. In reality it should be looking at all of the bits, filtered by those corresponding to packets that were actually sent. This flaw meant that the number of correctly ACked packets could be significantly underreported and might result in asynchronous state between TX and RX sides as well as driver and uCode. Fix this and also add a shortcut that doesn't require the code to loop through all 64 bits of the bitmap but rather stops when no higher packets are ACKed. In my experiments this fix greatly reduces throughput swing, making throughput stable and high. It is also likely related to some of the stalls observed in aggregation mode and maybe some of the buffer underruns observed, e.g., http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=1968 http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2098 http://bugzilla.intellinuxwireless.org/show_bug.cgi?id=2018 Signed-off-by: Daniel Halperin <dhalperi@cs.washington.edu> Signed-off-by: Reinette Chatre <reinette.chatre@intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c13
1 files changed, 8 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 0d3e13b2442f..10a0acdb9dd4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -1208,7 +1208,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1208 int i, sh, ack; 1208 int i, sh, ack;
1209 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); 1209 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
1210 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); 1210 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
1211 u64 bitmap; 1211 u64 bitmap, sent_bitmap;
1212 int successes = 0; 1212 int successes = 0;
1213 struct ieee80211_tx_info *info; 1213 struct ieee80211_tx_info *info;
1214 1214
@@ -1236,16 +1236,19 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1236 1236
1237 /* check for success or failure according to the 1237 /* check for success or failure according to the
1238 * transmitted bitmap and block-ack bitmap */ 1238 * transmitted bitmap and block-ack bitmap */
1239 bitmap &= agg->bitmap; 1239 sent_bitmap = bitmap & agg->bitmap;
1240 1240
1241 /* For each frame attempted in aggregation, 1241 /* For each frame attempted in aggregation,
1242 * update driver's record of tx frame's status. */ 1242 * update driver's record of tx frame's status. */
1243 for (i = 0; i < agg->frame_count ; i++) { 1243 i = 0;
1244 ack = bitmap & (1ULL << i); 1244 while (sent_bitmap) {
1245 successes += !!ack; 1245 ack = sent_bitmap & 1ULL;
1246 successes += ack;
1246 IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", 1247 IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
1247 ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, 1248 ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff,
1248 agg->start_idx + i); 1249 agg->start_idx + i);
1250 sent_bitmap >>= 1;
1251 ++i;
1249 } 1252 }
1250 1253
1251 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); 1254 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);