1329 lines · c
1// SPDX-License-Identifier: BSD-3-Clause-Clear2/*3 * Copyright (c) 2018-2019 The Linux Foundation. All rights reserved.4 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.5 */6 7#include <linux/module.h>8#include <linux/platform_device.h>9#include <linux/property.h>10#include <linux/of_device.h>11#include <linux/of.h>12#include <linux/dma-mapping.h>13#include <linux/of_address.h>14#include <linux/iommu.h>15#include "ahb.h"16#include "debug.h"17#include "hif.h"18#include "qmi.h"19#include <linux/remoteproc.h>20#include "pcic.h"21#include <linux/soc/qcom/smem.h>22#include <linux/soc/qcom/smem_state.h>23 24static const struct of_device_id ath11k_ahb_of_match[] = {25 /* TODO: Should we change the compatible string to something similar26 * to one that ath10k uses?27 */28 { .compatible = "qcom,ipq8074-wifi",29 .data = (void *)ATH11K_HW_IPQ8074,30 },31 { .compatible = "qcom,ipq6018-wifi",32 .data = (void *)ATH11K_HW_IPQ6018_HW10,33 },34 { .compatible = "qcom,wcn6750-wifi",35 .data = (void *)ATH11K_HW_WCN6750_HW10,36 },37 { .compatible = "qcom,ipq5018-wifi",38 .data = (void *)ATH11K_HW_IPQ5018_HW10,39 },40 { }41};42 43MODULE_DEVICE_TABLE(of, ath11k_ahb_of_match);44 45#define ATH11K_IRQ_CE0_OFFSET 446 47static const char *irq_name[ATH11K_IRQ_NUM_MAX] = {48 "misc-pulse1",49 "misc-latch",50 "sw-exception",51 "watchdog",52 "ce0",53 "ce1",54 "ce2",55 "ce3",56 "ce4",57 "ce5",58 "ce6",59 "ce7",60 "ce8",61 "ce9",62 "ce10",63 "ce11",64 "host2wbm-desc-feed",65 "host2reo-re-injection",66 "host2reo-command",67 "host2rxdma-monitor-ring3",68 "host2rxdma-monitor-ring2",69 "host2rxdma-monitor-ring1",70 "reo2ost-exception",71 "wbm2host-rx-release",72 "reo2host-status",73 "reo2host-destination-ring4",74 "reo2host-destination-ring3",75 "reo2host-destination-ring2",76 "reo2host-destination-ring1",77 "rxdma2host-monitor-destination-mac3",78 "rxdma2host-monitor-destination-mac2",79 "rxdma2host-monitor-destination-mac1",80 "ppdu-end-interrupts-mac3",81 "ppdu-end-interrupts-mac2",82 "ppdu-end-interrupts-mac1",83 "rxdma2host-monitor-status-ring-mac3",84 "rxdma2host-monitor-status-ring-mac2",85 "rxdma2host-monitor-status-ring-mac1",86 "host2rxdma-host-buf-ring-mac3",87 "host2rxdma-host-buf-ring-mac2",88 "host2rxdma-host-buf-ring-mac1",89 "rxdma2host-destination-ring-mac3",90 "rxdma2host-destination-ring-mac2",91 "rxdma2host-destination-ring-mac1",92 "host2tcl-input-ring4",93 "host2tcl-input-ring3",94 "host2tcl-input-ring2",95 "host2tcl-input-ring1",96 "wbm2host-tx-completions-ring3",97 "wbm2host-tx-completions-ring2",98 "wbm2host-tx-completions-ring1",99 "tcl2host-status-ring",100};101 102/* enum ext_irq_num - irq numbers that can be used by external modules103 * like datapath104 */105enum ext_irq_num {106 host2wbm_desc_feed = 16,107 host2reo_re_injection,108 host2reo_command,109 host2rxdma_monitor_ring3,110 host2rxdma_monitor_ring2,111 host2rxdma_monitor_ring1,112 reo2host_exception,113 wbm2host_rx_release,114 reo2host_status,115 reo2host_destination_ring4,116 reo2host_destination_ring3,117 reo2host_destination_ring2,118 reo2host_destination_ring1,119 rxdma2host_monitor_destination_mac3,120 rxdma2host_monitor_destination_mac2,121 rxdma2host_monitor_destination_mac1,122 ppdu_end_interrupts_mac3,123 ppdu_end_interrupts_mac2,124 ppdu_end_interrupts_mac1,125 rxdma2host_monitor_status_ring_mac3,126 rxdma2host_monitor_status_ring_mac2,127 rxdma2host_monitor_status_ring_mac1,128 host2rxdma_host_buf_ring_mac3,129 host2rxdma_host_buf_ring_mac2,130 host2rxdma_host_buf_ring_mac1,131 rxdma2host_destination_ring_mac3,132 rxdma2host_destination_ring_mac2,133 rxdma2host_destination_ring_mac1,134 host2tcl_input_ring4,135 host2tcl_input_ring3,136 host2tcl_input_ring2,137 host2tcl_input_ring1,138 wbm2host_tx_completions_ring3,139 wbm2host_tx_completions_ring2,140 wbm2host_tx_completions_ring1,141 tcl2host_status_ring,142};143 144static int145ath11k_ahb_get_msi_irq_wcn6750(struct ath11k_base *ab, unsigned int vector)146{147 return ab->pci.msi.irqs[vector];148}149 150static inline u32151ath11k_ahb_get_window_start_wcn6750(struct ath11k_base *ab, u32 offset)152{153 u32 window_start = 0;154 155 /* If offset lies within DP register range, use 1st window */156 if ((offset ^ HAL_SEQ_WCSS_UMAC_OFFSET) < ATH11K_PCI_WINDOW_RANGE_MASK)157 window_start = ATH11K_PCI_WINDOW_START;158 /* If offset lies within CE register range, use 2nd window */159 else if ((offset ^ HAL_SEQ_WCSS_UMAC_CE0_SRC_REG(ab)) <160 ATH11K_PCI_WINDOW_RANGE_MASK)161 window_start = 2 * ATH11K_PCI_WINDOW_START;162 163 return window_start;164}165 166static void167ath11k_ahb_window_write32_wcn6750(struct ath11k_base *ab, u32 offset, u32 value)168{169 u32 window_start;170 171 /* WCN6750 uses static window based register access*/172 window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);173 174 iowrite32(value, ab->mem + window_start +175 (offset & ATH11K_PCI_WINDOW_RANGE_MASK));176}177 178static u32 ath11k_ahb_window_read32_wcn6750(struct ath11k_base *ab, u32 offset)179{180 u32 window_start;181 u32 val;182 183 /* WCN6750 uses static window based register access */184 window_start = ath11k_ahb_get_window_start_wcn6750(ab, offset);185 186 val = ioread32(ab->mem + window_start +187 (offset & ATH11K_PCI_WINDOW_RANGE_MASK));188 return val;189}190 191static const struct ath11k_pci_ops ath11k_ahb_pci_ops_wcn6750 = {192 .wakeup = NULL,193 .release = NULL,194 .get_msi_irq = ath11k_ahb_get_msi_irq_wcn6750,195 .window_write32 = ath11k_ahb_window_write32_wcn6750,196 .window_read32 = ath11k_ahb_window_read32_wcn6750,197};198 199static inline u32 ath11k_ahb_read32(struct ath11k_base *ab, u32 offset)200{201 return ioread32(ab->mem + offset);202}203 204static inline void ath11k_ahb_write32(struct ath11k_base *ab, u32 offset, u32 value)205{206 iowrite32(value, ab->mem + offset);207}208 209static void ath11k_ahb_kill_tasklets(struct ath11k_base *ab)210{211 int i;212 213 for (i = 0; i < ab->hw_params.ce_count; i++) {214 struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];215 216 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)217 continue;218 219 tasklet_kill(&ce_pipe->intr_tq);220 }221}222 223static void ath11k_ahb_ext_grp_disable(struct ath11k_ext_irq_grp *irq_grp)224{225 int i;226 227 for (i = 0; i < irq_grp->num_irq; i++)228 disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);229}230 231static void __ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)232{233 int i;234 235 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {236 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];237 238 ath11k_ahb_ext_grp_disable(irq_grp);239 240 if (irq_grp->napi_enabled) {241 napi_synchronize(&irq_grp->napi);242 napi_disable(&irq_grp->napi);243 irq_grp->napi_enabled = false;244 }245 }246}247 248static void ath11k_ahb_ext_grp_enable(struct ath11k_ext_irq_grp *irq_grp)249{250 int i;251 252 for (i = 0; i < irq_grp->num_irq; i++)253 enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);254}255 256static void ath11k_ahb_setbit32(struct ath11k_base *ab, u8 bit, u32 offset)257{258 u32 val;259 260 val = ath11k_ahb_read32(ab, offset);261 ath11k_ahb_write32(ab, offset, val | BIT(bit));262}263 264static void ath11k_ahb_clearbit32(struct ath11k_base *ab, u8 bit, u32 offset)265{266 u32 val;267 268 val = ath11k_ahb_read32(ab, offset);269 ath11k_ahb_write32(ab, offset, val & ~BIT(bit));270}271 272static void ath11k_ahb_ce_irq_enable(struct ath11k_base *ab, u16 ce_id)273{274 const struct ce_attr *ce_attr;275 const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;276 u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;277 278 ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);279 ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);280 ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);281 282 ce_attr = &ab->hw_params.host_ce_config[ce_id];283 if (ce_attr->src_nentries)284 ath11k_ahb_setbit32(ab, ce_id, ie1_reg_addr);285 286 if (ce_attr->dest_nentries) {287 ath11k_ahb_setbit32(ab, ce_id, ie2_reg_addr);288 ath11k_ahb_setbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,289 ie3_reg_addr);290 }291}292 293static void ath11k_ahb_ce_irq_disable(struct ath11k_base *ab, u16 ce_id)294{295 const struct ce_attr *ce_attr;296 const struct ce_ie_addr *ce_ie_addr = ab->hw_params.ce_ie_addr;297 u32 ie1_reg_addr, ie2_reg_addr, ie3_reg_addr;298 299 ie1_reg_addr = ce_ie_addr->ie1_reg_addr + ATH11K_CE_OFFSET(ab);300 ie2_reg_addr = ce_ie_addr->ie2_reg_addr + ATH11K_CE_OFFSET(ab);301 ie3_reg_addr = ce_ie_addr->ie3_reg_addr + ATH11K_CE_OFFSET(ab);302 303 ce_attr = &ab->hw_params.host_ce_config[ce_id];304 if (ce_attr->src_nentries)305 ath11k_ahb_clearbit32(ab, ce_id, ie1_reg_addr);306 307 if (ce_attr->dest_nentries) {308 ath11k_ahb_clearbit32(ab, ce_id, ie2_reg_addr);309 ath11k_ahb_clearbit32(ab, ce_id + CE_HOST_IE_3_SHIFT,310 ie3_reg_addr);311 }312}313 314static void ath11k_ahb_sync_ce_irqs(struct ath11k_base *ab)315{316 int i;317 int irq_idx;318 319 for (i = 0; i < ab->hw_params.ce_count; i++) {320 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)321 continue;322 323 irq_idx = ATH11K_IRQ_CE0_OFFSET + i;324 synchronize_irq(ab->irq_num[irq_idx]);325 }326}327 328static void ath11k_ahb_sync_ext_irqs(struct ath11k_base *ab)329{330 int i, j;331 int irq_idx;332 333 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {334 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];335 336 for (j = 0; j < irq_grp->num_irq; j++) {337 irq_idx = irq_grp->irqs[j];338 synchronize_irq(ab->irq_num[irq_idx]);339 }340 }341}342 343static void ath11k_ahb_ce_irqs_enable(struct ath11k_base *ab)344{345 int i;346 347 for (i = 0; i < ab->hw_params.ce_count; i++) {348 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)349 continue;350 ath11k_ahb_ce_irq_enable(ab, i);351 }352}353 354static void ath11k_ahb_ce_irqs_disable(struct ath11k_base *ab)355{356 int i;357 358 for (i = 0; i < ab->hw_params.ce_count; i++) {359 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)360 continue;361 ath11k_ahb_ce_irq_disable(ab, i);362 }363}364 365static int ath11k_ahb_start(struct ath11k_base *ab)366{367 ath11k_ahb_ce_irqs_enable(ab);368 ath11k_ce_rx_post_buf(ab);369 370 return 0;371}372 373static void ath11k_ahb_ext_irq_enable(struct ath11k_base *ab)374{375 int i;376 377 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {378 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];379 380 if (!irq_grp->napi_enabled) {381 napi_enable(&irq_grp->napi);382 irq_grp->napi_enabled = true;383 }384 ath11k_ahb_ext_grp_enable(irq_grp);385 }386}387 388static void ath11k_ahb_ext_irq_disable(struct ath11k_base *ab)389{390 __ath11k_ahb_ext_irq_disable(ab);391 ath11k_ahb_sync_ext_irqs(ab);392}393 394static void ath11k_ahb_stop(struct ath11k_base *ab)395{396 if (!test_bit(ATH11K_FLAG_CRASH_FLUSH, &ab->dev_flags))397 ath11k_ahb_ce_irqs_disable(ab);398 ath11k_ahb_sync_ce_irqs(ab);399 ath11k_ahb_kill_tasklets(ab);400 del_timer_sync(&ab->rx_replenish_retry);401 ath11k_ce_cleanup_pipes(ab);402}403 404static int ath11k_ahb_power_up(struct ath11k_base *ab)405{406 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);407 int ret;408 409 ret = rproc_boot(ab_ahb->tgt_rproc);410 if (ret)411 ath11k_err(ab, "failed to boot the remote processor Q6\n");412 413 return ret;414}415 416static void ath11k_ahb_power_down(struct ath11k_base *ab)417{418 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);419 420 rproc_shutdown(ab_ahb->tgt_rproc);421}422 423static void ath11k_ahb_init_qmi_ce_config(struct ath11k_base *ab)424{425 struct ath11k_qmi_ce_cfg *cfg = &ab->qmi.ce_cfg;426 427 cfg->tgt_ce_len = ab->hw_params.target_ce_count;428 cfg->tgt_ce = ab->hw_params.target_ce_config;429 cfg->svc_to_ce_map_len = ab->hw_params.svc_to_ce_map_len;430 cfg->svc_to_ce_map = ab->hw_params.svc_to_ce_map;431 ab->qmi.service_ins_id = ab->hw_params.qmi_service_ins_id;432}433 434static void ath11k_ahb_free_ext_irq(struct ath11k_base *ab)435{436 int i, j;437 438 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {439 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];440 441 for (j = 0; j < irq_grp->num_irq; j++)442 free_irq(ab->irq_num[irq_grp->irqs[j]], irq_grp);443 444 netif_napi_del(&irq_grp->napi);445 free_netdev(irq_grp->napi_ndev);446 }447}448 449static void ath11k_ahb_free_irq(struct ath11k_base *ab)450{451 int irq_idx;452 int i;453 454 if (ab->hw_params.hybrid_bus_type)455 return ath11k_pcic_free_irq(ab);456 457 for (i = 0; i < ab->hw_params.ce_count; i++) {458 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)459 continue;460 irq_idx = ATH11K_IRQ_CE0_OFFSET + i;461 free_irq(ab->irq_num[irq_idx], &ab->ce.ce_pipe[i]);462 }463 464 ath11k_ahb_free_ext_irq(ab);465}466 467static void ath11k_ahb_ce_tasklet(struct tasklet_struct *t)468{469 struct ath11k_ce_pipe *ce_pipe = from_tasklet(ce_pipe, t, intr_tq);470 471 ath11k_ce_per_engine_service(ce_pipe->ab, ce_pipe->pipe_num);472 473 ath11k_ahb_ce_irq_enable(ce_pipe->ab, ce_pipe->pipe_num);474}475 476static irqreturn_t ath11k_ahb_ce_interrupt_handler(int irq, void *arg)477{478 struct ath11k_ce_pipe *ce_pipe = arg;479 480 /* last interrupt received for this CE */481 ce_pipe->timestamp = jiffies;482 483 ath11k_ahb_ce_irq_disable(ce_pipe->ab, ce_pipe->pipe_num);484 485 tasklet_schedule(&ce_pipe->intr_tq);486 487 return IRQ_HANDLED;488}489 490static int ath11k_ahb_ext_grp_napi_poll(struct napi_struct *napi, int budget)491{492 struct ath11k_ext_irq_grp *irq_grp = container_of(napi,493 struct ath11k_ext_irq_grp,494 napi);495 struct ath11k_base *ab = irq_grp->ab;496 int work_done;497 498 work_done = ath11k_dp_service_srng(ab, irq_grp, budget);499 if (work_done < budget) {500 napi_complete_done(napi, work_done);501 ath11k_ahb_ext_grp_enable(irq_grp);502 }503 504 if (work_done > budget)505 work_done = budget;506 507 return work_done;508}509 510static irqreturn_t ath11k_ahb_ext_interrupt_handler(int irq, void *arg)511{512 struct ath11k_ext_irq_grp *irq_grp = arg;513 514 /* last interrupt received for this group */515 irq_grp->timestamp = jiffies;516 517 ath11k_ahb_ext_grp_disable(irq_grp);518 519 napi_schedule(&irq_grp->napi);520 521 return IRQ_HANDLED;522}523 524static int ath11k_ahb_config_ext_irq(struct ath11k_base *ab)525{526 struct ath11k_hw_params *hw = &ab->hw_params;527 int i, j;528 int irq;529 int ret;530 531 for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) {532 struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];533 u32 num_irq = 0;534 535 irq_grp->ab = ab;536 irq_grp->grp_id = i;537 538 irq_grp->napi_ndev = alloc_netdev_dummy(0);539 if (!irq_grp->napi_ndev)540 return -ENOMEM;541 542 netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,543 ath11k_ahb_ext_grp_napi_poll);544 545 for (j = 0; j < ATH11K_EXT_IRQ_NUM_MAX; j++) {546 if (ab->hw_params.ring_mask->tx[i] & BIT(j)) {547 irq_grp->irqs[num_irq++] =548 wbm2host_tx_completions_ring1 - j;549 }550 551 if (ab->hw_params.ring_mask->rx[i] & BIT(j)) {552 irq_grp->irqs[num_irq++] =553 reo2host_destination_ring1 - j;554 }555 556 if (ab->hw_params.ring_mask->rx_err[i] & BIT(j))557 irq_grp->irqs[num_irq++] = reo2host_exception;558 559 if (ab->hw_params.ring_mask->rx_wbm_rel[i] & BIT(j))560 irq_grp->irqs[num_irq++] = wbm2host_rx_release;561 562 if (ab->hw_params.ring_mask->reo_status[i] & BIT(j))563 irq_grp->irqs[num_irq++] = reo2host_status;564 565 if (j < ab->hw_params.max_radios) {566 if (ab->hw_params.ring_mask->rxdma2host[i] & BIT(j)) {567 irq_grp->irqs[num_irq++] =568 rxdma2host_destination_ring_mac1 -569 ath11k_hw_get_mac_from_pdev_id(hw, j);570 }571 572 if (ab->hw_params.ring_mask->host2rxdma[i] & BIT(j)) {573 irq_grp->irqs[num_irq++] =574 host2rxdma_host_buf_ring_mac1 -575 ath11k_hw_get_mac_from_pdev_id(hw, j);576 }577 578 if (ab->hw_params.ring_mask->rx_mon_status[i] & BIT(j)) {579 irq_grp->irqs[num_irq++] =580 ppdu_end_interrupts_mac1 -581 ath11k_hw_get_mac_from_pdev_id(hw, j);582 irq_grp->irqs[num_irq++] =583 rxdma2host_monitor_status_ring_mac1 -584 ath11k_hw_get_mac_from_pdev_id(hw, j);585 }586 }587 }588 irq_grp->num_irq = num_irq;589 590 for (j = 0; j < irq_grp->num_irq; j++) {591 int irq_idx = irq_grp->irqs[j];592 593 irq = platform_get_irq_byname(ab->pdev,594 irq_name[irq_idx]);595 ab->irq_num[irq_idx] = irq;596 irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_DISABLE_UNLAZY);597 ret = request_irq(irq, ath11k_ahb_ext_interrupt_handler,598 IRQF_TRIGGER_RISING,599 irq_name[irq_idx], irq_grp);600 if (ret) {601 ath11k_err(ab, "failed request_irq for %d\n",602 irq);603 }604 }605 }606 607 return 0;608}609 610static int ath11k_ahb_config_irq(struct ath11k_base *ab)611{612 int irq, irq_idx, i;613 int ret;614 615 if (ab->hw_params.hybrid_bus_type)616 return ath11k_pcic_config_irq(ab);617 618 /* Configure CE irqs */619 for (i = 0; i < ab->hw_params.ce_count; i++) {620 struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];621 622 if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR)623 continue;624 625 irq_idx = ATH11K_IRQ_CE0_OFFSET + i;626 627 tasklet_setup(&ce_pipe->intr_tq, ath11k_ahb_ce_tasklet);628 irq = platform_get_irq_byname(ab->pdev, irq_name[irq_idx]);629 ret = request_irq(irq, ath11k_ahb_ce_interrupt_handler,630 IRQF_TRIGGER_RISING, irq_name[irq_idx],631 ce_pipe);632 if (ret)633 return ret;634 635 ab->irq_num[irq_idx] = irq;636 }637 638 /* Configure external interrupts */639 ret = ath11k_ahb_config_ext_irq(ab);640 641 return ret;642}643 644static int ath11k_ahb_map_service_to_pipe(struct ath11k_base *ab, u16 service_id,645 u8 *ul_pipe, u8 *dl_pipe)646{647 const struct service_to_pipe *entry;648 bool ul_set = false, dl_set = false;649 int i;650 651 for (i = 0; i < ab->hw_params.svc_to_ce_map_len; i++) {652 entry = &ab->hw_params.svc_to_ce_map[i];653 654 if (__le32_to_cpu(entry->service_id) != service_id)655 continue;656 657 switch (__le32_to_cpu(entry->pipedir)) {658 case PIPEDIR_NONE:659 break;660 case PIPEDIR_IN:661 WARN_ON(dl_set);662 *dl_pipe = __le32_to_cpu(entry->pipenum);663 dl_set = true;664 break;665 case PIPEDIR_OUT:666 WARN_ON(ul_set);667 *ul_pipe = __le32_to_cpu(entry->pipenum);668 ul_set = true;669 break;670 case PIPEDIR_INOUT:671 WARN_ON(dl_set);672 WARN_ON(ul_set);673 *dl_pipe = __le32_to_cpu(entry->pipenum);674 *ul_pipe = __le32_to_cpu(entry->pipenum);675 dl_set = true;676 ul_set = true;677 break;678 }679 }680 681 if (WARN_ON(!ul_set || !dl_set))682 return -ENOENT;683 684 return 0;685}686 687static int ath11k_ahb_hif_suspend(struct ath11k_base *ab)688{689 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);690 u32 wake_irq;691 u32 value = 0;692 int ret;693 694 if (!device_may_wakeup(ab->dev))695 return -EPERM;696 697 wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];698 699 ret = enable_irq_wake(wake_irq);700 if (ret) {701 ath11k_err(ab, "failed to enable wakeup irq :%d\n", ret);702 return ret;703 }704 705 value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,706 ATH11K_AHB_SMP2P_SMEM_SEQ_NO);707 value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_ENTER,708 ATH11K_AHB_SMP2P_SMEM_MSG);709 710 ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,711 ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);712 if (ret) {713 ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);714 return ret;715 }716 717 ath11k_dbg(ab, ATH11K_DBG_AHB, "device suspended\n");718 719 return ret;720}721 722static int ath11k_ahb_hif_resume(struct ath11k_base *ab)723{724 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);725 u32 wake_irq;726 u32 value = 0;727 int ret;728 729 if (!device_may_wakeup(ab->dev))730 return -EPERM;731 732 wake_irq = ab->irq_num[ATH11K_PCI_IRQ_CE0_OFFSET + ATH11K_PCI_CE_WAKE_IRQ];733 734 ret = disable_irq_wake(wake_irq);735 if (ret) {736 ath11k_err(ab, "failed to disable wakeup irq: %d\n", ret);737 return ret;738 }739 740 reinit_completion(&ab->wow.wakeup_completed);741 742 value = u32_encode_bits(ab_ahb->smp2p_info.seq_no++,743 ATH11K_AHB_SMP2P_SMEM_SEQ_NO);744 value |= u32_encode_bits(ATH11K_AHB_POWER_SAVE_EXIT,745 ATH11K_AHB_SMP2P_SMEM_MSG);746 747 ret = qcom_smem_state_update_bits(ab_ahb->smp2p_info.smem_state,748 ATH11K_AHB_SMP2P_SMEM_VALUE_MASK, value);749 if (ret) {750 ath11k_err(ab, "failed to send smp2p power save enter cmd :%d\n", ret);751 return ret;752 }753 754 ret = wait_for_completion_timeout(&ab->wow.wakeup_completed, 3 * HZ);755 if (ret == 0) {756 ath11k_warn(ab, "timed out while waiting for wow wakeup completion\n");757 return -ETIMEDOUT;758 }759 760 ath11k_dbg(ab, ATH11K_DBG_AHB, "device resumed\n");761 762 return 0;763}764 765static const struct ath11k_hif_ops ath11k_ahb_hif_ops_ipq8074 = {766 .start = ath11k_ahb_start,767 .stop = ath11k_ahb_stop,768 .read32 = ath11k_ahb_read32,769 .write32 = ath11k_ahb_write32,770 .read = NULL,771 .irq_enable = ath11k_ahb_ext_irq_enable,772 .irq_disable = ath11k_ahb_ext_irq_disable,773 .map_service_to_pipe = ath11k_ahb_map_service_to_pipe,774 .power_down = ath11k_ahb_power_down,775 .power_up = ath11k_ahb_power_up,776};777 778static const struct ath11k_hif_ops ath11k_ahb_hif_ops_wcn6750 = {779 .start = ath11k_pcic_start,780 .stop = ath11k_pcic_stop,781 .read32 = ath11k_pcic_read32,782 .write32 = ath11k_pcic_write32,783 .read = NULL,784 .irq_enable = ath11k_pcic_ext_irq_enable,785 .irq_disable = ath11k_pcic_ext_irq_disable,786 .get_msi_address = ath11k_pcic_get_msi_address,787 .get_user_msi_vector = ath11k_pcic_get_user_msi_assignment,788 .map_service_to_pipe = ath11k_pcic_map_service_to_pipe,789 .power_down = ath11k_ahb_power_down,790 .power_up = ath11k_ahb_power_up,791 .suspend = ath11k_ahb_hif_suspend,792 .resume = ath11k_ahb_hif_resume,793 .ce_irq_enable = ath11k_pci_enable_ce_irqs_except_wake_irq,794 .ce_irq_disable = ath11k_pci_disable_ce_irqs_except_wake_irq,795};796 797static int ath11k_core_get_rproc(struct ath11k_base *ab)798{799 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);800 struct device *dev = ab->dev;801 struct rproc *prproc;802 phandle rproc_phandle;803 804 if (of_property_read_u32(dev->of_node, "qcom,rproc", &rproc_phandle)) {805 ath11k_err(ab, "failed to get q6_rproc handle\n");806 return -ENOENT;807 }808 809 prproc = rproc_get_by_phandle(rproc_phandle);810 if (!prproc) {811 ath11k_dbg(ab, ATH11K_DBG_AHB, "failed to get rproc, deferring\n");812 return -EPROBE_DEFER;813 }814 ab_ahb->tgt_rproc = prproc;815 816 return 0;817}818 819static int ath11k_ahb_setup_msi_resources(struct ath11k_base *ab)820{821 struct platform_device *pdev = ab->pdev;822 phys_addr_t msi_addr_pa;823 dma_addr_t msi_addr_iova;824 struct resource *res;825 int int_prop;826 int ret;827 int i;828 829 ret = ath11k_pcic_init_msi_config(ab);830 if (ret) {831 ath11k_err(ab, "failed to init msi config: %d\n", ret);832 return ret;833 }834 835 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);836 if (!res) {837 ath11k_err(ab, "failed to fetch msi_addr\n");838 return -ENOENT;839 }840 841 msi_addr_pa = res->start;842 msi_addr_iova = dma_map_resource(ab->dev, msi_addr_pa, PAGE_SIZE,843 DMA_FROM_DEVICE, 0);844 if (dma_mapping_error(ab->dev, msi_addr_iova))845 return -ENOMEM;846 847 ab->pci.msi.addr_lo = lower_32_bits(msi_addr_iova);848 ab->pci.msi.addr_hi = upper_32_bits(msi_addr_iova);849 850 ret = of_property_read_u32_index(ab->dev->of_node, "interrupts", 1, &int_prop);851 if (ret)852 return ret;853 854 ab->pci.msi.ep_base_data = int_prop + 32;855 856 for (i = 0; i < ab->pci.msi.config->total_vectors; i++) {857 ret = platform_get_irq(pdev, i);858 if (ret < 0)859 return ret;860 861 ab->pci.msi.irqs[i] = ret;862 }863 864 set_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags);865 866 return 0;867}868 869static int ath11k_ahb_setup_smp2p_handle(struct ath11k_base *ab)870{871 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);872 873 if (!ab->hw_params.smp2p_wow_exit)874 return 0;875 876 ab_ahb->smp2p_info.smem_state = qcom_smem_state_get(ab->dev, "wlan-smp2p-out",877 &ab_ahb->smp2p_info.smem_bit);878 if (IS_ERR(ab_ahb->smp2p_info.smem_state)) {879 ath11k_err(ab, "failed to fetch smem state: %ld\n",880 PTR_ERR(ab_ahb->smp2p_info.smem_state));881 return PTR_ERR(ab_ahb->smp2p_info.smem_state);882 }883 884 return 0;885}886 887static void ath11k_ahb_release_smp2p_handle(struct ath11k_base *ab)888{889 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);890 891 if (!ab->hw_params.smp2p_wow_exit)892 return;893 894 qcom_smem_state_put(ab_ahb->smp2p_info.smem_state);895}896 897static int ath11k_ahb_setup_resources(struct ath11k_base *ab)898{899 struct platform_device *pdev = ab->pdev;900 struct resource *mem_res;901 void __iomem *mem;902 903 if (ab->hw_params.hybrid_bus_type)904 return ath11k_ahb_setup_msi_resources(ab);905 906 mem = devm_platform_get_and_ioremap_resource(pdev, 0, &mem_res);907 if (IS_ERR(mem)) {908 dev_err(&pdev->dev, "ioremap error\n");909 return PTR_ERR(mem);910 }911 912 ab->mem = mem;913 ab->mem_len = resource_size(mem_res);914 915 return 0;916}917 918static int ath11k_ahb_setup_msa_resources(struct ath11k_base *ab)919{920 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);921 struct device *dev = ab->dev;922 struct device_node *node;923 struct resource r;924 int ret;925 926 node = of_parse_phandle(dev->of_node, "memory-region", 0);927 if (!node)928 return -ENOENT;929 930 ret = of_address_to_resource(node, 0, &r);931 of_node_put(node);932 if (ret) {933 dev_err(dev, "failed to resolve msa fixed region\n");934 return ret;935 }936 937 ab_ahb->fw.msa_paddr = r.start;938 ab_ahb->fw.msa_size = resource_size(&r);939 940 node = of_parse_phandle(dev->of_node, "memory-region", 1);941 if (!node)942 return -ENOENT;943 944 ret = of_address_to_resource(node, 0, &r);945 of_node_put(node);946 if (ret) {947 dev_err(dev, "failed to resolve ce fixed region\n");948 return ret;949 }950 951 ab_ahb->fw.ce_paddr = r.start;952 ab_ahb->fw.ce_size = resource_size(&r);953 954 return 0;955}956 957static int ath11k_ahb_ce_remap(struct ath11k_base *ab)958{959 const struct ce_remap *ce_remap = ab->hw_params.ce_remap;960 struct platform_device *pdev = ab->pdev;961 962 if (!ce_remap) {963 /* no separate CE register space */964 ab->mem_ce = ab->mem;965 return 0;966 }967 968 /* ce register space is moved out of wcss unlike ipq8074 or ipq6018969 * and the space is not contiguous, hence remapping the CE registers970 * to a new space for accessing them.971 */972 ab->mem_ce = ioremap(ce_remap->base, ce_remap->size);973 if (!ab->mem_ce) {974 dev_err(&pdev->dev, "ce ioremap error\n");975 return -ENOMEM;976 }977 978 return 0;979}980 981static void ath11k_ahb_ce_unmap(struct ath11k_base *ab)982{983 if (ab->hw_params.ce_remap)984 iounmap(ab->mem_ce);985}986 987static int ath11k_ahb_fw_resources_init(struct ath11k_base *ab)988{989 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);990 struct device *host_dev = ab->dev;991 struct platform_device_info info = {0};992 struct iommu_domain *iommu_dom;993 struct platform_device *pdev;994 struct device_node *node;995 int ret;996 997 /* Chipsets not requiring MSA need not initialize998 * MSA resources, return success in such cases.999 */1000 if (!ab->hw_params.fixed_fw_mem)1001 return 0;1002 1003 ret = ath11k_ahb_setup_msa_resources(ab);1004 if (ret) {1005 ath11k_err(ab, "failed to setup msa resources\n");1006 return ret;1007 }1008 1009 node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");1010 if (!node) {1011 ab_ahb->fw.use_tz = true;1012 return 0;1013 }1014 1015 info.fwnode = &node->fwnode;1016 info.parent = host_dev;1017 info.name = node->name;1018 info.dma_mask = DMA_BIT_MASK(32);1019 1020 pdev = platform_device_register_full(&info);1021 if (IS_ERR(pdev)) {1022 of_node_put(node);1023 return PTR_ERR(pdev);1024 }1025 1026 ret = of_dma_configure(&pdev->dev, node, true);1027 if (ret) {1028 ath11k_err(ab, "dma configure fail: %d\n", ret);1029 goto err_unregister;1030 }1031 1032 ab_ahb->fw.dev = &pdev->dev;1033 1034 iommu_dom = iommu_paging_domain_alloc(ab_ahb->fw.dev);1035 if (IS_ERR(iommu_dom)) {1036 ath11k_err(ab, "failed to allocate iommu domain\n");1037 ret = PTR_ERR(iommu_dom);1038 goto err_unregister;1039 }1040 1041 ret = iommu_attach_device(iommu_dom, ab_ahb->fw.dev);1042 if (ret) {1043 ath11k_err(ab, "could not attach device: %d\n", ret);1044 goto err_iommu_free;1045 }1046 1047 ret = iommu_map(iommu_dom, ab_ahb->fw.msa_paddr,1048 ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size,1049 IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);1050 if (ret) {1051 ath11k_err(ab, "failed to map firmware region: %d\n", ret);1052 goto err_iommu_detach;1053 }1054 1055 ret = iommu_map(iommu_dom, ab_ahb->fw.ce_paddr,1056 ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size,1057 IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);1058 if (ret) {1059 ath11k_err(ab, "failed to map firmware CE region: %d\n", ret);1060 goto err_iommu_unmap;1061 }1062 1063 ab_ahb->fw.use_tz = false;1064 ab_ahb->fw.iommu_domain = iommu_dom;1065 of_node_put(node);1066 1067 return 0;1068 1069err_iommu_unmap:1070 iommu_unmap(iommu_dom, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);1071 1072err_iommu_detach:1073 iommu_detach_device(iommu_dom, ab_ahb->fw.dev);1074 1075err_iommu_free:1076 iommu_domain_free(iommu_dom);1077 1078err_unregister:1079 platform_device_unregister(pdev);1080 of_node_put(node);1081 1082 return ret;1083}1084 1085static int ath11k_ahb_fw_resource_deinit(struct ath11k_base *ab)1086{1087 struct ath11k_ahb *ab_ahb = ath11k_ahb_priv(ab);1088 struct iommu_domain *iommu;1089 size_t unmapped_size;1090 1091 /* Chipsets not requiring MSA would have not initialized1092 * MSA resources, return success in such cases.1093 */1094 if (!ab->hw_params.fixed_fw_mem)1095 return 0;1096 1097 if (ab_ahb->fw.use_tz)1098 return 0;1099 1100 iommu = ab_ahb->fw.iommu_domain;1101 1102 unmapped_size = iommu_unmap(iommu, ab_ahb->fw.msa_paddr, ab_ahb->fw.msa_size);1103 if (unmapped_size != ab_ahb->fw.msa_size)1104 ath11k_err(ab, "failed to unmap firmware: %zu\n",1105 unmapped_size);1106 1107 unmapped_size = iommu_unmap(iommu, ab_ahb->fw.ce_paddr, ab_ahb->fw.ce_size);1108 if (unmapped_size != ab_ahb->fw.ce_size)1109 ath11k_err(ab, "failed to unmap firmware CE memory: %zu\n",1110 unmapped_size);1111 1112 iommu_detach_device(iommu, ab_ahb->fw.dev);1113 iommu_domain_free(iommu);1114 1115 platform_device_unregister(to_platform_device(ab_ahb->fw.dev));1116 1117 return 0;1118}1119 1120static int ath11k_ahb_probe(struct platform_device *pdev)1121{1122 struct ath11k_base *ab;1123 const struct ath11k_hif_ops *hif_ops;1124 const struct ath11k_pci_ops *pci_ops;1125 enum ath11k_hw_rev hw_rev;1126 int ret;1127 1128 hw_rev = (uintptr_t)device_get_match_data(&pdev->dev);1129 1130 switch (hw_rev) {1131 case ATH11K_HW_IPQ8074:1132 case ATH11K_HW_IPQ6018_HW10:1133 case ATH11K_HW_IPQ5018_HW10:1134 hif_ops = &ath11k_ahb_hif_ops_ipq8074;1135 pci_ops = NULL;1136 break;1137 case ATH11K_HW_WCN6750_HW10:1138 hif_ops = &ath11k_ahb_hif_ops_wcn6750;1139 pci_ops = &ath11k_ahb_pci_ops_wcn6750;1140 break;1141 default:1142 dev_err(&pdev->dev, "unsupported device type %d\n", hw_rev);1143 return -EOPNOTSUPP;1144 }1145 1146 ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));1147 if (ret) {1148 dev_err(&pdev->dev, "failed to set 32-bit consistent dma\n");1149 return ret;1150 }1151 1152 ab = ath11k_core_alloc(&pdev->dev, sizeof(struct ath11k_ahb),1153 ATH11K_BUS_AHB);1154 if (!ab) {1155 dev_err(&pdev->dev, "failed to allocate ath11k base\n");1156 return -ENOMEM;1157 }1158 1159 ab->hif.ops = hif_ops;1160 ab->pdev = pdev;1161 ab->hw_rev = hw_rev;1162 ab->fw_mode = ATH11K_FIRMWARE_MODE_NORMAL;1163 platform_set_drvdata(pdev, ab);1164 1165 ret = ath11k_pcic_register_pci_ops(ab, pci_ops);1166 if (ret) {1167 ath11k_err(ab, "failed to register PCI ops: %d\n", ret);1168 goto err_core_free;1169 }1170 1171 ret = ath11k_core_pre_init(ab);1172 if (ret)1173 goto err_core_free;1174 1175 ret = ath11k_ahb_setup_resources(ab);1176 if (ret)1177 goto err_core_free;1178 1179 ret = ath11k_ahb_ce_remap(ab);1180 if (ret)1181 goto err_core_free;1182 1183 ret = ath11k_ahb_fw_resources_init(ab);1184 if (ret)1185 goto err_ce_unmap;1186 1187 ret = ath11k_ahb_setup_smp2p_handle(ab);1188 if (ret)1189 goto err_fw_deinit;1190 1191 ret = ath11k_hal_srng_init(ab);1192 if (ret)1193 goto err_release_smp2p_handle;1194 1195 ret = ath11k_ce_alloc_pipes(ab);1196 if (ret) {1197 ath11k_err(ab, "failed to allocate ce pipes: %d\n", ret);1198 goto err_hal_srng_deinit;1199 }1200 1201 ath11k_ahb_init_qmi_ce_config(ab);1202 1203 ret = ath11k_core_get_rproc(ab);1204 if (ret) {1205 ath11k_err(ab, "failed to get rproc: %d\n", ret);1206 goto err_ce_free;1207 }1208 1209 ret = ath11k_core_init(ab);1210 if (ret) {1211 ath11k_err(ab, "failed to init core: %d\n", ret);1212 goto err_ce_free;1213 }1214 1215 ret = ath11k_ahb_config_irq(ab);1216 if (ret) {1217 ath11k_err(ab, "failed to configure irq: %d\n", ret);1218 goto err_ce_free;1219 }1220 1221 ath11k_qmi_fwreset_from_cold_boot(ab);1222 1223 return 0;1224 1225err_ce_free:1226 ath11k_ce_free_pipes(ab);1227 1228err_hal_srng_deinit:1229 ath11k_hal_srng_deinit(ab);1230 1231err_release_smp2p_handle:1232 ath11k_ahb_release_smp2p_handle(ab);1233 1234err_fw_deinit:1235 ath11k_ahb_fw_resource_deinit(ab);1236 1237err_ce_unmap:1238 ath11k_ahb_ce_unmap(ab);1239 1240err_core_free:1241 ath11k_core_free(ab);1242 platform_set_drvdata(pdev, NULL);1243 1244 return ret;1245}1246 1247static void ath11k_ahb_remove_prepare(struct ath11k_base *ab)1248{1249 unsigned long left;1250 1251 if (test_bit(ATH11K_FLAG_RECOVERY, &ab->dev_flags)) {1252 left = wait_for_completion_timeout(&ab->driver_recovery,1253 ATH11K_AHB_RECOVERY_TIMEOUT);1254 if (!left)1255 ath11k_warn(ab, "failed to receive recovery response completion\n");1256 }1257 1258 set_bit(ATH11K_FLAG_UNREGISTERING, &ab->dev_flags);1259 cancel_work_sync(&ab->restart_work);1260 cancel_work_sync(&ab->qmi.event_work);1261}1262 1263static void ath11k_ahb_free_resources(struct ath11k_base *ab)1264{1265 struct platform_device *pdev = ab->pdev;1266 1267 ath11k_ahb_free_irq(ab);1268 ath11k_hal_srng_deinit(ab);1269 ath11k_ahb_release_smp2p_handle(ab);1270 ath11k_ahb_fw_resource_deinit(ab);1271 ath11k_ce_free_pipes(ab);1272 ath11k_ahb_ce_unmap(ab);1273 1274 ath11k_core_free(ab);1275 platform_set_drvdata(pdev, NULL);1276}1277 1278static void ath11k_ahb_remove(struct platform_device *pdev)1279{1280 struct ath11k_base *ab = platform_get_drvdata(pdev);1281 1282 if (test_bit(ATH11K_FLAG_QMI_FAIL, &ab->dev_flags)) {1283 ath11k_ahb_power_down(ab);1284 ath11k_debugfs_soc_destroy(ab);1285 ath11k_qmi_deinit_service(ab);1286 goto qmi_fail;1287 }1288 1289 ath11k_ahb_remove_prepare(ab);1290 ath11k_core_deinit(ab);1291 1292qmi_fail:1293 ath11k_ahb_free_resources(ab);1294}1295 1296static void ath11k_ahb_shutdown(struct platform_device *pdev)1297{1298 struct ath11k_base *ab = platform_get_drvdata(pdev);1299 1300 /* platform shutdown() & remove() are mutually exclusive.1301 * remove() is invoked during rmmod & shutdown() during1302 * system reboot/shutdown.1303 */1304 ath11k_ahb_remove_prepare(ab);1305 1306 if (!(test_bit(ATH11K_FLAG_REGISTERED, &ab->dev_flags)))1307 goto free_resources;1308 1309 ath11k_core_deinit(ab);1310 1311free_resources:1312 ath11k_ahb_free_resources(ab);1313}1314 1315static struct platform_driver ath11k_ahb_driver = {1316 .driver = {1317 .name = "ath11k",1318 .of_match_table = ath11k_ahb_of_match,1319 },1320 .probe = ath11k_ahb_probe,1321 .remove_new = ath11k_ahb_remove,1322 .shutdown = ath11k_ahb_shutdown,1323};1324 1325module_platform_driver(ath11k_ahb_driver);1326 1327MODULE_DESCRIPTION("Driver support for Qualcomm Technologies 802.11ax WLAN AHB devices");1328MODULE_LICENSE("Dual BSD/GPL");1329