4.9-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amitkumar Karwar akarwar@marvell.com
commit ec815dd2a5f110f627d7955e0027a3a008f68166 upstream.
Following is mwifiex driver-firmware host sleep handshake. It involves three threads. suspend handler, interrupt handler, interrupt processing in main work queue.
1) Enter suspend handler 2) Download HS_CFG command 3) Response from firmware for HS_CFG 4) Suspend thread waits until handshake completes(i.e hs_activate becomes true) 5) SLEEP from firmware 6) SLEEP confirm downloaded to firmware. 7) SLEEP confirm response from firmware 8) Driver processes SLEEP confirm response and set hs_activate to wake up suspend thread 9) Exit suspend handler 10) Read sleep cookie in loop and wait until it indicates firmware is sleep. 11) After processing SLEEP confirm response, we are at the end of interrupt processing routine. Recheck if there are interrupts received while we were processing them.
During suspend-resume stress test, it's been observed that we may end up acessing PCIe hardware(in 10 and 11) when PCIe bus is closed which leads to a kernel crash.
This patch solves the problem with below changes. a) action 10 above can be done before 8 b) Skip 11 if hs_activated is true. SLEEP confirm response is the last interrupt from firmware. No need to recheck for pending interrupts. c) Add flush_workqueue() in suspend handler.
Signed-off-by: Amitkumar Karwar akarwar@marvell.com Reviewed-by: Brian Norris briannorris@chromium.org Tested-by: Brian Norris briannorris@chromium.org Signed-off-by: Kalle Valo kvalo@codeaurora.org Signed-off-by: Amit Pundir amit.pundir@linaro.org Signed-off-by: Greg Kroah-Hartman gregkh@linuxfoundation.org
--- drivers/net/wireless/marvell/mwifiex/pcie.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
--- a/drivers/net/wireless/marvell/mwifiex/pcie.c +++ b/drivers/net/wireless/marvell/mwifiex/pcie.c @@ -118,6 +118,7 @@ static int mwifiex_pcie_suspend(struct d adapter = card->adapter;
hs_actived = mwifiex_enable_hs(adapter); + flush_workqueue(adapter->workqueue);
/* Indicate device suspended */ adapter->is_suspended = true; @@ -1676,9 +1677,6 @@ static int mwifiex_pcie_process_cmd_comp
if (!adapter->curr_cmd) { if (adapter->ps_state == PS_STATE_SLEEP_CFM) { - mwifiex_process_sleep_confirm_resp(adapter, skb->data, - skb->len); - mwifiex_pcie_enable_host_int(adapter); if (mwifiex_write_reg(adapter, PCIE_CPU_INT_EVENT, CPU_INTR_SLEEP_CFM_DONE)) { @@ -1691,6 +1689,9 @@ static int mwifiex_pcie_process_cmd_comp while (reg->sleep_cookie && (count++ < 10) && mwifiex_pcie_ok_to_access_hw(adapter)) usleep_range(50, 60); + mwifiex_pcie_enable_host_int(adapter); + mwifiex_process_sleep_confirm_resp(adapter, skb->data, + skb->len); } else { mwifiex_dbg(adapter, ERROR, "There is no command but got cmdrsp\n"); @@ -2329,6 +2330,8 @@ static int mwifiex_process_pcie_int(stru ret = mwifiex_pcie_process_cmd_complete(adapter); if (ret) return ret; + if (adapter->hs_activated) + return ret; }
if (card->msi_enable) {