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