summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/marvell
diff options
context:
space:
mode:
authorBrian Norris <briannorris@chromium.org>2017-01-13 15:35:37 -0800
committerKalle Valo <kvalo@codeaurora.org>2017-01-20 11:46:32 +0200
commit5d5ddb5e0d9bc3ff3f377c6e03a074d13606a6e5 (patch)
tree19bec6dcf1646883d46a582efa6821d6f7e373aa /drivers/net/wireless/marvell
parent062e008a6e83e7c4da7df0a9c6aefdbc849e2bb3 (diff)
downloadlinux-5d5ddb5e0d9bc3ff3f377c6e03a074d13606a6e5.tar.bz2
mwifiex: pcie: don't loop/retry interrupt status checks
The following sequence occurs when using IEEE power-save on 8997: (a) driver sees SLEEP event (b) driver issues SLEEP CONFIRM (c) driver recevies CMD interrupt; within the interrupt processing loop, we do (d) and (e): (d) wait for FW sleep cookie (and often time out; it takes a while), FW is putting card into low power mode (e) re-check PCIE_HOST_INT_STATUS register; quit loop with 0 value But at (e), no one actually signaled an interrupt (i.e., we didn't check adapter->int_status). And what's more, because the card is going to sleep, this register read appears to take a very long time in some cases -- 3 milliseconds in my case! Now, I propose that (e) is completely unnecessary. If there were any additional interrupts signaled after the start of this loop, then the interrupt handler would have set adapter->int_status to non-zero and queued more work for the main loop -- and we'd catch it on the next iteration of the main loop. So this patch drops all the looping/re-reading of PCIE_HOST_INT_STATUS, which avoids the problematic (and slow) register read in step (e). Incidentally, this is a very similar issue to the one fixed in commit ec815dd2a5f1 ("mwifiex: prevent register accesses after host is sleeping"), except that the register read is just very slow instead of fatal in this case. Tested on 8997 in both MSI and (though not technically supported at the moment) MSI-X mode. Signed-off-by: Brian Norris <briannorris@chromium.org> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Diffstat (limited to 'drivers/net/wireless/marvell')
-rw-r--r--drivers/net/wireless/marvell/mwifiex/pcie.c102
1 files changed, 32 insertions, 70 deletions
diff --git a/drivers/net/wireless/marvell/mwifiex/pcie.c b/drivers/net/wireless/marvell/mwifiex/pcie.c
index 396cd4a9423a..b8a07d35973a 100644
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c
+++ b/drivers/net/wireless/marvell/mwifiex/pcie.c
@@ -2334,79 +2334,41 @@ static int mwifiex_process_pcie_int(struct mwifiex_adapter *adapter)
}
}
}
- while (pcie_ireg & HOST_INTR_MASK) {
- if (pcie_ireg & HOST_INTR_DNLD_DONE) {
- pcie_ireg &= ~HOST_INTR_DNLD_DONE;
- mwifiex_dbg(adapter, INTR,
- "info: TX DNLD Done\n");
- ret = mwifiex_pcie_send_data_complete(adapter);
- if (ret)
- return ret;
- }
- if (pcie_ireg & HOST_INTR_UPLD_RDY) {
- pcie_ireg &= ~HOST_INTR_UPLD_RDY;
- mwifiex_dbg(adapter, INTR,
- "info: Rx DATA\n");
- ret = mwifiex_pcie_process_recv_data(adapter);
- if (ret)
- return ret;
- }
- if (pcie_ireg & HOST_INTR_EVENT_RDY) {
- pcie_ireg &= ~HOST_INTR_EVENT_RDY;
- mwifiex_dbg(adapter, INTR,
- "info: Rx EVENT\n");
- ret = mwifiex_pcie_process_event_ready(adapter);
- if (ret)
- return ret;
- }
-
- if (pcie_ireg & HOST_INTR_CMD_DONE) {
- pcie_ireg &= ~HOST_INTR_CMD_DONE;
- if (adapter->cmd_sent) {
- mwifiex_dbg(adapter, INTR,
- "info: CMD sent Interrupt\n");
- adapter->cmd_sent = false;
- }
- /* Handle command response */
- ret = mwifiex_pcie_process_cmd_complete(adapter);
- if (ret)
- return ret;
- if (adapter->hs_activated)
- return ret;
- }
-
- if (card->msi_enable) {
- spin_lock_irqsave(&adapter->int_lock, flags);
- adapter->int_status = 0;
- spin_unlock_irqrestore(&adapter->int_lock, flags);
- }
-
- if (mwifiex_pcie_ok_to_access_hw(adapter)) {
- if (mwifiex_read_reg(adapter, PCIE_HOST_INT_STATUS,
- &pcie_ireg)) {
- mwifiex_dbg(adapter, ERROR,
- "Read register failed\n");
- return -1;
- }
- if ((pcie_ireg != 0xFFFFFFFF) && (pcie_ireg)) {
- if (mwifiex_write_reg(adapter,
- PCIE_HOST_INT_STATUS,
- ~pcie_ireg)) {
- mwifiex_dbg(adapter, ERROR,
- "Write register failed\n");
- return -1;
- }
- }
-
- }
- if (!card->msi_enable) {
- spin_lock_irqsave(&adapter->int_lock, flags);
- pcie_ireg |= adapter->int_status;
- adapter->int_status = 0;
- spin_unlock_irqrestore(&adapter->int_lock, flags);
+ if (pcie_ireg & HOST_INTR_DNLD_DONE) {
+ pcie_ireg &= ~HOST_INTR_DNLD_DONE;
+ mwifiex_dbg(adapter, INTR, "info: TX DNLD Done\n");
+ ret = mwifiex_pcie_send_data_complete(adapter);
+ if (ret)
+ return ret;
+ }
+ if (pcie_ireg & HOST_INTR_UPLD_RDY) {
+ pcie_ireg &= ~HOST_INTR_UPLD_RDY;
+ mwifiex_dbg(adapter, INTR, "info: Rx DATA\n");
+ ret = mwifiex_pcie_process_recv_data(adapter);
+ if (ret)
+ return ret;
+ }
+ if (pcie_ireg & HOST_INTR_EVENT_RDY) {
+ pcie_ireg &= ~HOST_INTR_EVENT_RDY;
+ mwifiex_dbg(adapter, INTR, "info: Rx EVENT\n");
+ ret = mwifiex_pcie_process_event_ready(adapter);
+ if (ret)
+ return ret;
+ }
+ if (pcie_ireg & HOST_INTR_CMD_DONE) {
+ pcie_ireg &= ~HOST_INTR_CMD_DONE;
+ if (adapter->cmd_sent) {
+ mwifiex_dbg(adapter, INTR,
+ "info: CMD sent Interrupt\n");
+ adapter->cmd_sent = false;
}
+ /* Handle command response */
+ ret = mwifiex_pcie_process_cmd_complete(adapter);
+ if (ret)
+ return ret;
}
+
mwifiex_dbg(adapter, INTR,
"info: cmd_sent=%d data_sent=%d\n",
adapter->cmd_sent, adapter->data_sent);