2 * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 #include <linux/jiffies.h>
19 #include <linux/pm_runtime.h>
21 #define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
23 int wil_can_suspend(struct wil6210_priv
*wil
, bool is_runtime
)
26 struct wireless_dev
*wdev
= wil
->wdev
;
27 struct net_device
*ndev
= wil_to_ndev(wil
);
28 bool wmi_only
= test_bit(WMI_FW_CAPABILITY_WMI_ONLY
,
29 wil
->fw_capabilities
);
31 wil_dbg_pm(wil
, "can_suspend: %s\n", is_runtime
? "runtime" : "system");
33 if (wmi_only
|| debug_fw
) {
34 wil_dbg_pm(wil
, "Deny any suspend - %s mode\n",
35 wmi_only
? "wmi_only" : "debug_fw");
39 if (is_runtime
&& !wil
->platform_ops
.suspend
) {
43 if (!(ndev
->flags
& IFF_UP
)) {
44 /* can always sleep when down */
45 wil_dbg_pm(wil
, "Interface is down\n");
48 if (test_bit(wil_status_resetting
, wil
->status
)) {
49 wil_dbg_pm(wil
, "Delay suspend when resetting\n");
53 if (wil
->recovery_state
!= fw_recovery_idle
) {
54 wil_dbg_pm(wil
, "Delay suspend during recovery\n");
59 /* interface is running */
60 switch (wdev
->iftype
) {
61 case NL80211_IFTYPE_MONITOR
:
62 wil_dbg_pm(wil
, "Sniffer\n");
65 /* for STA-like interface, don't runtime suspend */
66 case NL80211_IFTYPE_STATION
:
67 case NL80211_IFTYPE_P2P_CLIENT
:
68 if (test_bit(wil_status_fwconnecting
, wil
->status
)) {
69 wil_dbg_pm(wil
, "Delay suspend when connecting\n");
73 /* Runtime pm not supported in case the interface is up */
75 wil_dbg_pm(wil
, "STA-like interface\n");
80 /* AP-like interface - can't suspend */
82 wil_dbg_pm(wil
, "AP-like interface\n");
88 wil_dbg_pm(wil
, "can_suspend: %s => %s (%d)\n",
89 is_runtime
? "runtime" : "system", rc
? "No" : "Yes", rc
);
92 wil
->suspend_stats
.rejected_by_host
++;
97 static int wil_resume_keep_radio_on(struct wil6210_priv
*wil
)
101 /* wil_status_resuming will be cleared when getting
102 * WMI_TRAFFIC_RESUME_EVENTID
104 set_bit(wil_status_resuming
, wil
->status
);
105 clear_bit(wil_status_suspended
, wil
->status
);
106 wil_c(wil
, RGF_USER_CLKS_CTL_0
, BIT_USER_CLKS_RST_PWGD
);
109 wil6210_bus_request(wil
, wil
->bus_request_kbps_pre_suspend
);
111 /* Send WMI resume request to the device */
112 rc
= wmi_resume(wil
);
114 wil_err(wil
, "device failed to resume (%d)\n", rc
);
119 wil_err(wil
, "wil_down failed (%d)\n", rc
);
124 wil_err(wil
, "wil_up failed (%d)\n", rc
);
129 /* Wake all queues */
130 if (test_bit(wil_status_fwconnected
, wil
->status
))
131 wil_update_net_queues_bh(wil
, NULL
, false);
135 set_bit(wil_status_suspended
, wil
->status
);
139 static int wil_suspend_keep_radio_on(struct wil6210_priv
*wil
)
142 unsigned long start
, data_comp_to
;
144 wil_dbg_pm(wil
, "suspend keep radio on\n");
146 /* Prevent handling of new tx and wmi commands */
147 set_bit(wil_status_suspending
, wil
->status
);
148 if (test_bit(wil_status_collecting_dumps
, wil
->status
)) {
149 /* Device collects crash dump, cancel the suspend */
150 wil_dbg_pm(wil
, "reject suspend while collecting crash dump\n");
151 clear_bit(wil_status_suspending
, wil
->status
);
152 wil
->suspend_stats
.rejected_by_host
++;
155 wil_update_net_queues_bh(wil
, NULL
, true);
157 if (!wil_is_tx_idle(wil
)) {
158 wil_dbg_pm(wil
, "Pending TX data, reject suspend\n");
159 wil
->suspend_stats
.rejected_by_host
++;
163 if (!wil_is_rx_idle(wil
)) {
164 wil_dbg_pm(wil
, "Pending RX data, reject suspend\n");
165 wil
->suspend_stats
.rejected_by_host
++;
169 if (!wil_is_wmi_idle(wil
)) {
170 wil_dbg_pm(wil
, "Pending WMI events, reject suspend\n");
171 wil
->suspend_stats
.rejected_by_host
++;
175 /* Send WMI suspend request to the device */
176 rc
= wmi_suspend(wil
);
178 wil_dbg_pm(wil
, "wmi_suspend failed, reject suspend (%d)\n",
183 /* Wait for completion of the pending RX packets */
185 data_comp_to
= jiffies
+ msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS
);
186 if (test_bit(wil_status_napi_en
, wil
->status
)) {
187 while (!wil_is_rx_idle(wil
)) {
188 if (time_after(jiffies
, data_comp_to
)) {
189 if (wil_is_rx_idle(wil
))
192 "TO waiting for idle RX, suspend failed\n");
193 wil
->suspend_stats
.r_on
.failed_suspends
++;
194 goto resume_after_fail
;
196 wil_dbg_ratelimited(wil
, "rx vring is not empty -> NAPI\n");
197 napi_synchronize(&wil
->napi_rx
);
202 /* In case of pending WMI events, reject the suspend
203 * and resume the device.
204 * This can happen if the device sent the WMI events before
205 * approving the suspend.
207 if (!wil_is_wmi_idle(wil
)) {
208 wil_err(wil
, "suspend failed due to pending WMI events\n");
209 wil
->suspend_stats
.r_on
.failed_suspends
++;
210 goto resume_after_fail
;
215 /* Disable device reset on PERST */
216 wil_s(wil
, RGF_USER_CLKS_CTL_0
, BIT_USER_CLKS_RST_PWGD
);
218 if (wil
->platform_ops
.suspend
) {
219 rc
= wil
->platform_ops
.suspend(wil
->platform_handle
, true);
221 wil_err(wil
, "platform device failed to suspend (%d)\n",
223 wil
->suspend_stats
.r_on
.failed_suspends
++;
224 wil_c(wil
, RGF_USER_CLKS_CTL_0
, BIT_USER_CLKS_RST_PWGD
);
226 goto resume_after_fail
;
230 /* Save the current bus request to return to the same in resume */
231 wil
->bus_request_kbps_pre_suspend
= wil
->bus_request_kbps
;
232 wil6210_bus_request(wil
, 0);
234 set_bit(wil_status_suspended
, wil
->status
);
235 clear_bit(wil_status_suspending
, wil
->status
);
240 set_bit(wil_status_resuming
, wil
->status
);
241 clear_bit(wil_status_suspending
, wil
->status
);
242 rc
= wmi_resume(wil
);
243 /* if resume succeeded, reject the suspend */
246 if (test_bit(wil_status_fwconnected
, wil
->status
))
247 wil_update_net_queues_bh(wil
, NULL
, false);
252 clear_bit(wil_status_suspending
, wil
->status
);
253 if (test_bit(wil_status_fwconnected
, wil
->status
))
254 wil_update_net_queues_bh(wil
, NULL
, false);
258 static int wil_suspend_radio_off(struct wil6210_priv
*wil
)
261 struct net_device
*ndev
= wil_to_ndev(wil
);
263 wil_dbg_pm(wil
, "suspend radio off\n");
265 set_bit(wil_status_suspending
, wil
->status
);
266 if (test_bit(wil_status_collecting_dumps
, wil
->status
)) {
267 /* Device collects crash dump, cancel the suspend */
268 wil_dbg_pm(wil
, "reject suspend while collecting crash dump\n");
269 clear_bit(wil_status_suspending
, wil
->status
);
270 wil
->suspend_stats
.rejected_by_host
++;
274 /* if netif up, hardware is alive, shut it down */
275 if (ndev
->flags
& IFF_UP
) {
278 wil_err(wil
, "wil_down : %d\n", rc
);
279 wil
->suspend_stats
.r_off
.failed_suspends
++;
284 /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */
285 wil_dbg_pm(wil
, "Disabling PCIe IRQ before suspending\n");
286 wil_disable_irq(wil
);
288 if (wil
->platform_ops
.suspend
) {
289 rc
= wil
->platform_ops
.suspend(wil
->platform_handle
, false);
292 wil
->suspend_stats
.r_off
.failed_suspends
++;
297 set_bit(wil_status_suspended
, wil
->status
);
300 clear_bit(wil_status_suspending
, wil
->status
);
301 wil_dbg_pm(wil
, "suspend radio off: %d\n", rc
);
306 static int wil_resume_radio_off(struct wil6210_priv
*wil
)
309 struct net_device
*ndev
= wil_to_ndev(wil
);
311 wil_dbg_pm(wil
, "Enabling PCIe IRQ\n");
313 /* if netif up, bring hardware up
314 * During open(), IFF_UP set after actual device method
315 * invocation. This prevent recursive call to wil_up()
316 * wil_status_suspended will be cleared in wil_reset
318 if (ndev
->flags
& IFF_UP
)
321 clear_bit(wil_status_suspended
, wil
->status
);
326 int wil_suspend(struct wil6210_priv
*wil
, bool is_runtime
, bool keep_radio_on
)
330 wil_dbg_pm(wil
, "suspend: %s\n", is_runtime
? "runtime" : "system");
332 if (test_bit(wil_status_suspended
, wil
->status
)) {
333 wil_dbg_pm(wil
, "trying to suspend while suspended\n");
338 rc
= wil_suspend_radio_off(wil
);
340 rc
= wil_suspend_keep_radio_on(wil
);
342 wil_dbg_pm(wil
, "suspend: %s => %d\n",
343 is_runtime
? "runtime" : "system", rc
);
348 int wil_resume(struct wil6210_priv
*wil
, bool is_runtime
, bool keep_radio_on
)
352 wil_dbg_pm(wil
, "resume: %s\n", is_runtime
? "runtime" : "system");
354 if (wil
->platform_ops
.resume
) {
355 rc
= wil
->platform_ops
.resume(wil
->platform_handle
,
358 wil_err(wil
, "platform_ops.resume : %d\n", rc
);
364 rc
= wil_resume_keep_radio_on(wil
);
366 rc
= wil_resume_radio_off(wil
);
369 wil_dbg_pm(wil
, "resume: %s => %d\n", is_runtime
? "runtime" : "system",
374 void wil_pm_runtime_allow(struct wil6210_priv
*wil
)
376 struct device
*dev
= wil_to_dev(wil
);
378 pm_runtime_put_noidle(dev
);
379 pm_runtime_set_autosuspend_delay(dev
, WIL6210_AUTOSUSPEND_DELAY_MS
);
380 pm_runtime_use_autosuspend(dev
);
381 pm_runtime_allow(dev
);
384 void wil_pm_runtime_forbid(struct wil6210_priv
*wil
)
386 struct device
*dev
= wil_to_dev(wil
);
388 pm_runtime_forbid(dev
);
389 pm_runtime_get_noresume(dev
);
392 int wil_pm_runtime_get(struct wil6210_priv
*wil
)
395 struct device
*dev
= wil_to_dev(wil
);
397 rc
= pm_runtime_get_sync(dev
);
399 wil_err(wil
, "pm_runtime_get_sync() failed, rc = %d\n", rc
);
400 pm_runtime_put_noidle(dev
);
407 void wil_pm_runtime_put(struct wil6210_priv
*wil
)
409 struct device
*dev
= wil_to_dev(wil
);
411 pm_runtime_mark_last_busy(dev
);
412 pm_runtime_put_autosuspend(dev
);