1 /* 2 * Copyright (c) 2012-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 <linux/module.h> 18 #include <linux/pci.h> 19 #include <linux/moduleparam.h> 20 #include <linux/interrupt.h> 21 #include <linux/suspend.h> 22 #include "wil6210.h" 23 #include <linux/rtnetlink.h> 24 25 static bool use_msi = true; 26 module_param(use_msi, bool, 0444); 27 MODULE_PARM_DESC(use_msi, " Use MSI interrupt, default - true"); 28 29 #ifdef CONFIG_PM 30 #ifdef CONFIG_PM_SLEEP 31 static int wil6210_pm_notify(struct notifier_block *notify_block, 32 unsigned long mode, void *unused); 33 #endif /* CONFIG_PM_SLEEP */ 34 #endif /* CONFIG_PM */ 35 36 static 37 void wil_set_capabilities(struct wil6210_priv *wil) 38 { 39 u32 jtag_id = wil_r(wil, RGF_USER_JTAG_DEV_ID); 40 u8 chip_revision = (wil_r(wil, RGF_USER_REVISION_ID) & 41 RGF_USER_REVISION_ID_MASK); 42 43 bitmap_zero(wil->hw_capabilities, hw_capability_last); 44 bitmap_zero(wil->fw_capabilities, WMI_FW_CAPABILITY_MAX); 45 wil->wil_fw_name = WIL_FW_NAME_DEFAULT; 46 wil->chip_revision = chip_revision; 47 48 switch (jtag_id) { 49 case JTAG_DEV_ID_SPARROW: 50 switch (chip_revision) { 51 case REVISION_ID_SPARROW_D0: 52 wil->hw_name = "Sparrow D0"; 53 wil->hw_version = HW_VER_SPARROW_D0; 54 if (wil_fw_verify_file_exists(wil, 55 WIL_FW_NAME_SPARROW_PLUS)) 56 wil->wil_fw_name = WIL_FW_NAME_SPARROW_PLUS; 57 break; 58 case REVISION_ID_SPARROW_B0: 59 wil->hw_name = "Sparrow B0"; 60 wil->hw_version = HW_VER_SPARROW_B0; 61 break; 62 default: 63 wil->hw_name = "Unknown"; 64 wil->hw_version = HW_VER_UNKNOWN; 65 break; 66 } 67 break; 68 default: 69 wil_err(wil, "Unknown board hardware, chip_id 0x%08x, chip_revision 0x%08x\n", 70 jtag_id, chip_revision); 71 wil->hw_name = "Unknown"; 72 wil->hw_version = HW_VER_UNKNOWN; 73 } 74 75 wil_info(wil, "Board hardware is %s\n", wil->hw_name); 76 77 /* extract FW capabilities from file without loading the FW */ 78 wil_request_firmware(wil, wil->wil_fw_name, false); 79 } 80 81 void wil_disable_irq(struct wil6210_priv *wil) 82 { 83 disable_irq(wil->pdev->irq); 84 } 85 86 void wil_enable_irq(struct wil6210_priv *wil) 87 { 88 enable_irq(wil->pdev->irq); 89 } 90 91 /* Bus ops */ 92 static int wil_if_pcie_enable(struct wil6210_priv *wil) 93 { 94 struct pci_dev *pdev = wil->pdev; 95 int rc; 96 /* on platforms with buggy ACPI, pdev->msi_enabled may be set to 97 * allow pci_enable_device to work. This indicates INTx was not routed 98 * and only MSI should be used 99 */ 100 int msi_only = pdev->msi_enabled; 101 bool _use_msi = use_msi; 102 bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, 103 wil->fw_capabilities); 104 105 wil_dbg_misc(wil, "if_pcie_enable, wmi_only %d\n", wmi_only); 106 107 pdev->msi_enabled = 0; 108 109 pci_set_master(pdev); 110 111 wil_dbg_misc(wil, "Setup %s interrupt\n", use_msi ? "MSI" : "INTx"); 112 113 if (use_msi && pci_enable_msi(pdev)) { 114 wil_err(wil, "pci_enable_msi failed, use INTx\n"); 115 _use_msi = false; 116 } 117 118 if (!_use_msi && msi_only) { 119 wil_err(wil, "Interrupt pin not routed, unable to use INTx\n"); 120 rc = -ENODEV; 121 goto stop_master; 122 } 123 124 rc = wil6210_init_irq(wil, pdev->irq, _use_msi); 125 if (rc) 126 goto stop_master; 127 128 /* need reset here to obtain MAC or in case of WMI-only FW, full reset 129 * and fw loading takes place 130 */ 131 mutex_lock(&wil->mutex); 132 rc = wil_reset(wil, wmi_only); 133 mutex_unlock(&wil->mutex); 134 if (rc) 135 goto release_irq; 136 137 return 0; 138 139 release_irq: 140 wil6210_fini_irq(wil, pdev->irq); 141 /* safe to call if no MSI */ 142 pci_disable_msi(pdev); 143 stop_master: 144 pci_clear_master(pdev); 145 return rc; 146 } 147 148 static int wil_if_pcie_disable(struct wil6210_priv *wil) 149 { 150 struct pci_dev *pdev = wil->pdev; 151 152 wil_dbg_misc(wil, "if_pcie_disable\n"); 153 154 pci_clear_master(pdev); 155 /* disable and release IRQ */ 156 wil6210_fini_irq(wil, pdev->irq); 157 /* safe to call if no MSI */ 158 pci_disable_msi(pdev); 159 /* TODO: disable HW */ 160 161 return 0; 162 } 163 164 static int wil_platform_rop_ramdump(void *wil_handle, void *buf, uint32_t size) 165 { 166 struct wil6210_priv *wil = wil_handle; 167 168 if (!wil) 169 return -EINVAL; 170 171 return wil_fw_copy_crash_dump(wil, buf, size); 172 } 173 174 static int wil_platform_rop_fw_recovery(void *wil_handle) 175 { 176 struct wil6210_priv *wil = wil_handle; 177 178 if (!wil) 179 return -EINVAL; 180 181 wil_fw_error_recovery(wil); 182 183 return 0; 184 } 185 186 static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) 187 { 188 struct wil6210_priv *wil; 189 struct device *dev = &pdev->dev; 190 int rc; 191 const struct wil_platform_rops rops = { 192 .ramdump = wil_platform_rop_ramdump, 193 .fw_recovery = wil_platform_rop_fw_recovery, 194 }; 195 196 /* check HW */ 197 dev_info(&pdev->dev, WIL_NAME 198 " device found [%04x:%04x] (rev %x)\n", 199 (int)pdev->vendor, (int)pdev->device, (int)pdev->revision); 200 201 if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) { 202 dev_err(&pdev->dev, "Not " WIL_NAME "? " 203 "BAR0 size is %lu while expecting %lu\n", 204 (ulong)pci_resource_len(pdev, 0), WIL6210_MEM_SIZE); 205 return -ENODEV; 206 } 207 208 wil = wil_if_alloc(dev); 209 if (IS_ERR(wil)) { 210 rc = (int)PTR_ERR(wil); 211 dev_err(dev, "wil_if_alloc failed: %d\n", rc); 212 return rc; 213 } 214 wil->pdev = pdev; 215 pci_set_drvdata(pdev, wil); 216 /* rollback to if_free */ 217 218 wil->platform_handle = 219 wil_platform_init(&pdev->dev, &wil->platform_ops, &rops, wil); 220 if (!wil->platform_handle) { 221 rc = -ENODEV; 222 wil_err(wil, "wil_platform_init failed\n"); 223 goto if_free; 224 } 225 /* rollback to err_plat */ 226 227 rc = pci_enable_device(pdev); 228 if (rc) { 229 wil_err(wil, 230 "pci_enable_device failed, retry with MSI only\n"); 231 /* Work around for platforms that can't allocate IRQ: 232 * retry with MSI only 233 */ 234 pdev->msi_enabled = 1; 235 rc = pci_enable_device(pdev); 236 } 237 if (rc) { 238 wil_err(wil, 239 "pci_enable_device failed, even with MSI only\n"); 240 goto err_plat; 241 } 242 /* rollback to err_disable_pdev */ 243 244 rc = pci_request_region(pdev, 0, WIL_NAME); 245 if (rc) { 246 wil_err(wil, "pci_request_region failed\n"); 247 goto err_disable_pdev; 248 } 249 /* rollback to err_release_reg */ 250 251 wil->csr = pci_ioremap_bar(pdev, 0); 252 if (!wil->csr) { 253 wil_err(wil, "pci_ioremap_bar failed\n"); 254 rc = -ENODEV; 255 goto err_release_reg; 256 } 257 /* rollback to err_iounmap */ 258 wil_info(wil, "CSR at %pR -> 0x%p\n", &pdev->resource[0], wil->csr); 259 260 wil_set_capabilities(wil); 261 wil6210_clear_irq(wil); 262 263 /* FW should raise IRQ when ready */ 264 rc = wil_if_pcie_enable(wil); 265 if (rc) { 266 wil_err(wil, "Enable device failed\n"); 267 goto err_iounmap; 268 } 269 /* rollback to bus_disable */ 270 271 rc = wil_if_add(wil); 272 if (rc) { 273 wil_err(wil, "wil_if_add failed: %d\n", rc); 274 goto bus_disable; 275 } 276 277 #ifdef CONFIG_PM 278 #ifdef CONFIG_PM_SLEEP 279 wil->pm_notify.notifier_call = wil6210_pm_notify; 280 rc = register_pm_notifier(&wil->pm_notify); 281 if (rc) 282 /* Do not fail the driver initialization, as suspend can 283 * be prevented in a later phase if needed 284 */ 285 wil_err(wil, "register_pm_notifier failed: %d\n", rc); 286 #endif /* CONFIG_PM_SLEEP */ 287 #endif /* CONFIG_PM */ 288 289 wil6210_debugfs_init(wil); 290 291 292 return 0; 293 294 bus_disable: 295 wil_if_pcie_disable(wil); 296 err_iounmap: 297 pci_iounmap(pdev, wil->csr); 298 err_release_reg: 299 pci_release_region(pdev, 0); 300 err_disable_pdev: 301 pci_disable_device(pdev); 302 err_plat: 303 if (wil->platform_ops.uninit) 304 wil->platform_ops.uninit(wil->platform_handle); 305 if_free: 306 wil_if_free(wil); 307 308 return rc; 309 } 310 311 static void wil_pcie_remove(struct pci_dev *pdev) 312 { 313 struct wil6210_priv *wil = pci_get_drvdata(pdev); 314 void __iomem *csr = wil->csr; 315 316 wil_dbg_misc(wil, "pcie_remove\n"); 317 318 #ifdef CONFIG_PM 319 #ifdef CONFIG_PM_SLEEP 320 unregister_pm_notifier(&wil->pm_notify); 321 #endif /* CONFIG_PM_SLEEP */ 322 #endif /* CONFIG_PM */ 323 324 wil6210_debugfs_remove(wil); 325 rtnl_lock(); 326 wil_p2p_wdev_free(wil); 327 rtnl_unlock(); 328 wil_if_remove(wil); 329 wil_if_pcie_disable(wil); 330 pci_iounmap(pdev, csr); 331 pci_release_region(pdev, 0); 332 pci_disable_device(pdev); 333 if (wil->platform_ops.uninit) 334 wil->platform_ops.uninit(wil->platform_handle); 335 wil_if_free(wil); 336 } 337 338 static const struct pci_device_id wil6210_pcie_ids[] = { 339 { PCI_DEVICE(0x1ae9, 0x0310) }, 340 { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */ 341 { /* end: all zeroes */ }, 342 }; 343 MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids); 344 345 #ifdef CONFIG_PM 346 #ifdef CONFIG_PM_SLEEP 347 348 static int wil6210_suspend(struct device *dev, bool is_runtime) 349 { 350 int rc = 0; 351 struct pci_dev *pdev = to_pci_dev(dev); 352 struct wil6210_priv *wil = pci_get_drvdata(pdev); 353 354 wil_dbg_pm(wil, "suspend: %s\n", is_runtime ? "runtime" : "system"); 355 356 rc = wil_can_suspend(wil, is_runtime); 357 if (rc) 358 goto out; 359 360 rc = wil_suspend(wil, is_runtime); 361 if (rc) 362 goto out; 363 364 /* TODO: how do I bring card in low power state? */ 365 366 /* disable bus mastering */ 367 pci_clear_master(pdev); 368 /* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */ 369 370 out: 371 return rc; 372 } 373 374 static int wil6210_resume(struct device *dev, bool is_runtime) 375 { 376 int rc = 0; 377 struct pci_dev *pdev = to_pci_dev(dev); 378 struct wil6210_priv *wil = pci_get_drvdata(pdev); 379 380 wil_dbg_pm(wil, "resume: %s\n", is_runtime ? "runtime" : "system"); 381 382 /* allow master */ 383 pci_set_master(pdev); 384 385 rc = wil_resume(wil, is_runtime); 386 if (rc) 387 pci_clear_master(pdev); 388 389 return rc; 390 } 391 392 static int wil6210_pm_notify(struct notifier_block *notify_block, 393 unsigned long mode, void *unused) 394 { 395 struct wil6210_priv *wil = container_of( 396 notify_block, struct wil6210_priv, pm_notify); 397 int rc = 0; 398 enum wil_platform_event evt; 399 400 wil_dbg_pm(wil, "pm_notify: mode (%ld)\n", mode); 401 402 switch (mode) { 403 case PM_HIBERNATION_PREPARE: 404 case PM_SUSPEND_PREPARE: 405 case PM_RESTORE_PREPARE: 406 rc = wil_can_suspend(wil, false); 407 if (rc) 408 break; 409 evt = WIL_PLATFORM_EVT_PRE_SUSPEND; 410 if (wil->platform_ops.notify) 411 rc = wil->platform_ops.notify(wil->platform_handle, 412 evt); 413 break; 414 case PM_POST_SUSPEND: 415 case PM_POST_HIBERNATION: 416 case PM_POST_RESTORE: 417 evt = WIL_PLATFORM_EVT_POST_SUSPEND; 418 if (wil->platform_ops.notify) 419 rc = wil->platform_ops.notify(wil->platform_handle, 420 evt); 421 break; 422 default: 423 wil_dbg_pm(wil, "unhandled notify mode %ld\n", mode); 424 break; 425 } 426 427 wil_dbg_pm(wil, "notification mode %ld: rc (%d)\n", mode, rc); 428 return rc; 429 } 430 431 static int wil6210_pm_suspend(struct device *dev) 432 { 433 return wil6210_suspend(dev, false); 434 } 435 436 static int wil6210_pm_resume(struct device *dev) 437 { 438 return wil6210_resume(dev, false); 439 } 440 #endif /* CONFIG_PM_SLEEP */ 441 442 #endif /* CONFIG_PM */ 443 444 static const struct dev_pm_ops wil6210_pm_ops = { 445 SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) 446 }; 447 448 static struct pci_driver wil6210_driver = { 449 .probe = wil_pcie_probe, 450 .remove = wil_pcie_remove, 451 .id_table = wil6210_pcie_ids, 452 .name = WIL_NAME, 453 .driver = { 454 .pm = &wil6210_pm_ops, 455 }, 456 }; 457 458 static int __init wil6210_driver_init(void) 459 { 460 int rc; 461 462 rc = wil_platform_modinit(); 463 if (rc) 464 return rc; 465 466 rc = pci_register_driver(&wil6210_driver); 467 if (rc) 468 wil_platform_modexit(); 469 return rc; 470 } 471 module_init(wil6210_driver_init); 472 473 static void __exit wil6210_driver_exit(void) 474 { 475 pci_unregister_driver(&wil6210_driver); 476 wil_platform_modexit(); 477 } 478 module_exit(wil6210_driver_exit); 479 480 MODULE_LICENSE("Dual BSD/GPL"); 481 MODULE_AUTHOR("Qualcomm Atheros <wil6210@qca.qualcomm.com>"); 482 MODULE_DESCRIPTION("Driver for 60g WiFi WIL6210 card"); 483