aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/dvm
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/iwlwifi/dvm')
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/agn.h4
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/lib.c7
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/mac80211.c7
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c45
4 files changed, 58 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/dvm/agn.h b/drivers/net/wireless/iwlwifi/dvm/agn.h
index 76b762e48703..e575b9b0cda8 100644
--- a/drivers/net/wireless/iwlwifi/dvm/agn.h
+++ b/drivers/net/wireless/iwlwifi/dvm/agn.h
@@ -178,7 +178,7 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
178/* lib */ 178/* lib */
179int iwlagn_send_tx_power(struct iwl_priv *priv); 179int iwlagn_send_tx_power(struct iwl_priv *priv);
180void iwlagn_temperature(struct iwl_priv *priv); 180void iwlagn_temperature(struct iwl_priv *priv);
181int iwlagn_txfifo_flush(struct iwl_priv *priv); 181int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk);
182void iwlagn_dev_txfifo_flush(struct iwl_priv *priv); 182void iwlagn_dev_txfifo_flush(struct iwl_priv *priv);
183int iwlagn_send_beacon_cmd(struct iwl_priv *priv); 183int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
184int iwl_send_statistics_request(struct iwl_priv *priv, 184int iwl_send_statistics_request(struct iwl_priv *priv,
@@ -212,6 +212,8 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
212 struct ieee80211_sta *sta, u16 tid, u8 buf_size); 212 struct ieee80211_sta *sta, u16 tid, u8 buf_size);
213int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, 213int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif,
214 struct ieee80211_sta *sta, u16 tid); 214 struct ieee80211_sta *sta, u16 tid);
215int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
216 struct ieee80211_sta *sta, u16 tid);
215int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv, 217int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
216 struct iwl_rx_cmd_buffer *rxb, 218 struct iwl_rx_cmd_buffer *rxb,
217 struct iwl_device_cmd *cmd); 219 struct iwl_device_cmd *cmd);
diff --git a/drivers/net/wireless/iwlwifi/dvm/lib.c b/drivers/net/wireless/iwlwifi/dvm/lib.c
index f2aeb1a8aa01..29ff93f9656e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/lib.c
+++ b/drivers/net/wireless/iwlwifi/dvm/lib.c
@@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
136 * 1. acquire mutex before calling 136 * 1. acquire mutex before calling
137 * 2. make sure rf is on and not in exit state 137 * 2. make sure rf is on and not in exit state
138 */ 138 */
139int iwlagn_txfifo_flush(struct iwl_priv *priv) 139int iwlagn_txfifo_flush(struct iwl_priv *priv, u32 scd_q_msk)
140{ 140{
141 struct iwl_txfifo_flush_cmd flush_cmd; 141 struct iwl_txfifo_flush_cmd flush_cmd;
142 struct iwl_host_cmd cmd = { 142 struct iwl_host_cmd cmd = {
@@ -162,6 +162,9 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv)
162 if (priv->nvm_data->sku_cap_11n_enable) 162 if (priv->nvm_data->sku_cap_11n_enable)
163 flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK; 163 flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK;
164 164
165 if (scd_q_msk)
166 flush_cmd.queue_control = cpu_to_le32(scd_q_msk);
167
165 IWL_DEBUG_INFO(priv, "queue control: 0x%x\n", 168 IWL_DEBUG_INFO(priv, "queue control: 0x%x\n",
166 flush_cmd.queue_control); 169 flush_cmd.queue_control);
167 flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL); 170 flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL);
@@ -173,7 +176,7 @@ void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
173{ 176{
174 mutex_lock(&priv->mutex); 177 mutex_lock(&priv->mutex);
175 ieee80211_stop_queues(priv->hw); 178 ieee80211_stop_queues(priv->hw);
176 if (iwlagn_txfifo_flush(priv)) { 179 if (iwlagn_txfifo_flush(priv, 0)) {
177 IWL_ERR(priv, "flush request fail\n"); 180 IWL_ERR(priv, "flush request fail\n");
178 goto done; 181 goto done;
179 } 182 }
diff --git a/drivers/net/wireless/iwlwifi/dvm/mac80211.c b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
index a7294fa4d7e5..fc3879804622 100644
--- a/drivers/net/wireless/iwlwifi/dvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/dvm/mac80211.c
@@ -777,9 +777,12 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
777 IWL_DEBUG_HT(priv, "start Tx\n"); 777 IWL_DEBUG_HT(priv, "start Tx\n");
778 ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn); 778 ret = iwlagn_tx_agg_start(priv, vif, sta, tid, ssn);
779 break; 779 break;
780 case IEEE80211_AMPDU_TX_STOP_CONT:
781 case IEEE80211_AMPDU_TX_STOP_FLUSH: 780 case IEEE80211_AMPDU_TX_STOP_FLUSH:
782 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT: 781 case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
782 IWL_DEBUG_HT(priv, "Flush Tx\n");
783 ret = iwlagn_tx_agg_flush(priv, vif, sta, tid);
784 break;
785 case IEEE80211_AMPDU_TX_STOP_CONT:
783 IWL_DEBUG_HT(priv, "stop Tx\n"); 786 IWL_DEBUG_HT(priv, "stop Tx\n");
784 ret = iwlagn_tx_agg_stop(priv, vif, sta, tid); 787 ret = iwlagn_tx_agg_stop(priv, vif, sta, tid);
785 if ((ret == 0) && (priv->agg_tids_count > 0)) { 788 if ((ret == 0) && (priv->agg_tids_count > 0)) {
@@ -1122,7 +1125,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, u32 queues, bool drop)
1122 */ 1125 */
1123 if (drop) { 1126 if (drop) {
1124 IWL_DEBUG_MAC80211(priv, "send flush command\n"); 1127 IWL_DEBUG_MAC80211(priv, "send flush command\n");
1125 if (iwlagn_txfifo_flush(priv)) { 1128 if (iwlagn_txfifo_flush(priv, 0)) {
1126 IWL_ERR(priv, "flush request fail\n"); 1129 IWL_ERR(priv, "flush request fail\n");
1127 goto done; 1130 goto done;
1128 } 1131 }
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index cc1e0c1a6f48..2c9e9897a3f1 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -674,6 +674,51 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
674 return ret; 674 return ret;
675} 675}
676 676
677int iwlagn_tx_agg_flush(struct iwl_priv *priv, struct ieee80211_vif *vif,
678 struct ieee80211_sta *sta, u16 tid)
679{
680 struct iwl_tid_data *tid_data;
681 enum iwl_agg_state agg_state;
682 int sta_id, txq_id;
683 sta_id = iwl_sta_id(sta);
684
685 /*
686 * First set the agg state to OFF to avoid calling
687 * ieee80211_stop_tx_ba_cb in iwlagn_check_ratid_empty.
688 */
689 spin_lock_bh(&priv->sta_lock);
690
691 tid_data = &priv->tid_data[sta_id][tid];
692 txq_id = tid_data->agg.txq_id;
693 agg_state = tid_data->agg.state;
694 IWL_DEBUG_TX_QUEUES(priv, "Flush AGG: sta %d tid %d q %d state %d\n",
695 sta_id, tid, txq_id, tid_data->agg.state);
696
697 tid_data->agg.state = IWL_AGG_OFF;
698
699 spin_unlock_bh(&priv->sta_lock);
700
701 if (iwlagn_txfifo_flush(priv, BIT(txq_id)))
702 IWL_ERR(priv, "Couldn't flush the AGG queue\n");
703
704 if (test_bit(txq_id, priv->agg_q_alloc)) {
705 /*
706 * If the transport didn't know that we wanted to start
707 * agreggation, don't tell it that we want to stop them.
708 * This can happen when we don't get the addBA response on
709 * time, or we hadn't time to drain the AC queues.
710 */
711 if (agg_state == IWL_AGG_ON)
712 iwl_trans_txq_disable(priv->trans, txq_id);
713 else
714 IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
715 agg_state);
716 iwlagn_dealloc_agg_txq(priv, txq_id);
717 }
718
719 return 0;
720}
721
677int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, 722int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
678 struct ieee80211_sta *sta, u16 tid, u8 buf_size) 723 struct ieee80211_sta *sta, u16 tid, u8 buf_size)
679{ 724{