aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-tx.c
diff options
context:
space:
mode:
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