aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c28
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-debugfs.c5
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans-pcie.c31
5 files changed, 54 insertions, 38 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index 1cac701c4182..69d0f9972988 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -772,7 +772,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
772 struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; 772 struct iwlagn_tx_resp *tx_resp = (void *)&pkt->u.raw[0];
773 struct ieee80211_hdr *hdr; 773 struct ieee80211_hdr *hdr;
774 u32 status = le16_to_cpu(tx_resp->status.status); 774 u32 status = le16_to_cpu(tx_resp->status.status);
775 u32 ssn = iwlagn_get_scd_ssn(tx_resp); 775 u16 ssn = iwlagn_get_scd_ssn(tx_resp);
776 int tid; 776 int tid;
777 int sta_id; 777 int sta_id;
778 int freed; 778 int freed;
@@ -794,8 +794,31 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb,
794 iwl_rx_reply_tx_agg(priv, tx_resp); 794 iwl_rx_reply_tx_agg(priv, tx_resp);
795 795
796 if (tx_resp->frame_count == 1) { 796 if (tx_resp->frame_count == 1) {
797 IWL_DEBUG_TX_REPLY(priv, "Q %d, ssn %d", txq_id, ssn); 797 u16 next_reclaimed = le16_to_cpu(tx_resp->seq_ctl);
798 next_reclaimed = SEQ_TO_SN(next_reclaimed + 0x10);
799
800 if (is_agg) {
801 /* If this is an aggregation queue, we can rely on the
802 * ssn since the wifi sequence number corresponds to
803 * the index in the TFD ring (%256).
804 * The seq_ctl is the sequence control of the packet
805 * to which this Tx response relates. But if there is a
806 * hole in the bitmap of the BA we received, this Tx
807 * response may allow to reclaim the hole and all the
808 * subsequent packets that were already acked.
809 * In that case, seq_ctl != ssn, and the next packet
810 * to be reclaimed will be ssn and not seq_ctl.
811 */
812 next_reclaimed = ssn;
813 }
814
798 __skb_queue_head_init(&skbs); 815 __skb_queue_head_init(&skbs);
816 priv->shrd->tid_data[sta_id][tid].next_reclaimed =
817 next_reclaimed;
818
819 IWL_DEBUG_TX_REPLY(priv, "Next reclaimed packet:%d",
820 next_reclaimed);
821
799 /*we can free until ssn % q.n_bd not inclusive */ 822 /*we can free until ssn % q.n_bd not inclusive */
800 iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id, 823 iwl_trans_reclaim(trans(priv), sta_id, tid, txq_id,
801 ssn, status, &skbs); 824 ssn, status, &skbs);
@@ -951,6 +974,7 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
951 /* Release all TFDs before the SSN, i.e. all TFDs in front of 974 /* Release all TFDs before the SSN, i.e. all TFDs in front of
952 * block-ack window (we assume that they've been successfully 975 * block-ack window (we assume that they've been successfully
953 * transmitted ... if not, it's too late anyway). */ 976 * transmitted ... if not, it's too late anyway). */
977 priv->shrd->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;
954 iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, ba_resp_scd_ssn, 978 iwl_trans_reclaim(trans(priv), sta_id, tid, scd_flow, ba_resp_scd_ssn,
955 0, &reclaimed_skbs); 979 0, &reclaimed_skbs);
956 freed = 0; 980 freed = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
index 074068e78320..7c5114da4f6f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c
+++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c
@@ -372,15 +372,14 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf,
372 i, station->sta.sta.addr, 372 i, station->sta.sta.addr,
373 station->sta.station_flags_msk); 373 station->sta.station_flags_msk);
374 pos += scnprintf(buf + pos, bufsz - pos, 374 pos += scnprintf(buf + pos, bufsz - pos,
375 "TID\tseq_num\ttxq_id\ttfds\trate_n_flags\n"); 375 "TID\tseq_num\ttxq_id\trate_n_flags\n");
376 376
377 for (j = 0; j < IWL_MAX_TID_COUNT; j++) { 377 for (j = 0; j < IWL_MAX_TID_COUNT; j++) {
378 tid_data = &priv->shrd->tid_data[i][j]; 378 tid_data = &priv->shrd->tid_data[i][j];
379 pos += scnprintf(buf + pos, bufsz - pos, 379 pos += scnprintf(buf + pos, bufsz - pos,
380 "%d:\t%#x\t%#x\t%u\t%#x", 380 "%d:\t%#x\t%#x\t%#x",
381 j, tid_data->seq_number, 381 j, tid_data->seq_number,
382 tid_data->agg.txq_id, 382 tid_data->agg.txq_id,
383 tid_data->tfds_in_queue,
384 tid_data->agg.rate_n_flags); 383 tid_data->agg.rate_n_flags);
385 384
386 if (tid_data->agg.wait_for_ba) 385 if (tid_data->agg.wait_for_ba)
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index df6d2123fe4f..8a9690714c13 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -231,12 +231,17 @@ enum iwl_agg_state {
231 * @state: state of the BA agreement establishment / tear down. 231 * @state: state of the BA agreement establishment / tear down.
232 * @txq_id: Tx queue used by the BA session - used by the transport layer. 232 * @txq_id: Tx queue used by the BA session - used by the transport layer.
233 * Needed by the upper layer for debugfs only. 233 * Needed by the upper layer for debugfs only.
234 * @ssn: the first packet to be sent in AGG HW queue in Tx AGG start flow, or
235 * the first packet to be sent in legacy HW queue in Tx AGG stop flow.
236 * Basically when next_reclaimed reaches ssn, we can tell mac80211 that
237 * we are ready to finish the Tx AGG stop / start flow.
234 * @wait_for_ba: Expect block-ack before next Tx reply 238 * @wait_for_ba: Expect block-ack before next Tx reply
235 */ 239 */
236struct iwl_ht_agg { 240struct iwl_ht_agg {
237 u32 rate_n_flags; 241 u32 rate_n_flags;
238 enum iwl_agg_state state; 242 enum iwl_agg_state state;
239 u16 txq_id; 243 u16 txq_id;
244 u16 ssn;
240 bool wait_for_ba; 245 bool wait_for_ba;
241}; 246};
242 247
@@ -246,13 +251,13 @@ struct iwl_ht_agg {
246 * This structs holds the states for each RA / TID. 251 * This structs holds the states for each RA / TID.
247 252
248 * @seq_number: the next WiFi sequence number to use 253 * @seq_number: the next WiFi sequence number to use
249 * @tfds_in_queue: number of packets sent to the HW queues. 254 * @next_reclaimed: the WiFi sequence number of the next packet to be acked.
250 * Exported for debugfs only 255 * This is basically (last acked packet++).
251 * @agg: aggregation state machine 256 * @agg: aggregation state machine
252 */ 257 */
253struct iwl_tid_data { 258struct iwl_tid_data {
254 u16 seq_number; 259 u16 seq_number;
255 u16 tfds_in_queue; 260 u16 next_reclaimed;
256 struct iwl_ht_agg agg; 261 struct iwl_ht_agg agg;
257}; 262};
258 263
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
index 79331fb10aa5..1b1077cc3534 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-tx.c
@@ -555,18 +555,22 @@ int iwl_trans_pcie_tx_agg_alloc(struct iwl_trans *trans,
555 555
556 spin_lock_irqsave(&trans->shrd->sta_lock, flags); 556 spin_lock_irqsave(&trans->shrd->sta_lock, flags);
557 tid_data = &trans->shrd->tid_data[sta_id][tid]; 557 tid_data = &trans->shrd->tid_data[sta_id][tid];
558 *ssn = SEQ_TO_SN(tid_data->seq_number);
559 tid_data->agg.txq_id = txq_id; 558 tid_data->agg.txq_id = txq_id;
559 tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
560
561 *ssn = tid_data->agg.ssn;
560 iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id); 562 iwl_set_swq_id(&trans_pcie->txq[txq_id], get_ac_from_tid(tid), txq_id);
561 563
562 if (tid_data->tfds_in_queue == 0) { 564 if (*ssn == tid_data->next_reclaimed) {
563 IWL_DEBUG_TX_QUEUES(trans, "HW queue is empty\n"); 565 IWL_DEBUG_TX_QUEUES(trans, "Proceed: ssn = next_recl = %d",
566 tid_data->agg.ssn);
564 tid_data->agg.state = IWL_AGG_ON; 567 tid_data->agg.state = IWL_AGG_ON;
565 iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid); 568 iwl_start_tx_ba_trans_ready(priv(trans), ctx, sta_id, tid);
566 } else { 569 } else {
567 IWL_DEBUG_TX_QUEUES(trans, 570 IWL_DEBUG_TX_QUEUES(trans, "Can't proceed: ssn %d, "
568 "HW queue is NOT empty: %d packets in HW" 571 "next_recl = %d",
569 " queue\n", tid_data->tfds_in_queue); 572 tid_data->agg.ssn,
573 tid_data->next_reclaimed);
570 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; 574 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
571 } 575 }
572 spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); 576 spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
@@ -647,6 +651,7 @@ int iwl_trans_pcie_tx_agg_disable(struct iwl_trans *trans,
647 "Stopping a non empty AGG HW QUEUE\n"); 651 "Stopping a non empty AGG HW QUEUE\n");
648 trans->shrd->tid_data[sta_id][tid].agg.state = 652 trans->shrd->tid_data[sta_id][tid].agg.state =
649 IWL_EMPTYING_HW_QUEUE_DELBA; 653 IWL_EMPTYING_HW_QUEUE_DELBA;
654 tid_data->agg.ssn = SEQ_TO_SN(tid_data->seq_number);
650 spin_unlock_irqrestore(&trans->shrd->sta_lock, flags); 655 spin_unlock_irqrestore(&trans->shrd->sta_lock, flags);
651 return 0; 656 return 0;
652 } 657 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
index 66e1b9fa0b8b..4d318431270b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
@@ -1109,7 +1109,7 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1109 IWL_ERR(trans, "sta_id = %d, tid = %d " 1109 IWL_ERR(trans, "sta_id = %d, tid = %d "
1110 "txq_id = %d, seq_num = %d", sta_id, 1110 "txq_id = %d, seq_num = %d", sta_id,
1111 tid, tid_data->agg.txq_id, 1111 tid, tid_data->agg.txq_id,
1112 seq_number >> 4); 1112 SEQ_TO_SN(seq_number));
1113 } 1113 }
1114 txq_id = tid_data->agg.txq_id; 1114 txq_id = tid_data->agg.txq_id;
1115 is_agg = true; 1115 is_agg = true;
@@ -1222,12 +1222,10 @@ static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
1222 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd); 1222 q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
1223 iwl_txq_update_write_ptr(trans, txq); 1223 iwl_txq_update_write_ptr(trans, txq);
1224 1224
1225 if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) { 1225 if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc) &&
1226 trans->shrd->tid_data[sta_id][tid].tfds_in_queue++; 1226 !ieee80211_has_morefrags(fc))
1227 if (!ieee80211_has_morefrags(fc))
1228 trans->shrd->tid_data[sta_id][tid].seq_number = 1227 trans->shrd->tid_data[sta_id][tid].seq_number =
1229 seq_number; 1228 seq_number;
1230 }
1231 1229
1232 /* 1230 /*
1233 * At this point the frame is "transmitted" successfully 1231 * At this point the frame is "transmitted" successfully
@@ -1304,10 +1302,11 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
1304 } 1302 }
1305 break; 1303 break;
1306 case IWL_EMPTYING_HW_QUEUE_ADDBA: 1304 case IWL_EMPTYING_HW_QUEUE_ADDBA:
1307 /* We are reclaiming the last packet of the queue */ 1305 /* There are no packets for this RA / TID in the HW any more */
1308 if (tid_data->tfds_in_queue == 0) { 1306 if (tid_data->agg.ssn == tid_data->next_reclaimed) {
1309 IWL_DEBUG_TX_QUEUES(trans, 1307 IWL_DEBUG_TX_QUEUES(trans,
1310 "HW queue empty: continue ADDBA flow\n"); 1308 "Can continue ADDBA flow ssn = next_recl ="
1309 " %d", tid_data->next_reclaimed);
1311 tid_data->agg.state = IWL_AGG_ON; 1310 tid_data->agg.state = IWL_AGG_ON;
1312 iwl_start_tx_ba_trans_ready(priv(trans), 1311 iwl_start_tx_ba_trans_ready(priv(trans),
1313 NUM_IWL_RXON_CTX, 1312 NUM_IWL_RXON_CTX,
@@ -1321,21 +1320,6 @@ static int iwlagn_txq_check_empty(struct iwl_trans *trans,
1321 return 0; 1320 return 0;
1322} 1321}
1323 1322
1324static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
1325 int sta_id, int tid, int freed)
1326{
1327 lockdep_assert_held(&trans->shrd->sta_lock);
1328
1329 if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
1330 trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
1331 else {
1332 IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
1333 trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
1334 freed);
1335 trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
1336 }
1337}
1338
1339static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid, 1323static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
1340 int txq_id, int ssn, u32 status, 1324 int txq_id, int ssn, u32 status,
1341 struct sk_buff_head *skbs) 1325 struct sk_buff_head *skbs)
@@ -1367,7 +1351,6 @@ static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
1367 iwl_wake_queue(trans, txq, "Packets reclaimed"); 1351 iwl_wake_queue(trans, txq, "Packets reclaimed");
1368 } 1352 }
1369 1353
1370 iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
1371 iwlagn_txq_check_empty(trans, sta_id, tid, txq_id); 1354 iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
1372} 1355}
1373 1356