aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c142
1 files changed, 63 insertions, 79 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index a709d05c5868..2816b432c62f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -2,7 +2,7 @@
2 * 2 *
3 * GPL LICENSE SUMMARY 3 * GPL LICENSE SUMMARY
4 * 4 *
5 * Copyright(c) 2008 - 2010 Intel Corporation. All rights reserved. 5 * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved.
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of version 2 of the GNU General Public License as 8 * it under the terms of version 2 of the GNU General Public License as
@@ -222,13 +222,8 @@ void iwlagn_tx_queue_set_status(struct iwl_priv *priv,
222 scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id); 222 scd_retry ? "BA" : "AC/CMD", txq_id, tx_fifo_id);
223} 223}
224 224
225int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, 225static int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id, int sta_id, int tid)
226 int tx_fifo, int sta_id, int tid, u16 ssn_idx)
227{ 226{
228 unsigned long flags;
229 u16 ra_tid;
230 int ret;
231
232 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || 227 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
233 (IWLAGN_FIRST_AMPDU_QUEUE + 228 (IWLAGN_FIRST_AMPDU_QUEUE +
234 priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) { 229 priv->cfg->base_params->num_of_ampdu_queues <= txq_id)) {
@@ -240,12 +235,33 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
240 return -EINVAL; 235 return -EINVAL;
241 } 236 }
242 237
243 ra_tid = BUILD_RAxTID(sta_id, tid);
244
245 /* Modify device's station table to Tx this TID */ 238 /* Modify device's station table to Tx this TID */
246 ret = iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); 239 return iwl_sta_tx_modify_enable_tid(priv, sta_id, tid);
247 if (ret) 240}
248 return ret; 241
242void iwlagn_txq_agg_queue_setup(struct iwl_priv *priv,
243 struct ieee80211_sta *sta,
244 int tid, int frame_limit)
245{
246 int sta_id, tx_fifo, txq_id, ssn_idx;
247 u16 ra_tid;
248 unsigned long flags;
249 struct iwl_tid_data *tid_data;
250
251 sta_id = iwl_sta_id(sta);
252 if (WARN_ON(sta_id == IWL_INVALID_STATION))
253 return;
254 if (WARN_ON(tid >= MAX_TID_COUNT))
255 return;
256
257 spin_lock_irqsave(&priv->sta_lock, flags);
258 tid_data = &priv->stations[sta_id].tid[tid];
259 ssn_idx = SEQ_TO_SN(tid_data->seq_number);
260 txq_id = tid_data->agg.txq_id;
261 tx_fifo = tid_data->agg.tx_fifo;
262 spin_unlock_irqrestore(&priv->sta_lock, flags);
263
264 ra_tid = BUILD_RAxTID(sta_id, tid);
249 265
250 spin_lock_irqsave(&priv->lock, flags); 266 spin_lock_irqsave(&priv->lock, flags);
251 267
@@ -271,10 +287,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
271 iwl_write_targ_mem(priv, priv->scd_base_addr + 287 iwl_write_targ_mem(priv, priv->scd_base_addr +
272 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) + 288 IWLAGN_SCD_CONTEXT_QUEUE_OFFSET(txq_id) +
273 sizeof(u32), 289 sizeof(u32),
274 ((SCD_WIN_SIZE << 290 ((frame_limit <<
275 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) & 291 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_POS) &
276 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) | 292 IWLAGN_SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK) |
277 ((SCD_FRAME_LIMIT << 293 ((frame_limit <<
278 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) & 294 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS) &
279 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK)); 295 IWLAGN_SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK));
280 296
@@ -284,12 +300,10 @@ int iwlagn_txq_agg_enable(struct iwl_priv *priv, int txq_id,
284 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1); 300 iwlagn_tx_queue_set_status(priv, &priv->txq[txq_id], tx_fifo, 1);
285 301
286 spin_unlock_irqrestore(&priv->lock, flags); 302 spin_unlock_irqrestore(&priv->lock, flags);
287
288 return 0;
289} 303}
290 304
291int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id, 305static int iwlagn_txq_agg_disable(struct iwl_priv *priv, u16 txq_id,
292 u16 ssn_idx, u8 tx_fifo) 306 u16 ssn_idx, u8 tx_fifo)
293{ 307{
294 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) || 308 if ((IWLAGN_FIRST_AMPDU_QUEUE > txq_id) ||
295 (IWLAGN_FIRST_AMPDU_QUEUE + 309 (IWLAGN_FIRST_AMPDU_QUEUE +
@@ -1034,11 +1048,11 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
1034 tid_data = &priv->stations[sta_id].tid[tid]; 1048 tid_data = &priv->stations[sta_id].tid[tid];
1035 *ssn = SEQ_TO_SN(tid_data->seq_number); 1049 *ssn = SEQ_TO_SN(tid_data->seq_number);
1036 tid_data->agg.txq_id = txq_id; 1050 tid_data->agg.txq_id = txq_id;
1051 tid_data->agg.tx_fifo = tx_fifo;
1037 iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id); 1052 iwl_set_swq_id(&priv->txq[txq_id], get_ac_from_tid(tid), txq_id);
1038 spin_unlock_irqrestore(&priv->sta_lock, flags); 1053 spin_unlock_irqrestore(&priv->sta_lock, flags);
1039 1054
1040 ret = priv->cfg->ops->lib->txq_agg_enable(priv, txq_id, tx_fifo, 1055 ret = iwlagn_txq_agg_enable(priv, txq_id, sta_id, tid);
1041 sta_id, tid, *ssn);
1042 if (ret) 1056 if (ret)
1043 return ret; 1057 return ret;
1044 1058
@@ -1125,8 +1139,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
1125 * to deactivate the uCode queue, just return "success" to allow 1139 * to deactivate the uCode queue, just return "success" to allow
1126 * mac80211 to clean up it own data. 1140 * mac80211 to clean up it own data.
1127 */ 1141 */
1128 priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, ssn, 1142 iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo_id);
1129 tx_fifo_id);
1130 spin_unlock_irqrestore(&priv->lock, flags); 1143 spin_unlock_irqrestore(&priv->lock, flags);
1131 1144
1132 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1145 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -1155,8 +1168,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
1155 u16 ssn = SEQ_TO_SN(tid_data->seq_number); 1168 u16 ssn = SEQ_TO_SN(tid_data->seq_number);
1156 int tx_fifo = get_fifo_from_tid(ctx, tid); 1169 int tx_fifo = get_fifo_from_tid(ctx, tid);
1157 IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n"); 1170 IWL_DEBUG_HT(priv, "HW queue empty: continue DELBA flow\n");
1158 priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, 1171 iwlagn_txq_agg_disable(priv, txq_id, ssn, tx_fifo);
1159 ssn, tx_fifo);
1160 tid_data->agg.state = IWL_AGG_OFF; 1172 tid_data->agg.state = IWL_AGG_OFF;
1161 ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid); 1173 ieee80211_stop_tx_ba_cb_irqsafe(ctx->vif, addr, tid);
1162 } 1174 }
@@ -1251,11 +1263,11 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1251 struct iwl_compressed_ba_resp *ba_resp) 1263 struct iwl_compressed_ba_resp *ba_resp)
1252 1264
1253{ 1265{
1254 int i, sh, ack; 1266 int sh;
1255 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); 1267 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
1256 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); 1268 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
1257 int successes = 0;
1258 struct ieee80211_tx_info *info; 1269 struct ieee80211_tx_info *info;
1270 u64 bitmap, sent_bitmap;
1259 1271
1260 if (unlikely(!agg->wait_for_ba)) { 1272 if (unlikely(!agg->wait_for_ba)) {
1261 if (unlikely(ba_resp->bitmap)) 1273 if (unlikely(ba_resp->bitmap))
@@ -1269,70 +1281,42 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1269 1281
1270 /* 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 */
1271 sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); 1283 sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4);
1272 if (sh < 0) /* tbw something is wrong with indices */ 1284 if (sh < 0)
1273 sh += 0x100; 1285 sh += 0x100;
1274 1286
1275 if (agg->frame_count > (64 - sh)) { 1287 /*
1276 IWL_DEBUG_TX_REPLY(priv, "more frames than bitmap size"); 1288 * Check for success or failure according to the
1277 return -1; 1289 * transmitted bitmap and block-ack bitmap
1278 } 1290 */
1279 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);
1280 /* 1299 /*
1281 * sent and ack information provided by uCode 1300 * set txed_2_done = txed,
1282 * use it instead of figure out ourself 1301 * so it won't impact rate scale
1283 */ 1302 */
1284 if (ba_resp->txed_2_done > ba_resp->txed) { 1303 ba_resp->txed = ba_resp->txed_2_done;
1285 IWL_DEBUG_TX_REPLY(priv, 1304 }
1286 "bogus sent(%d) and ack(%d) count\n", 1305 IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
1287 ba_resp->txed, ba_resp->txed_2_done); 1306 ba_resp->txed, ba_resp->txed_2_done);
1288 /*
1289 * set txed_2_done = txed,
1290 * so it won't impact rate scale
1291 */
1292 ba_resp->txed = ba_resp->txed_2_done;
1293 }
1294 IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
1295 ba_resp->txed, ba_resp->txed_2_done);
1296 } else {
1297 u64 bitmap, sent_bitmap;
1298
1299 /* don't use 64-bit values for now */
1300 bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
1301
1302 /* check for success or failure according to the
1303 * transmitted bitmap and block-ack bitmap */
1304 sent_bitmap = bitmap & agg->bitmap;
1305
1306 /* For each frame attempted in aggregation,
1307 * update driver's record of tx frame's status. */
1308 i = 0;
1309 while (sent_bitmap) {
1310 ack = sent_bitmap & 1ULL;
1311 successes += ack;
1312 IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n",
1313 ack ? "ACK" : "NACK", i,
1314 (agg->start_idx + i) & 0xff,
1315 agg->start_idx + i);
1316 sent_bitmap >>= 1;
1317 ++i;
1318 }
1319 1307
1320 IWL_DEBUG_TX_REPLY(priv, "Bitmap %llx\n", 1308 /* Find the first ACKed frame to store the TX status */
1321 (unsigned long long)bitmap); 1309 while (sent_bitmap && !(sent_bitmap & 1)) {
1310 agg->start_idx = (agg->start_idx + 1) & 0xff;
1311 sent_bitmap >>= 1;
1322 } 1312 }
1323 1313
1324 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);
1325 memset(&info->status, 0, sizeof(info->status)); 1315 memset(&info->status, 0, sizeof(info->status));
1326 info->flags |= IEEE80211_TX_STAT_ACK; 1316 info->flags |= IEEE80211_TX_STAT_ACK;
1327 info->flags |= IEEE80211_TX_STAT_AMPDU; 1317 info->flags |= IEEE80211_TX_STAT_AMPDU;
1328 if (!priv->cfg->base_params->no_agg_framecnt_info && ba_resp->txed) { 1318 info->status.ampdu_ack_len = ba_resp->txed_2_done;
1329 info->status.ampdu_ack_len = ba_resp->txed_2_done; 1319 info->status.ampdu_len = ba_resp->txed;
1330 info->status.ampdu_len = ba_resp->txed;
1331
1332 } else {
1333 info->status.ampdu_ack_len = successes;
1334 info->status.ampdu_len = agg->frame_count;
1335 }
1336 iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); 1320 iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
1337 1321
1338 return 0; 1322 return 0;