aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2008-06-30 05:23:11 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-06-30 17:37:40 -0400
commit653fa4a07525e4cd9e7b90e6fc1f792119910636 (patch)
tree8116450aaf0ed40fdbb268973996f7a06438deb9 /drivers/net/wireless/iwlwifi/iwl-tx.c
parent4b8817b2a06958efd868677880334229fe5a96cf (diff)
iwlwifi: setup compressed BA handler
This patch sets the compressed BA handler for 5000. This allows the rate scaling algorithm to take in count frames that were sent in AMPDUs. The compressed BA handler has been moved to iwl-rx.c since it is common to 4965 and 5000. Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: Zhu Yi <yi.zhu@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-tx.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c
index 7296e2846ec3..032641d4c7d1 100644
--- a/drivers/net/wireless/iwlwifi/iwl-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-tx.c
@@ -1350,6 +1350,149 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id)
1350} 1350}
1351EXPORT_SYMBOL(iwl_txq_check_empty); 1351EXPORT_SYMBOL(iwl_txq_check_empty);
1352 1352
1353/**
1354 * iwl_tx_status_reply_compressed_ba - Update tx status from block-ack
1355 *
1356 * Go through block-ack's bitmap of ACK'd frames, update driver's record of
1357 * ACK vs. not. This gets sent to mac80211, then to rate scaling algo.
1358 */
1359static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv,
1360 struct iwl_ht_agg *agg,
1361 struct iwl_compressed_ba_resp *ba_resp)
1362
1363{
1364 int i, sh, ack;
1365 u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl);
1366 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
1367 u64 bitmap;
1368 int successes = 0;
1369 struct ieee80211_tx_info *info;
1370
1371 if (unlikely(!agg->wait_for_ba)) {
1372 IWL_ERROR("Received BA when not expected\n");
1373 return -EINVAL;
1374 }
1375
1376 /* Mark that the expected block-ack response arrived */
1377 agg->wait_for_ba = 0;
1378 IWL_DEBUG_TX_REPLY("BA %d %d\n", agg->start_idx, ba_resp->seq_ctl);
1379
1380 /* Calculate shift to align block-ack bits with our Tx window bits */
1381 sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl>>4);
1382 if (sh < 0) /* tbw something is wrong with indices */
1383 sh += 0x100;
1384
1385 /* don't use 64-bit values for now */
1386 bitmap = le64_to_cpu(ba_resp->bitmap) >> sh;
1387
1388 if (agg->frame_count > (64 - sh)) {
1389 IWL_DEBUG_TX_REPLY("more frames than bitmap size");
1390 return -1;
1391 }
1392
1393 /* check for success or failure according to the
1394 * transmitted bitmap and block-ack bitmap */
1395 bitmap &= agg->bitmap;
1396
1397 /* For each frame attempted in aggregation,
1398 * update driver's record of tx frame's status. */
1399 for (i = 0; i < agg->frame_count ; i++) {
1400 ack = bitmap & (1 << i);
1401 successes += !!ack;
1402 IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n",
1403 ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff,
1404 agg->start_idx + i);
1405 }
1406
1407 info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]);
1408 memset(&info->status, 0, sizeof(info->status));
1409 info->flags = IEEE80211_TX_STAT_ACK;
1410 info->flags |= IEEE80211_TX_STAT_AMPDU;
1411 info->status.ampdu_ack_map = successes;
1412 info->status.ampdu_ack_len = agg->frame_count;
1413 iwl_hwrate_to_tx_control(priv, agg->rate_n_flags, info);
1414
1415 IWL_DEBUG_TX_REPLY("Bitmap %llx\n", (unsigned long long)bitmap);
1416
1417 return 0;
1418}
1419
1420/**
1421 * iwl_rx_reply_compressed_ba - Handler for REPLY_COMPRESSED_BA
1422 *
1423 * Handles block-acknowledge notification from device, which reports success
1424 * of frames sent via aggregation.
1425 */
1426void iwl_rx_reply_compressed_ba(struct iwl_priv *priv,
1427 struct iwl_rx_mem_buffer *rxb)
1428{
1429 struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
1430 struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba;
1431 int index;
1432 struct iwl_tx_queue *txq = NULL;
1433 struct iwl_ht_agg *agg;
1434 DECLARE_MAC_BUF(mac);
1435
1436 /* "flow" corresponds to Tx queue */
1437 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
1438
1439 /* "ssn" is start of block-ack Tx window, corresponds to index
1440 * (in Tx queue's circular buffer) of first TFD/frame in window */
1441 u16 ba_resp_scd_ssn = le16_to_cpu(ba_resp->scd_ssn);
1442
1443 if (scd_flow >= priv->hw_params.max_txq_num) {
1444 IWL_ERROR("BUG_ON scd_flow is bigger than number of queues");
1445 return;
1446 }
1447
1448 txq = &priv->txq[scd_flow];
1449 agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg;
1450
1451 /* Find index just before block-ack window */
1452 index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
1453
1454 /* TODO: Need to get this copy more safely - now good for debug */
1455
1456 IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, "
1457 "sta_id = %d\n",
1458 agg->wait_for_ba,
1459 print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32),
1460 ba_resp->sta_id);
1461 IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = "
1462 "%d, scd_ssn = %d\n",
1463 ba_resp->tid,
1464 ba_resp->seq_ctl,
1465 (unsigned long long)le64_to_cpu(ba_resp->bitmap),
1466 ba_resp->scd_flow,
1467 ba_resp->scd_ssn);
1468 IWL_DEBUG_TX_REPLY("DAT start_idx = %d, bitmap = 0x%llx \n",
1469 agg->start_idx,
1470 (unsigned long long)agg->bitmap);
1471
1472 /* Update driver's record of ACK vs. not for each frame in window */
1473 iwl_tx_status_reply_compressed_ba(priv, agg, ba_resp);
1474
1475 /* Release all TFDs before the SSN, i.e. all TFDs in front of
1476 * block-ack window (we assume that they've been successfully
1477 * transmitted ... if not, it's too late anyway). */
1478 if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) {
1479 /* calculate mac80211 ampdu sw queue to wake */
1480 int ampdu_q =
1481 scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues;
1482 int freed = iwl_tx_queue_reclaim(priv, scd_flow, index);
1483 priv->stations[ba_resp->sta_id].
1484 tid[ba_resp->tid].tfds_in_queue -= freed;
1485 if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
1486 priv->mac80211_registered &&
1487 agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)
1488 ieee80211_wake_queue(priv->hw, ampdu_q);
1489
1490 iwl_txq_check_empty(priv, ba_resp->sta_id,
1491 ba_resp->tid, scd_flow);
1492 }
1493}
1494EXPORT_SYMBOL(iwl_rx_reply_compressed_ba);
1495
1353#ifdef CONFIG_IWLWIF_DEBUG 1496#ifdef CONFIG_IWLWIF_DEBUG
1354#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x 1497#define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x
1355 1498