Commit af720fc6 authored by Emmanuel Grumbach's avatar Emmanuel Grumbach Committed by Greg Kroah-Hartman

iwlwifi: don't handle masked interrupt

commit 25a17265 upstream.

This can lead to a panic if the driver isn't ready to
handle them. Since our interrupt line is shared, we can get
an interrupt at any time (and CONFIG_DEBUG_SHIRQ checks
that even when the interrupt is being freed).

If the op_mode has gone away, we musn't call it. To avoid
this the transport disables the interrupts when the hw is
stopped and the op_mode is leaving.
If there is an event that would cause an interrupt the INTA
register is updated regardless of the enablement of the
interrupts: even if the interrupts are disabled, the INTA
will be changed, but the device won't issue an interrupt.
But the ISR can be called at any time, so we ought ignore
the value in the INTA otherwise we can call the op_mode
after it was freed.

I found this bug when the op_mode_start failed, and called
iwl_trans_stop_hw(trans, true). Then I played with the
RFKILL button, and removed the module.
While removing the module, the IRQ is freed, and the ISR is
called (CONFIG_DEBUG_SHIRQ enabled). Panic.
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: default avatarGregory Greenman <gregory.greenman@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
[bwh: Backported to 3.2:
 - Adjust context
 - Pass bus(trans), not trans, to iwl_{read,write}32()]
Signed-off-by: default avatarBen Hutchings <ben@decadent.org.uk>
[wujg: Backported to 3.4:
 - adjust context
 - Pass trans to iwl_{read,write}32()}]
Signed-off-by: default avatarJianguo Wu <wujianguo@huawei.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 8234281a
...@@ -1264,12 +1264,20 @@ static irqreturn_t iwl_isr(int irq, void *data) ...@@ -1264,12 +1264,20 @@ static irqreturn_t iwl_isr(int irq, void *data)
* back-to-back ISRs and sporadic interrupts from our NIC. * back-to-back ISRs and sporadic interrupts from our NIC.
* If we have something to service, the tasklet will re-enable ints. * If we have something to service, the tasklet will re-enable ints.
* If we *don't* have something, we'll re-enable before leaving here. */ * If we *don't* have something, we'll re-enable before leaving here. */
inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ inta_mask = iwl_read32(trans, CSR_INT_MASK);
iwl_write32(trans, CSR_INT_MASK, 0x00000000); iwl_write32(trans, CSR_INT_MASK, 0x00000000);
/* Discover which interrupts are active/pending */ /* Discover which interrupts are active/pending */
inta = iwl_read32(trans, CSR_INT); inta = iwl_read32(trans, CSR_INT);
if (inta & (~inta_mask)) {
IWL_DEBUG_ISR(trans,
"We got a masked interrupt (0x%08x)...Ack and ignore\n",
inta & (~inta_mask));
iwl_write32(trans, CSR_INT, inta & (~inta_mask));
inta &= inta_mask;
}
/* Ignore interrupt if there's nothing in NIC to service. /* Ignore interrupt if there's nothing in NIC to service.
* This may be due to IRQ shared with another device, * This may be due to IRQ shared with another device,
* or due to sporadic interrupts thrown from our NIC. */ * or due to sporadic interrupts thrown from our NIC. */
...@@ -1353,7 +1361,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data) ...@@ -1353,7 +1361,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
* If we have something to service, the tasklet will re-enable ints. * If we have something to service, the tasklet will re-enable ints.
* If we *don't* have something, we'll re-enable before leaving here. * If we *don't* have something, we'll re-enable before leaving here.
*/ */
inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ inta_mask = iwl_read32(trans, CSR_INT_MASK);
iwl_write32(trans, CSR_INT_MASK, 0x00000000); iwl_write32(trans, CSR_INT_MASK, 0x00000000);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment