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.c46
1 files changed, 35 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
index c402bfc83f3..52bec104046 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
@@ -567,10 +567,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
567 hdr_len = ieee80211_hdrlen(fc); 567 hdr_len = ieee80211_hdrlen(fc);
568 568
569 /* Find index into station table for destination station */ 569 /* Find index into station table for destination station */
570 if (!info->control.sta) 570 sta_id = iwl_sta_id_or_broadcast(priv, info->control.sta);
571 sta_id = priv->hw_params.bcast_sta_id;
572 else
573 sta_id = iwl_sta_id(info->control.sta);
574 if (sta_id == IWL_INVALID_STATION) { 571 if (sta_id == IWL_INVALID_STATION) {
575 IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", 572 IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n",
576 hdr->addr1); 573 hdr->addr1);
@@ -598,11 +595,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
598 } 595 }
599 596
600 txq_id = get_queue_from_ac(skb_get_queue_mapping(skb)); 597 txq_id = get_queue_from_ac(skb_get_queue_mapping(skb));
598
599 /* irqs already disabled/saved above when locking priv->lock */
600 spin_lock(&priv->sta_lock);
601
601 if (ieee80211_is_data_qos(fc)) { 602 if (ieee80211_is_data_qos(fc)) {
602 qc = ieee80211_get_qos_ctl(hdr); 603 qc = ieee80211_get_qos_ctl(hdr);
603 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 604 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
604 if (unlikely(tid >= MAX_TID_COUNT)) 605 if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) {
606 spin_unlock(&priv->sta_lock);
605 goto drop_unlock; 607 goto drop_unlock;
608 }
606 seq_number = priv->stations[sta_id].tid[tid].seq_number; 609 seq_number = priv->stations[sta_id].tid[tid].seq_number;
607 seq_number &= IEEE80211_SCTL_SEQ; 610 seq_number &= IEEE80211_SCTL_SEQ;
608 hdr->seq_ctrl = hdr->seq_ctrl & 611 hdr->seq_ctrl = hdr->seq_ctrl &
@@ -620,11 +623,18 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
620 swq_id = txq->swq_id; 623 swq_id = txq->swq_id;
621 q = &txq->q; 624 q = &txq->q;
622 625
623 if (unlikely(iwl_queue_space(q) < q->high_mark)) 626 if (unlikely(iwl_queue_space(q) < q->high_mark)) {
627 spin_unlock(&priv->sta_lock);
624 goto drop_unlock; 628 goto drop_unlock;
629 }
625 630
626 if (ieee80211_is_data_qos(fc)) 631 if (ieee80211_is_data_qos(fc)) {
627 priv->stations[sta_id].tid[tid].tfds_in_queue++; 632 priv->stations[sta_id].tid[tid].tfds_in_queue++;
633 if (!ieee80211_has_morefrags(fc))
634 priv->stations[sta_id].tid[tid].seq_number = seq_number;
635 }
636
637 spin_unlock(&priv->sta_lock);
628 638
629 /* Set up driver data for this TFD */ 639 /* Set up driver data for this TFD */
630 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); 640 memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info));
@@ -703,8 +713,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
703 713
704 if (!ieee80211_has_morefrags(hdr->frame_control)) { 714 if (!ieee80211_has_morefrags(hdr->frame_control)) {
705 txq->need_update = 1; 715 txq->need_update = 1;
706 if (qc)
707 priv->stations[sta_id].tid[tid].seq_number = seq_number;
708 } else { 716 } else {
709 wait_write_ptr = 1; 717 wait_write_ptr = 1;
710 txq->need_update = 0; 718 txq->need_update = 0;
@@ -1009,6 +1017,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
1009 if (ret) 1017 if (ret)
1010 return ret; 1018 return ret;
1011 1019
1020 spin_lock_irqsave(&priv->sta_lock, flags);
1021 tid_data = &priv->stations[sta_id].tid[tid];
1012 if (tid_data->tfds_in_queue == 0) { 1022 if (tid_data->tfds_in_queue == 0) {
1013 IWL_DEBUG_HT(priv, "HW queue is empty\n"); 1023 IWL_DEBUG_HT(priv, "HW queue is empty\n");
1014 tid_data->agg.state = IWL_AGG_ON; 1024 tid_data->agg.state = IWL_AGG_ON;
@@ -1018,6 +1028,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
1018 tid_data->tfds_in_queue); 1028 tid_data->tfds_in_queue);
1019 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; 1029 tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA;
1020 } 1030 }
1031 spin_unlock_irqrestore(&priv->sta_lock, flags);
1021 return ret; 1032 return ret;
1022} 1033}
1023 1034
@@ -1040,11 +1051,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
1040 return -ENXIO; 1051 return -ENXIO;
1041 } 1052 }
1042 1053
1054 spin_lock_irqsave(&priv->sta_lock, flags);
1055
1043 if (priv->stations[sta_id].tid[tid].agg.state == 1056 if (priv->stations[sta_id].tid[tid].agg.state ==
1044 IWL_EMPTYING_HW_QUEUE_ADDBA) { 1057 IWL_EMPTYING_HW_QUEUE_ADDBA) {
1045 IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); 1058 IWL_DEBUG_HT(priv, "AGG stop before setup done\n");
1046 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); 1059 ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
1047 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; 1060 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
1061 spin_unlock_irqrestore(&priv->sta_lock, flags);
1048 return 0; 1062 return 0;
1049 } 1063 }
1050 1064
@@ -1062,13 +1076,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
1062 IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n"); 1076 IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n");
1063 priv->stations[sta_id].tid[tid].agg.state = 1077 priv->stations[sta_id].tid[tid].agg.state =
1064 IWL_EMPTYING_HW_QUEUE_DELBA; 1078 IWL_EMPTYING_HW_QUEUE_DELBA;
1079 spin_unlock_irqrestore(&priv->sta_lock, flags);
1065 return 0; 1080 return 0;
1066 } 1081 }
1067 1082
1068 IWL_DEBUG_HT(priv, "HW queue is empty\n"); 1083 IWL_DEBUG_HT(priv, "HW queue is empty\n");
1069 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; 1084 priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF;
1070 1085
1071 spin_lock_irqsave(&priv->lock, flags); 1086 /* do not restore/save irqs */
1087 spin_unlock(&priv->sta_lock);
1088 spin_lock(&priv->lock);
1089
1072 /* 1090 /*
1073 * the only reason this call can fail is queue number out of range, 1091 * the only reason this call can fail is queue number out of range,
1074 * which can happen if uCode is reloaded and all the station 1092 * which can happen if uCode is reloaded and all the station
@@ -1092,6 +1110,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
1092 u8 *addr = priv->stations[sta_id].sta.sta.addr; 1110 u8 *addr = priv->stations[sta_id].sta.sta.addr;
1093 struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; 1111 struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid];
1094 1112
1113 WARN_ON(!spin_is_locked(&priv->sta_lock));
1114
1095 switch (priv->stations[sta_id].tid[tid].agg.state) { 1115 switch (priv->stations[sta_id].tid[tid].agg.state) {
1096 case IWL_EMPTYING_HW_QUEUE_DELBA: 1116 case IWL_EMPTYING_HW_QUEUE_DELBA:
1097 /* We are reclaiming the last packet of the */ 1117 /* We are reclaiming the last packet of the */
@@ -1116,6 +1136,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
1116 } 1136 }
1117 break; 1137 break;
1118 } 1138 }
1139
1119 return 0; 1140 return 0;
1120} 1141}
1121 1142
@@ -1279,6 +1300,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
1279 int index; 1300 int index;
1280 int sta_id; 1301 int sta_id;
1281 int tid; 1302 int tid;
1303 unsigned long flags;
1282 1304
1283 /* "flow" corresponds to Tx queue */ 1305 /* "flow" corresponds to Tx queue */
1284 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); 1306 u16 scd_flow = le16_to_cpu(ba_resp->scd_flow);
@@ -1301,7 +1323,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
1301 /* Find index just before block-ack window */ 1323 /* Find index just before block-ack window */
1302 index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); 1324 index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd);
1303 1325
1304 /* TODO: Need to get this copy more safely - now good for debug */ 1326 spin_lock_irqsave(&priv->sta_lock, flags);
1305 1327
1306 IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " 1328 IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, "
1307 "sta_id = %d\n", 1329 "sta_id = %d\n",
@@ -1337,4 +1359,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
1337 1359
1338 iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); 1360 iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow);
1339 } 1361 }
1362
1363 spin_unlock_irqrestore(&priv->sta_lock, flags);
1340} 1364}