diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-tx.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-tx.c | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 9370e062000d..ebfc460115d6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c | |||
@@ -709,6 +709,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
709 | { | 709 | { |
710 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | 710 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; |
711 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); | 711 | struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); |
712 | struct ieee80211_sta *sta = info->control.sta; | ||
713 | struct iwl_station_priv *sta_priv = NULL; | ||
712 | struct iwl_tx_queue *txq; | 714 | struct iwl_tx_queue *txq; |
713 | struct iwl_queue *q; | 715 | struct iwl_queue *q; |
714 | struct iwl_device_cmd *out_cmd; | 716 | struct iwl_device_cmd *out_cmd; |
@@ -771,6 +773,24 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
771 | 773 | ||
772 | IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); | 774 | IWL_DEBUG_TX(priv, "station Id %d\n", sta_id); |
773 | 775 | ||
776 | if (sta) | ||
777 | sta_priv = (void *)sta->drv_priv; | ||
778 | |||
779 | if (sta_priv && sta_id != priv->hw_params.bcast_sta_id && | ||
780 | sta_priv->asleep) { | ||
781 | WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)); | ||
782 | /* | ||
783 | * This sends an asynchronous command to the device, | ||
784 | * but we can rely on it being processed before the | ||
785 | * next frame is processed -- and the next frame to | ||
786 | * this station is the one that will consume this | ||
787 | * counter. | ||
788 | * For now set the counter to just 1 since we do not | ||
789 | * support uAPSD yet. | ||
790 | */ | ||
791 | iwl_sta_modify_sleep_tx_count(priv, sta_id, 1); | ||
792 | } | ||
793 | |||
774 | txq_id = skb_get_queue_mapping(skb); | 794 | txq_id = skb_get_queue_mapping(skb); |
775 | if (ieee80211_is_data_qos(fc)) { | 795 | if (ieee80211_is_data_qos(fc)) { |
776 | qc = ieee80211_get_qos_ctl(hdr); | 796 | qc = ieee80211_get_qos_ctl(hdr); |
@@ -930,6 +950,17 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) | |||
930 | ret = iwl_txq_update_write_ptr(priv, txq); | 950 | ret = iwl_txq_update_write_ptr(priv, txq); |
931 | spin_unlock_irqrestore(&priv->lock, flags); | 951 | spin_unlock_irqrestore(&priv->lock, flags); |
932 | 952 | ||
953 | /* | ||
954 | * At this point the frame is "transmitted" successfully | ||
955 | * and we will get a TX status notification eventually, | ||
956 | * regardless of the value of ret. "ret" only indicates | ||
957 | * whether or not we should update the write pointer. | ||
958 | */ | ||
959 | |||
960 | /* avoid atomic ops if it isn't an associated client */ | ||
961 | if (sta_priv && sta_priv->client) | ||
962 | atomic_inc(&sta_priv->pending_frames); | ||
963 | |||
933 | if (ret) | 964 | if (ret) |
934 | return ret; | 965 | return ret; |
935 | 966 | ||
@@ -1074,6 +1105,24 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) | |||
1074 | return ret ? ret : idx; | 1105 | return ret ? ret : idx; |
1075 | } | 1106 | } |
1076 | 1107 | ||
1108 | static void iwl_tx_status(struct iwl_priv *priv, struct sk_buff *skb) | ||
1109 | { | ||
1110 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; | ||
1111 | struct ieee80211_sta *sta; | ||
1112 | struct iwl_station_priv *sta_priv; | ||
1113 | |||
1114 | sta = ieee80211_find_sta(priv->vif, hdr->addr1); | ||
1115 | if (sta) { | ||
1116 | sta_priv = (void *)sta->drv_priv; | ||
1117 | /* avoid atomic ops if this isn't a client */ | ||
1118 | if (sta_priv->client && | ||
1119 | atomic_dec_return(&sta_priv->pending_frames) == 0) | ||
1120 | ieee80211_sta_block_awake(priv->hw, sta, false); | ||
1121 | } | ||
1122 | |||
1123 | ieee80211_tx_status_irqsafe(priv->hw, skb); | ||
1124 | } | ||
1125 | |||
1077 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | 1126 | int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) |
1078 | { | 1127 | { |
1079 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; | 1128 | struct iwl_tx_queue *txq = &priv->txq[txq_id]; |
@@ -1093,7 +1142,7 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) | |||
1093 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { | 1142 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) { |
1094 | 1143 | ||
1095 | tx_info = &txq->txb[txq->q.read_ptr]; | 1144 | tx_info = &txq->txb[txq->q.read_ptr]; |
1096 | ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb[0]); | 1145 | iwl_tx_status(priv, tx_info->skb[0]); |
1097 | tx_info->skb[0] = NULL; | 1146 | tx_info->skb[0] = NULL; |
1098 | 1147 | ||
1099 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) | 1148 | if (priv->cfg->ops->lib->txq_inval_byte_cnt_tbl) |