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 wil_clear_fw_log_addr(wil); 424 rc = wil_if_add(wil); 425 if (rc) { 426 wil_err(wil, "wil_if_add failed: %d\n", rc); 427 goto bus_disable; 428 } 429 430 /* in case of WMI-only FW, perform full reset and FW loading */ 431 if (test_bit(WMI_FW_CAPABILITY_WMI_ONLY, wil->fw_capabilities)) { 432 wil_dbg_misc(wil, "Loading WMI only FW\n"); 433 mutex_lock(&wil->mutex); 434 rc = wil_reset(wil, true); 435 mutex_unlock(&wil->mutex); 436 if (rc) { 437 wil_err(wil, "failed to load WMI only FW\n"); 438 goto if_remove; 439 } 440 } 441 442 if (IS_ENABLED(CONFIG_PM)) 443 wil->pm_notify.notifier_call = wil6210_pm_notify; 444 445 rc = register_pm_notifier(&wil->pm_notify); 446 if (rc) 447 /* Do not fail the driver initialization, as suspend can 448 * be prevented in a later phase if needed 449 */ 450 wil_err(wil, "register_pm_notifier failed: %d\n", rc); 451 452 wil6210_debugfs_init(wil); 453 454 wil_pm_runtime_allow(wil); 455 456 return 0; 457 458 if_remove: 459 wil_if_remove(wil); 460 bus_disable: 461 wil_if_pcie_disable(wil); 462 err_iounmap: 463 pci_iounmap(pdev, wil->csr); 464 err_release_reg: 465 pci_release_region(pdev, 0); 466 err_disable_pdev: 467 pci_disable_device(pdev); 468 err_plat: 469 wil_platform_ops_uninit(wil); 470 if_free: 471 wil_if_free(wil); 472 473 return rc; 474 } 475 476 static void wil_pcie_remove(struct pci_dev *pdev) 477 { 478 struct wil6210_priv *wil = pci_get_drvdata(pdev); 479 void __iomem *csr = wil->csr; 480 481 wil_dbg_misc(wil, "pcie_remove\n"); 482 483 unregister_pm_notifier(&wil->pm_notify); 484 485 wil_pm_runtime_forbid(wil); 486 487 wil6210_debugfs_remove(wil); 488 rtnl_lock(); 489 wil_p2p_wdev_free(wil); 490 wil_remove_all_additional_vifs(wil); 491 rtnl_unlock(); 492 wil_if_remove(wil); 493 wil_if_pcie_disable(wil); 494 pci_iounmap(pdev, csr); 495 pci_release_region(pdev, 0); 496 pci_disable_device(pdev); 497 wil_platform_ops_uninit(wil); 498 wil_if_free(wil); 499 } 500 501 static const struct pci_device_id wil6210_pcie_ids[] = { 502 { PCI_DEVICE(0x1ae9, 0x0310) }, 503 { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ 504 { PCI_DEVICE(0x17cb, 0x1201) }, /* Talyn */ 505 { /* end: all zeroes */ }, 506 }; 507 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 508 509 static int wil6210_suspend(struct device *dev, bool is_runtime) 510 { 511 int rc = 0; 512 struct pci_dev *pdev = to_pci_dev(dev); 513 struct wil6210_priv *wil = pci_get_drvdata(pdev); 514 bool keep_radio_on, active_ifaces; 515 516 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 517 518 mutex_lock(&wil->vif_mutex); 519 active_ifaces = wil_has_active_ifaces(wil, true, false); 520 mutex_unlock(&wil->vif_mutex); 521 keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; 522 523 rc = wil_can_suspend(wil, is_runtime); 524 if (rc) 525 goto out; 526 527 rc = wil_suspend(wil, is_runtime, keep_radio_on); 528 if (!rc) { 529 /* In case radio stays on, platform device will control 530 * PCIe master 531 */ 532 if (!keep_radio_on) { 533 /* disable bus mastering */ 534 pci_clear_master(pdev); 535 wil->suspend_stats.r_off.successful_suspends++; 536 } else { 537 wil->suspend_stats.r_on.successful_suspends++; 538 } 539 } 540 out: 541 return rc; 542 } 543 544 static int wil6210_resume(struct device *dev, bool is_runtime) 545 { 546 int rc = 0; 547 struct pci_dev *pdev = to_pci_dev(dev); 548 struct wil6210_priv *wil = pci_get_drvdata(pdev); 549 bool keep_radio_on, active_ifaces; 550 551 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 552 553 mutex_lock(&wil->vif_mutex); 554 active_ifaces = wil_has_active_ifaces(wil, true, false); 555 mutex_unlock(&wil->vif_mutex); 556 keep_radio_on = active_ifaces && wil->keep_radio_on_during_sleep; 557 558 /* In case radio stays on, platform device will control 559 * PCIe master 560 */ 561 if (!keep_radio_on) 562 /* allow master */ 563 pci_set_master(pdev); 564 rc = wil_resume(wil, is_runtime, keep_radio_on); 565 if (rc) { 566 wil_err(wil, "device failed to resume (%d)\n", rc); 567 if (!keep_radio_on) { 568 pci_clear_master(pdev); 569 wil->suspend_stats.r_off.failed_resumes++; 570 } else { 571 wil->suspend_stats.r_on.failed_resumes++; 572 } 573 } else { 574 if (keep_radio_on) 575 wil->suspend_stats.r_on.successful_resumes++; 576 else 577 wil->suspend_stats.r_off.successful_resumes++; 578 } 579 580 return rc; 581 } 582 583 static int wil6210_pm_notify(struct notifier_block *notify_block, 584 unsigned long mode, void *unused) 585 { 586 struct wil6210_priv *wil = container_of( 587 notify_block, struct wil6210_priv, pm_notify); 588 int rc = 0; 589 enum wil_platform_event evt; 590 591 wil_dbg_pm(wil, "pm_notify: mode (%ld)\n", mode); 592 593 switch (mode) { 594 case PM_HIBERNATION_PREPARE: 595 case PM_SUSPEND_PREPARE: 596 case PM_RESTORE_PREPARE: 597 rc = wil_can_suspend(wil, false); 598 if (rc) 599 break; 600 evt = WIL_PLATFORM_EVT_PRE_SUSPEND; 601 if (wil->platform_ops.notify) 602 rc = wil->platform_ops.notify(wil->platform_handle, 603 evt); 604 break; 605 case PM_POST_SUSPEND: 606 case PM_POST_HIBERNATION: 607 case PM_POST_RESTORE: 608 evt = WIL_PLATFORM_EVT_POST_SUSPEND; 609 if (wil->platform_ops.notify) 610 rc = wil->platform_ops.notify(wil->platform_handle, 611 evt); 612 break; 613 default: 614 wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode); 615 break; 616 } 617 618 wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc); 619 return rc; 620 } 621 622 static int __maybe_unused wil6210_pm_suspend(struct device *dev) 623 { 624 return wil6210_suspend(dev, false); 625 } 626 627 static int __maybe_unused wil6210_pm_resume(struct device *dev) 628 { 629 return wil6210_resume(dev, false); 630 } 631 632 static int __maybe_unused wil6210_pm_runtime_idle(struct device *dev) 633 { 634 struct pci_dev *pdev = to_pci_dev(dev); 635 struct wil6210_priv *wil = pci_get_drvdata(pdev); 636 637 wil_dbg_pm(wil, "Runtime idle\n"); 638 639 return wil_can_suspend(wil, true); 640 } 641 642 static int __maybe_unused wil6210_pm_runtime_resume(struct device *dev) 643 { 644 return wil6210_resume(dev, true); 645 } 646 647 static int __maybe_unused wil6210_pm_runtime_suspend(struct device *dev) 648 { 649 struct pci_dev *pdev = to_pci_dev(dev); 650 struct wil6210_priv *wil = pci_get_drvdata(pdev); 651 652 if (test_bit(wil_status_suspended, wil->status)) { 653 wil_dbg_pm(wil, "trying to suspend while suspended\n"); 654 return 1; 655 } 656 657 return wil6210_suspend(dev, true); 658 } 659 660 static const struct dev_pm_ops wil6210_pm_ops = { 661 SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) 662 SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend, 663 wil6210_pm_runtime_resume, 664 wil6210_pm_runtime_idle) 665 }; 666 667 static struct pci_driver wil6210_driver = { 668 .probe = wil_pcie_probe, 669 .remove = wil_pcie_remove, 670 .id_table = wil6210_pcie_ids, 671 .name = WIL_NAME, 672 .driver = { 673 .pm = &wil6210_pm_ops, 674 }, 675 }; 676 677 static int __init wil6210_driver_init(void) 678 { 679 int rc; 680 681 rc = wil_platform_modinit(); 682 if (rc) 683 return rc; 684 685 rc = pci_register_driver(&wil6210_driver); 686 if (rc) 687 wil_platform_modexit(); 688 return rc; 689 } 690 module_init(wil6210_driver_init); 691 692 static void __exit wil6210_driver_exit(void) 693 { 694 pci_unregister_driver(&wil6210_driver); 695 wil_platform_modexit(); 696 } 697 module_exit(wil6210_driver_exit); 698 699 MODULE_LICENSE("Dual BSD/GPL"); 700 MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); 701 MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); 702