aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-agn-tx.c
diff options
context:
space:
mode:
authorReinette Chatre <reinette.chatre@intel.com>2010-05-05 05:26:06 -0400
committerReinette Chatre <reinette.chatre@intel.com>2010-05-13 13:44:16 -0400
commit9c5ac091b269912cd30fade987f4bc615ef3be90 (patch)
tree698fe77ad1f144ca1c2e3ba9738946a22253399f /drivers/net/wireless/iwlwifi/iwl-agn-tx.c
parent94adfaa406420ae035b1b760e3d5015775fe7b7c (diff)
iwlwifi: fix and add missing sta_lock usage
There are a few places where sta_lock is used, but the station information protected by it is accessed outside of the lock. Address this in two ways, if the access won't sleep then just move the access into the lock, if the access can sleep then copy the needed station information to the stack to be accessed without risk of it changing while access in progress. Additionally, a number of other places access station station information without holding the sta_lock, fix those as well. Signed-off-by: Reinette Chatre <reinette.chatre@intel.com> Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-tx.c41
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}