int wil_reset(struct wil6210_priv *wil, bool load_fw)
{
int rc;
+ unsigned long status_flags = BIT(wil_status_resetting);
wil_dbg_misc(wil, "reset\n");
}
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);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
/* prevent NAPI from being scheduled and prevent wmi commands */
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);
wil_mask_irq(wil);
wil_rx_fini(wil);
if (rc) {
wil_bl_crash_info(wil, true);
- return rc;
+ goto out;
}
rc = wil_get_bl_info(wil);
if (rc == -EAGAIN && !load_fw) /* ignore RF error if not going up */
rc = 0;
if (rc)
- return rc;
+ goto out;
wil_set_oob_mode(wil, oob_mode);
if (load_fw) {
/* Loading f/w from the file */
rc = wil_request_firmware(wil, wil->wil_fw_name, true);
if (rc)
- return rc;
+ goto out;
rc = wil_request_firmware(wil, WIL_BOARD_FILE_NAME, true);
if (rc)
- return rc;
+ goto out;
wil_pre_fw_config(wil);
wil_release_cpu(wil);
reinit_completion(&wil->wmi_call);
reinit_completion(&wil->halp.comp);
+ clear_bit(wil_status_resetting, wil->status);
+
if (load_fw) {
wil_configure_interrupt_moderation(wil);
wil_unmask_irq(wil);
}
return rc;
+
+out:
+ clear_bit(wil_status_resetting, wil->status);
+ return rc;
}
void wil_fw_error_recovery(struct wil6210_priv *wil)
wil_abort_scan(wil, false);
mutex_unlock(&wil->p2p_wdev_mutex);
- wil_reset(wil, false);
-
- return 0;
+ return wil_reset(wil, false);
}
int wil_down(struct wil6210_priv *wil)
/* Prevent handling of new tx and wmi commands */
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);
if (!wil_is_tx_idle(wil)) {
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 (ndev->flags & IFF_UP) {
rc = wil_down(wil);
set_bit(wil_status_suspended, wil->status);
out:
+ clear_bit(wil_status_suspending, wil->status);
wil_dbg_pm(wil, "suspend radio off: %d\n", rc);
return rc;
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 */
for (i = 0; i < ARRAY_SIZE(fw_mapping); i++) {
map = &fw_mapping[i];
(const void __iomem * __force)data, len);
}
+ clear_bit(wil_status_collecting_dumps, wil->status);
+
return 0;
}