GNU Linux-libre 4.19.268-gnu1
[releases.git] / drivers / net / wireless / ath / wil6210 / pm.c
1 /*
2  * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
3  * Copyright (c) 2018, The Linux Foundation. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #include "wil6210.h"
19 #include <linux/jiffies.h>
20 #include <linux/pm_runtime.h>
21
22 #define WIL6210_AUTOSUSPEND_DELAY_MS (1000)
23
24 static void wil_pm_wake_connected_net_queues(struct wil6210_priv *wil)
25 {
26         int i;
27
28         mutex_lock(&wil->vif_mutex);
29         for (i = 0; i < wil->max_vifs; i++) {
30                 struct wil6210_vif *vif = wil->vifs[i];
31
32                 if (vif && test_bit(wil_vif_fwconnected, vif->status))
33                         wil_update_net_queues_bh(wil, vif, NULL, false);
34         }
35         mutex_unlock(&wil->vif_mutex);
36 }
37
38 static void wil_pm_stop_all_net_queues(struct wil6210_priv *wil)
39 {
40         int i;
41
42         mutex_lock(&wil->vif_mutex);
43         for (i = 0; i < wil->max_vifs; i++) {
44                 struct wil6210_vif *vif = wil->vifs[i];
45
46                 if (vif)
47                         wil_update_net_queues_bh(wil, vif, NULL, true);
48         }
49         mutex_unlock(&wil->vif_mutex);
50 }
51
52 static bool
53 wil_can_suspend_vif(struct wil6210_priv *wil, struct wil6210_vif *vif,
54                     bool is_runtime)
55 {
56         struct wireless_dev *wdev = vif_to_wdev(vif);
57
58         switch (wdev->iftype) {
59         case NL80211_IFTYPE_MONITOR:
60                 wil_dbg_pm(wil, "Sniffer\n");
61                 return false;
62
63         /* for STA-like interface, don't runtime suspend */
64         case NL80211_IFTYPE_STATION:
65         case NL80211_IFTYPE_P2P_CLIENT:
66                 if (test_bit(wil_vif_fwconnecting, vif->status)) {
67                         wil_dbg_pm(wil, "Delay suspend when connecting\n");
68                         return false;
69                 }
70                 if (is_runtime) {
71                         wil_dbg_pm(wil, "STA-like interface\n");
72                         return false;
73                 }
74                 break;
75         /* AP-like interface - can't suspend */
76         default:
77                 wil_dbg_pm(wil, "AP-like interface\n");
78                 return false;
79         }
80
81         return true;
82 }
83
84 int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
85 {
86         int rc = 0, i;
87         bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY,
88                                  wil->fw_capabilities);
89         bool active_ifaces;
90
91         wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system");
92
93         if (wmi_only || debug_fw) {
94                 wil_dbg_pm(wil, "Deny any suspend - %s mode\n",
95                            wmi_only ? "wmi_only" : "debug_fw");
96                 rc = -EBUSY;
97                 goto out;
98         }
99         if (is_runtime && !wil->platform_ops.suspend) {
100                 rc = -EBUSY;
101                 goto out;
102         }
103
104         mutex_lock(&wil->vif_mutex);
105         active_ifaces = wil_has_active_ifaces(wil, true, false);
106         mutex_unlock(&wil->vif_mutex);
107
108         if (!active_ifaces) {
109                 /* can always sleep when down */
110                 wil_dbg_pm(wil, "Interface is down\n");
111                 goto out;
112         }
113         if (test_bit(wil_status_resetting, wil->status)) {
114                 wil_dbg_pm(wil, "Delay suspend when resetting\n");
115                 rc = -EBUSY;
116                 goto out;
117         }
118         if (wil->recovery_state != fw_recovery_idle) {
119                 wil_dbg_pm(wil, "Delay suspend during recovery\n");
120                 rc = -EBUSY;
121                 goto out;
122         }
123
124         /* interface is running */
125         mutex_lock(&wil->vif_mutex);
126         for (i = 0; i < wil->max_vifs; i++) {
127                 struct wil6210_vif *vif = wil->vifs[i];
128
129                 if (!vif)
130                         continue;
131                 if (!wil_can_suspend_vif(wil, vif, is_runtime)) {
132                         rc = -EBUSY;
133                         mutex_unlock(&wil->vif_mutex);
134                         goto out;
135                 }
136         }
137         mutex_unlock(&wil->vif_mutex);
138
139 out:
140         wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n",
141                    is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc);
142
143         if (rc)
144                 wil->suspend_stats.rejected_by_host++;
145
146         return rc;
147 }
148
149 static int wil_resume_keep_radio_on(struct wil6210_priv *wil)
150 {
151         int rc = 0;
152
153         /* wil_status_resuming will be cleared when getting
154          * WMI_TRAFFIC_RESUME_EVENTID
155          */
156         set_bit(wil_status_resuming, wil->status);
157         clear_bit(wil_status_suspended, wil->status);
158         wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
159         wil_unmask_irq(wil);
160
161         wil6210_bus_request(wil, wil->bus_request_kbps_pre_suspend);
162
163         /* Send WMI resume request to the device */
164         rc = wmi_resume(wil);
165         if (rc) {
166                 wil_err(wil, "device failed to resume (%d)\n", rc);
167                 if (no_fw_recovery)
168                         goto out;
169                 rc = wil_down(wil);
170                 if (rc) {
171                         wil_err(wil, "wil_down failed (%d)\n", rc);
172                         goto out;
173                 }
174                 rc = wil_up(wil);
175                 if (rc) {
176                         wil_err(wil, "wil_up failed (%d)\n", rc);
177                         goto out;
178                 }
179         }
180
181         /* Wake all queues */
182         wil_pm_wake_connected_net_queues(wil);
183
184 out:
185         if (rc)
186                 set_bit(wil_status_suspended, wil->status);
187         return rc;
188 }
189
190 static int wil_suspend_keep_radio_on(struct wil6210_priv *wil)
191 {
192         int rc = 0;
193         unsigned long start, data_comp_to;
194
195         wil_dbg_pm(wil, "suspend keep radio on\n");
196
197         /* Prevent handling of new tx and wmi commands */
198         set_bit(wil_status_suspending, wil->status);
199         if (test_bit(wil_status_collecting_dumps, wil->status)) {
200                 /* Device collects crash dump, cancel the suspend */
201                 wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
202                 clear_bit(wil_status_suspending, wil->status);
203                 wil->suspend_stats.rejected_by_host++;
204                 return -EBUSY;
205         }
206         wil_pm_stop_all_net_queues(wil);
207
208         if (!wil_is_tx_idle(wil)) {
209                 wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
210                 wil->suspend_stats.rejected_by_host++;
211                 goto reject_suspend;
212         }
213
214         if (!wil->txrx_ops.is_rx_idle(wil)) {
215                 wil_dbg_pm(wil, "Pending RX data, reject suspend\n");
216                 wil->suspend_stats.rejected_by_host++;
217                 goto reject_suspend;
218         }
219
220         if (!wil_is_wmi_idle(wil)) {
221                 wil_dbg_pm(wil, "Pending WMI events, reject suspend\n");
222                 wil->suspend_stats.rejected_by_host++;
223                 goto reject_suspend;
224         }
225
226         /* Send WMI suspend request to the device */
227         rc = wmi_suspend(wil);
228         if (rc) {
229                 wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n",
230                            rc);
231                 goto reject_suspend;
232         }
233
234         /* Wait for completion of the pending RX packets */
235         start = jiffies;
236         data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS);
237         if (test_bit(wil_status_napi_en, wil->status)) {
238                 while (!wil->txrx_ops.is_rx_idle(wil)) {
239                         if (time_after(jiffies, data_comp_to)) {
240                                 if (wil->txrx_ops.is_rx_idle(wil))
241                                         break;
242                                 wil_err(wil,
243                                         "TO waiting for idle RX, suspend failed\n");
244                                 wil->suspend_stats.r_on.failed_suspends++;
245                                 goto resume_after_fail;
246                         }
247                         wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n");
248                         napi_synchronize(&wil->napi_rx);
249                         msleep(20);
250                 }
251         }
252
253         /* In case of pending WMI events, reject the suspend
254          * and resume the device.
255          * This can happen if the device sent the WMI events before
256          * approving the suspend.
257          */
258         if (!wil_is_wmi_idle(wil)) {
259                 wil_err(wil, "suspend failed due to pending WMI events\n");
260                 wil->suspend_stats.r_on.failed_suspends++;
261                 goto resume_after_fail;
262         }
263
264         wil_mask_irq(wil);
265
266         /* Disable device reset on PERST */
267         wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
268
269         if (wil->platform_ops.suspend) {
270                 rc = wil->platform_ops.suspend(wil->platform_handle, true);
271                 if (rc) {
272                         wil_err(wil, "platform device failed to suspend (%d)\n",
273                                 rc);
274                         wil->suspend_stats.r_on.failed_suspends++;
275                         wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
276                         wil_unmask_irq(wil);
277                         goto resume_after_fail;
278                 }
279         }
280
281         /* Save the current bus request to return to the same in resume */
282         wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps;
283         wil6210_bus_request(wil, 0);
284
285         set_bit(wil_status_suspended, wil->status);
286         clear_bit(wil_status_suspending, wil->status);
287
288         return rc;
289
290 resume_after_fail:
291         set_bit(wil_status_resuming, wil->status);
292         clear_bit(wil_status_suspending, wil->status);
293         rc = wmi_resume(wil);
294         /* if resume succeeded, reject the suspend */
295         if (!rc) {
296                 rc = -EBUSY;
297                 wil_pm_wake_connected_net_queues(wil);
298         }
299         return rc;
300
301 reject_suspend:
302         clear_bit(wil_status_suspending, wil->status);
303         wil_pm_wake_connected_net_queues(wil);
304         return -EBUSY;
305 }
306
307 static int wil_suspend_radio_off(struct wil6210_priv *wil)
308 {
309         int rc = 0;
310         bool active_ifaces;
311
312         wil_dbg_pm(wil, "suspend radio off\n");
313
314         set_bit(wil_status_suspending, wil->status);
315         if (test_bit(wil_status_collecting_dumps, wil->status)) {
316                 /* Device collects crash dump, cancel the suspend */
317                 wil_dbg_pm(wil, "reject suspend while collecting crash dump\n");
318                 clear_bit(wil_status_suspending, wil->status);
319                 wil->suspend_stats.rejected_by_host++;
320                 return -EBUSY;
321         }
322
323         /* if netif up, hardware is alive, shut it down */
324         mutex_lock(&wil->vif_mutex);
325         active_ifaces = wil_has_active_ifaces(wil, true, false);
326         mutex_unlock(&wil->vif_mutex);
327
328         if (active_ifaces) {
329                 rc = wil_down(wil);
330                 if (rc) {
331                         wil_err(wil, "wil_down : %d\n", rc);
332                         wil->suspend_stats.r_off.failed_suspends++;
333                         goto out;
334                 }
335         }
336
337         /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */
338         wil_dbg_pm(wil, "Disabling PCIe IRQ before suspending\n");
339         wil_disable_irq(wil);
340
341         if (wil->platform_ops.suspend) {
342                 rc = wil->platform_ops.suspend(wil->platform_handle, false);
343                 if (rc) {
344                         wil_enable_irq(wil);
345                         wil->suspend_stats.r_off.failed_suspends++;
346                         goto out;
347                 }
348         }
349
350         set_bit(wil_status_suspended, wil->status);
351
352 out:
353         clear_bit(wil_status_suspending, wil->status);
354         wil_dbg_pm(wil, "suspend radio off: %d\n", rc);
355
356         return rc;
357 }
358
359 static int wil_resume_radio_off(struct wil6210_priv *wil)
360 {
361         int rc = 0;
362         bool active_ifaces;
363
364         wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
365         wil_enable_irq(wil);
366         /* if any netif up, bring hardware up
367          * During open(), IFF_UP set after actual device method
368          * invocation. This prevent recursive call to wil_up()
369          * wil_status_suspended will be cleared in wil_reset
370          */
371         mutex_lock(&wil->vif_mutex);
372         active_ifaces = wil_has_active_ifaces(wil, true, false);
373         mutex_unlock(&wil->vif_mutex);
374         if (active_ifaces)
375                 rc = wil_up(wil);
376         else
377                 clear_bit(wil_status_suspended, wil->status);
378
379         return rc;
380 }
381
382 int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
383 {
384         int rc = 0;
385
386         wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
387
388         if (test_bit(wil_status_suspended, wil->status)) {
389                 wil_dbg_pm(wil, "trying to suspend while suspended\n");
390                 return 0;
391         }
392
393         if (!keep_radio_on)
394                 rc = wil_suspend_radio_off(wil);
395         else
396                 rc = wil_suspend_keep_radio_on(wil);
397
398         wil_dbg_pm(wil, "suspend: %s => %d\n",
399                    is_runtime ? "runtime" : "system", rc);
400
401         return rc;
402 }
403
404 int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
405 {
406         int rc = 0;
407
408         wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
409
410         if (wil->platform_ops.resume) {
411                 rc = wil->platform_ops.resume(wil->platform_handle,
412                                               keep_radio_on);
413                 if (rc) {
414                         wil_err(wil, "platform_ops.resume : %d\n", rc);
415                         goto out;
416                 }
417         }
418
419         if (keep_radio_on)
420                 rc = wil_resume_keep_radio_on(wil);
421         else
422                 rc = wil_resume_radio_off(wil);
423
424 out:
425         wil_dbg_pm(wil, "resume: %s => %d\n", is_runtime ? "runtime" : "system",
426                    rc);
427         return rc;
428 }
429
430 void wil_pm_runtime_allow(struct wil6210_priv *wil)
431 {
432         struct device *dev = wil_to_dev(wil);
433
434         pm_runtime_put_noidle(dev);
435         pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS);
436         pm_runtime_use_autosuspend(dev);
437         pm_runtime_allow(dev);
438 }
439
440 void wil_pm_runtime_forbid(struct wil6210_priv *wil)
441 {
442         struct device *dev = wil_to_dev(wil);
443
444         pm_runtime_forbid(dev);
445         pm_runtime_get_noresume(dev);
446 }
447
448 int wil_pm_runtime_get(struct wil6210_priv *wil)
449 {
450         int rc;
451         struct device *dev = wil_to_dev(wil);
452
453         rc = pm_runtime_get_sync(dev);
454         if (rc < 0) {
455                 wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc);
456                 pm_runtime_put_noidle(dev);
457                 return rc;
458         }
459
460         return 0;
461 }
462
463 void wil_pm_runtime_put(struct wil6210_priv *wil)
464 {
465         struct device *dev = wil_to_dev(wil);
466
467         pm_runtime_mark_last_busy(dev);
468         pm_runtime_put_autosuspend(dev);
469 }