diff options
author | Emmanuel Grumbach <emmanuel.grumbach@intel.com> | 2013-06-13 04:45:59 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-07-21 21:21:30 -0400 |
commit | f4ab9ece03dfc4b15c63b5fd5506183554976903 (patch) | |
tree | b00c9ab3f0805e23977311a1aeb2be8543c673c9 /drivers/net | |
parent | 65a1fb23bc5b2f21b44f8b81c89ccda808b3b321 (diff) |
iwlwifi: pcie: fix race in queue unmapping
commit b967613d7e7c7bad176f5627c55e2d8c5aa2480e upstream.
When a queue is disabled, it frees all its entries. Later,
the op_mode might still get notifications from the firmware
that triggers to free entries in the tx queue. The transport
should be prepared for these races and know to ignore
reclaim calls on queues that have been disabled and whose
entries have been freed.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/wireless/iwlwifi/pcie/tx.c | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c index c5e30294c5ac..51fca425def7 100644 --- a/drivers/net/wireless/iwlwifi/pcie/tx.c +++ b/drivers/net/wireless/iwlwifi/pcie/tx.c | |||
@@ -576,9 +576,12 @@ static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id) | |||
576 | 576 | ||
577 | spin_lock_bh(&txq->lock); | 577 | spin_lock_bh(&txq->lock); |
578 | while (q->write_ptr != q->read_ptr) { | 578 | while (q->write_ptr != q->read_ptr) { |
579 | IWL_DEBUG_TX_REPLY(trans, "Q %d Free %d\n", | ||
580 | txq_id, q->read_ptr); | ||
579 | iwl_pcie_txq_free_tfd(trans, txq); | 581 | iwl_pcie_txq_free_tfd(trans, txq); |
580 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); | 582 | q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd); |
581 | } | 583 | } |
584 | txq->active = false; | ||
582 | spin_unlock_bh(&txq->lock); | 585 | spin_unlock_bh(&txq->lock); |
583 | } | 586 | } |
584 | 587 | ||
@@ -927,6 +930,12 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn, | |||
927 | 930 | ||
928 | spin_lock_bh(&txq->lock); | 931 | spin_lock_bh(&txq->lock); |
929 | 932 | ||
933 | if (!txq->active) { | ||
934 | IWL_DEBUG_TX_QUEUES(trans, "Q %d inactive - ignoring idx %d\n", | ||
935 | txq_id, ssn); | ||
936 | goto out; | ||
937 | } | ||
938 | |||
930 | if (txq->q.read_ptr == tfd_num) | 939 | if (txq->q.read_ptr == tfd_num) |
931 | goto out; | 940 | goto out; |
932 | 941 | ||
@@ -1103,6 +1112,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo, | |||
1103 | (fifo << SCD_QUEUE_STTS_REG_POS_TXF) | | 1112 | (fifo << SCD_QUEUE_STTS_REG_POS_TXF) | |
1104 | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | | 1113 | (1 << SCD_QUEUE_STTS_REG_POS_WSL) | |
1105 | SCD_QUEUE_STTS_REG_MSK); | 1114 | SCD_QUEUE_STTS_REG_MSK); |
1115 | trans_pcie->txq[txq_id].active = true; | ||
1106 | IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", | 1116 | IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n", |
1107 | txq_id, fifo, ssn & 0xff); | 1117 | txq_id, fifo, ssn & 0xff); |
1108 | } | 1118 | } |