1 // SPDX-License-Identifier: BSD-3-Clause-Clear 2 /* 3 * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. 4 * Copyright (c) 2021-2022, Qualcomm Innovation Center, Inc. All rights reserved. 5 */ 6 7 #include "core.h" 8 #include "pcic.h" 9 #include "debug.h" 10 11 static const char *irq_name[ATH11K_IRQ_NUM_MAX] = { 12 "bhi", 13 "mhi-er0", 14 "mhi-er1", 15 "ce0", 16 "ce1", 17 "ce2", 18 "ce3", 19 "ce4", 20 "ce5", 21 "ce6", 22 "ce7", 23 "ce8", 24 "ce9", 25 "ce10", 26 "ce11", 27 "host2wbm-desc-feed", 28 "host2reo-re-injection", 29 "host2reo-command", 30 "host2rxdma-monitor-ring3", 31 "host2rxdma-monitor-ring2", 32 "host2rxdma-monitor-ring1", 33 "reo2ost-exception", 34 "wbm2host-rx-release", 35 "reo2host-status", 36 "reo2host-destination-ring4", 37 "reo2host-destination-ring3", 38 "reo2host-destination-ring2", 39 "reo2host-destination-ring1", 40 "rxdma2host-monitor-destination-mac3", 41 "rxdma2host-monitor-destination-mac2", 42 "rxdma2host-monitor-destination-mac1", 43 "ppdu-end-interrupts-mac3", 44 "ppdu-end-interrupts-mac2", 45 "ppdu-end-interrupts-mac1", 46 "rxdma2host-monitor-status-ring-mac3", 47 "rxdma2host-monitor-status-ring-mac2", 48 "rxdma2host-monitor-status-ring-mac1", 49 "host2rxdma-host-buf-ring-mac3", 50 "host2rxdma-host-buf-ring-mac2", 51 "host2rxdma-host-buf-ring-mac1", 52 "rxdma2host-destination-ring-mac3", 53 "rxdma2host-destination-ring-mac2", 54 "rxdma2host-destination-ring-mac1", 55 "host2tcl-input-ring4", 56 "host2tcl-input-ring3", 57 "host2tcl-input-ring2", 58 "host2tcl-input-ring1", 59 "wbm2host-tx-completions-ring3", 60 "wbm2host-tx-completions-ring2", 61 "wbm2host-tx-completions-ring1", 62 "tcl2host-status-ring", 63 }; 64 65 static const struct ath11k_msi_config ath11k_msi_config[] = { 66 { 67 .total_vectors = 32, 68 .total_users = 4, 69 .users = (struct ath11k_msi_user[]) { 70 { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 71 { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 72 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 73 { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 74 }, 75 .hw_rev = ATH11K_HW_QCA6390_HW20, 76 }, 77 { 78 .total_vectors = 16, 79 .total_users = 3, 80 .users = (struct ath11k_msi_user[]) { 81 { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 82 { .name = "CE", .num_vectors = 5, .base_vector = 3 }, 83 { .name = "DP", .num_vectors = 8, .base_vector = 8 }, 84 }, 85 .hw_rev = ATH11K_HW_QCN9074_HW10, 86 }, 87 { 88 .total_vectors = 32, 89 .total_users = 4, 90 .users = (struct ath11k_msi_user[]) { 91 { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 92 { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 93 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 94 { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 95 }, 96 .hw_rev = ATH11K_HW_WCN6855_HW20, 97 }, 98 { 99 .total_vectors = 32, 100 .total_users = 4, 101 .users = (struct ath11k_msi_user[]) { 102 { .name = "MHI", .num_vectors = 3, .base_vector = 0 }, 103 { .name = "CE", .num_vectors = 10, .base_vector = 3 }, 104 { .name = "WAKE", .num_vectors = 1, .base_vector = 13 }, 105 { .name = "DP", .num_vectors = 18, .base_vector = 14 }, 106 }, 107 .hw_rev = ATH11K_HW_WCN6855_HW21, 108 }, 109 { 110 .total_vectors = 28, 111 .total_users = 2, 112 .users = (struct ath11k_msi_user[]) { 113 { .name = "CE", .num_vectors = 10, .base_vector = 0 }, 114 { .name = "DP", .num_vectors = 18, .base_vector = 10 }, 115 }, 116 .hw_rev = ATH11K_HW_WCN6750_HW10, 117 }, 118 }; 119 120 int ath11k_pcic_init_msi_config(struct ath11k_base *ab) 121 { 122 const struct ath11k_msi_config *msi_config; 123 int i; 124 125 for (i = 0; i < ARRAY_SIZE(ath11k_msi_config); i++) { 126 msi_config = &ath11k_msi_config[i]; 127 128 if (msi_config->hw_rev == ab->hw_rev) 129 break; 130 } 131 132 if (i == ARRAY_SIZE(ath11k_msi_config)) { 133 ath11k_err(ab, "failed to fetch msi config, unsupported hw version: 0x%x\n", 134 ab->hw_rev); 135 return -EINVAL; 136 } 137 138 ab->pci.msi.config = msi_config; 139 return 0; 140 } 141 EXPORT_SYMBOL(ath11k_pcic_init_msi_config); 142 143 void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value) 144 { 145 int ret = 0; 146 147 /* for offset beyond BAR + 4K - 32, may 148 * need to wakeup the device to access. 149 */ 150 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && 151 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup) 152 ret = ab->pci.ops->wakeup(ab); 153 154 if (offset < ATH11K_PCI_WINDOW_START) 155 iowrite32(value, ab->mem + offset); 156 else 157 ab->pci.ops->window_write32(ab, offset, value); 158 159 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && 160 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release && 161 !ret) 162 ab->pci.ops->release(ab); 163 } 164 EXPORT_SYMBOL(ath11k_pcic_write32); 165 166 u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset) 167 { 168 int ret = 0; 169 u32 val; 170 171 /* for offset beyond BAR + 4K - 32, may 172 * need to wakeup the device to access. 173 */ 174 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && 175 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->wakeup) 176 ret = ab->pci.ops->wakeup(ab); 177 178 if (offset < ATH11K_PCI_WINDOW_START) 179 val = ioread32(ab->mem + offset); 180 else 181 val = ab->pci.ops->window_read32(ab, offset); 182 183 if (test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) && 184 offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF && ab->pci.ops->release && 185 !ret) 186 ab->pci.ops->release(ab); 187 188 return val; 189 } 190 EXPORT_SYMBOL(ath11k_pcic_read32); 191 192 void ath11k_pcic_get_msi_address(struct ath11k_base *ab, u32 *msi_addr_lo, 193 u32 *msi_addr_hi) 194 { 195 *msi_addr_lo = ab->pci.msi.addr_lo; 196 *msi_addr_hi = ab->pci.msi.addr_hi; 197 } 198 EXPORT_SYMBOL(ath11k_pcic_get_msi_address); 199 200 int ath11k_pcic_get_user_msi_assignment(struct ath11k_base *ab, char *user_name, 201 int *num_vectors, u32 *user_base_data, 202 u32 *base_vector) 203 { 204 const struct ath11k_msi_config *msi_config = ab->pci.msi.config; 205 int idx; 206 207 for (idx = 0; idx < msi_config->total_users; idx++) { 208 if (strcmp(user_name, msi_config->users[idx].name) == 0) { 209 *num_vectors = msi_config->users[idx].num_vectors; 210 *base_vector = msi_config->users[idx].base_vector; 211 *user_base_data = *base_vector + ab->pci.msi.ep_base_data; 212 213 ath11k_dbg(ab, ATH11K_DBG_PCI, 214 "Assign MSI to user: %s, num_vectors: %d, user_base_data: %u, base_vector: %u\n", 215 user_name, *num_vectors, *user_base_data, 216 *base_vector); 217 218 return 0; 219 } 220 } 221 222 ath11k_err(ab, "Failed to find MSI assignment for %s!\n", user_name); 223 224 return -EINVAL; 225 } 226 EXPORT_SYMBOL(ath11k_pcic_get_user_msi_assignment); 227 228 void ath11k_pcic_get_ce_msi_idx(struct ath11k_base *ab, u32 ce_id, u32 *msi_idx) 229 { 230 u32 i, msi_data_idx; 231 232 for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 233 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 234 continue; 235 236 if (ce_id == i) 237 break; 238 239 msi_data_idx++; 240 } 241 *msi_idx = msi_data_idx; 242 } 243 EXPORT_SYMBOL(ath11k_pcic_get_ce_msi_idx); 244 245 static void ath11k_pcic_free_ext_irq(struct ath11k_base *ab) 246 { 247 int i, j; 248 249 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 250 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 251 252 for (j = 0; j < irq_grp->num_irq; j++) 253 free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp); 254 255 netif_napi_del(&irq_grp->napi); 256 } 257 } 258 259 void ath11k_pcic_free_irq(struct ath11k_base *ab) 260 { 261 int i, irq_idx; 262 263 for (i = 0; i < ab->hw_params.ce_count; i++) { 264 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 265 continue; 266 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 267 free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]); 268 } 269 270 ath11k_pcic_free_ext_irq(ab); 271 } 272 EXPORT_SYMBOL(ath11k_pcic_free_irq); 273 274 static void ath11k_pcic_ce_irq_enable(struct ath11k_base *ab, u16 ce_id) 275 { 276 u32 irq_idx; 277 278 /* In case of one MSI vector, we handle irq enable/disable in a 279 * uniform way since we only have one irq 280 */ 281 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 282 return; 283 284 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 285 enable_irq(ab->irq_num[irq_idx]); 286 } 287 288 static void ath11k_pcic_ce_irq_disable(struct ath11k_base *ab, u16 ce_id) 289 { 290 u32 irq_idx; 291 292 /* In case of one MSI vector, we handle irq enable/disable in a 293 * uniform way since we only have one irq 294 */ 295 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 296 return; 297 298 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_id; 299 disable_irq_nosync(ab->irq_num[irq_idx]); 300 } 301 302 static void ath11k_pcic_ce_irqs_disable(struct ath11k_base *ab) 303 { 304 int i; 305 306 clear_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 307 308 for (i = 0; i < ab->hw_params.ce_count; i++) { 309 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 310 continue; 311 ath11k_pcic_ce_irq_disable(ab, i); 312 } 313 } 314 315 static void ath11k_pcic_sync_ce_irqs(struct ath11k_base *ab) 316 { 317 int i; 318 int irq_idx; 319 320 for (i = 0; i < ab->hw_params.ce_count; i++) { 321 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 322 continue; 323 324 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 325 synchronize_irq(ab->irq_num[irq_idx]); 326 } 327 } 328 329 static void ath11k_pcic_ce_tasklet(struct tasklet_struct *t) 330 { 331 struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq); 332 int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 333 334 ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num); 335 336 enable_irq(ce_pipe->ab->irq_num[irq_idx]); 337 } 338 339 static irqreturn_t ath11k_pcic_ce_interrupt_handler(int irq, void *arg) 340 { 341 struct ath11k_ce_pipe *ce_pipe = arg; 342 struct ath11k_base *ab = ce_pipe->ab; 343 int irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + ce_pipe->pipe_num; 344 345 if (!test_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags)) 346 return IRQ_HANDLED; 347 348 /* last interrupt received for this CE */ 349 ce_pipe->timestamp = jiffies; 350 351 disable_irq_nosync(ab->irq_num[irq_idx]); 352 353 tasklet_schedule(&ce_pipe->intr_tq); 354 355 return IRQ_HANDLED; 356 } 357 358 static void ath11k_pcic_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp) 359 { 360 struct ath11k_base *ab = irq_grp->ab; 361 int i; 362 363 /* In case of one MSI vector, we handle irq enable/disable 364 * in a uniform way since we only have one irq 365 */ 366 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 367 return; 368 369 for (i = 0; i < irq_grp->num_irq; i++) 370 disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 371 } 372 373 static void __ath11k_pcic_ext_irq_disable(struct ath11k_base *sc) 374 { 375 int i; 376 377 clear_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &sc->dev_flags); 378 379 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 380 struct ath11k_ext_irq_grp *irq_grp = &sc->ext_irq_grp[i]; 381 382 ath11k_pcic_ext_grp_disable(irq_grp); 383 384 if (irq_grp->napi_enabled) { 385 napi_synchronize(&irq_grp->napi); 386 napi_disable(&irq_grp->napi); 387 irq_grp->napi_enabled = false; 388 } 389 } 390 } 391 392 static void ath11k_pcic_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp) 393 { 394 struct ath11k_base *ab = irq_grp->ab; 395 int i; 396 397 /* In case of one MSI vector, we handle irq enable/disable in a 398 * uniform way since we only have one irq 399 */ 400 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 401 return; 402 403 for (i = 0; i < irq_grp->num_irq; i++) 404 enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 405 } 406 407 void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab) 408 { 409 int i; 410 411 set_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags); 412 413 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 414 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 415 416 if (!irq_grp->napi_enabled) { 417 napi_enable(&irq_grp->napi); 418 irq_grp->napi_enabled = true; 419 } 420 ath11k_pcic_ext_grp_enable(irq_grp); 421 } 422 } 423 EXPORT_SYMBOL(ath11k_pcic_ext_irq_enable); 424 425 static void ath11k_pcic_sync_ext_irqs(struct ath11k_base *ab) 426 { 427 int i, j, irq_idx; 428 429 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 430 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 431 432 for (j = 0; j < irq_grp->num_irq; j++) { 433 irq_idx = irq_grp->irqs[j]; 434 synchronize_irq(ab->irq_num[irq_idx]); 435 } 436 } 437 } 438 439 void ath11k_pcic_ext_irq_disable(struct ath11k_base *ab) 440 { 441 __ath11k_pcic_ext_irq_disable(ab); 442 ath11k_pcic_sync_ext_irqs(ab); 443 } 444 EXPORT_SYMBOL(ath11k_pcic_ext_irq_disable); 445 446 static int ath11k_pcic_ext_grp_napi_poll(struct napi_struct *napi, int budget) 447 { 448 struct ath11k_ext_irq_grp *irq_grp = container_of(napi, 449 struct ath11k_ext_irq_grp, 450 napi); 451 struct ath11k_base *ab = irq_grp->ab; 452 int work_done; 453 int i; 454 455 work_done = ath11k_dp_service_srng(ab, irq_grp, budget); 456 if (work_done < budget) { 457 napi_complete_done(napi, work_done); 458 for (i = 0; i < irq_grp->num_irq; i++) 459 enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 460 } 461 462 if (work_done > budget) 463 work_done = budget; 464 465 return work_done; 466 } 467 468 static irqreturn_t ath11k_pcic_ext_interrupt_handler(int irq, void *arg) 469 { 470 struct ath11k_ext_irq_grp *irq_grp = arg; 471 struct ath11k_base *ab = irq_grp->ab; 472 int i; 473 474 if (!test_bit(ATH11K_FLAG_EXT_IRQ_ENABLED, &ab->dev_flags)) 475 return IRQ_HANDLED; 476 477 ath11k_dbg(irq_grp->ab, ATH11K_DBG_PCI, "ext irq:%d\n", irq); 478 479 /* last interrupt received for this group */ 480 irq_grp->timestamp = jiffies; 481 482 for (i = 0; i < irq_grp->num_irq; i++) 483 disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]); 484 485 napi_schedule(&irq_grp->napi); 486 487 return IRQ_HANDLED; 488 } 489 490 static int 491 ath11k_pcic_get_msi_irq(struct ath11k_base *ab, unsigned int vector) 492 { 493 return ab->pci.ops->get_msi_irq(ab, vector); 494 } 495 496 static int ath11k_pcic_ext_irq_config(struct ath11k_base *ab) 497 { 498 int i, j, ret, num_vectors = 0; 499 u32 user_base_data = 0, base_vector = 0; 500 unsigned long irq_flags; 501 502 ret = ath11k_pcic_get_user_msi_assignment(ab, "DP", &num_vectors, 503 &user_base_data, 504 &base_vector); 505 if (ret < 0) 506 return ret; 507 508 irq_flags = IRQF_SHARED; 509 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 510 irq_flags |= IRQF_NOBALANCING; 511 512 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { 513 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i]; 514 u32 num_irq = 0; 515 516 irq_grp->ab = ab; 517 irq_grp->grp_id = i; 518 init_dummy_netdev(&irq_grp->napi_ndev); 519 netif_napi_add(&irq_grp->napi_ndev, &irq_grp->napi, 520 ath11k_pcic_ext_grp_napi_poll, NAPI_POLL_WEIGHT); 521 522 if (ab->hw_params.ring_mask->tx[i] || 523 ab->hw_params.ring_mask->rx[i] || 524 ab->hw_params.ring_mask->rx_err[i] || 525 ab->hw_params.ring_mask->rx_wbm_rel[i] || 526 ab->hw_params.ring_mask->reo_status[i] || 527 ab->hw_params.ring_mask->rxdma2host[i] || 528 ab->hw_params.ring_mask->host2rxdma[i] || 529 ab->hw_params.ring_mask->rx_mon_status[i]) { 530 num_irq = 1; 531 } 532 533 irq_grp->num_irq = num_irq; 534 irq_grp->irqs[0] = ATH11K_PCI_IRQ_DP_OFFSET + i; 535 536 for (j = 0; j < irq_grp->num_irq; j++) { 537 int irq_idx = irq_grp->irqs[j]; 538 int vector = (i % num_vectors) + base_vector; 539 int irq = ath11k_pcic_get_msi_irq(ab, vector); 540 541 if (irq < 0) 542 return irq; 543 544 ab->irq_num[irq_idx] = irq; 545 546 ath11k_dbg(ab, ATH11K_DBG_PCI, 547 "irq:%d group:%d\n", irq, i); 548 549 irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY); 550 ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler, 551 irq_flags, "DP_EXT_IRQ", irq_grp); 552 if (ret) { 553 ath11k_err(ab, "failed request irq %d: %d\n", 554 vector, ret); 555 return ret; 556 } 557 } 558 ath11k_pcic_ext_grp_disable(irq_grp); 559 } 560 561 return 0; 562 } 563 564 int ath11k_pcic_config_irq(struct ath11k_base *ab) 565 { 566 struct ath11k_ce_pipe *ce_pipe; 567 u32 msi_data_start; 568 u32 msi_data_count, msi_data_idx; 569 u32 msi_irq_start; 570 unsigned int msi_data; 571 int irq, i, ret, irq_idx; 572 unsigned long irq_flags; 573 574 ret = ath11k_pcic_get_user_msi_assignment(ab, "CE", &msi_data_count, 575 &msi_data_start, &msi_irq_start); 576 if (ret) 577 return ret; 578 579 irq_flags = IRQF_SHARED; 580 if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) 581 irq_flags |= IRQF_NOBALANCING; 582 583 /* Configure CE irqs */ 584 for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { 585 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 586 continue; 587 588 msi_data = (msi_data_idx % msi_data_count) + msi_irq_start; 589 irq = ath11k_pcic_get_msi_irq(ab, msi_data); 590 if (irq < 0) 591 return irq; 592 593 ce_pipe = &ab->ce.ce_pipe[i]; 594 595 irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i; 596 597 tasklet_setup(&ce_pipe->intr_tq, ath11k_pcic_ce_tasklet); 598 599 ret = request_irq(irq, ath11k_pcic_ce_interrupt_handler, 600 irq_flags, irq_name[irq_idx], ce_pipe); 601 if (ret) { 602 ath11k_err(ab, "failed to request irq %d: %d\n", 603 irq_idx, ret); 604 return ret; 605 } 606 607 ab->irq_num[irq_idx] = irq; 608 msi_data_idx++; 609 610 ath11k_pcic_ce_irq_disable(ab, i); 611 } 612 613 ret = ath11k_pcic_ext_irq_config(ab); 614 if (ret) 615 return ret; 616 617 return 0; 618 } 619 EXPORT_SYMBOL(ath11k_pcic_config_irq); 620 621 void ath11k_pcic_ce_irqs_enable(struct ath11k_base *ab) 622 { 623 int i; 624 625 set_bit(ATH11K_FLAG_CE_IRQ_ENABLED, &ab->dev_flags); 626 627 for (i = 0; i < ab->hw_params.ce_count; i++) { 628 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 629 continue; 630 ath11k_pcic_ce_irq_enable(ab, i); 631 } 632 } 633 EXPORT_SYMBOL(ath11k_pcic_ce_irqs_enable); 634 635 static void ath11k_pcic_kill_tasklets(struct ath11k_base *ab) 636 { 637 int i; 638 639 for (i = 0; i < ab->hw_params.ce_count; i++) { 640 struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i]; 641 642 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) 643 continue; 644 645 tasklet_kill(&ce_pipe->intr_tq); 646 } 647 } 648 649 void ath11k_pcic_ce_irq_disable_sync(struct ath11k_base *ab) 650 { 651 ath11k_pcic_ce_irqs_disable(ab); 652 ath11k_pcic_sync_ce_irqs(ab); 653 ath11k_pcic_kill_tasklets(ab); 654 } 655 EXPORT_SYMBOL(ath11k_pcic_ce_irq_disable_sync); 656 657 void ath11k_pcic_stop(struct ath11k_base *ab) 658 { 659 ath11k_pcic_ce_irq_disable_sync(ab); 660 ath11k_ce_cleanup_pipes(ab); 661 } 662 EXPORT_SYMBOL(ath11k_pcic_stop); 663 664 int ath11k_pcic_start(struct ath11k_base *ab) 665 { 666 set_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags); 667 668 ath11k_pcic_ce_irqs_enable(ab); 669 ath11k_ce_rx_post_buf(ab); 670 671 return 0; 672 } 673 EXPORT_SYMBOL(ath11k_pcic_start); 674 675 int ath11k_pcic_map_service_to_pipe(struct ath11k_base *ab, u16 service_id, 676 u8 *ul_pipe, u8 *dl_pipe) 677 { 678 const struct service_to_pipe *entry; 679 bool ul_set = false, dl_set = false; 680 int i; 681 682 for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) { 683 entry = &ab->hw_params.svc_to_ce_map[i]; 684 685 if (__le32_to_cpu(entry->service_id) != service_id) 686 continue; 687 688 switch (__le32_to_cpu(entry->pipedir)) { 689 case PIPEDIR_NONE: 690 break; 691 case PIPEDIR_IN: 692 WARN_ON(dl_set); 693 *dl_pipe = __le32_to_cpu(entry->pipenum); 694 dl_set = true; 695 break; 696 case PIPEDIR_OUT: 697 WARN_ON(ul_set); 698 *ul_pipe = __le32_to_cpu(entry->pipenum); 699 ul_set = true; 700 break; 701 case PIPEDIR_INOUT: 702 WARN_ON(dl_set); 703 WARN_ON(ul_set); 704 *dl_pipe = __le32_to_cpu(entry->pipenum); 705 *ul_pipe = __le32_to_cpu(entry->pipenum); 706 dl_set = true; 707 ul_set = true; 708 break; 709 } 710 } 711 712 if (WARN_ON(!ul_set || !dl_set)) 713 return -ENOENT; 714 715 return 0; 716 } 717 EXPORT_SYMBOL(ath11k_pcic_map_service_to_pipe); 718 719 int ath11k_pcic_register_pci_ops(struct ath11k_base *ab, 720 const struct ath11k_pci_ops *pci_ops) 721 { 722 if (!pci_ops) 723 return 0; 724 725 /* Return error if mandatory pci_ops callbacks are missing */ 726 if (!pci_ops->get_msi_irq || !pci_ops->window_write32 || 727 !pci_ops->window_read32) 728 return -EINVAL; 729 730 ab->pci.ops = pci_ops; 731 return 0; 732 } 733 EXPORT_SYMBOL(ath11k_pcic_register_pci_ops); 734