aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2013-06-13 04:45:59 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-07-21 21:21:30 -0400
commitf4ab9ece03dfc4b15c63b5fd5506183554976903 (patch)
treeb00c9ab3f0805e23977311a1aeb2be8543c673c9 /drivers/net
parent65a1fb23bc5b2f21b44f8b81c89ccda808b3b321 (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.c10
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}