1 /* 2 * Copyright (c) 2014,2017 Qualcomm Atheros, Inc. 3 * 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. 7 * 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. 15 */ 16 17 #include "wil6210.h" 18 19 int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) 20 { 21 int rc = 0; 22 struct wireless_dev *wdev = wil->wdev; 23 24 wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); 25 26 if (!netif_running(wil_to_ndev(wil))) { 27 /* can always sleep when down */ 28 wil_dbg_pm(wil, "Interface is down\n"); 29 goto out; 30 } 31 if (test_bit(wil_status_resetting, wil->status)) { 32 wil_dbg_pm(wil, "Delay suspend when resetting\n"); 33 rc = -EBUSY; 34 goto out; 35 } 36 if (wil->recovery_state != fw_recovery_idle) { 37 wil_dbg_pm(wil, "Delay suspend during recovery\n"); 38 rc = -EBUSY; 39 goto out; 40 } 41 42 /* interface is running */ 43 switch (wdev->iftype) { 44 case NL80211_IFTYPE_MONITOR: 45 case NL80211_IFTYPE_STATION: 46 case NL80211_IFTYPE_P2P_CLIENT: 47 if (test_bit(wil_status_fwconnecting, wil->status)) { 48 wil_dbg_pm(wil, "Delay suspend when connecting\n"); 49 rc = -EBUSY; 50 goto out; 51 } 52 break; 53 /* AP-like interface - can't suspend */ 54 default: 55 wil_dbg_pm(wil, "AP-like interface\n"); 56 rc = -EBUSY; 57 break; 58 } 59 60 out: 61 wil_dbg_pm(wil, "can_suspend: %s => %s (%d)\n", 62 is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc); 63 64 return rc; 65 } 66 67 int wil_suspend(struct wil6210_priv *wil, bool is_runtime) 68 { 69 int rc = 0; 70 struct net_device *ndev = wil_to_ndev(wil); 71 72 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 73 74 /* if netif up, hardware is alive, shut it down */ 75 if (ndev->flags & IFF_UP) { 76 rc = wil_down(wil); 77 if (rc) { 78 wil_err(wil, "wil_down : %d\n", rc); 79 goto out; 80 } 81 } 82 83 if (wil->platform_ops.suspend) 84 rc = wil->platform_ops.suspend(wil->platform_handle); 85 86 out: 87 wil_dbg_pm(wil, "suspend: %s => %d\n", 88 is_runtime ? "runtime" : "system", rc); 89 return rc; 90 } 91 92 int wil_resume(struct wil6210_priv *wil, bool is_runtime) 93 { 94 int rc = 0; 95 struct net_device *ndev = wil_to_ndev(wil); 96 97 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 98 99 if (wil->platform_ops.resume) { 100 rc = wil->platform_ops.resume(wil->platform_handle); 101 if (rc) { 102 wil_err(wil, "platform_ops.resume : %d\n", rc); 103 goto out; 104 } 105 } 106 107 /* if netif up, bring hardware up 108 * During open(), IFF_UP set after actual device method 109 * invocation. This prevent recursive call to wil_up() 110 */ 111 if (ndev->flags & IFF_UP) 112 rc = wil_up(wil); 113 114 out: 115 wil_dbg_pm(wil, "resume: %s => %d\n", 116 is_runtime ? "runtime" : "system", rc); 117 return rc; 118 } 119