]>
Commit | Line | Data |
---|---|---|
6f345252 GKH |
1 | From wujianguo@huawei.com Fri Mar 7 16:58:50 2014 |
2 | From: Emmanuel Grumbach <emmanuel.grumbach@intel.com> | |
3 | Date: Thu, 27 Feb 2014 09:52:57 +0800 | |
4 | Subject: iwlwifi: don't handle masked interrupt | |
5 | To: <gregkh@linuxfoundation.org> | |
6 | Cc: <stable@vger.kernel.org>, <lizefan@huawei.com>, Emmanuel Grumbach <emmanuel.grumbach@intel.com>, Jianguo Wu <wujianguo@huawei.com> | |
7 | Message-ID: <1393465983-10548-4-git-send-email-wujianguo@huawei.com> | |
8 | ||
9 | ||
10 | From: Emmanuel Grumbach <emmanuel.grumbach@intel.com> | |
11 | ||
12 | commit 25a172655f837bdb032e451f95441bb4acec51bb upstream. | |
13 | ||
14 | This can lead to a panic if the driver isn't ready to | |
15 | handle them. Since our interrupt line is shared, we can get | |
16 | an interrupt at any time (and CONFIG_DEBUG_SHIRQ checks | |
17 | that even when the interrupt is being freed). | |
18 | ||
19 | If the op_mode has gone away, we musn't call it. To avoid | |
20 | this the transport disables the interrupts when the hw is | |
21 | stopped and the op_mode is leaving. | |
22 | If there is an event that would cause an interrupt the INTA | |
23 | register is updated regardless of the enablement of the | |
24 | interrupts: even if the interrupts are disabled, the INTA | |
25 | will be changed, but the device won't issue an interrupt. | |
26 | But the ISR can be called at any time, so we ought ignore | |
27 | the value in the INTA otherwise we can call the op_mode | |
28 | after it was freed. | |
29 | ||
30 | I found this bug when the op_mode_start failed, and called | |
31 | iwl_trans_stop_hw(trans, true). Then I played with the | |
32 | RFKILL button, and removed the module. | |
33 | While removing the module, the IRQ is freed, and the ISR is | |
34 | called (CONFIG_DEBUG_SHIRQ enabled). Panic. | |
35 | ||
36 | Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com> | |
37 | Reviewed-by: Gregory Greenman <gregory.greenman@intel.com> | |
38 | Signed-off-by: Johannes Berg <johannes.berg@intel.com> | |
39 | [bwh: Backported to 3.2: | |
40 | - Adjust context | |
41 | - Pass bus(trans), not trans, to iwl_{read,write}32()] | |
42 | Signed-off-by: Ben Hutchings <ben@decadent.org.uk> | |
43 | [wujg: Backported to 3.4: | |
44 | - adjust context | |
45 | - Pass trans to iwl_{read,write}32()}] | |
46 | Signed-off-by: Jianguo Wu <wujianguo@huawei.com> | |
47 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
48 | --- | |
49 | drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | 12 ++++++++++-- | |
50 | 1 file changed, 10 insertions(+), 2 deletions(-) | |
51 | ||
52 | --- a/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | |
53 | +++ b/drivers/net/wireless/iwlwifi/iwl-trans-pcie-rx.c | |
54 | @@ -1264,12 +1264,20 @@ static irqreturn_t iwl_isr(int irq, void | |
55 | * back-to-back ISRs and sporadic interrupts from our NIC. | |
56 | * If we have something to service, the tasklet will re-enable ints. | |
57 | * If we *don't* have something, we'll re-enable before leaving here. */ | |
58 | - inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ | |
59 | + inta_mask = iwl_read32(trans, CSR_INT_MASK); | |
60 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); | |
61 | ||
62 | /* Discover which interrupts are active/pending */ | |
63 | inta = iwl_read32(trans, CSR_INT); | |
64 | ||
65 | + if (inta & (~inta_mask)) { | |
66 | + IWL_DEBUG_ISR(trans, | |
67 | + "We got a masked interrupt (0x%08x)...Ack and ignore\n", | |
68 | + inta & (~inta_mask)); | |
69 | + iwl_write32(trans, CSR_INT, inta & (~inta_mask)); | |
70 | + inta &= inta_mask; | |
71 | + } | |
72 | + | |
73 | /* Ignore interrupt if there's nothing in NIC to service. | |
74 | * This may be due to IRQ shared with another device, | |
75 | * or due to sporadic interrupts thrown from our NIC. */ | |
76 | @@ -1353,7 +1361,7 @@ irqreturn_t iwl_isr_ict(int irq, void *d | |
77 | * If we have something to service, the tasklet will re-enable ints. | |
78 | * If we *don't* have something, we'll re-enable before leaving here. | |
79 | */ | |
80 | - inta_mask = iwl_read32(trans, CSR_INT_MASK); /* just for debug */ | |
81 | + inta_mask = iwl_read32(trans, CSR_INT_MASK); | |
82 | iwl_write32(trans, CSR_INT_MASK, 0x00000000); | |
83 | ||
84 |