From 682e5f64de0ab5be3fb2de9f66a1da87de48ec09 Mon Sep 17 00:00:00 2001 From: Emmanuel Grumbach Date: Mon, 26 Mar 2012 15:50:55 +0200 Subject: [PATCH] iwlwifi: split between AGG_ON and AGG_STARTING This allows not to notify the transport about aggregation stopped while aggregation haven't been started. Signed-off-by: Emmanuel Grumbach Signed-off-by: Wey-Yi Guy --- drivers/net/wireless/iwlwifi/iwl-agn-tx.c | 20 +++++++++++++++++--- drivers/net/wireless/iwlwifi/iwl-dev.h | 2 ++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c index 76fea8f5f9c..b77a079a136 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-tx.c @@ -522,6 +522,7 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, { struct iwl_tid_data *tid_data; int sta_id, txq_id; + enum iwl_agg_state agg_state; sta_id = iwl_sta_id(sta); @@ -545,6 +546,13 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, */ IWL_DEBUG_HT(priv, "AGG stop before setup done\n"); goto turn_off; + case IWL_AGG_STARTING: + /* + * This can happen when the session is stopped before + * we receive ADDBA response + */ + IWL_DEBUG_HT(priv, "AGG stop before AGG became operational\n"); + goto turn_off; case IWL_AGG_ON: break; default: @@ -576,12 +584,17 @@ int iwlagn_tx_agg_stop(struct iwl_priv *priv, struct ieee80211_vif *vif, IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); turn_off: + agg_state = priv->tid_data[sta_id][tid].agg.state; priv->tid_data[sta_id][tid].agg.state = IWL_AGG_OFF; spin_unlock_bh(&priv->sta_lock); if (test_bit(txq_id, priv->agg_q_alloc)) { - iwl_trans_tx_agg_disable(priv->trans, txq_id); + /* If the transport didn't know that we wanted to start + * agreggation, don't tell it that we want to stop them + */ + if (agg_state != IWL_AGG_STARTING) + iwl_trans_tx_agg_disable(priv->trans, txq_id); iwlagn_dealloc_agg_txq(priv, txq_id); } @@ -634,7 +647,7 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif, if (*ssn == tid_data->next_reclaimed) { IWL_DEBUG_TX_QUEUES(priv, "Can proceed: ssn = next_recl = %d\n", tid_data->agg.ssn); - tid_data->agg.state = IWL_AGG_ON; + tid_data->agg.state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid); } else { IWL_DEBUG_TX_QUEUES(priv, "Can't proceed: ssn %d, " @@ -661,6 +674,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif, spin_lock_bh(&priv->sta_lock); ssn = priv->tid_data[sta_priv->sta_id][tid].agg.ssn; q = priv->tid_data[sta_priv->sta_id][tid].agg.txq_id; + priv->tid_data[sta_priv->sta_id][tid].agg.state = IWL_AGG_ON; spin_unlock_bh(&priv->sta_lock); fifo = ctx->ac_to_fifo[tid_to_ac[tid]]; @@ -745,7 +759,7 @@ static void iwlagn_check_ratid_empty(struct iwl_priv *priv, int sta_id, u8 tid) IWL_DEBUG_TX_QUEUES(priv, "Can continue ADDBA flow ssn = next_recl =" " %d", tid_data->next_reclaimed); - tid_data->agg.state = IWL_AGG_ON; + tid_data->agg.state = IWL_AGG_STARTING; ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid); } break; diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index f3eccf6709d..3816429cdbd 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -194,6 +194,7 @@ struct iwl_qos_info { * These states relate to a specific RA / TID. * * @IWL_AGG_OFF: aggregation is not used + * @IWL_AGG_STARTING: aggregation are starting (between start and oper) * @IWL_AGG_ON: aggregation session is up * @IWL_EMPTYING_HW_QUEUE_ADDBA: establishing a BA session - waiting for the * HW queue to be empty from packets for this RA /TID. @@ -202,6 +203,7 @@ struct iwl_qos_info { */ enum iwl_agg_state { IWL_AGG_OFF = 0, + IWL_AGG_STARTING, IWL_AGG_ON, IWL_EMPTYING_HW_QUEUE_ADDBA, IWL_EMPTYING_HW_QUEUE_DELBA, -- 2.41.0