diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 41 |
1 files changed, 34 insertions, 7 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 18b15466fce1..52bec1040467 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -595,11 +595,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
595 | } | 595 | } |
596 | 596 | ||
597 | 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 | |||
598 | if (ieee80211_is_data_qos(fc)) { | 602 | if (ieee80211_is_data_qos(fc)) { |
599 | qc = ieee80211_get_qos_ctl(hdr); | 603 | qc = ieee80211_get_qos_ctl(hdr); |
600 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | 604 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
601 | if (unlikely(tid >= MAX_TID_COUNT)) | 605 | if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { |
606 | spin_unlock(&priv->sta_lock); | ||
602 | goto drop_unlock; | 607 | goto drop_unlock; |
608 | } | ||
603 | seq_number = priv->stations[sta_id].tid[tid].seq_number; | 609 | seq_number = priv->stations[sta_id].tid[tid].seq_number; |
604 | seq_number &= IEEE80211_SCTL_SEQ; | 610 | seq_number &= IEEE80211_SCTL_SEQ; |
605 | hdr->seq_ctrl = hdr->seq_ctrl & | 611 | hdr->seq_ctrl = hdr->seq_ctrl & |
@@ -617,11 +623,18 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
617 | swq_id = txq->swq_id; | 623 | swq_id = txq->swq_id; |
618 | q = &txq->q; | 624 | q = &txq->q; |
619 | 625 | ||
620 | 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); | ||
621 | goto drop_unlock; | 628 | goto drop_unlock; |
629 | } | ||
622 | 630 | ||
623 | if (ieee80211_is_data_qos(fc)) | 631 | if (ieee80211_is_data_qos(fc)) { |
624 | 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); | ||
625 | 638 | ||
626 | /* Set up driver data for this TFD */ | 639 | /* Set up driver data for this TFD */ |
627 | 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)); |
@@ -700,8 +713,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
700 | 713 | ||
701 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | 714 | if (!ieee80211_has_morefrags(hdr->frame_control)) { |
702 | txq->need_update = 1; | 715 | txq->need_update = 1; |
703 | if (qc) | ||
704 | priv->stations[sta_id].tid[tid].seq_number = seq_number; | ||
705 | } else { | 716 | } else { |
706 | wait_write_ptr = 1; | 717 | wait_write_ptr = 1; |
707 | txq->need_update = 0; | 718 | txq->need_update = 0; |
@@ -1006,6 +1017,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1006 | if (ret) | 1017 | if (ret) |
1007 | return ret; | 1018 | return ret; |
1008 | 1019 | ||
1020 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1021 | tid_data = &priv->stations[sta_id].tid[tid]; | ||
1009 | if (tid_data->tfds_in_queue == 0) { | 1022 | if (tid_data->tfds_in_queue == 0) { |
1010 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1023 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1011 | tid_data->agg.state = IWL_AGG_ON; | 1024 | tid_data->agg.state = IWL_AGG_ON; |
@@ -1015,6 +1028,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1015 | tid_data->tfds_in_queue); | 1028 | tid_data->tfds_in_queue); |
1016 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; | 1029 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; |
1017 | } | 1030 | } |
1031 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1018 | return ret; | 1032 | return ret; |
1019 | } | 1033 | } |
1020 | 1034 | ||
@@ -1037,11 +1051,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1037 | return -ENXIO; | 1051 | return -ENXIO; |
1038 | } | 1052 | } |
1039 | 1053 | ||
1054 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1055 | |||
1040 | if (priv->stations[sta_id].tid[tid].agg.state == | 1056 | if (priv->stations[sta_id].tid[tid].agg.state == |
1041 | IWL_EMPTYING_HW_QUEUE_ADDBA) { | 1057 | IWL_EMPTYING_HW_QUEUE_ADDBA) { |
1042 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | 1058 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); |
1043 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 1059 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
1044 | 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); | ||
1045 | return 0; | 1062 | return 0; |
1046 | } | 1063 | } |
1047 | 1064 | ||
@@ -1059,13 +1076,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1059 | 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"); |
1060 | priv->stations[sta_id].tid[tid].agg.state = | 1077 | priv->stations[sta_id].tid[tid].agg.state = |
1061 | IWL_EMPTYING_HW_QUEUE_DELBA; | 1078 | IWL_EMPTYING_HW_QUEUE_DELBA; |
1079 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1062 | return 0; | 1080 | return 0; |
1063 | } | 1081 | } |
1064 | 1082 | ||
1065 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1083 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1066 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 1084 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; |
1067 | 1085 | ||
1068 | spin_lock_irqsave(&priv->lock, flags); | 1086 | /* do not restore/save irqs */ |
1087 | spin_unlock(&priv->sta_lock); | ||
1088 | spin_lock(&priv->lock); | ||
1089 | |||
1069 | /* | 1090 | /* |
1070 | * 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, |
1071 | * which can happen if uCode is reloaded and all the station | 1092 | * which can happen if uCode is reloaded and all the station |
@@ -1089,6 +1110,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1089 | u8 *addr = priv->stations[sta_id].sta.sta.addr; | 1110 | u8 *addr = priv->stations[sta_id].sta.sta.addr; |
1090 | 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]; |
1091 | 1112 | ||
1113 | WARN_ON(!spin_is_locked(&priv->sta_lock)); | ||
1114 | |||
1092 | switch (priv->stations[sta_id].tid[tid].agg.state) { | 1115 | switch (priv->stations[sta_id].tid[tid].agg.state) { |
1093 | case IWL_EMPTYING_HW_QUEUE_DELBA: | 1116 | case IWL_EMPTYING_HW_QUEUE_DELBA: |
1094 | /* We are reclaiming the last packet of the */ | 1117 | /* We are reclaiming the last packet of the */ |
@@ -1113,6 +1136,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1113 | } | 1136 | } |
1114 | break; | 1137 | break; |
1115 | } | 1138 | } |
1139 | |||
1116 | return 0; | 1140 | return 0; |
1117 | } | 1141 | } |
1118 | 1142 | ||
@@ -1276,6 +1300,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1276 | int index; | 1300 | int index; |
1277 | int sta_id; | 1301 | int sta_id; |
1278 | int tid; | 1302 | int tid; |
1303 | unsigned long flags; | ||
1279 | 1304 | ||
1280 | /* "flow" corresponds to Tx queue */ | 1305 | /* "flow" corresponds to Tx queue */ |
1281 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 1306 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); |
@@ -1298,7 +1323,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1298 | /* Find index just before block-ack window */ | 1323 | /* Find index just before block-ack window */ |
1299 | 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); |
1300 | 1325 | ||
1301 | /* TODO: Need to get this copy more safely - now good for debug */ | 1326 | spin_lock_irqsave(&priv->sta_lock, flags); |
1302 | 1327 | ||
1303 | 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, " |
1304 | "sta_id = %d\n", | 1329 | "sta_id = %d\n", |
@@ -1334,4 +1359,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1334 | 1359 | ||
1335 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); | 1360 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); |
1336 | } | 1361 | } |
1362 | |||
1363 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1337 | } | 1364 | } |