wifi: iwlwifi: mvm: fix mvmtxq->stopped handling

Bugzilla: https://bugzilla.redhat.com/2183490

commit b58e3d4311b54b6dd0e37165277965da0c9eb21d
Author: Johannes Berg <johannes.berg@intel.com>
Date:   Fri Mar 17 10:53:24 2023 +0100

    wifi: iwlwifi: mvm: fix mvmtxq->stopped handling
    
    This could race if the queue is redirected while full, then
    the flushing internally would start it while it's not yet
    usable again. Fix it by using two state bits instead of just
    one.
    
    Reviewed-by: Benjamin Berg <benjamin.berg@intel.com>
    Tested-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
    Signed-off-by: Johannes Berg <johannes.berg@intel.com>

Signed-off-by: Jose Ignacio Tornos Martinez <jtornosm@redhat.com>
This commit is contained in:
Jose Ignacio Tornos Martinez 2023-03-31 14:56:07 +02:00
parent f133fabaa6
commit 11d7b51846
4 changed files with 13 additions and 5 deletions

View File

@ -729,7 +729,10 @@ void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
rcu_read_lock();
do {
while (likely(!mvmtxq->stopped &&
while (likely(!test_bit(IWL_MVM_TXQ_STATE_STOP_FULL,
&mvmtxq->state) &&
!test_bit(IWL_MVM_TXQ_STATE_STOP_REDIRECT,
&mvmtxq->state) &&
!test_bit(IWL_MVM_STATUS_IN_D3, &mvm->status))) {
skb = ieee80211_tx_dequeue(hw, txq);

View File

@ -729,7 +729,9 @@ struct iwl_mvm_txq {
struct list_head list;
u16 txq_id;
atomic_t tx_request;
bool stopped;
#define IWL_MVM_TXQ_STATE_STOP_FULL 0
#define IWL_MVM_TXQ_STATE_STOP_REDIRECT 1
unsigned long state;
};
static inline struct iwl_mvm_txq *

View File

@ -1680,7 +1680,10 @@ static void iwl_mvm_queue_state_change(struct iwl_op_mode *op_mode,
txq = sta->txq[tid];
mvmtxq = iwl_mvm_txq_from_mac80211(txq);
mvmtxq->stopped = !start;
if (start)
clear_bit(IWL_MVM_TXQ_STATE_STOP_FULL, &mvmtxq->state);
else
set_bit(IWL_MVM_TXQ_STATE_STOP_FULL, &mvmtxq->state);
if (start && mvmsta->sta_state != IEEE80211_STA_NOTEXIST)
iwl_mvm_mac_itxq_xmit(mvm->hw, txq);

View File

@ -692,7 +692,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) {
@ -735,7 +735,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;
}