Beispiel #1
0
Datei: pm.c Projekt: avagin/linux
static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
{
	int i;

	mutex_lock(&wil->vif_mutex);
	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
		struct wil6210_vif *vif = wil->vifs[i];

		if (vif)
			wil_update_net_queues_bh(wil, vif, NULL, true);
	}
	mutex_unlock(&wil->vif_mutex);
}
Beispiel #2
0
Datei: pm.c Projekt: avagin/linux
static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
{
	int i;

	mutex_lock(&wil->vif_mutex);
	for (i = 0; i < GET_MAX_VIFS(wil); i++) {
		struct wil6210_vif *vif = wil->vifs[i];

		if (vif && test_bit(wil_vif_fwconnected, vif->status))
			wil_update_net_queues_bh(wil, vif, NULL, false);
	}
	mutex_unlock(&wil->vif_mutex);
}
Beispiel #3
0
static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
{
	int rc = 0;

	/* wil_status_resuming will be cleared when getting
	 * WMI_TRAFFIC_RESUME_EVENTID
	 */
	set_bit(wil_status_resuming, wil->status);
	clear_bit(wil_status_suspended, wil->status);
	wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
	wil_unmask_irq(wil);

	wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend);

	/* Send WMI resume request to the device */
	rc = wmi_resume(wil);
	if (rc) {
		wil_err(wil, "device failed to resume (%d)\n", rc);
		if (no_fw_recovery)
			goto out;
		rc = wil_down(wil);
		if (rc) {
			wil_err(wil, "wil_down failed (%d)\n", rc);
			goto out;
		}
		rc = wil_up(wil);
		if (rc) {
			wil_err(wil, "wil_up failed (%d)\n", rc);
			goto out;
		}
	}

	/* Wake all queues */
	if (test_bit(wil_status_fwconnected, wil->status))
		wil_update_net_queues_bh(wil, NULL, false);

out:
	if (rc)
		set_bit(wil_status_suspended, wil->status);
	return rc;
}
Beispiel #4
0
static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
{
	int rc = 0;
	unsigned long start, data_comp_to;

	wil_dbg_pm(wil, "suspend keep radio on\n");

	/* 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, "Pending TX data, reject suspend\n");
		wil->suspend_stats.rejected_by_host++;
		goto reject_suspend;
	}

	if (!wil_is_rx_idle(wil)) {
		wil_dbg_pm(wil, "Pending RX data, reject suspend\n");
		wil->suspend_stats.rejected_by_host++;
		goto reject_suspend;
	}

	if (!wil_is_wmi_idle(wil)) {
		wil_dbg_pm(wil, "Pending WMI events, reject suspend\n");
		wil->suspend_stats.rejected_by_host++;
		goto reject_suspend;
	}

	/* Send WMI suspend request to the device */
	rc = wmi_suspend(wil);
	if (rc) {
		wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n",
			   rc);
		goto reject_suspend;
	}

	/* Wait for completion of the pending RX packets */
	start = jiffies;
	data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS);
	if (test_bit(wil_status_napi_en, wil->status)) {
		while (!wil_is_rx_idle(wil)) {
			if (time_after(jiffies, data_comp_to)) {
				if (wil_is_rx_idle(wil))
					break;
				wil_err(wil,
					"TO waiting for idle RX, suspend failed\n");
				wil->suspend_stats.r_on.failed_suspends++;
				goto resume_after_fail;
			}
			wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n");
			napi_synchronize(&wil->napi_rx);
			msleep(20);
		}
	}

	/* In case of pending WMI events, reject the suspend
	 * and resume the device.
	 * This can happen if the device sent the WMI events before
	 * approving the suspend.
	 */
	if (!wil_is_wmi_idle(wil)) {
		wil_err(wil, "suspend failed due to pending WMI events\n");
		wil->suspend_stats.r_on.failed_suspends++;
		goto resume_after_fail;
	}

	wil_mask_irq(wil);

	/* Disable device reset on PERST */
	wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);

	if (wil->platform_ops.suspend) {
		rc = wil->platform_ops.suspend(wil->platform_handle, true);
		if (rc) {
			wil_err(wil, "platform device failed to suspend (%d)\n",
				rc);
			wil->suspend_stats.r_on.failed_suspends++;
			wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
			wil_unmask_irq(wil);
			goto resume_after_fail;
		}
	}

	/* Save the current bus request to return to the same in resume */
	wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps;
	wil6210_bus_request(wil, 0);

	set_bit(wil_status_suspended, wil->status);
	clear_bit(wil_status_suspending, wil->status);

	return rc;

resume_after_fail:
	set_bit(wil_status_resuming, wil->status);
	clear_bit(wil_status_suspending, wil->status);
	rc = wmi_resume(wil);
	/* if resume succeeded, reject the suspend */
	if (!rc) {
		rc = -EBUSY;
		if (test_bit(wil_status_fwconnected, wil->status))
			wil_update_net_queues_bh(wil, NULL, false);
	}
	return rc;

reject_suspend:
	clear_bit(wil_status_suspending, wil->status);
	if (test_bit(wil_status_fwconnected, wil->status))
		wil_update_net_queues_bh(wil, NULL, false);
	return -EBUSY;
}