root/drivers/net/wireless/ath/wil6210/pm.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. wil_pm_wake_connected_net_queues
  2. wil_pm_stop_all_net_queues
  3. wil_can_suspend_vif
  4. wil_can_suspend
  5. wil_resume_keep_radio_on
  6. wil_suspend_keep_radio_on
  7. wil_suspend_radio_off
  8. wil_resume_radio_off
  9. wil_suspend
  10. wil_resume
  11. wil_pm_runtime_allow
  12. wil_pm_runtime_forbid
  13. wil_pm_runtime_get
  14. wil_pm_runtime_put

   1 /*
   2  * Copyright (c) 2014,2017 Qualcomm Atheros, Inc.
   3  * Copyright (c) 2018-2019, 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 < GET_MAX_VIFS(wil); 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 < GET_MAX_VIFS(wil); 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 < GET_MAX_VIFS(wil); 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 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         rc = down_write_trylock(&wil->mem_lock);
 199         if (!rc) {
 200                 wil_err(wil,
 201                         "device is busy. down_write_trylock failed, returned (0x%x)\n",
 202                         rc);
 203                 wil->suspend_stats.rejected_by_host++;
 204                 return -EBUSY;
 205         }
 206 
 207         set_bit(wil_status_suspending, wil->status);
 208         up_write(&wil->mem_lock);
 209 
 210         wil_pm_stop_all_net_queues(wil);
 211 
 212         if (!wil_is_tx_idle(wil)) {
 213                 wil_dbg_pm(wil, "Pending TX data, reject suspend\n");
 214                 wil->suspend_stats.rejected_by_host++;
 215                 goto reject_suspend;
 216         }
 217 
 218         if (!wil->txrx_ops.is_rx_idle(wil)) {
 219                 wil_dbg_pm(wil, "Pending RX data, reject suspend\n");
 220                 wil->suspend_stats.rejected_by_host++;
 221                 goto reject_suspend;
 222         }
 223 
 224         if (!wil_is_wmi_idle(wil)) {
 225                 wil_dbg_pm(wil, "Pending WMI events, reject suspend\n");
 226                 wil->suspend_stats.rejected_by_host++;
 227                 goto reject_suspend;
 228         }
 229 
 230         /* Send WMI suspend request to the device */
 231         rc = wmi_suspend(wil);
 232         if (rc) {
 233                 wil_dbg_pm(wil, "wmi_suspend failed, reject suspend (%d)\n",
 234                            rc);
 235                 goto reject_suspend;
 236         }
 237 
 238         /* Wait for completion of the pending RX packets */
 239         data_comp_to = jiffies + msecs_to_jiffies(WIL_DATA_COMPLETION_TO_MS);
 240         if (test_bit(wil_status_napi_en, wil->status)) {
 241                 while (!wil->txrx_ops.is_rx_idle(wil)) {
 242                         if (time_after(jiffies, data_comp_to)) {
 243                                 if (wil->txrx_ops.is_rx_idle(wil))
 244                                         break;
 245                                 wil_err(wil,
 246                                         "TO waiting for idle RX, suspend failed\n");
 247                                 wil->suspend_stats.r_on.failed_suspends++;
 248                                 goto resume_after_fail;
 249                         }
 250                         wil_dbg_ratelimited(wil, "rx vring is not empty -> NAPI\n");
 251                         napi_synchronize(&wil->napi_rx);
 252                         msleep(20);
 253                 }
 254         }
 255 
 256         /* In case of pending WMI events, reject the suspend
 257          * and resume the device.
 258          * This can happen if the device sent the WMI events before
 259          * approving the suspend.
 260          */
 261         if (!wil_is_wmi_idle(wil)) {
 262                 wil_err(wil, "suspend failed due to pending WMI events\n");
 263                 wil->suspend_stats.r_on.failed_suspends++;
 264                 goto resume_after_fail;
 265         }
 266 
 267         wil_mask_irq(wil);
 268 
 269         /* Disable device reset on PERST */
 270         wil_s(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
 271 
 272         if (wil->platform_ops.suspend) {
 273                 rc = wil->platform_ops.suspend(wil->platform_handle, true);
 274                 if (rc) {
 275                         wil_err(wil, "platform device failed to suspend (%d)\n",
 276                                 rc);
 277                         wil->suspend_stats.r_on.failed_suspends++;
 278                         wil_c(wil, RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
 279                         wil_unmask_irq(wil);
 280                         goto resume_after_fail;
 281                 }
 282         }
 283 
 284         /* Save the current bus request to return to the same in resume */
 285         wil->bus_request_kbps_pre_suspend = wil->bus_request_kbps;
 286         wil6210_bus_request(wil, 0);
 287 
 288         set_bit(wil_status_suspended, wil->status);
 289         clear_bit(wil_status_suspending, wil->status);
 290 
 291         return rc;
 292 
 293 resume_after_fail:
 294         set_bit(wil_status_resuming, wil->status);
 295         clear_bit(wil_status_suspending, wil->status);
 296         rc = wmi_resume(wil);
 297         /* if resume succeeded, reject the suspend */
 298         if (!rc) {
 299                 rc = -EBUSY;
 300                 wil_pm_wake_connected_net_queues(wil);
 301         }
 302         return rc;
 303 
 304 reject_suspend:
 305         clear_bit(wil_status_suspending, wil->status);
 306         wil_pm_wake_connected_net_queues(wil);
 307         return -EBUSY;
 308 }
 309 
 310 static int wil_suspend_radio_off(struct wil6210_priv *wil)
 311 {
 312         int rc = 0;
 313         bool active_ifaces;
 314 
 315         wil_dbg_pm(wil, "suspend radio off\n");
 316 
 317         rc = down_write_trylock(&wil->mem_lock);
 318         if (!rc) {
 319                 wil_err(wil,
 320                         "device is busy. down_write_trylock failed, returned (0x%x)\n",
 321                         rc);
 322                 wil->suspend_stats.rejected_by_host++;
 323                 return -EBUSY;
 324         }
 325 
 326         set_bit(wil_status_suspending, wil->status);
 327         up_write(&wil->mem_lock);
 328 
 329         /* if netif up, hardware is alive, shut it down */
 330         mutex_lock(&wil->vif_mutex);
 331         active_ifaces = wil_has_active_ifaces(wil, true, false);
 332         mutex_unlock(&wil->vif_mutex);
 333 
 334         if (active_ifaces) {
 335                 rc = wil_down(wil);
 336                 if (rc) {
 337                         wil_err(wil, "wil_down : %d\n", rc);
 338                         wil->suspend_stats.r_off.failed_suspends++;
 339                         goto out;
 340                 }
 341         }
 342 
 343         /* Disable PCIe IRQ to prevent sporadic IRQs when PCIe is suspending */
 344         wil_dbg_pm(wil, "Disabling PCIe IRQ before suspending\n");
 345         wil_disable_irq(wil);
 346 
 347         if (wil->platform_ops.suspend) {
 348                 rc = wil->platform_ops.suspend(wil->platform_handle, false);
 349                 if (rc) {
 350                         wil_enable_irq(wil);
 351                         wil->suspend_stats.r_off.failed_suspends++;
 352                         goto out;
 353                 }
 354         }
 355 
 356         set_bit(wil_status_suspended, wil->status);
 357 
 358 out:
 359         clear_bit(wil_status_suspending, wil->status);
 360         wil_dbg_pm(wil, "suspend radio off: %d\n", rc);
 361 
 362         return rc;
 363 }
 364 
 365 static int wil_resume_radio_off(struct wil6210_priv *wil)
 366 {
 367         int rc = 0;
 368         bool active_ifaces;
 369 
 370         wil_dbg_pm(wil, "Enabling PCIe IRQ\n");
 371         wil_enable_irq(wil);
 372         /* if any netif up, bring hardware up
 373          * During open(), IFF_UP set after actual device method
 374          * invocation. This prevent recursive call to wil_up()
 375          * wil_status_suspended will be cleared in wil_reset
 376          */
 377         mutex_lock(&wil->vif_mutex);
 378         active_ifaces = wil_has_active_ifaces(wil, true, false);
 379         mutex_unlock(&wil->vif_mutex);
 380         if (active_ifaces)
 381                 rc = wil_up(wil);
 382         else
 383                 clear_bit(wil_status_suspended, wil->status);
 384 
 385         return rc;
 386 }
 387 
 388 int wil_suspend(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
 389 {
 390         int rc = 0;
 391 
 392         wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system");
 393 
 394         if (test_bit(wil_status_suspended, wil->status)) {
 395                 wil_dbg_pm(wil, "trying to suspend while suspended\n");
 396                 return 0;
 397         }
 398 
 399         if (!keep_radio_on)
 400                 rc = wil_suspend_radio_off(wil);
 401         else
 402                 rc = wil_suspend_keep_radio_on(wil);
 403 
 404         wil_dbg_pm(wil, "suspend: %s => %d\n",
 405                    is_runtime ? "runtime" : "system", rc);
 406 
 407         return rc;
 408 }
 409 
 410 int wil_resume(struct wil6210_priv *wil, bool is_runtime, bool keep_radio_on)
 411 {
 412         int rc = 0;
 413 
 414         wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system");
 415 
 416         if (wil->platform_ops.resume) {
 417                 rc = wil->platform_ops.resume(wil->platform_handle,
 418                                               keep_radio_on);
 419                 if (rc) {
 420                         wil_err(wil, "platform_ops.resume : %d\n", rc);
 421                         goto out;
 422                 }
 423         }
 424 
 425         if (keep_radio_on)
 426                 rc = wil_resume_keep_radio_on(wil);
 427         else
 428                 rc = wil_resume_radio_off(wil);
 429 
 430 out:
 431         wil_dbg_pm(wil, "resume: %s => %d\n", is_runtime ? "runtime" : "system",
 432                    rc);
 433         return rc;
 434 }
 435 
 436 void wil_pm_runtime_allow(struct wil6210_priv *wil)
 437 {
 438         struct device *dev = wil_to_dev(wil);
 439 
 440         pm_runtime_put_noidle(dev);
 441         pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS);
 442         pm_runtime_use_autosuspend(dev);
 443         pm_runtime_allow(dev);
 444 }
 445 
 446 void wil_pm_runtime_forbid(struct wil6210_priv *wil)
 447 {
 448         struct device *dev = wil_to_dev(wil);
 449 
 450         pm_runtime_forbid(dev);
 451         pm_runtime_get_noresume(dev);
 452 }
 453 
 454 int wil_pm_runtime_get(struct wil6210_priv *wil)
 455 {
 456         int rc;
 457         struct device *dev = wil_to_dev(wil);
 458 
 459         rc = pm_runtime_get_sync(dev);
 460         if (rc < 0) {
 461                 wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc);
 462                 pm_runtime_put_noidle(dev);
 463                 return rc;
 464         }
 465 
 466         return 0;
 467 }
 468 
 469 void wil_pm_runtime_put(struct wil6210_priv *wil)
 470 {
 471         struct device *dev = wil_to_dev(wil);
 472 
 473         pm_runtime_mark_last_busy(dev);
 474         pm_runtime_put_autosuspend(dev);
 475 }

/* [<][>][^][v][top][bottom][index][help] */