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