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