1 /* 2 * Copyright (c) 2012-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 <linux/module.h> 19 #include <linux/pci.h> 20 #include <linux/moduleparam.h> 21 #include <linux/interrupt.h> 22 #include <linux/suspend.h> 23 #include "wil6210.h" 24 #include <linux/rtnetlink.h> 25 #include <linux/pm_runtime.h> 26 27 static int n_msi = 3; 28 module_param(n_msi, int, 0444); 29 MODULE_PARM_DESC(n_msi, " Use MSI interrupt: 0 - use INTx, 1 - single, or 3 - (default) "); 30 31 bool ftm_mode; 32 module_param(ftm_mode, bool, 0444); 33 MODULE_PARM_DESC(ftm_mode, " Set factory test mode, default - false"); 34 35 static int wil6210_pm_notify(struct notifier_block *notify_block, 36 unsigned long mode, void *unused); 37 38 static 39 int wil_set_capabilities(struct wil6210_priv *wil) 40 { 41 const char *wil_fw_name; 42 u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); 43 u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & 44 RGF_USER_REVISION_ID_MASK); 45 int platform_capa; 46 struct fw_map *iccm_section, *sct; 47 48 bitmap_zero(wil->hw_capa, hw_capa_last); 49 bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); 50 bitmap_zero(wil->platform_capa, WIL_PLATFORM_CAPA_MAX); 51 wil->wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_DEFAULT : 52 WIL_FW_NAME_DEFAULT; 53 wil->chip_revision = chip_revision; 54 55 switch (jtag_id) { 56 case JTAG_DEV_ID_SPARROW: 57 memcpy(fw_mapping, sparrow_fw_mapping, 58 sizeof(sparrow_fw_mapping)); 59 switch (chip_revision) { 60 case REVISION_ID_SPARROW_D0: 61 wil->hw_name = "Sparrow D0"; 62 wil->hw_version = HW_VER_SPARROW_D0; 63 wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_SPARROW_PLUS : 64 WIL_FW_NAME_SPARROW_PLUS; 65 66 if (wil_fw_verify_file_exists(wil, wil_fw_name)) 67 wil->wil_fw_name = wil_fw_name; 68 sct = wil_find_fw_mapping("mac_rgf_ext"); 69 if (!sct) { 70 wil_err(wil, "mac_rgf_ext section not found in fw_mapping\n"); 71 return -EINVAL; 72 } 73 memcpy(sct, &sparrow_d0_mac_rgf_ext, sizeof(*sct)); 74 break; 75 case REVISION_ID_SPARROW_B0: 76 wil->hw_name = "Sparrow B0"; 77 wil->hw_version = HW_VER_SPARROW_B0; 78 break; 79 default: 80 wil->hw_name = "Unknown"; 81 wil->hw_version = HW_VER_UNKNOWN; 82 break; 83 } 84 wil->rgf_fw_assert_code_addr = SPARROW_RGF_FW_ASSERT_CODE; 85 wil->rgf_ucode_assert_code_addr = SPARROW_RGF_UCODE_ASSERT_CODE; 86 break; 87 case JTAG_DEV_ID_TALYN: 88 wil->hw_name = "Talyn-MA"; 89 wil->hw_version = HW_VER_TALYN; 90 memcpy(fw_mapping, talyn_fw_mapping, sizeof(talyn_fw_mapping)); 91 wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; 92 wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; 93 if (wil_r(wil, RGF_USER_OTP_HW_RD_MACHINE_1) & 94 BIT_NO_FLASH_INDICATION) 95 set_bit(hw_capa_no_flash, wil->hw_capa); 96 wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : 97 WIL_FW_NAME_TALYN; 98 if (wil_fw_verify_file_exists(wil, wil_fw_name)) 99 wil->wil_fw_name = wil_fw_name; 100 break; 101 case JTAG_DEV_ID_TALYN_MB: 102 wil->hw_name = "Talyn-MB"; 103 wil->hw_version = HW_VER_TALYN_MB; 104 memcpy(fw_mapping, talyn_mb_fw_mapping, 105 sizeof(talyn_mb_fw_mapping)); 106 wil->rgf_fw_assert_code_addr = TALYN_RGF_FW_ASSERT_CODE; 107 wil->rgf_ucode_assert_code_addr = TALYN_RGF_UCODE_ASSERT_CODE; 108 set_bit(hw_capa_no_flash, wil->hw_capa); 109 wil->use_enhanced_dma_hw = true; 110 wil->use_rx_hw_reordering = true; 111 wil->use_compressed_rx_status = true; 112 wil_fw_name = ftm_mode ? WIL_FW_NAME_FTM_TALYN : 113 WIL_FW_NAME_TALYN; 114 if (wil_fw_verify_file_exists(wil, wil_fw_name)) 115 wil->wil_fw_name = wil_fw_name; 116 break; 117 default: 118 wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", 119 jtag_id, chip_revision); 120 wil->hw_name = "Unknown"; 121 wil->hw_version = HW_VER_UNKNOWN; 122 return -EINVAL; 123 } 124 125 wil_init_txrx_ops(wil); 126 127 iccm_section = wil_find_fw_mapping("fw_code"); 128 if (!iccm_section) { 129 wil_err(wil, "fw_code section not found in fw_mapping\n"); 130 return -EINVAL; 131 } 132 wil->iccm_base = iccm_section->host; 133 134 wil_info(wil, "Board hardware is %s, flash %sexist\n", wil->hw_name, 135 test_bit(hw_capa_no_flash, wil->hw_capa) ? "doesn't " : ""); 136 137 /* Get platform capabilities */ 138 if (wil->platform_ops.get_capa) { 139 platform_capa = 140 wil->platform_ops.get_capa(wil->platform_handle); 141 memcpy(wil->platform_capa, &platform_capa, 142 min(sizeof(wil->platform_capa), sizeof(platform_capa))); 143 } 144 145 wil_info(wil, "platform_capa 0x%lx\n", *wil->platform_capa); 146 147 /* extract FW capabilities from file without loading the FW */ 148 wil_request_firmware(wil, wil->wil_fw_name, false); 149 wil_refresh_fw_capabilities(wil); 150 151 return 0; 152 } 153 154 void wil_disable_irq(struct wil6210_priv *wil) 155 { 156 int irq = wil->pdev->irq; 157 158 disable_irq(irq); 159 if (wil->n_msi == 3) { 160 disable_irq(irq + 1); 161 disable_irq(irq + 2); 162 } 163 } 164 165 void wil_enable_irq(struct wil6210_priv *wil) 166 { 167 int irq = wil->pdev->irq; 168 169 enable_irq(irq); 170 if (wil->n_msi == 3) { 171 enable_irq(irq + 1); 172 enable_irq(irq + 2); 173 } 174 } 175 176 static void wil_remove_all_additional_vifs(struct wil6210_priv *wil) 177 { 178 struct wil6210_vif *vif; 179 int i; 180 181 for (i = 1; i < GET_MAX_VIFS(wil); i++) { 182 vif = wil->vifs[i]; 183 if (vif) { 184 wil_vif_prepare_stop(vif); 185 wil_vif_remove(wil, vif->mid); 186 } 187 } 188 } 189 190 /* Bus ops */ 191 static int wil_if_pcie_enable(struct wil6210_priv *wil) 192 { 193 struct pci_dev *pdev = wil->pdev; 194 int rc; 195 /* on platforms with buggy ACPI, pdev->msi_enabled may be set to 196 * allow pci_enable_device to work. This indicates INTx was not routed 197 * and only MSI should be used 198 */ 199 int msi_only = pdev->msi_enabled; 200 201 wil_dbg_misc(wil, "if_pcie_enable\n"); 202 203 pci_set_master(pdev); 204 205 /* how many MSI interrupts to request? */ 206 switch (n_msi) { 207 case 3: 208 case 1: 209 wil_dbg_misc(wil, "Setup %d MSI interrupts\n", n_msi); 210 break; 211 case 0: 212 wil_dbg_misc(wil, "MSI interrupts disabled, use INTx\n"); 213 break; 214 default: 215 wil_err(wil, "Invalid n_msi=%d, default to 1\n", n_msi); 216 n_msi = 1; 217 } 218 219 if (n_msi == 3 && 220 pci_alloc_irq_vectors(pdev, n_msi, n_msi, PCI_IRQ_MSI) < n_msi) { 221 wil_err(wil, "3 MSI mode failed, try 1 MSI\n"); 222 n_msi = 1; 223 } 224 225 if (n_msi == 1 && pci_enable_msi(pdev)) { 226 wil_err(wil, "pci_enable_msi failed, use INTx\n"); 227 n_msi = 0; 228 } 229 230 wil->n_msi = n_msi; 231 232 if (wil->n_msi == 0 && msi_only) { 233 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); 234 rc = -ENODEV; 235 goto stop_master; 236 } 237 238 rc = wil6210_init_irq(wil, pdev->irq); 239 if (rc) 240 goto release_vectors; 241 242 /* need reset here to obtain MAC */ 243 mutex_lock(&wil->mutex); 244 rc = wil_reset(wil, false); 245 mutex_unlock(&wil->mutex); 246 if (rc) 247 goto release_irq; 248 249 return 0; 250 251 release_irq: 252 wil6210_fini_irq(wil, pdev->irq); 253 release_vectors: 254 /* safe to call if no allocation */ 255 pci_free_irq_vectors(pdev); 256 stop_master: 257 pci_clear_master(pdev); 258 return rc; 259 } 260 261 static int wil_if_pcie_disable(struct wil6210_priv *wil) 262 { 263 struct pci_dev *pdev = wil->pdev; 264 265 wil_dbg_misc(wil, "if_pcie_disable\n"); 266 267 pci_clear_master(pdev); 268 /* disable and release IRQ */ 269 wil6210_fini_irq(wil, pdev->irq); 270 /* safe to call if no MSI */ 271 pci_disable_msi(pdev); 272 /* TODO: disable HW */ 273 274 return 0; 275 } 276 277 static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size) 278 { 279 struct wil6210_priv *wil = wil_handle; 280 281 if (!wil) 282 return -EINVAL; 283 284 return wil_fw_copy_crash_dump(wil, buf, size); 285 } 286 287 static int wil_platform_rop_fw_recovery(void *wil_handle) 288 { 289 struct wil6210_priv *wil = wil_handle; 290 291 if (!wil) 292 return -EINVAL; 293 294 wil_fw_error_recovery(wil); 295 296 return 0; 297 } 298 299 static void wil_platform_ops_uninit(struct wil6210_priv *wil) 300 { 301 if (wil->platform_ops.uninit) 302 wil->platform_ops.uninit(wil->platform_handle); 303 memset(&wil->platform_ops, 0, sizeof(wil->platform_ops)); 304 } 305 306 static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) 307 { 308 struct wil6210_priv *wil; 309 struct device *dev = &pdev->dev; 310 int rc; 311 const struct wil_platform_rops rops = { 312 .ramdump = wil_platform_rop_ramdump, 313 .fw_recovery = wil_platform_rop_fw_recovery, 314 }; 315 u32 bar_size = pci_resource_len(pdev, 0); 316 int dma_addr_size[] = {64, 48, 40, 32}; /* keep descending order */ 317 int i, start_idx; 318 319 /* check HW */ 320 dev_info(&pdev->dev, WIL_NAME 321 " device found [%04x:%04x] (rev %x) bar size 0x%x\n", 322 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision, 323 bar_size); 324 325 if ((bar_size < WIL6210_MIN_MEM_SIZE) || 326 (bar_size > WIL6210_MAX_MEM_SIZE)) { 327 dev_err(&pdev->dev, "Unexpected BAR0 size 0x%x\n", 328 bar_size); 329 return -ENODEV; 330 } 331 332 wil = wil_if_alloc(dev); 333 if (IS_ERR(wil)) { 334 rc = (int)PTR_ERR(wil); 335 dev_err(dev, "wil_if_alloc failed: %d\n", rc); 336 return rc; 337 } 338 339 wil->pdev = pdev; 340 pci_set_drvdata(pdev, wil); 341 wil->bar_size = bar_size; 342 /* rollback to if_free */ 343 344 wil->platform_handle = 345 wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil); 346 if (!wil->platform_handle) { 347 rc = -ENODEV; 348 wil_err(wil, "wil_platform_init failed\n"); 349 goto if_free; 350 } 351 /* rollback to err_plat */ 352 rc = pci_enable_device(pdev); 353 if (rc && pdev->msi_enabled == 0) { 354 wil_err(wil, 355 "pci_enable_device failed, retry with MSI only\n"); 356 /* Work around for platforms that can't allocate IRQ: 357 * retry with MSI only 358 */ 359 pdev->msi_enabled = 1; 360 rc = pci_enable_device(pdev); 361 } 362 if (rc) { 363 wil_err(wil, 364 "pci_enable_device failed, even with MSI only\n"); 365 goto err_plat; 366 } 367 /* rollback to err_disable_pdev */ 368 pci_set_power_state(pdev, PCI_D0); 369 370 rc = pci_request_region(pdev, 0, WIL_NAME); 371 if (rc) { 372 wil_err(wil, "pci_request_region failed\n"); 373 goto err_disable_pdev; 374 } 375 /* rollback to err_release_reg */ 376 377 wil->csr = pci_ioremap_bar(pdev, 0); 378 if (!wil->csr) { 379 wil_err(wil, "pci_ioremap_bar failed\n"); 380 rc = -ENODEV; 381 goto err_release_reg; 382 } 383 /* rollback to err_iounmap */ 384 wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); 385 386 rc = wil_set_capabilities(wil); 387 if (rc) { 388 wil_err(wil, "wil_set_capabilities failed, rc %d\n", rc); 389 goto err_iounmap; 390 } 391 392 /* device supports >32bit addresses. 393 * for legacy DMA start from 48 bit. 394 */ 395 start_idx = wil->use_enhanced_dma_hw ? 0 : 1; 396 397 for (i = start_idx; i < ARRAY_SIZE(dma_addr_size); i++) { 398 rc = dma_set_mask_and_coherent(dev, 399 DMA_BIT_MASK(dma_addr_size[i])); 400 if (rc) { 401 dev_err(dev, "dma_set_mask_and_coherent(%d) failed: %d\n", 402 dma_addr_size[i], rc); 403 continue; 404 } 405 dev_info(dev, "using dma mask %d", dma_addr_size[i]); 406 wil->dma_addr_size = dma_addr_size[i]; 407 break; 408 } 409 410 if (wil->dma_addr_size == 0) 411 goto err_iounmap; 412 413 wil6210_clear_irq(wil); 414 415 /* FW should raise IRQ when ready */ 416 rc = wil_if_pcie_enable(wil); 417 if (rc) { 418 wil_err(wil, "Enable device failed\n"); 419 goto err_iounmap; 420 } 421 /* rollback to bus_disable */ 422 423 rc = wil_if_add(wil); 424 if (rc) { 425 wil_err(wil, "wil_if_add failed: %d\n", rc); 426 goto bus_disable; 427 } 428 429 /* in case of WMI-only FW, perform full reset and FW loading */ 430 if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) { 431 wil_dbg_misc(wil, "Loading WMI only FW\n"); 432 mutex_lock(&wil->mutex); 433 rc = wil_reset(wil, true); 434 mutex_unlock(&wil->mutex); 435 if (rc) { 436 wil_err(wil, "failed to load WMI only FW\n"); 437 goto if_remove; 438 } 439 } 440 441 if (IS_ENABLED(CONFIG_PM)) 442 wil->pm_notify.notifier_call = wil6210_pm_notify; 443 444 rc = register_pm_notifier(&wil->pm_notify); 445 if (rc) 446 /* Do not fail the driver initialization, as suspend can 447 * be prevented in a later phase if needed 448 */ 449 wil_err(wil, "register_pm_notifier failed: %d\n", rc); 450 451 wil6210_debugfs_init(wil); 452 453 wil_pm_runtime_allow(wil); 454 455 return 0; 456 457 if_remove: 458 wil_if_remove(wil); 459 bus_disable: 460 wil_if_pcie_disable(wil); 461 err_iounmap: 462 pci_iounmap(pdev, wil->csr); 463 err_release_reg: 464 pci_release_region(pdev, 0); 465 err_disable_pdev: 466 pci_disable_device(pdev); 467 err_plat: 468 wil_platform_ops_uninit(wil); 469 if_free: 470 wil_if_free(wil); 471 472 return rc; 473 } 474 475 static void wil_pcie_remove(struct pci_dev *pdev) 476 { 477 struct wil6210_priv *wil = pci_get_drvdata(pdev); 478 void __iomem *csr = wil->csr; 479 480 wil_dbg_misc(wil, "pcie_remove\n"); 481 482 unregister_pm_notifier(&wil->pm_notify); 483 484 wil_pm_runtime_forbid(wil); 485 486 wil6210_debugfs_remove(wil); 487 rtnl_lock(); 488 wil_p2p_wdev_free(wil); 489 wil_remove_all_additional_vifs(wil); 490 rtnl_unlock(); 491 wil_if_remove(wil); 492 wil_if_pcie_disable(wil); 493 pci_iounmap(pdev, csr); 494 pci_release_region(pdev, 0); 495 pci_disable_device(pdev); 496 wil_platform_ops_uninit(wil); 497 wil_if_free(wil); 498 } 499 500 static const struct pci_device_id wil6210_pcie_ids[] = { 501 { PCI_DEVICE(0x1ae9, 0x0310) }, 502 { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ 503 { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */ 504 { /* end: all zeroes */ }, 505 }; 506 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 507 508 static int wil6210_suspend(struct device *dev, bool is_runtime) 509 { 510 int rc = 0; 511 struct pci_dev *pdev = to_pci_dev(dev); 512 struct wil6210_priv *wil = pci_get_drvdata(pdev); 513 bool keep_radio_on, active_ifaces; 514 515 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 516 517 mutex_lock(&wil->vif_mutex); 518 active_ifaces = wil_has_active_ifaces(wil, true, false); 519 mutex_unlock(&wil->vif_mutex); 520 keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; 521 522 rc = wil_can_suspend(wil, is_runtime); 523 if (rc) 524 goto out; 525 526 rc = wil_suspend(wil, is_runtime, keep_radio_on); 527 if (!rc) { 528 /* In case radio stays on, platform device will control 529 * PCIe master 530 */ 531 if (!keep_radio_on) { 532 /* disable bus mastering */ 533 pci_clear_master(pdev); 534 wil->suspend_stats.r_off.successful_suspends++; 535 } else { 536 wil->suspend_stats.r_on.successful_suspends++; 537 } 538 } 539 out: 540 return rc; 541 } 542 543 static int wil6210_resume(struct device *dev, bool is_runtime) 544 { 545 int rc = 0; 546 struct pci_dev *pdev = to_pci_dev(dev); 547 struct wil6210_priv *wil = pci_get_drvdata(pdev); 548 bool keep_radio_on, active_ifaces; 549 550 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 551 552 mutex_lock(&wil->vif_mutex); 553 active_ifaces = wil_has_active_ifaces(wil, true, false); 554 mutex_unlock(&wil->vif_mutex); 555 keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; 556 557 /* In case radio stays on, platform device will control 558 * PCIe master 559 */ 560 if (!keep_radio_on) 561 /* allow master */ 562 pci_set_master(pdev); 563 rc = wil_resume(wil, is_runtime, keep_radio_on); 564 if (rc) { 565 wil_err(wil, "device failed to resume (%d)\n", rc); 566 if (!keep_radio_on) { 567 pci_clear_master(pdev); 568 wil->suspend_stats.r_off.failed_resumes++; 569 } else { 570 wil->suspend_stats.r_on.failed_resumes++; 571 } 572 } else { 573 if (keep_radio_on) 574 wil->suspend_stats.r_on.successful_resumes++; 575 else 576 wil->suspend_stats.r_off.successful_resumes++; 577 } 578 579 return rc; 580 } 581 582 static int wil6210_pm_notify(struct notifier_block *notify_block, 583 unsigned long mode, void *unused) 584 { 585 struct wil6210_priv *wil = container_of( 586 notify_block, struct wil6210_priv, pm_notify); 587 int rc = 0; 588 enum wil_platform_event evt; 589 590 wil_dbg_pm(wil, "pm_notify: mode (%ld)\n", mode); 591 592 switch (mode) { 593 case PM_HIBERNATION_PREPARE: 594 case PM_SUSPEND_PREPARE: 595 case PM_RESTORE_PREPARE: 596 rc = wil_can_suspend(wil, false); 597 if (rc) 598 break; 599 evt = WIL_PLATFORM_EVT_PRE_SUSPEND; 600 if (wil->platform_ops.notify) 601 rc = wil->platform_ops.notify(wil->platform_handle, 602 evt); 603 break; 604 case PM_POST_SUSPEND: 605 case PM_POST_HIBERNATION: 606 case PM_POST_RESTORE: 607 evt = WIL_PLATFORM_EVT_POST_SUSPEND; 608 if (wil->platform_ops.notify) 609 rc = wil->platform_ops.notify(wil->platform_handle, 610 evt); 611 break; 612 default: 613 wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode); 614 break; 615 } 616 617 wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc); 618 return rc; 619 } 620 621 static int __maybe_unused wil6210_pm_suspend(struct device *dev) 622 { 623 return wil6210_suspend(dev, false); 624 } 625 626 static int __maybe_unused wil6210_pm_resume(struct device *dev) 627 { 628 return wil6210_resume(dev, false); 629 } 630 631 static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev) 632 { 633 struct pci_dev *pdev = to_pci_dev(dev); 634 struct wil6210_priv *wil = pci_get_drvdata(pdev); 635 636 wil_dbg_pm(wil, "Runtime idle\n"); 637 638 return wil_can_suspend(wil, true); 639 } 640 641 static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev) 642 { 643 return wil6210_resume(dev, true); 644 } 645 646 static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev) 647 { 648 struct pci_dev *pdev = to_pci_dev(dev); 649 struct wil6210_priv *wil = pci_get_drvdata(pdev); 650 651 if (test_bit(wil_status_suspended, wil->status)) { 652 wil_dbg_pm(wil, "trying to suspend while suspended\n"); 653 return 1; 654 } 655 656 return wil6210_suspend(dev, true); 657 } 658 659 static const struct dev_pm_ops wil6210_pm_ops = { 660 SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) 661 SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend, 662 wil6210_pm_runtime_resume, 663 wil6210_pm_runtime_idle) 664 }; 665 666 static struct pci_driver wil6210_driver = { 667 .probe = wil_pcie_probe, 668 .remove = wil_pcie_remove, 669 .id_table = wil6210_pcie_ids, 670 .name = WIL_NAME, 671 .driver = { 672 .pm = &wil6210_pm_ops, 673 }, 674 }; 675 676 static int __init wil6210_driver_init(void) 677 { 678 int rc; 679 680 rc = wil_platform_modinit(); 681 if (rc) 682 return rc; 683 684 rc = pci_register_driver(&wil6210_driver); 685 if (rc) 686 wil_platform_modexit(); 687 return rc; 688 } 689 module_init(wil6210_driver_init); 690 691 static void __exit wil6210_driver_exit(void) 692 { 693 pci_unregister_driver(&wil6210_driver); 694 wil_platform_modexit(); 695 } 696 module_exit(wil6210_driver_exit); 697 698 MODULE_LICENSE("Dual BSD/GPL"); 699 MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); 700 MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); 701