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