aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorDaniel Halperin <dhalperi@cs.washington.edu>2011-03-16 20:17:36 -0400
committerWey-Yi Guy <wey-yi.w.guy@intel.com>2011-03-25 09:57:59 -0400
commitd0eb633431ec922f8f9b2040f46d9b42a4cec193 (patch)
tree426628322ca6f5d8bccf4a61c92a9f421b5ee849 /drivers/net/wireless/iwlwifi
parent374920cb0512f5938fdf1f5af4f9afa7502dd0f9 (diff)
iwlwifi: cleanup and bugfix tx aggregation code
Since the driver split, there's no need for no_agg_framecnt_info since all devices have this set to false. Secondly, the compressed block ack handling code was broken. Fix this. (1) A shift less than zero simply implies that the buffer wrapped, this is expected. Remove the incorrect comment. (2) The (agg->frame_count > (64-sh)) condition can happen if the last frame is dropped. E.g., if I send 7 frames and the 6th is received but the 7th is lost, the other side may only shift the window 6, not 7 frames since the last bit is a 0. This is perfectly fine behavior and doesn't invalidate the feedback. (3) Store the feedback from a Compressed BA in the first newly received frame, rather than the start of the window. This way it will get processed by the rate selection code. Feedback stored in a non-received frame is likely to get overwritten by the retransmission. This is based on the approach taken by minstrel_ht. Signed-off-by: Daniel Halperin <dhalperi@cs.washington.edu> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.h3
2 files changed, 27 insertions, 58 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index fb63a03a395..cb8eacd5fdb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -1263,11 +1263,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1263 struct iwl_compressed_ba_resp *ba_resp) 1263 struct iwl_compressed_ba_resp *ba_resp)
1264 1264
1265{ 1265{
1266 int i, sh, ack; 1266 int sh;
1267 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); 1267 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
1268 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); 1268 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
1269 int successes = 0;
1270 struct ieee80211_tx_info *info; 1269 struct ieee80211_tx_info *info;
1270 u64 bitmap, sent_bitmap;
1271 1271
1272 if (unlikely(!agg->wait_for_ba)) { 1272 if (unlikely(!agg->wait_for_ba)) {
1273 if (unlikely(ba_resp->bitmap)) 1273 if (unlikely(ba_resp->bitmap))
@@ -1281,70 +1281,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1281 1281
1282 /* Calculate shift to align block-ack bits with our Tx window bits */ 1282 /* Calculate shift to align block-ack bits with our Tx window bits */
1283 sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); 1283 sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
1284 if (sh < 0) /* tbw something is wrong with indices */ 1284 if (sh < 0)
1285 sh += 0x100; 1285 sh += 0x100;
1286 1286
1287 if (agg->frame_count > (64 - sh)) { 1287 /*
1288 IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); 1288 * Check for success or failure according to the
1289 return -1; 1289 * transmitted bitmap and block-ack bitmap
1290 } 1290 */
1291 if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { 1291 bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
1292 sent_bitmap = bitmap & agg->bitmap;
1293
1294 /* Sanity check values reported by uCode */
1295 if (ba_resp->txed_2_done > ba_resp->txed) {
1296 IWL_DEBUG_TX_REPLY(priv,
1297 "bogus sent(%d) and ack(%d) count\n",
1298 ba_resp->txed, ba_resp->txed_2_done);
1292 /* 1299 /*
1293 * sent and ack information provided by uCode 1300 * set txed_2_done = txed,
1294 * use it instead of figure out ourself 1301 * so it won't impact rate scale
1295 */ 1302 */
1296 if (ba_resp->txed_2_done > ba_resp->txed) { 1303 ba_resp->txed = ba_resp->txed_2_done;
1297 IWL_DEBUG_TX_REPLY(priv, 1304 }
1298 "bogus sent(%d) and ack(%d) count\n", 1305 IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
1299 ba_resp->txed, ba_resp->txed_2_done); 1306 ba_resp->txed, ba_resp->txed_2_done);
1300 /*
1301 * set txed_2_done = txed,
1302 * so it won't impact rate scale
1303 */
1304 ba_resp->txed = ba_resp->txed_2_done;
1305 }
1306 IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
1307 ba_resp->txed, ba_resp->txed_2_done);
1308 } else {
1309 u64 bitmap, sent_bitmap;
1310
1311 /* don't use 64-bit values for now */
1312 bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
1313
1314 /* check for success or failure according to the
1315 * transmitted bitmap and block-ack bitmap */
1316 sent_bitmap = bitmap & agg->bitmap;
1317
1318 /* For each frame attempted in aggregation,
1319 * update driver's record of tx frame's status. */
1320 i = 0;
1321 while (sent_bitmap) {
1322 ack = sent_bitmap & 1ULL;
1323 successes += ack;
1324 IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
1325 ack ? "ACK" : "NACK", i,
1326 (agg->start_idx + i) & 0xff,
1327 agg->start_idx + i);
1328 sent_bitmap >>= 1;
1329 ++i;
1330 }
1331 1307
1332 IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", 1308 /* Find the first ACKed frame to store the TX status */
1333 (unsigned long long)bitmap); 1309 while (sent_bitmap && !(sent_bitmap & 1)) {
1310 agg->start_idx = (agg->start_idx + 1) & 0xff;
1311 sent_bitmap >>= 1;
1334 } 1312 }
1335 1313
1336 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); 1314 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb);
1337 memset(&info->status, 0, sizeof(info->status)); 1315 memset(&info->status, 0, sizeof(info->status));
1338 info->flags |= IEEE80211_TX_STAT_ACK; 1316 info->flags |= IEEE80211_TX_STAT_ACK;
1339 info->flags |= IEEE80211_TX_STAT_AMPDU; 1317 info->flags |= IEEE80211_TX_STAT_AMPDU;
1340 if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { 1318 info->status.ampdu_ack_len = ba_resp->txed_2_done;
1341 info->status.ampdu_ack_len = ba_resp->txed_2_done; 1319 info->status.ampdu_len = ba_resp->txed;
1342 info->status.ampdu_len = ba_resp->txed;
1343
1344 } else {
1345 info->status.ampdu_ack_len = successes;
1346 info->status.ampdu_len = agg->frame_count;
1347 }
1348 iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); 1320 iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
1349 1321
1350 return 0; 1322 return 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h
index 1f4f6dd1800..3e680af7ff7 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.h
+++ b/drivers/net/wireless/iwlwifi/iwl-core.h
@@ -281,8 +281,6 @@ struct iwl_mod_params {
281 * @chain_noise_calib_by_driver: driver has the capability to perform 281 * @chain_noise_calib_by_driver: driver has the capability to perform
282 * chain noise calibration operation 282 * chain noise calibration operation
283 * @shadow_reg_enable: HW shadhow register bit 283 * @shadow_reg_enable: HW shadhow register bit
284 * @no_agg_framecnt_info: uCode do not provide aggregation frame count
285 * information
286 */ 284 */
287struct iwl_base_params { 285struct iwl_base_params {
288 int eeprom_size; 286 int eeprom_size;
@@ -312,7 +310,6 @@ struct iwl_base_params {
312 const bool sensitivity_calib_by_driver; 310 const bool sensitivity_calib_by_driver;
313 const bool chain_noise_calib_by_driver; 311 const bool chain_noise_calib_by_driver;
314 const bool shadow_reg_enable; 312 const bool shadow_reg_enable;
315 const bool no_agg_framecnt_info;
316}; 313};
317/* 314/*
318 * @advanced_bt_coexist: support advanced bt coexist 315 * @advanced_bt_coexist: support advanced bt coexist