Commit a8fd16d7 authored by Maya Erez's avatar Maya Erez Committed by Kalle Valo

wil6210: prevent parallel suspend and dump collection

Suspend and crash dump operations can happen simultaneously
in case there is a FW assert during the suspend procedure
or when SSR calls all the devices crashdump callbacks.

To prevent that, a new flag is added, indicating that the
dumps collection is in progress, in order to allow the
suspend/reset decline if the dumps collection already started.
Signed-off-by: default avatarMaya Erez <qca_merez@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@codeaurora.org>
parent 594b59ec
...@@ -998,6 +998,7 @@ static void wil_pre_fw_config(struct wil6210_priv *wil) ...@@ -998,6 +998,7 @@ static void wil_pre_fw_config(struct wil6210_priv *wil)
int wil_reset(struct wil6210_priv *wil, bool load_fw) int wil_reset(struct wil6210_priv *wil, bool load_fw)
{ {
int rc; int rc;
unsigned long status_flags = BIT(wil_status_resetting);
wil_dbg_misc(wil, "reset\n"); wil_dbg_misc(wil, "reset\n");
...@@ -1037,6 +1038,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1037,6 +1038,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
} }
set_bit(wil_status_resetting, wil->status); set_bit(wil_status_resetting, wil->status);
if (test_bit(wil_status_collecting_dumps, wil->status)) {
/* Device collects crash dump, cancel the reset.
* following crash dump collection, reset would take place.
*/
wil_dbg_misc(wil, "reject reset while collecting crash dump\n");
rc = -EBUSY;
goto out;
}
cancel_work_sync(&wil->disconnect_worker); cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false); wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
...@@ -1051,7 +1060,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1051,7 +1060,11 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
/* prevent NAPI from being scheduled and prevent wmi commands */ /* prevent NAPI from being scheduled and prevent wmi commands */
mutex_lock(&wil->wmi_mutex); mutex_lock(&wil->wmi_mutex);
bitmap_zero(wil->status, wil_status_last); if (test_bit(wil_status_suspending, wil->status))
status_flags |= BIT(wil_status_suspending);
bitmap_and(wil->status, wil->status, &status_flags,
wil_status_last);
wil_dbg_misc(wil, "wil->status (0x%lx)\n", *wil->status);
mutex_unlock(&wil->wmi_mutex); mutex_unlock(&wil->wmi_mutex);
wil_mask_irq(wil); wil_mask_irq(wil);
...@@ -1069,14 +1082,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1069,14 +1082,14 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
wil_rx_fini(wil); wil_rx_fini(wil);
if (rc) { if (rc) {
wil_bl_crash_info(wil, true); wil_bl_crash_info(wil, true);
return rc; goto out;
} }
rc = wil_get_bl_info(wil); rc = wil_get_bl_info(wil);
if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */ if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
rc = 0; rc = 0;
if (rc) if (rc)
return rc; goto out;
wil_set_oob_mode(wil, oob_mode); wil_set_oob_mode(wil, oob_mode);
if (load_fw) { if (load_fw) {
...@@ -1088,10 +1101,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1088,10 +1101,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
/* Loading f/w from the file */ /* Loading f/w from the file */
rc = wil_request_firmware(wil, wil->wil_fw_name, true); rc = wil_request_firmware(wil, wil->wil_fw_name, true);
if (rc) if (rc)
return rc; goto out;
rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true); rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
if (rc) if (rc)
return rc; goto out;
wil_pre_fw_config(wil); wil_pre_fw_config(wil);
wil_release_cpu(wil); wil_release_cpu(wil);
...@@ -1103,6 +1116,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1103,6 +1116,8 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
reinit_completion(&wil->wmi_call); reinit_completion(&wil->wmi_call);
reinit_completion(&wil->halp.comp); reinit_completion(&wil->halp.comp);
clear_bit(wil_status_resetting, wil->status);
if (load_fw) { if (load_fw) {
wil_configure_interrupt_moderation(wil); wil_configure_interrupt_moderation(wil);
wil_unmask_irq(wil); wil_unmask_irq(wil);
...@@ -1136,6 +1151,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw) ...@@ -1136,6 +1151,10 @@ int wil_reset(struct wil6210_priv *wil, bool load_fw)
} }
return rc; return rc;
out:
clear_bit(wil_status_resetting, wil->status);
return rc;
} }
void wil_fw_error_recovery(struct wil6210_priv *wil) void wil_fw_error_recovery(struct wil6210_priv *wil)
...@@ -1241,9 +1260,7 @@ int __wil_down(struct wil6210_priv *wil) ...@@ -1241,9 +1260,7 @@ int __wil_down(struct wil6210_priv *wil)
wil_abort_scan(wil, false); wil_abort_scan(wil, false);
mutex_unlock(&wil->p2p_wdev_mutex); mutex_unlock(&wil->p2p_wdev_mutex);
wil_reset(wil, false); return wil_reset(wil, false);
return 0;
} }
int wil_down(struct wil6210_priv *wil) int wil_down(struct wil6210_priv *wil)
......
...@@ -145,6 +145,13 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil) ...@@ -145,6 +145,13 @@ static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
/* Prevent handling of new tx and wmi commands */ /* Prevent handling of new tx and wmi commands */
set_bit(wil_status_suspending, wil->status); set_bit(wil_status_suspending, wil->status);
if (test_bit(wil_status_collecting_dumps, wil->status)) {
/* Device collects crash dump, cancel the suspend */
wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
clear_bit(wil_status_suspending, wil->status);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
wil_update_net_queues_bh(wil, NULL, true); wil_update_net_queues_bh(wil, NULL, true);
if (!wil_is_tx_idle(wil)) { if (!wil_is_tx_idle(wil)) {
...@@ -255,6 +262,15 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) ...@@ -255,6 +262,15 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
wil_dbg_pm(wil, "suspend radio off\n"); wil_dbg_pm(wil, "suspend radio off\n");
set_bit(wil_status_suspending, wil->status);
if (test_bit(wil_status_collecting_dumps, wil->status)) {
/* Device collects crash dump, cancel the suspend */
wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
clear_bit(wil_status_suspending, wil->status);
wil->suspend_stats.rejected_by_host++;
return -EBUSY;
}
/* if netif up, hardware is alive, shut it down */ /* if netif up, hardware is alive, shut it down */
if (ndev->flags & IFF_UP) { if (ndev->flags & IFF_UP) {
rc = wil_down(wil); rc = wil_down(wil);
...@@ -281,6 +297,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil) ...@@ -281,6 +297,7 @@ static int wil_suspend_radio_off(struct wil6210_priv *wil)
set_bit(wil_status_suspended, wil->status); set_bit(wil_status_suspended, wil->status);
out: out:
clear_bit(wil_status_suspending, wil->status);
wil_dbg_pm(wil, "suspend radio off: %d\n", rc); wil_dbg_pm(wil, "suspend radio off: %d\n", rc);
return rc; return rc;
......
...@@ -445,6 +445,7 @@ enum { /* for wil6210_priv.status */ ...@@ -445,6 +445,7 @@ enum { /* for wil6210_priv.status */
wil_status_suspending, /* suspend in progress */ wil_status_suspending, /* suspend in progress */
wil_status_suspended, /* suspend completed, device is suspended */ wil_status_suspended, /* suspend completed, device is suspended */
wil_status_resuming, /* resume in progress */ wil_status_resuming, /* resume in progress */
wil_status_collecting_dumps, /* crashdump collection in progress */
wil_status_last /* keep last */ wil_status_last /* keep last */
}; };
......
...@@ -72,6 +72,15 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) ...@@ -72,6 +72,15 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
return -EINVAL; return -EINVAL;
} }
set_bit(wil_status_collecting_dumps, wil->status);
if (test_bit(wil_status_suspending, wil->status) ||
test_bit(wil_status_suspended, wil->status) ||
test_bit(wil_status_resetting, wil->status)) {
wil_err(wil, "cannot collect fw dump during suspend/reset\n");
clear_bit(wil_status_collecting_dumps, wil->status);
return -EINVAL;
}
/* copy to crash dump area */ /* copy to crash dump area */
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) { for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
map = &fw_mapping[i]; map = &fw_mapping[i];
...@@ -91,6 +100,8 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size) ...@@ -91,6 +100,8 @@ int wil_fw_copy_crash_dump(struct wil6210_priv *wil, void *dest, u32 size)
(const void __iomem * __force)data, len); (const void __iomem * __force)data, len);
} }
clear_bit(wil_status_collecting_dumps, wil->status);
return 0; return 0;
} }
......
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