1 /* 2 * Copyright (c) 2013-2020 The Linux Foundation. All rights reserved. 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/slab.h> 18 #include <linux/interrupt.h> 19 #include <linux/if_arp.h> 20 #ifdef CONFIG_PCI_MSM 21 #include <linux/msm_pcie.h> 22 #endif 23 #include "hif_io32.h" 24 #include "if_ipci.h" 25 #include "hif.h" 26 #include "target_type.h" 27 #include "hif_main.h" 28 #include "ce_main.h" 29 #include "ce_api.h" 30 #include "ce_internal.h" 31 #include "ce_reg.h" 32 #include "ce_bmi.h" 33 #include "regtable.h" 34 #include "hif_hw_version.h" 35 #include <linux/debugfs.h> 36 #include <linux/seq_file.h> 37 #include "qdf_status.h" 38 #include "qdf_atomic.h" 39 #include "pld_common.h" 40 #include "mp_dev.h" 41 #include "hif_debug.h" 42 43 #include "ce_tasklet.h" 44 #include "targaddrs.h" 45 #include "hif_exec.h" 46 47 #include "ipci_api.h" 48 49 void hif_ipci_enable_power_management(struct hif_softc *hif_sc, 50 bool is_packet_log_enabled) 51 { 52 } 53 54 void hif_ipci_disable_power_management(struct hif_softc *hif_ctx) 55 { 56 } 57 58 void hif_ipci_display_stats(struct hif_softc *hif_ctx) 59 { 60 hif_display_ce_stats(hif_ctx); 61 } 62 63 void hif_ipci_clear_stats(struct hif_softc *hif_ctx) 64 { 65 struct hif_ipci_softc *ipci_ctx = HIF_GET_IPCI_SOFTC(hif_ctx); 66 67 if (!ipci_ctx) { 68 HIF_ERROR("%s, hif_ctx null", __func__); 69 return; 70 } 71 hif_clear_ce_stats(&ipci_ctx->ce_sc); 72 } 73 74 QDF_STATUS hif_ipci_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) 75 { 76 struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(hif_ctx); 77 78 hif_ctx->bus_type = bus_type; 79 80 qdf_spinlock_create(&sc->irq_lock); 81 82 return hif_ce_open(hif_ctx); 83 } 84 85 int hif_ipci_bus_configure(struct hif_softc *hif_sc) 86 { 87 int status = 0; 88 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(hif_sc); 89 90 hif_ce_prepare_config(hif_sc); 91 92 /* initialize sleep state adjust variables */ 93 hif_state->sleep_timer_init = true; 94 hif_state->keep_awake_count = 0; 95 hif_state->fake_sleep = false; 96 hif_state->sleep_ticks = 0; 97 98 status = hif_wlan_enable(hif_sc); 99 if (status) { 100 HIF_ERROR("%s: hif_wlan_enable error = %d", 101 __func__, status); 102 goto timer_free; 103 } 104 105 A_TARGET_ACCESS_LIKELY(hif_sc); 106 107 status = hif_config_ce(hif_sc); 108 if (status) 109 goto disable_wlan; 110 111 status = hif_configure_irq(hif_sc); 112 if (status < 0) 113 goto unconfig_ce; 114 115 A_TARGET_ACCESS_UNLIKELY(hif_sc); 116 117 return status; 118 119 unconfig_ce: 120 hif_unconfig_ce(hif_sc); 121 disable_wlan: 122 A_TARGET_ACCESS_UNLIKELY(hif_sc); 123 hif_wlan_disable(hif_sc); 124 125 timer_free: 126 qdf_timer_stop(&hif_state->sleep_timer); 127 qdf_timer_free(&hif_state->sleep_timer); 128 hif_state->sleep_timer_init = false; 129 130 HIF_ERROR("%s: failed, status = %d", __func__, status); 131 return status; 132 } 133 134 void hif_ipci_close(struct hif_softc *hif_sc) 135 { 136 hif_ce_close(hif_sc); 137 } 138 139 /** 140 * hif_ce_srng_msi_free_irq(): free CE msi IRQ 141 * @scn: struct hif_softc 142 * 143 * Return: ErrorNo 144 */ 145 static int hif_ce_srng_msi_free_irq(struct hif_softc *scn) 146 { 147 int ret; 148 int ce_id, irq; 149 uint32_t msi_data_start; 150 uint32_t msi_data_count; 151 uint32_t msi_irq_start; 152 struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn); 153 154 ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE", 155 &msi_data_count, &msi_data_start, 156 &msi_irq_start); 157 if (ret) 158 return ret; 159 160 /* needs to match the ce_id -> irq data mapping 161 * used in the srng parameter configuration 162 */ 163 for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { 164 unsigned int msi_data; 165 166 if (!ce_sc->tasklets[ce_id].inited) 167 continue; 168 169 msi_data = (ce_id % msi_data_count) + msi_irq_start; 170 irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data); 171 172 hif_debug("%s: (ce_id %d, msi_data %d, irq %d)", __func__, 173 ce_id, msi_data, irq); 174 175 free_irq(irq, &ce_sc->tasklets[ce_id]); 176 } 177 178 return ret; 179 } 180 181 /** 182 * hif_ipci_deconfigure_grp_irq(): deconfigure HW block IRQ 183 * @scn: struct hif_softc 184 * 185 * Return: none 186 */ 187 static void hif_ipci_deconfigure_grp_irq(struct hif_softc *scn) 188 { 189 int i, j, irq; 190 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 191 struct hif_exec_context *hif_ext_group; 192 193 for (i = 0; i < hif_state->hif_num_extgroup; i++) { 194 hif_ext_group = hif_state->hif_ext_group[i]; 195 if (hif_ext_group->irq_requested) { 196 hif_ext_group->irq_requested = false; 197 for (j = 0; j < hif_ext_group->numirq; j++) { 198 irq = hif_ext_group->os_irq[j]; 199 free_irq(irq, hif_ext_group); 200 } 201 hif_ext_group->numirq = 0; 202 } 203 } 204 } 205 206 void hif_ipci_nointrs(struct hif_softc *scn) 207 { 208 int ret; 209 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 210 211 ce_unregister_irq(hif_state, CE_ALL_BITMAP); 212 213 if (scn->request_irq_done == false) 214 return; 215 216 hif_ipci_deconfigure_grp_irq(scn); 217 218 ret = hif_ce_srng_msi_free_irq(scn); 219 if (ret != -EINVAL) { 220 /* ce irqs freed in hif_ce_srng_msi_free_irq */ 221 222 if (scn->wake_irq) 223 free_irq(scn->wake_irq, scn); 224 scn->wake_irq = 0; 225 } 226 227 scn->request_irq_done = false; 228 } 229 230 void hif_ipci_disable_bus(struct hif_softc *scn) 231 { 232 struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn); 233 void __iomem *mem; 234 235 /* Attach did not succeed, all resources have been 236 * freed in error handler 237 */ 238 if (!sc) 239 return; 240 241 mem = (void __iomem *)sc->mem; 242 if (mem) { 243 hif_dump_pipe_debug_count(scn); 244 if (scn->athdiag_procfs_inited) { 245 athdiag_procfs_remove(); 246 scn->athdiag_procfs_inited = false; 247 } 248 scn->mem = NULL; 249 } 250 HIF_INFO("%s: X", __func__); 251 } 252 253 #if defined(CONFIG_PCI_MSM) 254 void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag) 255 { 256 int errno; 257 258 HIF_INFO("wlan: %s pcie power collapse", flag ? "disable" : "enable"); 259 260 errno = pld_wlan_pm_control(scn->qdf_dev->dev, flag); 261 if (errno) 262 HIF_ERROR("%s: Failed pld_wlan_pm_control; errno %d", 263 __func__, errno); 264 } 265 #else 266 void hif_ipci_prevent_linkdown(struct hif_softc *scn, bool flag) 267 { 268 HIF_INFO("wlan: %s pcie power collapse", (flag ? "disable" : "enable")); 269 } 270 #endif 271 272 int hif_ipci_bus_suspend(struct hif_softc *scn) 273 { 274 hif_apps_irqs_disable(GET_HIF_OPAQUE_HDL(scn)); 275 276 if (hif_drain_tasklets(scn)) { 277 hif_apps_irqs_enable(GET_HIF_OPAQUE_HDL(scn)); 278 return -EBUSY; 279 } 280 281 return 0; 282 } 283 284 int hif_ipci_bus_resume(struct hif_softc *scn) 285 { 286 hif_apps_irqs_enable(GET_HIF_OPAQUE_HDL(scn)); 287 288 return 0; 289 } 290 291 int hif_ipci_bus_suspend_noirq(struct hif_softc *scn) 292 { 293 if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn))) 294 qdf_atomic_set(&scn->link_suspended, 1); 295 296 hif_apps_wake_irq_enable(GET_HIF_OPAQUE_HDL(scn)); 297 298 return 0; 299 } 300 301 int hif_ipci_bus_resume_noirq(struct hif_softc *scn) 302 { 303 hif_apps_wake_irq_disable(GET_HIF_OPAQUE_HDL(scn)); 304 305 if (hif_can_suspend_link(GET_HIF_OPAQUE_HDL(scn))) 306 qdf_atomic_set(&scn->link_suspended, 0); 307 308 return 0; 309 } 310 311 void hif_ipci_disable_isr(struct hif_softc *scn) 312 { 313 struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(scn); 314 315 hif_exec_kill(&scn->osc); 316 hif_nointrs(scn); 317 /* Cancel the pending tasklet */ 318 ce_tasklet_kill(scn); 319 tasklet_kill(&sc->intr_tq); 320 qdf_atomic_set(&scn->active_tasklet_cnt, 0); 321 qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0); 322 } 323 324 int hif_ipci_dump_registers(struct hif_softc *hif_ctx) 325 { 326 int status; 327 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); 328 329 status = hif_dump_ce_registers(scn); 330 331 if (status) 332 HIF_ERROR("%s: Dump CE Registers Failed", __func__); 333 334 return 0; 335 } 336 337 /** 338 * hif_ce_interrupt_handler() - interrupt handler for copy engine 339 * @irq: irq number 340 * @context: tasklet context 341 * 342 * Return: irqreturn_t 343 */ 344 static irqreturn_t hif_ce_interrupt_handler(int irq, void *context) 345 { 346 struct ce_tasklet_entry *tasklet_entry = context; 347 348 return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry); 349 } 350 351 extern const char *ce_name[]; 352 353 /** 354 * hif_ce_msi_map_ce_to_irq() - map CE to IRQ 355 * @scn: hif context 356 * @ce_id: CE Id 357 * 358 * Return: IRQ number 359 */ 360 static int hif_ce_msi_map_ce_to_irq(struct hif_softc *scn, int ce_id) 361 { 362 struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn); 363 364 return ipci_scn->ce_msi_irq_num[ce_id]; 365 } 366 367 /* hif_ce_srng_msi_irq_disable() - disable the irq for msi 368 * @hif_sc: hif context 369 * @ce_id: which ce to disable copy complete interrupts for 370 * 371 * @Return: none 372 */ 373 static void hif_ce_srng_msi_irq_disable(struct hif_softc *hif_sc, int ce_id) 374 { 375 disable_irq_nosync(hif_ce_msi_map_ce_to_irq(hif_sc, ce_id)); 376 } 377 378 /* hif_ce_srng_msi_irq_enable() - enable the irq for msi 379 * @hif_sc: hif context 380 * @ce_id: which ce to enable copy complete interrupts for 381 * 382 * @Return: none 383 */ 384 static void hif_ce_srng_msi_irq_enable(struct hif_softc *hif_sc, int ce_id) 385 { 386 enable_irq(hif_ce_msi_map_ce_to_irq(hif_sc, ce_id)); 387 } 388 389 /* hif_ce_msi_configure_irq() - configure the irq 390 * @scn: hif context 391 * 392 * @Return: none 393 */ 394 static int hif_ce_msi_configure_irq(struct hif_softc *scn) 395 { 396 int ret; 397 int ce_id, irq; 398 uint32_t msi_data_start; 399 uint32_t msi_data_count; 400 uint32_t msi_irq_start; 401 struct HIF_CE_state *ce_sc = HIF_GET_CE_STATE(scn); 402 struct hif_ipci_softc *ipci_sc = HIF_GET_IPCI_SOFTC(scn); 403 404 /* do wake irq assignment */ 405 ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "WAKE", 406 &msi_data_count, &msi_data_start, 407 &msi_irq_start); 408 if (ret) 409 return ret; 410 411 scn->wake_irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_irq_start); 412 ret = request_irq(scn->wake_irq, hif_wake_interrupt_handler, 413 IRQF_NO_SUSPEND, "wlan_wake_irq", scn); 414 if (ret) 415 return ret; 416 417 /* do ce irq assignments */ 418 ret = pld_get_user_msi_assignment(scn->qdf_dev->dev, "CE", 419 &msi_data_count, &msi_data_start, 420 &msi_irq_start); 421 if (ret) 422 goto free_wake_irq; 423 424 scn->bus_ops.hif_irq_disable = &hif_ce_srng_msi_irq_disable; 425 scn->bus_ops.hif_irq_enable = &hif_ce_srng_msi_irq_enable; 426 scn->bus_ops.hif_map_ce_to_irq = &hif_ce_msi_map_ce_to_irq; 427 428 /* needs to match the ce_id -> irq data mapping 429 * used in the srng parameter configuration 430 */ 431 for (ce_id = 0; ce_id < scn->ce_count; ce_id++) { 432 unsigned int msi_data = (ce_id % msi_data_count) + 433 msi_irq_start; 434 irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data); 435 HIF_DBG("%s: (ce_id %d, msi_data %d, irq %d tasklet %pK)", 436 __func__, ce_id, msi_data, irq, 437 &ce_sc->tasklets[ce_id]); 438 439 /* implies the ce is also initialized */ 440 if (!ce_sc->tasklets[ce_id].inited) 441 continue; 442 443 ipci_sc->ce_msi_irq_num[ce_id] = irq; 444 ret = request_irq(irq, hif_ce_interrupt_handler, 445 IRQF_SHARED, 446 ce_name[ce_id], 447 &ce_sc->tasklets[ce_id]); 448 if (ret) 449 goto free_irq; 450 } 451 452 return ret; 453 454 free_irq: 455 /* the request_irq for the last ce_id failed so skip it. */ 456 while (ce_id > 0 && ce_id < scn->ce_count) { 457 unsigned int msi_data; 458 459 ce_id--; 460 msi_data = (ce_id % msi_data_count) + msi_irq_start; 461 irq = pld_get_msi_irq(scn->qdf_dev->dev, msi_data); 462 free_irq(irq, &ce_sc->tasklets[ce_id]); 463 } 464 465 free_wake_irq: 466 free_irq(scn->wake_irq, scn->qdf_dev->dev); 467 scn->wake_irq = 0; 468 469 return ret; 470 } 471 472 /** 473 * hif_exec_grp_irq_disable() - disable the irq for group 474 * @hif_ext_group: hif exec context 475 * 476 * Return: none 477 */ 478 static void hif_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group) 479 { 480 int i; 481 482 for (i = 0; i < hif_ext_group->numirq; i++) 483 disable_irq_nosync(hif_ext_group->os_irq[i]); 484 } 485 486 /** 487 * hif_exec_grp_irq_enable() - enable the irq for group 488 * @hif_ext_group: hif exec context 489 * 490 * Return: none 491 */ 492 static void hif_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group) 493 { 494 int i; 495 496 for (i = 0; i < hif_ext_group->numirq; i++) 497 enable_irq(hif_ext_group->os_irq[i]); 498 } 499 500 const char *hif_ipci_get_irq_name(int irq_no) 501 { 502 return "pci-dummy"; 503 } 504 505 int hif_ipci_configure_grp_irq(struct hif_softc *scn, 506 struct hif_exec_context *hif_ext_group) 507 { 508 int ret = 0; 509 int irq = 0; 510 int j; 511 512 hif_ext_group->irq_enable = &hif_exec_grp_irq_enable; 513 hif_ext_group->irq_disable = &hif_exec_grp_irq_disable; 514 hif_ext_group->irq_name = &hif_ipci_get_irq_name; 515 hif_ext_group->work_complete = &hif_dummy_grp_done; 516 517 for (j = 0; j < hif_ext_group->numirq; j++) { 518 irq = hif_ext_group->irq[j]; 519 520 hif_info("request_irq = %d for grp %d", 521 irq, hif_ext_group->grp_id); 522 ret = request_irq(irq, 523 hif_ext_group_interrupt_handler, 524 IRQF_SHARED | IRQF_NO_SUSPEND, 525 "wlan_EXT_GRP", 526 hif_ext_group); 527 if (ret) { 528 HIF_ERROR("%s: request_irq failed ret = %d", 529 __func__, ret); 530 return -EFAULT; 531 } 532 hif_ext_group->os_irq[j] = irq; 533 } 534 hif_ext_group->irq_requested = true; 535 return 0; 536 } 537 538 int hif_configure_irq(struct hif_softc *scn) 539 { 540 int ret = 0; 541 542 HIF_TRACE("%s: E", __func__); 543 544 if (hif_is_polled_mode_enabled(GET_HIF_OPAQUE_HDL(scn))) { 545 scn->request_irq_done = false; 546 return 0; 547 } 548 549 ret = hif_ce_msi_configure_irq(scn); 550 if (ret == 0) 551 goto end; 552 553 if (ret < 0) { 554 HIF_ERROR("%s: hif_ipci_configure_irq error = %d", 555 __func__, ret); 556 return ret; 557 } 558 end: 559 scn->request_irq_done = true; 560 return 0; 561 } 562 563 /** 564 * hif_ipci_get_soc_info_pld() - get soc info for ipcie bus from pld target 565 * @sc: ipci context 566 * @dev: device structure 567 * 568 * Return: none 569 */ 570 static void hif_ipci_get_soc_info_pld(struct hif_ipci_softc *sc, 571 struct device *dev) 572 { 573 struct pld_soc_info info; 574 575 pld_get_soc_info(dev, &info); 576 sc->mem = info.v_addr; 577 sc->ce_sc.ol_sc.mem = info.v_addr; 578 sc->ce_sc.ol_sc.mem_pa = info.p_addr; 579 } 580 581 /** 582 * hif_ipci_get_soc_info_nopld() - get soc info for ipcie bus for non pld target 583 * @sc: ipci context 584 * @dev: device structure 585 * 586 * Return: none 587 */ 588 static void hif_ipci_get_soc_info_nopld(struct hif_ipci_softc *sc, 589 struct device *dev) 590 {} 591 592 /** 593 * hif_is_pld_based_target() - verify if the target is pld based 594 * @sc: ipci context 595 * @device_id: device id 596 * 597 * Return: none 598 */ 599 static bool hif_is_pld_based_target(struct hif_ipci_softc *sc, 600 int device_id) 601 { 602 if (!pld_have_platform_driver_support(sc->dev)) 603 return false; 604 605 switch (device_id) { 606 #ifdef QCA_WIFI_QCA6750 607 case QCA6750_DEVICE_ID: 608 #endif 609 return true; 610 } 611 return false; 612 } 613 614 /** 615 * hif_ipci_init_deinit_ops_attach() - attach ops for ipci 616 * @sc: ipci context 617 * @device_id: device id 618 * 619 * Return: none 620 */ 621 static void hif_ipci_init_deinit_ops_attach(struct hif_ipci_softc *sc, 622 int device_id) 623 { 624 if (hif_is_pld_based_target(sc, device_id)) 625 sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_pld; 626 else 627 sc->hif_ipci_get_soc_info = hif_ipci_get_soc_info_nopld; 628 } 629 630 QDF_STATUS hif_ipci_enable_bus(struct hif_softc *ol_sc, 631 struct device *dev, void *bdev, 632 const struct hif_bus_id *bid, 633 enum hif_enable_type type) 634 { 635 int ret = 0; 636 uint32_t hif_type, target_type; 637 struct hif_ipci_softc *sc = HIF_GET_IPCI_SOFTC(ol_sc); 638 struct hif_opaque_softc *hif_hdl = GET_HIF_OPAQUE_HDL(ol_sc); 639 uint16_t revision_id = 0; 640 struct pci_dev *pdev = bdev; 641 struct hif_target_info *tgt_info; 642 int device_id = QCA6750_DEVICE_ID; 643 644 if (!ol_sc) { 645 HIF_ERROR("%s: hif_ctx is NULL", __func__); 646 return QDF_STATUS_E_NOMEM; 647 } 648 649 sc->dev = dev; 650 tgt_info = hif_get_target_info_handle(hif_hdl); 651 hif_ipci_init_deinit_ops_attach(sc, device_id); 652 sc->hif_ipci_get_soc_info(sc, dev); 653 HIF_TRACE("%s: hif_enable_pci done", __func__); 654 655 device_disable_async_suspend(&pdev->dev); 656 657 ret = hif_get_device_type(device_id, revision_id, 658 &hif_type, &target_type); 659 if (ret < 0) { 660 HIF_ERROR("%s: invalid device id/revision_id", __func__); 661 return QDF_STATUS_E_ABORTED; 662 } 663 HIF_TRACE("%s: hif_type = 0x%x, target_type = 0x%x", 664 __func__, hif_type, target_type); 665 666 hif_register_tbl_attach(ol_sc, hif_type); 667 hif_target_register_tbl_attach(ol_sc, target_type); 668 sc->use_register_windowing = false; 669 tgt_info->target_type = target_type; 670 671 if (!ol_sc->mem_pa) { 672 HIF_ERROR("%s: ERROR - BAR0 uninitialized", __func__); 673 ret = -EIO; 674 return QDF_STATUS_E_ABORTED; 675 } 676 677 return 0; 678 } 679 680 bool hif_ipci_needs_bmi(struct hif_softc *scn) 681 { 682 return !ce_srng_based(scn); 683 } 684 685 #ifdef FORCE_WAKE 686 int hif_force_wake_request(struct hif_opaque_softc *hif_handle) 687 { 688 uint32_t timeout = 0, value; 689 struct hif_softc *scn = (struct hif_softc *)hif_handle; 690 struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn); 691 692 if (pld_force_wake_request(scn->qdf_dev->dev)) { 693 hif_err("force wake request send failed"); 694 return -EINVAL; 695 } 696 697 HIF_STATS_INC(ipci_scn, mhi_force_wake_request_vote, 1); 698 while (!pld_is_device_awake(scn->qdf_dev->dev) && 699 timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS) { 700 qdf_mdelay(FORCE_WAKE_DELAY_MS); 701 timeout += FORCE_WAKE_DELAY_MS; 702 } 703 704 if (pld_is_device_awake(scn->qdf_dev->dev) <= 0) { 705 hif_err("Unable to wake up mhi"); 706 HIF_STATS_INC(ipci_scn, mhi_force_wake_failure, 1); 707 return -EINVAL; 708 } 709 HIF_STATS_INC(ipci_scn, mhi_force_wake_success, 1); 710 hif_write32_mb(scn, 711 scn->mem + 712 PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG, 713 0); 714 hif_write32_mb(scn, 715 scn->mem + 716 PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG, 717 1); 718 719 HIF_STATS_INC(ipci_scn, soc_force_wake_register_write_success, 1); 720 /* 721 * do not reset the timeout 722 * total_wake_time = MHI_WAKE_TIME + PCI_WAKE_TIME < 50 ms 723 */ 724 do { 725 value = 726 hif_read32_mb(scn, 727 scn->mem + 728 PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0_SOC_PCIE_REG); 729 if (value) 730 break; 731 qdf_mdelay(FORCE_WAKE_DELAY_MS); 732 timeout += FORCE_WAKE_DELAY_MS; 733 } while (timeout <= FORCE_WAKE_DELAY_TIMEOUT_MS); 734 735 if (!value) { 736 hif_err("failed handshake mechanism"); 737 HIF_STATS_INC(ipci_scn, soc_force_wake_failure, 1); 738 return -ETIMEDOUT; 739 } 740 741 HIF_STATS_INC(ipci_scn, soc_force_wake_success, 1); 742 743 return 0; 744 } 745 746 int hif_force_wake_release(struct hif_opaque_softc *hif_handle) 747 { 748 int ret; 749 struct hif_softc *scn = (struct hif_softc *)hif_handle; 750 struct hif_ipci_softc *ipci_scn = HIF_GET_IPCI_SOFTC(scn); 751 752 ret = pld_force_wake_release(scn->qdf_dev->dev); 753 if (ret) { 754 hif_err("force wake release failure"); 755 HIF_STATS_INC(ipci_scn, mhi_force_wake_release_failure, 1); 756 return ret; 757 } 758 759 HIF_STATS_INC(ipci_scn, mhi_force_wake_release_success, 1); 760 hif_write32_mb(scn, 761 scn->mem + 762 PCIE_PCIE_LOCAL_REG_PCIE_SOC_WAKE_PCIE_LOCAL_REG, 763 0); 764 HIF_STATS_INC(ipci_scn, soc_force_wake_release_success, 1); 765 return 0; 766 } 767 768 void hif_print_ipci_stats(struct hif_ipci_softc *ipci_handle) 769 { 770 hif_debug("mhi_force_wake_request_vote: %d", 771 ipci_handle->stats.mhi_force_wake_request_vote); 772 hif_debug("mhi_force_wake_failure: %d", 773 ipci_handle->stats.mhi_force_wake_failure); 774 hif_debug("mhi_force_wake_success: %d", 775 ipci_handle->stats.mhi_force_wake_success); 776 hif_debug("soc_force_wake_register_write_success: %d", 777 ipci_handle->stats.soc_force_wake_register_write_success); 778 hif_debug("soc_force_wake_failure: %d", 779 ipci_handle->stats.soc_force_wake_failure); 780 hif_debug("soc_force_wake_success: %d", 781 ipci_handle->stats.soc_force_wake_success); 782 hif_debug("mhi_force_wake_release_failure: %d", 783 ipci_handle->stats.mhi_force_wake_release_failure); 784 hif_debug("mhi_force_wake_release_success: %d", 785 ipci_handle->stats.mhi_force_wake_release_success); 786 hif_debug("oc_force_wake_release_success: %d", 787 ipci_handle->stats.soc_force_wake_release_success); 788 } 789 #endif /* FORCE_WAKE */ 790