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