diff options
author | Daniel Halperin <dhalperi@cs.washington.edu> | 2011-03-16 20:17:36 -0400 |
---|---|---|
committer | Wey-Yi Guy <wey-yi.w.guy@intel.com> | 2011-03-25 09:57:59 -0400 |
commit | d0eb633431ec922f8f9b2040f46d9b42a4cec193 (patch) | |
tree | 426628322ca6f5d8bccf4a61c92a9f421b5ee849 /drivers/net/wireless/iwlwifi | |
parent | 374920cb0512f5938fdf1f5af4f9afa7502dd0f9 (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.c | 82 | ||||
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-core.h | 3 |
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 fb63a03a395e..cb8eacd5fdb5 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 1f4f6dd18009..3e680af7ff70 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 | */ |
287 | struct iwl_base_params { | 285 | struct 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 |