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