summaryrefslogtreecommitdiff
path: root/drivers/net/wireless
diff options
context:
space:
mode:
authorEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-12-03 11:39:07 +0300
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-12-14 11:20:29 +0300
commit03d6c3b0fa4f5f0379cede079ec828a6c999fe43 (patch)
treef4574f8536ad855e0de62fe0104b0e022f3b3af8 /drivers/net/wireless
parent0a79a0c011cb291675e3b80760a452fcba5c59d9 (diff)
downloadlinux-03d6c3b0fa4f5f0379cede079ec828a6c999fe43.tar.xz
iwlwifi: pcie: re-ACK all interrupts after device reset
When we reset the device, the CSR_INT gets cleared as well as CSR_INT_MASK. Meaning that we shouldn't get any interrupt but, due to a hardware bug, recent devices will keep sending interrupts. This leads to an interrupt storm while stopping the device. The way to fix this is to ACK all the interrupts after the device is reset so that the value of CSR_INT will stay 0xffffffff. Fixes: 522713c81e4e ("iwlwifi: pcie: properly reset the device") Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 5d79a1f44b8e..d151af36b6cc 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -1012,16 +1012,21 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
/* Stop the device, and put it in low power state */
iwl_pcie_apm_stop(trans);
- /* Upon stop, the APM issues an interrupt if HW RF kill is set.
- * Clean again the interrupt here
+ /* stop and reset the on-board processor */
+ iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
+ udelay(20);
+
+ /*
+ * Upon stop, the APM issues an interrupt if HW RF kill is set.
+ * This is a bug in certain verions of the hardware.
+ * Certain devices also keep sending HW RF kill interrupt all
+ * the time, unless the interrupt is ACKed even if the interrupt
+ * should be masked. Re-ACK all the interrupts here.
*/
spin_lock(&trans_pcie->irq_lock);
iwl_disable_interrupts(trans);
spin_unlock(&trans_pcie->irq_lock);
- /* stop and reset the on-board processor */
- iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
- udelay(20);
/* clear all status bits */
clear_bit(STATUS_SYNC_HCMD_ACTIVE, &trans->status);