diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 61 |
1 files changed, 55 insertions, 6 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 6199bf60d313..888a8e9fe9ef 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -710,6 +710,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
710 | { | 710 | { |
711 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 711 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
712 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 712 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
713 | struct ieee80211_sta *sta = info->control.sta; | ||
714 | struct iwl_station_priv *sta_priv = NULL; | ||
713 | struct iwl_tx_queue *txq; | 715 | struct iwl_tx_queue *txq; |
714 | struct iwl_queue *q; | 716 | struct iwl_queue *q; |
715 | struct iwl_device_cmd *out_cmd; | 717 | struct iwl_device_cmd *out_cmd; |
@@ -772,6 +774,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
772 | 774 | ||
773 | IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | 775 | IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); |
774 | 776 | ||
777 | if (sta) | ||
778 | sta_priv = (void *)sta->drv_priv; | ||
779 | |||
780 | if (sta_priv && sta_id != priv->hw_params.bcast_sta_id && | ||
781 | sta_priv->asleep) { | ||
782 | WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); | ||
783 | /* | ||
784 | * This sends an asynchronous command to the device, | ||
785 | * but we can rely on it being processed before the | ||
786 | * next frame is processed -- and the next frame to | ||
787 | * this station is the one that will consume this | ||
788 | * counter. | ||
789 | * For now set the counter to just 1 since we do not | ||
790 | * support uAPSD yet. | ||
791 | */ | ||
792 | iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); | ||
793 | } | ||
794 | |||
775 | txq_id = skb_get_queue_mapping(skb); | 795 | txq_id = skb_get_queue_mapping(skb); |
776 | if (ieee80211_is_data_qos(fc)) { | 796 | if (ieee80211_is_data_qos(fc)) { |
777 | qc = ieee80211_get_qos_ctl(hdr); | 797 | qc = ieee80211_get_qos_ctl(hdr); |
@@ -931,6 +951,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
931 | ret = iwl_txq_update_write_ptr(priv, txq); | 951 | ret = iwl_txq_update_write_ptr(priv, txq); |
932 | spin_unlock_irqrestore(&priv->lock, flags); | 952 | spin_unlock_irqrestore(&priv->lock, flags); |
933 | 953 | ||
954 | /* | ||
955 | * At this point the frame is "transmitted" successfully | ||
956 | * and we will get a TX status notification eventually, | ||
957 | * regardless of the value of ret. "ret" only indicates | ||
958 | * whether or not we should update the write pointer. | ||
959 | */ | ||
960 | |||
961 | /* avoid atomic ops if it isn't an associated client */ | ||
962 | if (sta_priv && sta_priv->client) | ||
963 | atomic_inc(&sta_priv->pending_frames); | ||
964 | |||
934 | if (ret) | 965 | if (ret) |
935 | return ret; | 966 | return ret; |
936 | 967 | ||
@@ -992,7 +1023,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
992 | } | 1023 | } |
993 | 1024 | ||
994 | if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { | 1025 | if (iwl_queue_space(q) < ((cmd->flags & CMD_ASYNC) ? 2 : 1)) { |
995 | IWL_ERR(priv, "No space for Tx\n"); | 1026 | IWL_ERR(priv, "No space in command queue\n"); |
996 | if (iwl_within_ct_kill_margin(priv)) | 1027 | if (iwl_within_ct_kill_margin(priv)) |
997 | iwl_tt_enter_ct_kill(priv); | 1028 | iwl_tt_enter_ct_kill(priv); |
998 | else { | 1029 | else { |
@@ -1075,6 +1106,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1075 | return ret ? ret : idx; | 1106 | return ret ? ret : idx; |
1076 | } | 1107 | } |
1077 | 1108 | ||
1109 | static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) | ||
1110 | { | ||
1111 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1112 | struct ieee80211_sta *sta; | ||
1113 | struct iwl_station_priv *sta_priv; | ||
1114 | |||
1115 | sta = ieee80211_find_sta(priv->vif, hdr->addr1); | ||
1116 | if (sta) { | ||
1117 | sta_priv = (void *)sta->drv_priv; | ||
1118 | /* avoid atomic ops if this isn't a client */ | ||
1119 | if (sta_priv->client && | ||
1120 | atomic_dec_return(&sta_priv->pending_frames) == 0) | ||
1121 | ieee80211_sta_block_awake(priv->hw, sta, false); | ||
1122 | } | ||
1123 | |||
1124 | ieee80211_tx_status_irqsafe(priv->hw, skb); | ||
1125 | } | ||
1126 | |||
1078 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | 1127 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) |
1079 | { | 1128 | { |
1080 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 1129 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; |
@@ -1094,7 +1143,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | |||
1094 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 1143 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
1095 | 1144 | ||
1096 | tx_info = &txq->txb[txq->q.read_ptr]; | 1145 | tx_info = &txq->txb[txq->q.read_ptr]; |
1097 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); | 1146 | iwl_tx_status(priv, tx_info->skb[0]); |
1098 | tx_info->skb[0] = NULL; | 1147 | tx_info->skb[0] = NULL; |
1099 | 1148 | ||
1100 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) | 1149 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) |
@@ -1264,7 +1313,7 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) | |||
1264 | if (tid_data->tfds_in_queue == 0) { | 1313 | if (tid_data->tfds_in_queue == 0) { |
1265 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); | 1314 | IWL_DEBUG_HT(priv, "HW queue is empty\n"); |
1266 | tid_data->agg.state = IWL_AGG_ON; | 1315 | tid_data->agg.state = IWL_AGG_ON; |
1267 | ieee80211_start_tx_ba_cb_irqsafe(priv->hw, ra, tid); | 1316 | ieee80211_start_tx_ba_cb_irqsafe(priv->vif, ra, tid); |
1268 | } else { | 1317 | } else { |
1269 | IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", | 1318 | IWL_DEBUG_HT(priv, "HW queue is NOT empty: %d packets in HW queue\n", |
1270 | tid_data->tfds_in_queue); | 1319 | tid_data->tfds_in_queue); |
@@ -1329,7 +1378,7 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) | |||
1329 | if (ret) | 1378 | if (ret) |
1330 | return ret; | 1379 | return ret; |
1331 | 1380 | ||
1332 | ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, ra, tid); | 1381 | ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, ra, tid); |
1333 | 1382 | ||
1334 | return 0; | 1383 | return 0; |
1335 | } | 1384 | } |
@@ -1353,7 +1402,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) | |||
1353 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, | 1402 | priv->cfg->ops->lib->txq_agg_disable(priv, txq_id, |
1354 | ssn, tx_fifo); | 1403 | ssn, tx_fifo); |
1355 | tid_data->agg.state = IWL_AGG_OFF; | 1404 | tid_data->agg.state = IWL_AGG_OFF; |
1356 | ieee80211_stop_tx_ba_cb_irqsafe(priv->hw, addr, tid); | 1405 | ieee80211_stop_tx_ba_cb_irqsafe(priv->vif, addr, tid); |
1357 | } | 1406 | } |
1358 | break; | 1407 | break; |
1359 | case IWL_EMPTYING_HW_QUEUE_ADDBA: | 1408 | case IWL_EMPTYING_HW_QUEUE_ADDBA: |
@@ -1361,7 +1410,7 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) | |||
1361 | if (tid_data->tfds_in_queue == 0) { | 1410 | if (tid_data->tfds_in_queue == 0) { |
1362 | IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); | 1411 | IWL_DEBUG_HT(priv, "HW queue empty: continue ADDBA flow\n"); |
1363 | tid_data->agg.state = IWL_AGG_ON; | 1412 | tid_data->agg.state = IWL_AGG_ON; |
1364 | ieee80211_start_tx_ba_cb_irqsafe(priv->hw, addr, tid); | 1413 | ieee80211_start_tx_ba_cb_irqsafe(priv->vif, addr, tid); |
1365 | } | 1414 | } |
1366 | break; | 1415 | break; |
1367 | } | 1416 | } |