Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+25 −8
Original line number Original line Diff line number Diff line
@@ -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)
	}
	}


	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)


	/* 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)
	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)
		/* 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)
	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)
	}
	}


	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)
	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)
+17 −0
Original line number Original line Diff line number Diff line
@@ -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)


	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)
	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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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 */
};
};


+11 −0
Original line number Original line Diff line number Diff line
@@ -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)
				     (const void __iomem * __force)data, len);
				     (const void __iomem * __force)data, len);
	}
	}


	clear_bit(wil_status_collecting_dumps, wil->status);

	return 0;
	return 0;
}
}