diff options
Diffstat (limited to 'drivers/net/wireless/intel/iwlwifi/mvm/sta.c')
| -rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 29 | 
1 files changed, 24 insertions, 5 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c index 69634fb82a9b..9caae77995ca 100644 --- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c +++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c @@ -384,8 +384,11 @@ static int iwl_mvm_disable_txq(struct iwl_mvm *mvm, struct ieee80211_sta *sta,  		struct iwl_mvm_txq *mvmtxq =  			iwl_mvm_txq_from_tid(sta, tid); -		mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; +		spin_lock_bh(&mvm->add_stream_lock);  		list_del_init(&mvmtxq->list); +		clear_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state); +		mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; +		spin_unlock_bh(&mvm->add_stream_lock);  	}  	/* Regardless if this is a reserved TXQ for a STA - mark it as false */ @@ -479,8 +482,11 @@ static int iwl_mvm_remove_sta_queue_marking(struct iwl_mvm *mvm, int queue)  			disable_agg_tids |= BIT(tid);  		mvmsta->tid_data[tid].txq_id = IWL_MVM_INVALID_QUEUE; -		mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; +		spin_lock_bh(&mvm->add_stream_lock);  		list_del_init(&mvmtxq->list); +		clear_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state); +		mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE; +		spin_unlock_bh(&mvm->add_stream_lock);  	}  	mvmsta->tfd_queue_msk &= ~BIT(queue); /* Don't use this queue anymore */ @@ -693,7 +699,7 @@ static int iwl_mvm_redirect_queue(struct iwl_mvm *mvm, int queue, int tid,  			    queue, iwl_mvm_ac_to_tx_fifo[ac]);  	/* Stop the queue and wait for it to empty */ -	txq->stopped = true; +	set_bit(IWL_MVM_TXQ_STATE_STOP_REDIRECT, &txq->state);  	ret = iwl_trans_wait_tx_queues_empty(mvm->trans, BIT(queue));  	if (ret) { @@ -736,7 +742,7 @@ static int iwl_mvm_redirect_queue(struct iwl_mvm *mvm, int queue, int tid,  out:  	/* Continue using the queue */ -	txq->stopped = false; +	clear_bit(IWL_MVM_TXQ_STATE_STOP_REDIRECT, &txq->state);  	return ret;  } @@ -1444,12 +1450,22 @@ void iwl_mvm_add_new_dqa_stream_wk(struct work_struct *wk)  		 * a queue in the function itself.  		 */  		if (iwl_mvm_sta_alloc_queue(mvm, txq->sta, txq->ac, tid)) { +			spin_lock_bh(&mvm->add_stream_lock);  			list_del_init(&mvmtxq->list); +			spin_unlock_bh(&mvm->add_stream_lock);  			continue;  		} -		list_del_init(&mvmtxq->list); +		/* now we're ready, any remaining races/concurrency will be +		 * handled in iwl_mvm_mac_itxq_xmit() +		 */ +		set_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state); +  		local_bh_disable(); +		spin_lock(&mvm->add_stream_lock); +		list_del_init(&mvmtxq->list); +		spin_unlock(&mvm->add_stream_lock); +  		iwl_mvm_mac_itxq_xmit(mvm->hw, txq);  		local_bh_enable();  	} @@ -1864,8 +1880,11 @@ static void iwl_mvm_disable_sta_queues(struct iwl_mvm *mvm,  		struct iwl_mvm_txq *mvmtxq =  			iwl_mvm_txq_from_mac80211(sta->txq[i]); +		spin_lock_bh(&mvm->add_stream_lock);  		mvmtxq->txq_id = IWL_MVM_INVALID_QUEUE;  		list_del_init(&mvmtxq->list); +		clear_bit(IWL_MVM_TXQ_STATE_READY, &mvmtxq->state); +		spin_unlock_bh(&mvm->add_stream_lock);  	}  }  |