diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 46 |
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 | } |