John W. Linville a43c59f
From b49ba04a3a0382e7314d990707c21094c410425a Mon Sep 17 00:00:00 2001
John W. Linville a43c59f
From: Johannes Berg <johannes.berg@intel.com>
John W. Linville a43c59f
Date: Thu, 19 Jan 2012 08:20:57 -0800
John W. Linville a43c59f
Subject: [PATCH 8/8] iwlwifi: fix PCI-E transport "inta" race
John W. Linville a43c59f
John W. Linville a43c59f
When an interrupt comes in, we read the reason
John W. Linville a43c59f
bits and collect them into "trans_pcie->inta".
John W. Linville a43c59f
This happens with the spinlock held. However,
John W. Linville a43c59f
there's a bug resetting this variable -- that
John W. Linville a43c59f
happens after the spinlock has been released.
John W. Linville a43c59f
This means that it is possible for interrupts
John W. Linville a43c59f
to be missed if the reset happens after some
John W. Linville a43c59f
other interrupt reasons were already added to
John W. Linville a43c59f
the variable.
John W. Linville a43c59f
John W. Linville a43c59f
I found this by code inspection, looking for a
John W. Linville a43c59f
reason that we sometimes see random commands
John W. Linville a43c59f
time out. It seems possible that this causes
John W. Linville a43c59f
such behaviour, but I can't say for sure right
John W. Linville a43c59f
now since it happens extremely infrequently on
John W. Linville a43c59f
my test systems.
John W. Linville a43c59f
John W. Linville a43c59f
Cc: stable@vger.kernel.org [3.2]
John W. Linville a43c59f
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
John W. Linville a43c59f
Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com>
John W. Linville a43c59f
Signed-off-by: John W. Linville <linville@tuxdriver.com>
John W. Linville a43c59f
---
John W. Linville a43c59f
 drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c |    4 ++--
John W. Linville a43c59f
 1 files changed, 2 insertions(+), 2 deletions(-)
John W. Linville a43c59f
John W. Linville a43c59f
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
John W. Linville a43c59f
index 752493f..65d1f05 100644
John W. Linville a43c59f
--- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
John W. Linville a43c59f
+++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c
John W. Linville a43c59f
@@ -972,11 +972,11 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
John W. Linville a43c59f
 	}
John W. Linville a43c59f
 #endif
John W. Linville a43c59f
 
John W. Linville a43c59f
-	spin_unlock_irqrestore(&trans->shrd->lock, flags);
John W. Linville a43c59f
-
John W. Linville a43c59f
 	/* saved interrupt in inta variable now we can reset trans_pcie->inta */
John W. Linville a43c59f
 	trans_pcie->inta = 0;
John W. Linville a43c59f
 
John W. Linville a43c59f
+	spin_unlock_irqrestore(&trans->shrd->lock, flags);
John W. Linville a43c59f
+
John W. Linville a43c59f
 	/* Now service all interrupt bits discovered above. */
John W. Linville a43c59f
 	if (inta & CSR_INT_BIT_HW_ERR) {
John W. Linville a43c59f
 		IWL_ERR(trans, "Hardware error detected.  Restarting.\n");
John W. Linville a43c59f
-- 
John W. Linville a43c59f
1.7.4.4
John W. Linville a43c59f