diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-agn-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 77 |
1 files changed, 52 insertions, 25 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index c402bfc83f36..10a0acdb9dd4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c | |||
@@ -469,7 +469,8 @@ static void iwlagn_tx_cmd_build_rate(struct iwl_priv *priv, | |||
469 | } | 469 | } |
470 | 470 | ||
471 | /* Set up antennas */ | 471 | /* Set up antennas */ |
472 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); | 472 | priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant, |
473 | priv->hw_params.valid_tx_ant); | ||
473 | rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); | 474 | rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); |
474 | 475 | ||
475 | /* Set the rate in the TX cmd */ | 476 | /* Set the rate in the TX cmd */ |
@@ -567,10 +568,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
567 | hdr_len = ieee80211_hdrlen(fc); | 568 | hdr_len = ieee80211_hdrlen(fc); |
568 | 569 | ||
569 | /* Find index into station table for destination station */ | 570 | /* Find index into station table for destination station */ |
570 | if (!info->control.sta) | 571 | 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) { | 572 | if (sta_id == IWL_INVALID_STATION) { |
575 | IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", | 573 | IWL_DEBUG_DROP(priv, "Dropping - INVALID STATION: %pM\n", |
576 | hdr->addr1); | 574 | hdr->addr1); |
@@ -598,11 +596,17 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
598 | } | 596 | } |
599 | 597 | ||
600 | txq_id = get_queue_from_ac(skb_get_queue_mapping(skb)); | 598 | txq_id = get_queue_from_ac(skb_get_queue_mapping(skb)); |
599 | |||
600 | /* irqs already disabled/saved above when locking priv->lock */ | ||
601 | spin_lock(&priv->sta_lock); | ||
602 | |||
601 | if (ieee80211_is_data_qos(fc)) { | 603 | if (ieee80211_is_data_qos(fc)) { |
602 | qc = ieee80211_get_qos_ctl(hdr); | 604 | qc = ieee80211_get_qos_ctl(hdr); |
603 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; | 605 | tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK; |
604 | if (unlikely(tid >= MAX_TID_COUNT)) | 606 | if (WARN_ON_ONCE(tid >= MAX_TID_COUNT)) { |
607 | spin_unlock(&priv->sta_lock); | ||
605 | goto drop_unlock; | 608 | goto drop_unlock; |
609 | } | ||
606 | seq_number = priv->stations[sta_id].tid[tid].seq_number; | 610 | seq_number = priv->stations[sta_id].tid[tid].seq_number; |
607 | seq_number &= IEEE80211_SCTL_SEQ; | 611 | seq_number &= IEEE80211_SCTL_SEQ; |
608 | hdr->seq_ctrl = hdr->seq_ctrl & | 612 | hdr->seq_ctrl = hdr->seq_ctrl & |
@@ -620,15 +624,22 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
620 | swq_id = txq->swq_id; | 624 | swq_id = txq->swq_id; |
621 | q = &txq->q; | 625 | q = &txq->q; |
622 | 626 | ||
623 | if (unlikely(iwl_queue_space(q) < q->high_mark)) | 627 | if (unlikely(iwl_queue_space(q) < q->high_mark)) { |
628 | spin_unlock(&priv->sta_lock); | ||
624 | goto drop_unlock; | 629 | goto drop_unlock; |
630 | } | ||
625 | 631 | ||
626 | if (ieee80211_is_data_qos(fc)) | 632 | if (ieee80211_is_data_qos(fc)) { |
627 | priv->stations[sta_id].tid[tid].tfds_in_queue++; | 633 | priv->stations[sta_id].tid[tid].tfds_in_queue++; |
634 | if (!ieee80211_has_morefrags(fc)) | ||
635 | priv->stations[sta_id].tid[tid].seq_number = seq_number; | ||
636 | } | ||
637 | |||
638 | spin_unlock(&priv->sta_lock); | ||
628 | 639 | ||
629 | /* Set up driver data for this TFD */ | 640 | /* Set up driver data for this TFD */ |
630 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); | 641 | memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); |
631 | txq->txb[q->write_ptr].skb[0] = skb; | 642 | txq->txb[q->write_ptr].skb = skb; |
632 | 643 | ||
633 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ | 644 | /* Set up first empty entry in queue's array of Tx/cmd buffers */ |
634 | out_cmd = txq->cmd[q->write_ptr]; | 645 | out_cmd = txq->cmd[q->write_ptr]; |
@@ -694,8 +705,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
694 | txcmd_phys = pci_map_single(priv->pci_dev, | 705 | txcmd_phys = pci_map_single(priv->pci_dev, |
695 | &out_cmd->hdr, len, | 706 | &out_cmd->hdr, len, |
696 | PCI_DMA_BIDIRECTIONAL); | 707 | PCI_DMA_BIDIRECTIONAL); |
697 | pci_unmap_addr_set(out_meta, mapping, txcmd_phys); | 708 | dma_unmap_addr_set(out_meta, mapping, txcmd_phys); |
698 | pci_unmap_len_set(out_meta, len, len); | 709 | dma_unmap_len_set(out_meta, len, len); |
699 | /* Add buffer containing Tx command and MAC(!) header to TFD's | 710 | /* Add buffer containing Tx command and MAC(!) header to TFD's |
700 | * first entry */ | 711 | * first entry */ |
701 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, | 712 | priv->cfg->ops->lib->txq_attach_buf_to_tfd(priv, txq, |
@@ -703,8 +714,6 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
703 | 714 | ||
704 | if (!ieee80211_has_morefrags(hdr->frame_control)) { | 715 | if (!ieee80211_has_morefrags(hdr->frame_control)) { |
705 | txq->need_update = 1; | 716 | txq->need_update = 1; |
706 | if (qc) | ||
707 | priv->stations[sta_id].tid[tid].seq_number = seq_number; | ||
708 | } else { | 717 | } else { |
709 | wait_write_ptr = 1; | 718 | wait_write_ptr = 1; |
710 | txq->need_update = 0; | 719 | txq->need_update = 0; |
@@ -1009,6 +1018,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1009 | if (ret) | 1018 | if (ret) |
1010 | return ret; | 1019 | return ret; |
1011 | 1020 | ||
1021 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1022 | tid_data = &priv->stations[sta_id].tid[tid]; | ||
1012 | if (tid_data->tfds_in_queue == 0) { | 1023 | if (tid_data->tfds_in_queue == 0) { |
1013 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1024 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1014 | tid_data->agg.state = IWL_AGG_ON; | 1025 | tid_data->agg.state = IWL_AGG_ON; |
@@ -1018,6 +1029,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1018 | tid_data->tfds_in_queue); | 1029 | tid_data->tfds_in_queue); |
1019 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; | 1030 | tid_data->agg.state = IWL_EMPTYING_HW_QUEUE_ADDBA; |
1020 | } | 1031 | } |
1032 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1021 | return ret; | 1033 | return ret; |
1022 | } | 1034 | } |
1023 | 1035 | ||
@@ -1040,11 +1052,14 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, | |||
1040 | return -ENXIO; | 1052 | return -ENXIO; |
1041 | } | 1053 | } |
1042 | 1054 | ||
1055 | spin_lock_irqsave(&priv->sta_lock, flags); | ||
1056 | |||
1043 | if (priv->stations[sta_id].tid[tid].agg.state == | 1057 | if (priv->stations[sta_id].tid[tid].agg.state == |
1044 | IWL_EMPTYING_HW_QUEUE_ADDBA) { | 1058 | IWL_EMPTYING_HW_QUEUE_ADDBA) { |
1045 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); | 1059 | IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); |
1046 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); | 1060 | ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid); |
1047 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 1061 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; |
1062 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1048 | return 0; | 1063 | return 0; |
1049 | } | 1064 | } |
1050 | 1065 | ||
@@ -1062,13 +1077,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"); | 1077 | IWL_DEBUG_HT(priv, "Stopping a non empty AGG HW QUEUE\n"); |
1063 | priv->stations[sta_id].tid[tid].agg.state = | 1078 | priv->stations[sta_id].tid[tid].agg.state = |
1064 | IWL_EMPTYING_HW_QUEUE_DELBA; | 1079 | IWL_EMPTYING_HW_QUEUE_DELBA; |
1080 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1065 | return 0; | 1081 | return 0; |
1066 | } | 1082 | } |
1067 | 1083 | ||
1068 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1084 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1069 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; | 1085 | priv->stations[sta_id].tid[tid].agg.state = IWL_AGG_OFF; |
1070 | 1086 | ||
1071 | spin_lock_irqsave(&priv->lock, flags); | 1087 | /* do not restore/save irqs */ |
1088 | spin_unlock(&priv->sta_lock); | ||
1089 | spin_lock(&priv->lock); | ||
1090 | |||
1072 | /* | 1091 | /* |
1073 | * the only reason this call can fail is queue number out of range, | 1092 | * 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 | 1093 | * which can happen if uCode is reloaded and all the station |
@@ -1092,6 +1111,8 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1092 | u8 *addr = priv->stations[sta_id].sta.sta.addr; | 1111 | u8 *addr = priv->stations[sta_id].sta.sta.addr; |
1093 | struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; | 1112 | struct iwl_tid_data *tid_data = &priv->stations[sta_id].tid[tid]; |
1094 | 1113 | ||
1114 | WARN_ON(!spin_is_locked(&priv->sta_lock)); | ||
1115 | |||
1095 | switch (priv->stations[sta_id].tid[tid].agg.state) { | 1116 | switch (priv->stations[sta_id].tid[tid].agg.state) { |
1096 | case IWL_EMPTYING_HW_QUEUE_DELBA: | 1117 | case IWL_EMPTYING_HW_QUEUE_DELBA: |
1097 | /* We are reclaiming the last packet of the */ | 1118 | /* We are reclaiming the last packet of the */ |
@@ -1116,6 +1137,7 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv, | |||
1116 | } | 1137 | } |
1117 | break; | 1138 | break; |
1118 | } | 1139 | } |
1140 | |||
1119 | return 0; | 1141 | return 0; |
1120 | } | 1142 | } |
1121 | 1143 | ||
@@ -1157,12 +1179,12 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | |||
1157 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 1179 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
1158 | 1180 | ||
1159 | tx_info = &txq->txb[txq->q.read_ptr]; | 1181 | tx_info = &txq->txb[txq->q.read_ptr]; |
1160 | iwlagn_tx_status(priv, tx_info->skb[0]); | 1182 | iwlagn_tx_status(priv, tx_info->skb); |
1161 | 1183 | ||
1162 | hdr = (struct ieee80211_hdr *)tx_info->skb[0]->data; | 1184 | hdr = (struct ieee80211_hdr *)tx_info->skb->data; |
1163 | if (hdr && ieee80211_is_data_qos(hdr->frame_control)) | 1185 | if (hdr && ieee80211_is_data_qos(hdr->frame_control)) |
1164 | nfreed++; | 1186 | nfreed++; |
1165 | tx_info->skb[0] = NULL; | 1187 | tx_info->skb = NULL; |
1166 | 1188 | ||
1167 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) | 1189 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) |
1168 | priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); | 1190 | priv->cfg->ops->lib->txq_inval_byte_cnt_tbl(priv, txq); |
@@ -1186,7 +1208,7 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1186 | int i, sh, ack; | 1208 | int i, sh, ack; |
1187 | u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); | 1209 | u16 seq_ctl = le16_to_cpu(ba_resp->seq_ctl); |
1188 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 1210 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); |
1189 | u64 bitmap; | 1211 | u64 bitmap, sent_bitmap; |
1190 | int successes = 0; | 1212 | int successes = 0; |
1191 | struct ieee80211_tx_info *info; | 1213 | struct ieee80211_tx_info *info; |
1192 | 1214 | ||
@@ -1214,24 +1236,26 @@ static int iwlagn_tx_status_reply_compressed_ba(struct iwl_priv *priv, | |||
1214 | 1236 | ||
1215 | /* check for success or failure according to the | 1237 | /* check for success or failure according to the |
1216 | * transmitted bitmap and block-ack bitmap */ | 1238 | * transmitted bitmap and block-ack bitmap */ |
1217 | bitmap &= agg->bitmap; | 1239 | sent_bitmap = bitmap & agg->bitmap; |
1218 | 1240 | ||
1219 | /* For each frame attempted in aggregation, | 1241 | /* For each frame attempted in aggregation, |
1220 | * update driver's record of tx frame's status. */ | 1242 | * update driver's record of tx frame's status. */ |
1221 | for (i = 0; i < agg->frame_count ; i++) { | 1243 | i = 0; |
1222 | ack = bitmap & (1ULL << i); | 1244 | while (sent_bitmap) { |
1223 | successes += !!ack; | 1245 | ack = sent_bitmap & 1ULL; |
1246 | successes += ack; | ||
1224 | IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", | 1247 | IWL_DEBUG_TX_REPLY(priv, "%s ON i=%d idx=%d raw=%d\n", |
1225 | ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, | 1248 | ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, |
1226 | agg->start_idx + i); | 1249 | agg->start_idx + i); |
1250 | sent_bitmap >>= 1; | ||
1251 | ++i; | ||
1227 | } | 1252 | } |
1228 | 1253 | ||
1229 | info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb[0]); | 1254 | info = IEEE80211_SKB_CB(priv->txq[scd_flow].txb[agg->start_idx].skb); |
1230 | memset(&info->status, 0, sizeof(info->status)); | 1255 | memset(&info->status, 0, sizeof(info->status)); |
1231 | info->flags |= IEEE80211_TX_STAT_ACK; | 1256 | info->flags |= IEEE80211_TX_STAT_ACK; |
1232 | info->flags |= IEEE80211_TX_STAT_AMPDU; | 1257 | info->flags |= IEEE80211_TX_STAT_AMPDU; |
1233 | info->status.ampdu_ack_len = successes; | 1258 | info->status.ampdu_ack_len = successes; |
1234 | info->status.ampdu_ack_map = bitmap; | ||
1235 | info->status.ampdu_len = agg->frame_count; | 1259 | info->status.ampdu_len = agg->frame_count; |
1236 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); | 1260 | iwlagn_hwrate_to_tx_control(priv, agg->rate_n_flags, info); |
1237 | 1261 | ||
@@ -1279,6 +1303,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1279 | int index; | 1303 | int index; |
1280 | int sta_id; | 1304 | int sta_id; |
1281 | int tid; | 1305 | int tid; |
1306 | unsigned long flags; | ||
1282 | 1307 | ||
1283 | /* "flow" corresponds to Tx queue */ | 1308 | /* "flow" corresponds to Tx queue */ |
1284 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); | 1309 | u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); |
@@ -1301,7 +1326,7 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1301 | /* Find index just before block-ack window */ | 1326 | /* Find index just before block-ack window */ |
1302 | index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); | 1327 | index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); |
1303 | 1328 | ||
1304 | /* TODO: Need to get this copy more safely - now good for debug */ | 1329 | spin_lock_irqsave(&priv->sta_lock, flags); |
1305 | 1330 | ||
1306 | IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " | 1331 | IWL_DEBUG_TX_REPLY(priv, "REPLY_COMPRESSED_BA [%d] Received from %pM, " |
1307 | "sta_id = %d\n", | 1332 | "sta_id = %d\n", |
@@ -1337,4 +1362,6 @@ void iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, | |||
1337 | 1362 | ||
1338 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); | 1363 | iwlagn_txq_check_empty(priv, sta_id, tid, scd_flow); |
1339 | } | 1364 | } |
1365 | |||
1366 | spin_unlock_irqrestore(&priv->sta_lock, flags); | ||
1340 | } | 1367 | } |