1 /* 2 * Copyright (c) 2013-2018 The Linux Foundation. All rights reserved. 3 * 4 * Permission to use, copy, modify, and/or distribute this software for 5 * any purpose with or without fee is hereby granted, provided that the 6 * above copyright notice and this permission notice appear in all 7 * copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL 10 * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED 11 * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE 12 * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 14 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 15 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 16 * PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /** 20 * DOC: if_ahb.c 21 * 22 * c file for ahb specific implementations. 23 */ 24 25 #include "hif.h" 26 #include "target_type.h" 27 #include "hif_main.h" 28 #include "hif_debug.h" 29 #include "hif_io32.h" 30 #include "ce_main.h" 31 #include "ce_api.h" 32 #include "ce_tasklet.h" 33 #include "if_ahb.h" 34 #include "if_pci.h" 35 #include "ahb_api.h" 36 #include "pci_api.h" 37 #include "hif_napi.h" 38 #include "qal_vbus_dev.h" 39 40 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 1, 0) 41 #define IRQF_DISABLED 0x00000020 42 #endif 43 44 #define HIF_IC_CE0_IRQ_OFFSET 4 45 #define HIF_IC_MAX_IRQ 54 46 47 static uint8_t ic_irqnum[HIF_IC_MAX_IRQ]; 48 /* integrated chip irq names */ 49 const char *ic_irqname[HIF_IC_MAX_IRQ] = { 50 "misc-pulse1", 51 "misc-latch", 52 "sw-exception", 53 "watchdog", 54 "ce0", 55 "ce1", 56 "ce2", 57 "ce3", 58 "ce4", 59 "ce5", 60 "ce6", 61 "ce7", 62 "ce8", 63 "ce9", 64 "ce10", 65 "ce11", 66 "ce12", 67 "ce13", 68 "host2wbm-desc-feed", 69 "host2reo-re-injection", 70 "host2reo-command", 71 "host2rxdma-monitor-ring3", 72 "host2rxdma-monitor-ring2", 73 "host2rxdma-monitor-ring1", 74 "reo2ost-exception", 75 "wbm2host-rx-release", 76 "reo2host-status", 77 "reo2host-destination-ring4", 78 "reo2host-destination-ring3", 79 "reo2host-destination-ring2", 80 "reo2host-destination-ring1", 81 "rxdma2host-monitor-destination-mac3", 82 "rxdma2host-monitor-destination-mac2", 83 "rxdma2host-monitor-destination-mac1", 84 "ppdu-end-interrupts-mac3", 85 "ppdu-end-interrupts-mac2", 86 "ppdu-end-interrupts-mac1", 87 "rxdma2host-monitor-status-ring-mac3", 88 "rxdma2host-monitor-status-ring-mac2", 89 "rxdma2host-monitor-status-ring-mac1", 90 "host2rxdma-host-buf-ring-mac3", 91 "host2rxdma-host-buf-ring-mac2", 92 "host2rxdma-host-buf-ring-mac1", 93 "rxdma2host-destination-ring-mac3", 94 "rxdma2host-destination-ring-mac2", 95 "rxdma2host-destination-ring-mac1", 96 "host2tcl-input-ring4", 97 "host2tcl-input-ring3", 98 "host2tcl-input-ring2", 99 "host2tcl-input-ring1", 100 "wbm2host-tx-completions-ring3", 101 "wbm2host-tx-completions-ring2", 102 "wbm2host-tx-completions-ring1", 103 "tcl2host-status-ring", 104 }; 105 106 /** 107 * hif_disable_isr() - disable isr 108 * 109 * This function disables isr and kills tasklets 110 * 111 * @hif_ctx: struct hif_softc 112 * 113 * Return: void 114 */ 115 void hif_ahb_disable_isr(struct hif_softc *scn) 116 { 117 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 118 119 hif_exec_kill(&scn->osc); 120 hif_nointrs(scn); 121 ce_tasklet_kill(scn); 122 tasklet_kill(&sc->intr_tq); 123 qdf_atomic_set(&scn->active_tasklet_cnt, 0); 124 qdf_atomic_set(&scn->active_grp_tasklet_cnt, 0); 125 } 126 127 /** 128 * hif_dump_registers() - dump bus debug registers 129 * @scn: struct hif_opaque_softc 130 * 131 * This function dumps hif bus debug registers 132 * 133 * Return: 0 for success or error code 134 */ 135 int hif_ahb_dump_registers(struct hif_softc *hif_ctx) 136 { 137 int status; 138 struct hif_softc *scn = HIF_GET_SOFTC(hif_ctx); 139 140 status = hif_dump_ce_registers(scn); 141 if (status) 142 HIF_ERROR("%s: Dump CE Registers Failed status %d", __func__, 143 status); 144 145 return 0; 146 } 147 148 /** 149 * hif_ahb_close() - hif_bus_close 150 * @scn: pointer to the hif context. 151 * 152 * This is a callback function for hif_bus_close. 153 * 154 * 155 * Return: n/a 156 */ 157 void hif_ahb_close(struct hif_softc *scn) 158 { 159 hif_ce_close(scn); 160 } 161 162 /** 163 * hif_bus_open() - hif_ahb open 164 * @hif_ctx: hif context 165 * @bus_type: bus type 166 * 167 * This is a callback function for hif_bus_open. 168 * 169 * Return: n/a 170 */ 171 QDF_STATUS hif_ahb_open(struct hif_softc *hif_ctx, enum qdf_bus_type bus_type) 172 { 173 174 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(hif_ctx); 175 176 qdf_spinlock_create(&sc->irq_lock); 177 return hif_ce_open(hif_ctx); 178 } 179 180 /** 181 * hif_bus_configure() - Configure the bus 182 * @scn: pointer to the hif context. 183 * 184 * This function configure the ahb bus 185 * 186 * return: 0 for success. nonzero for failure. 187 */ 188 int hif_ahb_bus_configure(struct hif_softc *scn) 189 { 190 return hif_pci_bus_configure(scn); 191 } 192 193 /** 194 * hif_configure_msi_ahb - Configure MSI interrupts 195 * @sc : pointer to the hif context 196 * 197 * return: 0 for success. nonzero for failure. 198 */ 199 200 int hif_configure_msi_ahb(struct hif_pci_softc *sc) 201 { 202 return 0; 203 } 204 205 /** 206 * hif_ahb_configure_legacy_irq() - Configure Legacy IRQ 207 * @sc: pointer to the hif context. 208 * 209 * This function registers the irq handler and enables legacy interrupts 210 * 211 * return: 0 for success. nonzero for failure. 212 */ 213 int hif_ahb_configure_legacy_irq(struct hif_pci_softc *sc) 214 { 215 int ret = 0; 216 struct hif_softc *scn = HIF_GET_SOFTC(sc); 217 struct platform_device *pdev = (struct platform_device *)sc->pdev; 218 int irq = 0; 219 220 /* do not support MSI or MSI IRQ failed */ 221 tasklet_init(&sc->intr_tq, wlan_tasklet, (unsigned long)sc); 222 qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev, "legacy", &irq); 223 if (irq < 0) { 224 dev_err(&pdev->dev, "Unable to get irq\n"); 225 ret = -1; 226 goto end; 227 } 228 ret = request_irq(irq, hif_pci_legacy_ce_interrupt_handler, 229 IRQF_DISABLED, "wlan_ahb", sc); 230 if (ret) { 231 dev_err(&pdev->dev, "ath_request_irq failed\n"); 232 ret = -1; 233 goto end; 234 } 235 sc->irq = irq; 236 237 /* Use Legacy PCI Interrupts */ 238 hif_write32_mb(sc, sc->mem + (SOC_CORE_BASE_ADDRESS | 239 PCIE_INTR_ENABLE_ADDRESS), 240 PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 241 /* read once to flush */ 242 hif_read32_mb(sc, sc->mem + (SOC_CORE_BASE_ADDRESS | 243 PCIE_INTR_ENABLE_ADDRESS)); 244 245 end: 246 return ret; 247 } 248 249 int hif_ahb_configure_irq(struct hif_pci_softc *sc) 250 { 251 int ret = 0; 252 struct hif_softc *scn = HIF_GET_SOFTC(sc); 253 struct platform_device *pdev = (struct platform_device *)sc->pdev; 254 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 255 struct CE_attr *host_ce_conf = hif_state->host_ce_config; 256 int irq = 0; 257 int i; 258 259 /* configure per CE interrupts */ 260 for (i = 0; i < scn->ce_count; i++) { 261 if (host_ce_conf[i].flags & CE_ATTR_DISABLE_INTR) 262 continue; 263 qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev, 264 ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], &irq); 265 ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i] = irq; 266 ret = request_irq(irq , 267 hif_ahb_interrupt_handler, 268 IRQF_TRIGGER_RISING, ic_irqname[HIF_IC_CE0_IRQ_OFFSET + i], 269 &hif_state->tasklets[i]); 270 if (ret) { 271 dev_err(&pdev->dev, "ath_request_irq failed\n"); 272 ret = -1; 273 goto end; 274 } 275 hif_ahb_irq_enable(scn, i); 276 } 277 278 end: 279 return ret; 280 } 281 282 int hif_ahb_configure_grp_irq(struct hif_softc *scn, 283 struct hif_exec_context *hif_ext_group) 284 { 285 int ret = 0; 286 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 287 struct platform_device *pdev = (struct platform_device *)sc->pdev; 288 int irq = 0; 289 int j; 290 291 /* configure external interrupts */ 292 hif_ext_group->irq_enable = &hif_ahb_exec_grp_irq_enable; 293 hif_ext_group->irq_disable = &hif_ahb_exec_grp_irq_disable; 294 hif_ext_group->work_complete = &hif_dummy_grp_done; 295 296 qdf_spin_lock_irqsave(&hif_ext_group->irq_lock); 297 298 for (j = 0; j < hif_ext_group->numirq; j++) { 299 qal_vbus_get_irq((struct qdf_pfm_hndl *)pdev, 300 ic_irqname[hif_ext_group->irq[j]], &irq); 301 302 ic_irqnum[hif_ext_group->irq[j]] = irq; 303 irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 304 ret = request_irq(irq, hif_ext_group_interrupt_handler, 305 IRQF_TRIGGER_RISING, 306 ic_irqname[hif_ext_group->irq[j]], 307 hif_ext_group); 308 if (ret) { 309 dev_err(&pdev->dev, 310 "ath_request_irq failed\n"); 311 ret = -1; 312 goto end; 313 } 314 hif_ext_group->os_irq[j] = irq; 315 } 316 qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock); 317 318 qdf_spin_lock_irqsave(&hif_ext_group->irq_lock); 319 hif_ext_group->irq_requested = true; 320 321 end: 322 qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock); 323 return ret; 324 } 325 326 void hif_ahb_deconfigure_grp_irq(struct hif_softc *scn) 327 { 328 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 329 struct hif_exec_context *hif_ext_group; 330 int i, j; 331 int irq = 0; 332 333 /* configure external interrupts */ 334 for (i = 0; i < hif_state->hif_num_extgroup; i++) { 335 hif_ext_group = hif_state->hif_ext_group[i]; 336 if (hif_ext_group->irq_requested == true) { 337 qdf_spin_lock_irqsave(&hif_ext_group->irq_lock); 338 hif_ext_group->irq_requested = false; 339 for (j = 0; j < hif_ext_group->numirq; j++) { 340 irq = hif_ext_group->os_irq[j]; 341 irq_clear_status_flags(irq, 342 IRQ_DISABLE_UNLAZY); 343 free_irq(irq, hif_ext_group); 344 } 345 qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock); 346 } 347 } 348 } 349 350 irqreturn_t hif_ahb_interrupt_handler(int irq, void *context) 351 { 352 struct ce_tasklet_entry *tasklet_entry = context; 353 return ce_dispatch_interrupt(tasklet_entry->ce_id, tasklet_entry); 354 } 355 356 /** 357 * hif_target_sync() : ensure the target is ready 358 * @scn: hif control structure 359 * 360 * Informs fw that we plan to use legacy interupts so that 361 * it can begin booting. Ensures that the fw finishes booting 362 * before continuing. Should be called before trying to write 363 * to the targets other registers for the first time. 364 * 365 * Return: none 366 */ 367 int hif_target_sync_ahb(struct hif_softc *scn) 368 { 369 int val = 0; 370 int limit = 0; 371 372 while (limit < 50) { 373 hif_write32_mb(scn, scn->mem + 374 (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS), 375 PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 376 qdf_mdelay(10); 377 val = hif_read32_mb(scn, scn->mem + 378 (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS)); 379 if (val == 0) 380 break; 381 limit++; 382 } 383 hif_write32_mb(scn, scn->mem + 384 (SOC_CORE_BASE_ADDRESS | PCIE_INTR_ENABLE_ADDRESS), 385 PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL); 386 hif_write32_mb(scn, scn->mem + FW_INDICATOR_ADDRESS, FW_IND_HOST_READY); 387 if (HAS_FW_INDICATOR) { 388 int wait_limit = 500; 389 int fw_ind = 0; 390 391 while (1) { 392 fw_ind = hif_read32_mb(scn, scn->mem + 393 FW_INDICATOR_ADDRESS); 394 if (fw_ind & FW_IND_INITIALIZED) 395 break; 396 if (wait_limit-- < 0) 397 break; 398 hif_write32_mb(scn, scn->mem + (SOC_CORE_BASE_ADDRESS | 399 PCIE_INTR_ENABLE_ADDRESS), 400 PCIE_INTR_FIRMWARE_MASK); 401 qdf_mdelay(10); 402 } 403 if (wait_limit < 0) { 404 HIF_TRACE("%s: FW signal timed out", __func__); 405 return -EIO; 406 } 407 HIF_TRACE("%s: Got FW signal, retries = %x", __func__, 408 500-wait_limit); 409 } 410 411 return 0; 412 } 413 414 /** 415 * hif_disable_bus() - Disable the bus 416 * @scn : pointer to the hif context 417 * 418 * This function disables the bus and helds the target in reset state 419 * 420 * Return: none 421 */ 422 void hif_ahb_disable_bus(struct hif_softc *scn) 423 { 424 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 425 void __iomem *mem; 426 struct platform_device *pdev = (struct platform_device *)sc->pdev; 427 struct resource *memres = NULL; 428 int mem_pa_size = 0; 429 struct hif_target_info *tgt_info = NULL; 430 struct qdf_vbus_resource *vmres = NULL; 431 432 tgt_info = &scn->target_info; 433 /*Disable WIFI clock input*/ 434 if (sc->mem) { 435 qal_vbus_get_resource((struct qdf_pfm_hndl *)pdev, &vmres, 436 IORESOURCE_MEM, 0); 437 memres = (struct resource *)vmres; 438 if (!memres) { 439 HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", 440 __func__); 441 return; 442 } 443 mem_pa_size = memres->end - memres->start + 1; 444 445 /* Should not be executed on 8074 platform */ 446 if ((tgt_info->target_type != TARGET_TYPE_QCA8074) && 447 (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) { 448 hif_ahb_clk_enable_disable(&pdev->dev, 0); 449 450 hif_ahb_device_reset(scn); 451 } 452 mem = (void __iomem *)sc->mem; 453 if (mem) { 454 devm_iounmap(&pdev->dev, mem); 455 devm_release_mem_region(&pdev->dev, scn->mem_pa, 456 mem_pa_size); 457 sc->mem = NULL; 458 } 459 } 460 scn->mem = NULL; 461 } 462 463 /** 464 * hif_enable_bus() - Enable the bus 465 * @dev: dev 466 * @bdev: bus dev 467 * @bid: bus id 468 * @type: bus type 469 * 470 * This function enables the radio bus by enabling necessary 471 * clocks and waits for the target to get ready to proceed futher 472 * 473 * Return: QDF_STATUS 474 */ 475 QDF_STATUS hif_ahb_enable_bus(struct hif_softc *ol_sc, 476 struct device *dev, void *bdev, 477 const struct hif_bus_id *bid, 478 enum hif_enable_type type) 479 { 480 int ret = 0; 481 int hif_type; 482 int target_type; 483 const struct platform_device_id *id = (struct platform_device_id *)bid; 484 struct platform_device *pdev = bdev; 485 struct hif_target_info *tgt_info = NULL; 486 struct resource *memres = NULL; 487 void __iomem *mem = NULL; 488 uint32_t revision_id = 0; 489 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(ol_sc); 490 491 sc->pdev = (struct pci_dev *)pdev; 492 sc->dev = &pdev->dev; 493 sc->devid = id->driver_data; 494 495 ret = hif_get_device_type(id->driver_data, revision_id, 496 &hif_type, &target_type); 497 if (ret < 0) { 498 HIF_ERROR("%s: invalid device ret %d id %d revision_id %d", 499 __func__, ret, (int)id->driver_data, revision_id); 500 return QDF_STATUS_E_FAILURE; 501 } 502 503 memres = platform_get_resource(pdev, IORESOURCE_MEM, 0); 504 if (!memres) { 505 HIF_INFO("%s: Failed to get IORESOURCE_MEM\n", __func__); 506 return -EIO; 507 } 508 509 ret = dma_set_mask(dev, DMA_BIT_MASK(32)); 510 if (ret) { 511 HIF_INFO("ath: 32-bit DMA not available\n"); 512 goto err_cleanup1; 513 } 514 515 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) 516 ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 517 #else 518 ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); 519 #endif 520 if (ret) { 521 HIF_ERROR("%s: failed to set dma mask error = %d", 522 __func__, ret); 523 return ret; 524 } 525 526 /* Arrange for access to Target SoC registers. */ 527 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 9, 0) 528 mem = devm_ioremap_resource(&pdev->dev, memres); 529 #else 530 mem = devm_request_and_ioremap(&pdev->dev, memres); 531 #endif 532 if (IS_ERR(mem)) { 533 HIF_INFO("ath: ioremap error\n"); 534 ret = PTR_ERR(mem); 535 goto err_cleanup1; 536 } 537 538 sc->mem = mem; 539 ol_sc->mem = mem; 540 ol_sc->mem_pa = memres->start; 541 542 tgt_info = hif_get_target_info_handle((struct hif_opaque_softc *)ol_sc); 543 544 tgt_info->target_type = target_type; 545 hif_register_tbl_attach(ol_sc, hif_type); 546 hif_target_register_tbl_attach(ol_sc, target_type); 547 548 /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */ 549 if ((tgt_info->target_type != TARGET_TYPE_QCA8074) && 550 (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) { 551 if (hif_ahb_enable_radio(sc, pdev, id) != 0) { 552 HIF_INFO("error in enabling soc\n"); 553 return -EIO; 554 } 555 556 if (hif_target_sync_ahb(ol_sc) < 0) { 557 ret = -EIO; 558 goto err_target_sync; 559 } 560 } 561 HIF_TRACE("%s: X - hif_type = 0x%x, target_type = 0x%x", 562 __func__, hif_type, target_type); 563 564 return QDF_STATUS_SUCCESS; 565 err_target_sync: 566 /* QCA_WIFI_QCA8074_VP:Should not be executed on 8074 VP platform */ 567 if ((tgt_info->target_type != TARGET_TYPE_QCA8074) && 568 (tgt_info->target_type != TARGET_TYPE_QCA8074V2)) { 569 HIF_INFO("Error: Disabling target\n"); 570 hif_ahb_disable_bus(ol_sc); 571 } 572 err_cleanup1: 573 return ret; 574 } 575 576 577 /** 578 * hif_reset_soc() - reset soc 579 * 580 * @hif_ctx: HIF context 581 * 582 * This function resets soc and helds the 583 * target in reset state 584 * 585 * Return: void 586 */ 587 /* Function to reset SoC */ 588 void hif_ahb_reset_soc(struct hif_softc *hif_ctx) 589 { 590 hif_ahb_device_reset(hif_ctx); 591 } 592 593 594 /** 595 * hif_nointrs() - disable IRQ 596 * 597 * @scn: struct hif_softc 598 * 599 * This function stops interrupt(s) 600 * 601 * Return: none 602 */ 603 void hif_ahb_nointrs(struct hif_softc *scn) 604 { 605 int i; 606 struct hif_pci_softc *sc = HIF_GET_PCI_SOFTC(scn); 607 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 608 struct CE_attr *host_ce_conf = hif_state->host_ce_config; 609 610 ce_unregister_irq(hif_state, CE_ALL_BITMAP); 611 612 if (scn->request_irq_done == false) 613 return; 614 615 if (sc->num_msi_intrs > 0) { 616 /* MSI interrupt(s) */ 617 for (i = 0; i < sc->num_msi_intrs; i++) { 618 free_irq(sc->irq + i, sc); 619 } 620 sc->num_msi_intrs = 0; 621 } else { 622 if (!scn->per_ce_irq) { 623 free_irq(sc->irq, sc); 624 } else { 625 for (i = 0; i < scn->ce_count; i++) { 626 if (host_ce_conf[i].flags 627 & CE_ATTR_DISABLE_INTR) 628 continue; 629 630 free_irq(ic_irqnum[HIF_IC_CE0_IRQ_OFFSET + i], 631 &hif_state->tasklets[i]); 632 } 633 hif_ahb_deconfigure_grp_irq(scn); 634 } 635 } 636 scn->request_irq_done = false; 637 638 } 639 640 /** 641 * ce_irq_enable() - enable copy engine IRQ 642 * @scn: struct hif_softc 643 * @ce_id: ce_id 644 * 645 * This function enables the interrupt for the radio. 646 * 647 * Return: N/A 648 */ 649 void hif_ahb_irq_enable(struct hif_softc *scn, int ce_id) 650 { 651 uint32_t regval; 652 uint32_t reg_offset = 0; 653 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 654 struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; 655 struct hif_target_info *tgt_info = &scn->target_info; 656 657 if (scn->per_ce_irq) { 658 if (target_ce_conf->pipedir & PIPEDIR_OUT) { 659 reg_offset = HOST_IE_ADDRESS; 660 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); 661 regval = hif_read32_mb(scn, scn->mem + reg_offset); 662 regval |= HOST_IE_REG1_CE_BIT(ce_id); 663 hif_write32_mb(scn, scn->mem + reg_offset, regval); 664 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); 665 } 666 if (target_ce_conf->pipedir & PIPEDIR_IN) { 667 reg_offset = HOST_IE_ADDRESS_2; 668 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); 669 regval = hif_read32_mb(scn, scn->mem + reg_offset); 670 regval |= HOST_IE_REG2_CE_BIT(ce_id); 671 hif_write32_mb(scn, scn->mem + reg_offset, regval); 672 if (tgt_info->target_type == TARGET_TYPE_QCA8074) { 673 /* Enable destination ring interrupts for 8074 674 * TODO: To be removed in 2.0 HW */ 675 regval = hif_read32_mb(scn, scn->mem + 676 HOST_IE_ADDRESS_3); 677 regval |= HOST_IE_REG3_CE_BIT(ce_id); 678 } 679 hif_write32_mb(scn, scn->mem + HOST_IE_ADDRESS_3, 680 regval); 681 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); 682 } 683 } else { 684 hif_pci_irq_enable(scn, ce_id); 685 } 686 } 687 688 /** 689 * ce_irq_disable() - disable copy engine IRQ 690 * @scn: struct hif_softc 691 * @ce_id: ce_id 692 * 693 * Return: N/A 694 */ 695 void hif_ahb_irq_disable(struct hif_softc *scn, int ce_id) 696 { 697 uint32_t regval; 698 uint32_t reg_offset = 0; 699 struct HIF_CE_state *hif_state = HIF_GET_CE_STATE(scn); 700 struct CE_pipe_config *target_ce_conf = &hif_state->target_ce_config[ce_id]; 701 struct hif_target_info *tgt_info = &scn->target_info; 702 703 if (scn->per_ce_irq) { 704 if (target_ce_conf->pipedir & PIPEDIR_OUT) { 705 reg_offset = HOST_IE_ADDRESS; 706 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); 707 regval = hif_read32_mb(scn, scn->mem + reg_offset); 708 regval &= ~HOST_IE_REG1_CE_BIT(ce_id); 709 hif_write32_mb(scn, scn->mem + reg_offset, regval); 710 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); 711 } 712 if (target_ce_conf->pipedir & PIPEDIR_IN) { 713 reg_offset = HOST_IE_ADDRESS_2; 714 qdf_spin_lock_irqsave(&hif_state->irq_reg_lock); 715 regval = hif_read32_mb(scn, scn->mem + reg_offset); 716 regval &= ~HOST_IE_REG2_CE_BIT(ce_id); 717 hif_write32_mb(scn, scn->mem + reg_offset, regval); 718 if (tgt_info->target_type == TARGET_TYPE_QCA8074) { 719 /* Disable destination ring interrupts for 8074 720 * TODO: To be removed in 2.0 HW */ 721 regval = hif_read32_mb(scn, scn->mem + 722 HOST_IE_ADDRESS_3); 723 regval &= ~HOST_IE_REG3_CE_BIT(ce_id); 724 } 725 hif_write32_mb(scn, scn->mem + HOST_IE_ADDRESS_3, 726 regval); 727 qdf_spin_unlock_irqrestore(&hif_state->irq_reg_lock); 728 } 729 } 730 } 731 732 void hif_ahb_exec_grp_irq_disable(struct hif_exec_context *hif_ext_group) 733 { 734 int i; 735 736 qdf_spin_lock_irqsave(&hif_ext_group->irq_lock); 737 if (hif_ext_group->irq_enabled) { 738 for (i = 0; i < hif_ext_group->numirq; i++) { 739 disable_irq_nosync(hif_ext_group->os_irq[i]); 740 } 741 hif_ext_group->irq_enabled = false; 742 } 743 qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock); 744 } 745 746 void hif_ahb_exec_grp_irq_enable(struct hif_exec_context *hif_ext_group) 747 { 748 int i; 749 750 qdf_spin_lock_irqsave(&hif_ext_group->irq_lock); 751 if (!hif_ext_group->irq_enabled) { 752 for (i = 0; i < hif_ext_group->numirq; i++) { 753 enable_irq(hif_ext_group->os_irq[i]); 754 } 755 hif_ext_group->irq_enabled = true; 756 } 757 qdf_spin_unlock_irqrestore(&hif_ext_group->irq_lock); 758 } 759 760 /** 761 * hif_ahb_needs_bmi() - return true if the soc needs bmi through the driver 762 * @scn: hif context 763 * 764 * Return: true if soc needs driver bmi otherwise false 765 */ 766 bool hif_ahb_needs_bmi(struct hif_softc *scn) 767 { 768 return !ce_srng_based(scn); 769 } 770