Path: blob/main/sys/contrib/dev/athk/ath10k/snoc.c
48378 views
// SPDX-License-Identifier: ISC1/*2* Copyright (c) 2018 The Linux Foundation. All rights reserved.3*/45#include <linux/bits.h>6#include <linux/clk.h>7#include <linux/kernel.h>8#include <linux/module.h>9#include <linux/of.h>10#include <linux/of_device.h>11#include <linux/platform_device.h>12#include <linux/property.h>13#include <linux/regulator/consumer.h>14#include <linux/remoteproc/qcom_rproc.h>15#include <linux/of_address.h>16#include <linux/iommu.h>1718#include "ce.h"19#include "coredump.h"20#include "debug.h"21#include "hif.h"22#include "htc.h"23#include "snoc.h"2425#define ATH10K_SNOC_RX_POST_RETRY_MS 5026#define CE_POLL_PIPE 427#define ATH10K_SNOC_WAKE_IRQ 22829static char *const ce_name[] = {30"WLAN_CE_0",31"WLAN_CE_1",32"WLAN_CE_2",33"WLAN_CE_3",34"WLAN_CE_4",35"WLAN_CE_5",36"WLAN_CE_6",37"WLAN_CE_7",38"WLAN_CE_8",39"WLAN_CE_9",40"WLAN_CE_10",41"WLAN_CE_11",42};4344static const char * const ath10k_regulators[] = {45"vdd-0.8-cx-mx",46"vdd-1.8-xo",47"vdd-1.3-rfa",48"vdd-3.3-ch0",49"vdd-3.3-ch1",50};5152static const char * const ath10k_clocks[] = {53"cxo_ref_clk_pin", "qdss",54};5556static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);57static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);58static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state);59static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state);60static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);61static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);6263static const struct ath10k_snoc_drv_priv drv_priv = {64.hw_rev = ATH10K_HW_WCN3990,65.dma_mask = DMA_BIT_MASK(35),66.msa_size = 0x100000,67};6869#define WCN3990_SRC_WR_IDX_OFFSET 0x3C70#define WCN3990_DST_WR_IDX_OFFSET 0x407172static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {73{74.ce_id = __cpu_to_le16(0),75.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),76},7778{79.ce_id = __cpu_to_le16(3),80.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),81},8283{84.ce_id = __cpu_to_le16(4),85.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),86},8788{89.ce_id = __cpu_to_le16(5),90.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),91},9293{94.ce_id = __cpu_to_le16(7),95.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),96},9798{99.ce_id = __cpu_to_le16(1),100.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),101},102103{104.ce_id = __cpu_to_le16(2),105.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),106},107108{109.ce_id = __cpu_to_le16(7),110.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),111},112113{114.ce_id = __cpu_to_le16(8),115.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),116},117118{119.ce_id = __cpu_to_le16(9),120.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),121},122123{124.ce_id = __cpu_to_le16(10),125.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),126},127128{129.ce_id = __cpu_to_le16(11),130.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),131},132};133134static struct ce_attr host_ce_config_wlan[] = {135/* CE0: host->target HTC control streams */136{137.flags = CE_ATTR_FLAGS,138.src_nentries = 16,139.src_sz_max = 2048,140.dest_nentries = 0,141.send_cb = ath10k_snoc_htc_tx_cb,142},143144/* CE1: target->host HTT + HTC control */145{146.flags = CE_ATTR_FLAGS,147.src_nentries = 0,148.src_sz_max = 2048,149.dest_nentries = 512,150.recv_cb = ath10k_snoc_htt_htc_rx_cb,151},152153/* CE2: target->host WMI */154{155.flags = CE_ATTR_FLAGS,156.src_nentries = 0,157.src_sz_max = 2048,158.dest_nentries = 64,159.recv_cb = ath10k_snoc_htc_rx_cb,160},161162/* CE3: host->target WMI */163{164.flags = CE_ATTR_FLAGS,165.src_nentries = 32,166.src_sz_max = 2048,167.dest_nentries = 0,168.send_cb = ath10k_snoc_htc_tx_cb,169},170171/* CE4: host->target HTT */172{173.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,174.src_nentries = 2048,175.src_sz_max = 256,176.dest_nentries = 0,177.send_cb = ath10k_snoc_htt_tx_cb,178},179180/* CE5: target->host HTT (ipa_uc->target ) */181{182.flags = CE_ATTR_FLAGS,183.src_nentries = 0,184.src_sz_max = 512,185.dest_nentries = 512,186.recv_cb = ath10k_snoc_htt_rx_cb,187},188189/* CE6: target autonomous hif_memcpy */190{191.flags = CE_ATTR_FLAGS,192.src_nentries = 0,193.src_sz_max = 0,194.dest_nentries = 0,195},196197/* CE7: ce_diag, the Diagnostic Window */198{199.flags = CE_ATTR_FLAGS,200.src_nentries = 2,201.src_sz_max = 2048,202.dest_nentries = 2,203},204205/* CE8: Target to uMC */206{207.flags = CE_ATTR_FLAGS,208.src_nentries = 0,209.src_sz_max = 2048,210.dest_nentries = 128,211},212213/* CE9 target->host HTT */214{215.flags = CE_ATTR_FLAGS,216.src_nentries = 0,217.src_sz_max = 2048,218.dest_nentries = 512,219.recv_cb = ath10k_snoc_htt_htc_rx_cb,220},221222/* CE10: target->host HTT */223{224.flags = CE_ATTR_FLAGS,225.src_nentries = 0,226.src_sz_max = 2048,227.dest_nentries = 512,228.recv_cb = ath10k_snoc_htt_htc_rx_cb,229},230231/* CE11: target -> host PKTLOG */232{233.flags = CE_ATTR_FLAGS,234.src_nentries = 0,235.src_sz_max = 2048,236.dest_nentries = 512,237.recv_cb = ath10k_snoc_pktlog_rx_cb,238},239};240241static struct ce_pipe_config target_ce_config_wlan[] = {242/* CE0: host->target HTC control and raw streams */243{244.pipenum = __cpu_to_le32(0),245.pipedir = __cpu_to_le32(PIPEDIR_OUT),246.nentries = __cpu_to_le32(32),247.nbytes_max = __cpu_to_le32(2048),248.flags = __cpu_to_le32(CE_ATTR_FLAGS),249.reserved = __cpu_to_le32(0),250},251252/* CE1: target->host HTT + HTC control */253{254.pipenum = __cpu_to_le32(1),255.pipedir = __cpu_to_le32(PIPEDIR_IN),256.nentries = __cpu_to_le32(32),257.nbytes_max = __cpu_to_le32(2048),258.flags = __cpu_to_le32(CE_ATTR_FLAGS),259.reserved = __cpu_to_le32(0),260},261262/* CE2: target->host WMI */263{264.pipenum = __cpu_to_le32(2),265.pipedir = __cpu_to_le32(PIPEDIR_IN),266.nentries = __cpu_to_le32(64),267.nbytes_max = __cpu_to_le32(2048),268.flags = __cpu_to_le32(CE_ATTR_FLAGS),269.reserved = __cpu_to_le32(0),270},271272/* CE3: host->target WMI */273{274.pipenum = __cpu_to_le32(3),275.pipedir = __cpu_to_le32(PIPEDIR_OUT),276.nentries = __cpu_to_le32(32),277.nbytes_max = __cpu_to_le32(2048),278.flags = __cpu_to_le32(CE_ATTR_FLAGS),279.reserved = __cpu_to_le32(0),280},281282/* CE4: host->target HTT */283{284.pipenum = __cpu_to_le32(4),285.pipedir = __cpu_to_le32(PIPEDIR_OUT),286.nentries = __cpu_to_le32(256),287.nbytes_max = __cpu_to_le32(256),288.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),289.reserved = __cpu_to_le32(0),290},291292/* CE5: target->host HTT (HIF->HTT) */293{294.pipenum = __cpu_to_le32(5),295.pipedir = __cpu_to_le32(PIPEDIR_OUT),296.nentries = __cpu_to_le32(1024),297.nbytes_max = __cpu_to_le32(64),298.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),299.reserved = __cpu_to_le32(0),300},301302/* CE6: Reserved for target autonomous hif_memcpy */303{304.pipenum = __cpu_to_le32(6),305.pipedir = __cpu_to_le32(PIPEDIR_INOUT),306.nentries = __cpu_to_le32(32),307.nbytes_max = __cpu_to_le32(16384),308.flags = __cpu_to_le32(CE_ATTR_FLAGS),309.reserved = __cpu_to_le32(0),310},311312/* CE7 used only by Host */313{314.pipenum = __cpu_to_le32(7),315.pipedir = __cpu_to_le32(4),316.nentries = __cpu_to_le32(0),317.nbytes_max = __cpu_to_le32(0),318.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),319.reserved = __cpu_to_le32(0),320},321322/* CE8 Target to uMC */323{324.pipenum = __cpu_to_le32(8),325.pipedir = __cpu_to_le32(PIPEDIR_IN),326.nentries = __cpu_to_le32(32),327.nbytes_max = __cpu_to_le32(2048),328.flags = __cpu_to_le32(0),329.reserved = __cpu_to_le32(0),330},331332/* CE9 target->host HTT */333{334.pipenum = __cpu_to_le32(9),335.pipedir = __cpu_to_le32(PIPEDIR_IN),336.nentries = __cpu_to_le32(32),337.nbytes_max = __cpu_to_le32(2048),338.flags = __cpu_to_le32(CE_ATTR_FLAGS),339.reserved = __cpu_to_le32(0),340},341342/* CE10 target->host HTT */343{344.pipenum = __cpu_to_le32(10),345.pipedir = __cpu_to_le32(PIPEDIR_IN),346.nentries = __cpu_to_le32(32),347.nbytes_max = __cpu_to_le32(2048),348.flags = __cpu_to_le32(CE_ATTR_FLAGS),349.reserved = __cpu_to_le32(0),350},351352/* CE11 target autonomous qcache memcpy */353{354.pipenum = __cpu_to_le32(11),355.pipedir = __cpu_to_le32(PIPEDIR_IN),356.nentries = __cpu_to_le32(32),357.nbytes_max = __cpu_to_le32(2048),358.flags = __cpu_to_le32(CE_ATTR_FLAGS),359.reserved = __cpu_to_le32(0),360},361};362363static struct ce_service_to_pipe target_service_to_ce_map_wlan[] = {364{365__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),366__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */367__cpu_to_le32(3),368},369{370__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),371__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */372__cpu_to_le32(2),373},374{375__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),376__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */377__cpu_to_le32(3),378},379{380__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),381__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */382__cpu_to_le32(2),383},384{385__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),386__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */387__cpu_to_le32(3),388},389{390__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),391__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */392__cpu_to_le32(2),393},394{395__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),396__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */397__cpu_to_le32(3),398},399{400__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),401__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */402__cpu_to_le32(2),403},404{405__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),406__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */407__cpu_to_le32(3),408},409{410__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),411__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */412__cpu_to_le32(2),413},414{415__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),416__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */417__cpu_to_le32(0),418},419{420__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),421__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */422__cpu_to_le32(2),423},424{ /* not used */425__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),426__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */427__cpu_to_le32(0),428},429{ /* not used */430__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),431__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */432__cpu_to_le32(2),433},434{435__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),436__cpu_to_le32(PIPEDIR_OUT), /* out = UL = host -> target */437__cpu_to_le32(4),438},439{440__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),441__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */442__cpu_to_le32(1),443},444{ /* not used */445__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),446__cpu_to_le32(PIPEDIR_OUT),447__cpu_to_le32(5),448},449{ /* in = DL = target -> host */450__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG),451__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */452__cpu_to_le32(9),453},454{ /* in = DL = target -> host */455__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG),456__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */457__cpu_to_le32(10),458},459{ /* in = DL = target -> host pktlog */460__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG),461__cpu_to_le32(PIPEDIR_IN), /* in = DL = target -> host */462__cpu_to_le32(11),463},464/* (Additions here) */465466{ /* must be last */467__cpu_to_le32(0),468__cpu_to_le32(0),469__cpu_to_le32(0),470},471};472473static void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)474{475struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);476477iowrite32(value, ar_snoc->mem + offset);478}479480static u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)481{482struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);483u32 val;484485val = ioread32(ar_snoc->mem + offset);486487return val;488}489490static int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe)491{492struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;493struct ath10k *ar = pipe->hif_ce_state;494struct ath10k_ce *ce = ath10k_ce_priv(ar);495struct sk_buff *skb;496dma_addr_t paddr;497int ret;498499skb = dev_alloc_skb(pipe->buf_sz);500if (!skb)501return -ENOMEM;502503WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");504505paddr = dma_map_single(ar->dev, skb->data,506skb->len + skb_tailroom(skb),507DMA_FROM_DEVICE);508if (unlikely(dma_mapping_error(ar->dev, paddr))) {509ath10k_warn(ar, "failed to dma map snoc rx buf\n");510dev_kfree_skb_any(skb);511return -EIO;512}513514ATH10K_SKB_RXCB(skb)->paddr = paddr;515516spin_lock_bh(&ce->ce_lock);517ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr);518spin_unlock_bh(&ce->ce_lock);519if (ret) {520dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),521DMA_FROM_DEVICE);522dev_kfree_skb_any(skb);523return ret;524}525526return 0;527}528529static void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe)530{531struct ath10k *ar = pipe->hif_ce_state;532struct ath10k_ce *ce = ath10k_ce_priv(ar);533struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);534struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;535int ret, num;536537if (pipe->buf_sz == 0)538return;539540if (!ce_pipe->dest_ring)541return;542543spin_lock_bh(&ce->ce_lock);544num = __ath10k_ce_rx_num_free_bufs(ce_pipe);545spin_unlock_bh(&ce->ce_lock);546while (num--) {547ret = __ath10k_snoc_rx_post_buf(pipe);548if (ret) {549if (ret == -ENOSPC)550break;551ath10k_warn(ar, "failed to post rx buf: %d\n", ret);552mod_timer(&ar_snoc->rx_post_retry, jiffies +553ATH10K_SNOC_RX_POST_RETRY_MS);554break;555}556}557}558559static void ath10k_snoc_rx_post(struct ath10k *ar)560{561struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);562int i;563564for (i = 0; i < CE_COUNT; i++)565ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]);566}567568static void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state,569void (*callback)(struct ath10k *ar,570struct sk_buff *skb))571{572struct ath10k *ar = ce_state->ar;573struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);574struct ath10k_snoc_pipe *pipe_info = &ar_snoc->pipe_info[ce_state->id];575struct sk_buff *skb;576struct sk_buff_head list;577void *transfer_context;578unsigned int nbytes, max_nbytes;579580__skb_queue_head_init(&list);581while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,582&nbytes) == 0) {583skb = transfer_context;584max_nbytes = skb->len + skb_tailroom(skb);585dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,586max_nbytes, DMA_FROM_DEVICE);587588if (unlikely(max_nbytes < nbytes)) {589ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)\n",590nbytes, max_nbytes);591dev_kfree_skb_any(skb);592continue;593}594595skb_put(skb, nbytes);596__skb_queue_tail(&list, skb);597}598599while ((skb = __skb_dequeue(&list))) {600ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n",601ce_state->id, skb->len);602603callback(ar, skb);604}605606ath10k_snoc_rx_post_pipe(pipe_info);607}608609static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state)610{611ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);612}613614static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)615{616/* CE4 polling needs to be done whenever CE pipe which transports617* HTT Rx (target->host) is processed.618*/619ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);620621ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);622}623624/* Called by lower (CE) layer when data is received from the Target.625* WCN3990 firmware uses separate CE(CE11) to transfer pktlog data.626*/627static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)628{629ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);630}631632static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)633{634skb_pull(skb, sizeof(struct ath10k_htc_hdr));635ath10k_htt_t2h_msg_handler(ar, skb);636}637638static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state)639{640ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);641ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver);642}643644static void ath10k_snoc_rx_replenish_retry(struct timer_list *t)645{646struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry);647struct ath10k *ar = ar_snoc->ar;648649ath10k_snoc_rx_post(ar);650}651652static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)653{654struct ath10k *ar = ce_state->ar;655struct sk_buff_head list;656struct sk_buff *skb;657658__skb_queue_head_init(&list);659while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {660if (!skb)661continue;662663__skb_queue_tail(&list, skb);664}665666while ((skb = __skb_dequeue(&list)))667ath10k_htc_tx_completion_handler(ar, skb);668}669670static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)671{672struct ath10k *ar = ce_state->ar;673struct sk_buff *skb;674675while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {676if (!skb)677continue;678679dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,680skb->len, DMA_TO_DEVICE);681ath10k_htt_hif_tx_complete(ar, skb);682}683}684685static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,686struct ath10k_hif_sg_item *items, int n_items)687{688struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);689struct ath10k_ce *ce = ath10k_ce_priv(ar);690struct ath10k_snoc_pipe *snoc_pipe;691struct ath10k_ce_pipe *ce_pipe;692int err, i = 0;693694snoc_pipe = &ar_snoc->pipe_info[pipe_id];695ce_pipe = snoc_pipe->ce_hdl;696spin_lock_bh(&ce->ce_lock);697698for (i = 0; i < n_items - 1; i++) {699ath10k_dbg(ar, ATH10K_DBG_SNOC,700"snoc tx item %d paddr %pad len %d n_items %d\n",701i, &items[i].paddr, items[i].len, n_items);702703err = ath10k_ce_send_nolock(ce_pipe,704items[i].transfer_context,705items[i].paddr,706items[i].len,707items[i].transfer_id,708CE_SEND_FLAG_GATHER);709if (err)710goto err;711}712713ath10k_dbg(ar, ATH10K_DBG_SNOC,714"snoc tx item %d paddr %pad len %d n_items %d\n",715i, &items[i].paddr, items[i].len, n_items);716717err = ath10k_ce_send_nolock(ce_pipe,718items[i].transfer_context,719items[i].paddr,720items[i].len,721items[i].transfer_id,7220);723if (err)724goto err;725726spin_unlock_bh(&ce->ce_lock);727728return 0;729730err:731for (; i > 0; i--)732__ath10k_ce_send_revert(ce_pipe);733734spin_unlock_bh(&ce->ce_lock);735return err;736}737738static int ath10k_snoc_hif_get_target_info(struct ath10k *ar,739struct bmi_target_info *target_info)740{741target_info->version = ATH10K_HW_WCN3990;742target_info->type = ATH10K_HW_WCN3990;743744return 0;745}746747static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)748{749struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);750751ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");752753return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);754}755756static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,757int force)758{759int resources;760761ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");762763if (!force) {764resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);765766if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))767return;768}769ath10k_ce_per_engine_service(ar, pipe);770}771772static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,773u16 service_id,774u8 *ul_pipe, u8 *dl_pipe)775{776const struct ce_service_to_pipe *entry;777bool ul_set = false, dl_set = false;778int i;779780ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n");781782for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {783entry = &target_service_to_ce_map_wlan[i];784785if (__le32_to_cpu(entry->service_id) != service_id)786continue;787788switch (__le32_to_cpu(entry->pipedir)) {789case PIPEDIR_NONE:790break;791case PIPEDIR_IN:792WARN_ON(dl_set);793*dl_pipe = __le32_to_cpu(entry->pipenum);794dl_set = true;795break;796case PIPEDIR_OUT:797WARN_ON(ul_set);798*ul_pipe = __le32_to_cpu(entry->pipenum);799ul_set = true;800break;801case PIPEDIR_INOUT:802WARN_ON(dl_set);803WARN_ON(ul_set);804*dl_pipe = __le32_to_cpu(entry->pipenum);805*ul_pipe = __le32_to_cpu(entry->pipenum);806dl_set = true;807ul_set = true;808break;809}810}811812if (!ul_set || !dl_set)813return -ENOENT;814815return 0;816}817818static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,819u8 *ul_pipe, u8 *dl_pipe)820{821ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n");822823(void)ath10k_snoc_hif_map_service_to_pipe(ar,824ATH10K_HTC_SVC_ID_RSVD_CTRL,825ul_pipe, dl_pipe);826}827828static inline void ath10k_snoc_irq_disable(struct ath10k *ar)829{830ath10k_ce_disable_interrupts(ar);831}832833static inline void ath10k_snoc_irq_enable(struct ath10k *ar)834{835ath10k_ce_enable_interrupts(ar);836}837838static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)839{840struct ath10k_ce_pipe *ce_pipe;841struct ath10k_ce_ring *ce_ring;842struct sk_buff *skb;843struct ath10k *ar;844int i;845846ar = snoc_pipe->hif_ce_state;847ce_pipe = snoc_pipe->ce_hdl;848ce_ring = ce_pipe->dest_ring;849850if (!ce_ring)851return;852853if (!snoc_pipe->buf_sz)854return;855856for (i = 0; i < ce_ring->nentries; i++) {857skb = ce_ring->per_transfer_context[i];858if (!skb)859continue;860861ce_ring->per_transfer_context[i] = NULL;862863dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,864skb->len + skb_tailroom(skb),865DMA_FROM_DEVICE);866dev_kfree_skb_any(skb);867}868}869870static void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)871{872struct ath10k_ce_pipe *ce_pipe;873struct ath10k_ce_ring *ce_ring;874struct sk_buff *skb;875struct ath10k *ar;876int i;877878ar = snoc_pipe->hif_ce_state;879ce_pipe = snoc_pipe->ce_hdl;880ce_ring = ce_pipe->src_ring;881882if (!ce_ring)883return;884885if (!snoc_pipe->buf_sz)886return;887888for (i = 0; i < ce_ring->nentries; i++) {889skb = ce_ring->per_transfer_context[i];890if (!skb)891continue;892893ce_ring->per_transfer_context[i] = NULL;894895ath10k_htc_tx_completion_handler(ar, skb);896}897}898899static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)900{901struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);902struct ath10k_snoc_pipe *pipe_info;903int pipe_num;904905del_timer_sync(&ar_snoc->rx_post_retry);906for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {907pipe_info = &ar_snoc->pipe_info[pipe_num];908ath10k_snoc_rx_pipe_cleanup(pipe_info);909ath10k_snoc_tx_pipe_cleanup(pipe_info);910}911}912913static void ath10k_snoc_hif_stop(struct ath10k *ar)914{915if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))916ath10k_snoc_irq_disable(ar);917918ath10k_core_napi_sync_disable(ar);919ath10k_snoc_buffer_cleanup(ar);920ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");921}922923static int ath10k_snoc_hif_start(struct ath10k *ar)924{925struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);926927bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);928929dev_set_threaded(&ar->napi_dev, true);930ath10k_core_napi_enable(ar);931ath10k_snoc_irq_enable(ar);932ath10k_snoc_rx_post(ar);933934clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);935936ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");937938return 0;939}940941static int ath10k_snoc_init_pipes(struct ath10k *ar)942{943int i, ret;944945for (i = 0; i < CE_COUNT; i++) {946ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);947if (ret) {948ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",949i, ret);950return ret;951}952}953954return 0;955}956957static int ath10k_snoc_wlan_enable(struct ath10k *ar,958enum ath10k_firmware_mode fw_mode)959{960struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];961struct ath10k_qmi_wlan_enable_cfg cfg;962enum wlfw_driver_mode_enum_v01 mode;963int pipe_num;964965for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {966tgt_cfg[pipe_num].pipe_num =967target_ce_config_wlan[pipe_num].pipenum;968tgt_cfg[pipe_num].pipe_dir =969target_ce_config_wlan[pipe_num].pipedir;970tgt_cfg[pipe_num].nentries =971target_ce_config_wlan[pipe_num].nentries;972tgt_cfg[pipe_num].nbytes_max =973target_ce_config_wlan[pipe_num].nbytes_max;974tgt_cfg[pipe_num].flags =975target_ce_config_wlan[pipe_num].flags;976tgt_cfg[pipe_num].reserved = 0;977}978979cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /980sizeof(struct ath10k_tgt_pipe_cfg);981cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)982&tgt_cfg;983cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /984sizeof(struct ath10k_svc_pipe_cfg);985cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)986&target_service_to_ce_map_wlan;987cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map);988cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)989&target_shadow_reg_cfg_map;990991switch (fw_mode) {992case ATH10K_FIRMWARE_MODE_NORMAL:993mode = QMI_WLFW_MISSION_V01;994break;995case ATH10K_FIRMWARE_MODE_UTF:996mode = QMI_WLFW_FTM_V01;997break;998default:999ath10k_err(ar, "invalid firmware mode %d\n", fw_mode);1000return -EINVAL;1001}10021003return ath10k_qmi_wlan_enable(ar, &cfg, mode,1004NULL);1005}10061007static int ath10k_hw_power_on(struct ath10k *ar)1008{1009struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1010int ret;10111012ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");10131014ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);1015if (ret)1016return ret;10171018ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);1019if (ret)1020goto vreg_off;10211022return ret;10231024vreg_off:1025regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1026return ret;1027}10281029static int ath10k_hw_power_off(struct ath10k *ar)1030{1031struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);10321033ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");10341035clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);10361037return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1038}10391040static void ath10k_snoc_wlan_disable(struct ath10k *ar)1041{1042struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);10431044/* If both ATH10K_FLAG_CRASH_FLUSH and ATH10K_SNOC_FLAG_RECOVERY1045* flags are not set, it means that the driver has restarted1046* due to a crash inject via debugfs. In this case, the driver1047* needs to restart the firmware and hence send qmi wlan disable,1048* during the driver restart sequence.1049*/1050if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags) ||1051!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1052ath10k_qmi_wlan_disable(ar);1053}10541055static void ath10k_snoc_hif_power_down(struct ath10k *ar)1056{1057ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");10581059ath10k_snoc_wlan_disable(ar);1060ath10k_ce_free_rri(ar);1061ath10k_hw_power_off(ar);1062}10631064static int ath10k_snoc_hif_power_up(struct ath10k *ar,1065enum ath10k_firmware_mode fw_mode)1066{1067int ret;10681069ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",1070__func__, ar->state);10711072ret = ath10k_hw_power_on(ar);1073if (ret) {1074ath10k_err(ar, "failed to power on device: %d\n", ret);1075return ret;1076}10771078ret = ath10k_snoc_wlan_enable(ar, fw_mode);1079if (ret) {1080ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);1081goto err_hw_power_off;1082}10831084ath10k_ce_alloc_rri(ar);10851086ret = ath10k_snoc_init_pipes(ar);1087if (ret) {1088ath10k_err(ar, "failed to initialize CE: %d\n", ret);1089goto err_free_rri;1090}10911092return 0;10931094err_free_rri:1095ath10k_ce_free_rri(ar);1096ath10k_snoc_wlan_disable(ar);10971098err_hw_power_off:1099ath10k_hw_power_off(ar);11001101return ret;1102}11031104static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,1105u8 fw_log_mode)1106{1107u8 fw_dbg_mode;11081109if (fw_log_mode)1110fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;1111else1112fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;11131114return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);1115}11161117#ifdef CONFIG_PM1118static int ath10k_snoc_hif_suspend(struct ath10k *ar)1119{1120struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1121int ret;11221123if (!device_may_wakeup(ar->dev))1124return -EPERM;11251126ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1127if (ret) {1128ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret);1129return ret;1130}11311132ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n");11331134return ret;1135}11361137static int ath10k_snoc_hif_resume(struct ath10k *ar)1138{1139struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1140int ret;11411142if (!device_may_wakeup(ar->dev))1143return -EPERM;11441145ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1146if (ret) {1147ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret);1148return ret;1149}11501151ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n");11521153return ret;1154}1155#endif11561157static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {1158.read32 = ath10k_snoc_read32,1159.write32 = ath10k_snoc_write32,1160.start = ath10k_snoc_hif_start,1161.stop = ath10k_snoc_hif_stop,1162.map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe,1163.get_default_pipe = ath10k_snoc_hif_get_default_pipe,1164.power_up = ath10k_snoc_hif_power_up,1165.power_down = ath10k_snoc_hif_power_down,1166.tx_sg = ath10k_snoc_hif_tx_sg,1167.send_complete_check = ath10k_snoc_hif_send_complete_check,1168.get_free_queue_number = ath10k_snoc_hif_get_free_queue_number,1169.get_target_info = ath10k_snoc_hif_get_target_info,1170.set_target_log_mode = ath10k_snoc_hif_set_target_log_mode,11711172#ifdef CONFIG_PM1173.suspend = ath10k_snoc_hif_suspend,1174.resume = ath10k_snoc_hif_resume,1175#endif1176};11771178static const struct ath10k_bus_ops ath10k_snoc_bus_ops = {1179.read32 = ath10k_snoc_read32,1180.write32 = ath10k_snoc_write32,1181};11821183static int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq)1184{1185struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1186int i;11871188for (i = 0; i < CE_COUNT_MAX; i++) {1189if (ar_snoc->ce_irqs[i].irq_line == irq)1190return i;1191}1192ath10k_err(ar, "No matching CE id for irq %d\n", irq);11931194return -EINVAL;1195}11961197static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg)1198{1199struct ath10k *ar = arg;1200struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1201int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq);12021203if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) {1204ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,1205ce_id);1206return IRQ_HANDLED;1207}12081209ath10k_ce_disable_interrupt(ar, ce_id);1210set_bit(ce_id, ar_snoc->pending_ce_irqs);12111212napi_schedule(&ar->napi);12131214return IRQ_HANDLED;1215}12161217static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)1218{1219struct ath10k *ar = container_of(ctx, struct ath10k, napi);1220struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1221int done = 0;1222int ce_id;12231224if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {1225napi_complete(ctx);1226return done;1227}12281229for (ce_id = 0; ce_id < CE_COUNT; ce_id++)1230if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {1231ath10k_ce_per_engine_service(ar, ce_id);1232ath10k_ce_enable_interrupt(ar, ce_id);1233}12341235done = ath10k_htt_txrx_compl_task(ar, budget);12361237if (done < budget)1238napi_complete(ctx);12391240return done;1241}12421243static void ath10k_snoc_init_napi(struct ath10k *ar)1244{1245netif_napi_add(&ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll);1246}12471248static int ath10k_snoc_request_irq(struct ath10k *ar)1249{1250struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1251int ret, id;12521253for (id = 0; id < CE_COUNT_MAX; id++) {1254ret = request_irq(ar_snoc->ce_irqs[id].irq_line,1255ath10k_snoc_per_engine_handler, 0,1256ce_name[id], ar);1257if (ret) {1258ath10k_err(ar,1259"failed to register IRQ handler for CE %d: %d\n",1260id, ret);1261goto err_irq;1262}1263}12641265return 0;12661267err_irq:1268for (id -= 1; id >= 0; id--)1269free_irq(ar_snoc->ce_irqs[id].irq_line, ar);12701271return ret;1272}12731274static void ath10k_snoc_free_irq(struct ath10k *ar)1275{1276struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1277int id;12781279for (id = 0; id < CE_COUNT_MAX; id++)1280free_irq(ar_snoc->ce_irqs[id].irq_line, ar);1281}12821283static int ath10k_snoc_resource_init(struct ath10k *ar)1284{1285struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1286struct platform_device *pdev;1287struct resource *res;1288int i, ret = 0;12891290pdev = ar_snoc->dev;1291res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");1292if (!res) {1293ath10k_err(ar, "Memory base not found in DT\n");1294return -EINVAL;1295}12961297ar_snoc->mem_pa = res->start;1298ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa,1299resource_size(res));1300if (!ar_snoc->mem) {1301ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n",1302&ar_snoc->mem_pa);1303return -EINVAL;1304}13051306for (i = 0; i < CE_COUNT; i++) {1307ret = platform_get_irq(ar_snoc->dev, i);1308if (ret < 0)1309return ret;1310ar_snoc->ce_irqs[i].irq_line = ret;1311}13121313ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data",1314&ar_snoc->xo_cal_data);1315ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret);1316if (ret == 0) {1317ar_snoc->xo_cal_supported = true;1318ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n",1319ar_snoc->xo_cal_data);1320}13211322return 0;1323}13241325static void ath10k_snoc_quirks_init(struct ath10k *ar)1326{1327struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1328struct device *dev = &ar_snoc->dev->dev;13291330if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))1331set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);1332}13331334int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)1335{1336struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1337struct ath10k_bus_params bus_params = {};1338int ret;13391340if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))1341return 0;13421343switch (type) {1344case ATH10K_QMI_EVENT_FW_READY_IND:1345if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {1346ath10k_core_start_recovery(ar);1347break;1348}13491350bus_params.dev_type = ATH10K_DEV_TYPE_LL;1351bus_params.chip_id = ar_snoc->target_info.soc_version;1352ret = ath10k_core_register(ar, &bus_params);1353if (ret) {1354ath10k_err(ar, "Failed to register driver core: %d\n",1355ret);1356return ret;1357}1358set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);1359break;1360case ATH10K_QMI_EVENT_FW_DOWN_IND:1361set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);1362set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);1363break;1364default:1365ath10k_err(ar, "invalid fw indication: %llx\n", type);1366return -EINVAL;1367}13681369return 0;1370}13711372static int ath10k_snoc_setup_resource(struct ath10k *ar)1373{1374struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1375struct ath10k_ce *ce = ath10k_ce_priv(ar);1376struct ath10k_snoc_pipe *pipe;1377int i, ret;13781379timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0);1380spin_lock_init(&ce->ce_lock);1381for (i = 0; i < CE_COUNT; i++) {1382pipe = &ar_snoc->pipe_info[i];1383pipe->ce_hdl = &ce->ce_states[i];1384pipe->pipe_num = i;1385pipe->hif_ce_state = ar;13861387ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);1388if (ret) {1389ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",1390i, ret);1391return ret;1392}13931394pipe->buf_sz = host_ce_config_wlan[i].src_sz_max;1395}1396ath10k_snoc_init_napi(ar);13971398return 0;1399}14001401static void ath10k_snoc_release_resource(struct ath10k *ar)1402{1403int i;14041405netif_napi_del(&ar->napi);1406for (i = 0; i < CE_COUNT; i++)1407ath10k_ce_free_pipe(ar, i);1408}14091410static void ath10k_msa_dump_memory(struct ath10k *ar,1411struct ath10k_fw_crash_data *crash_data)1412{1413const struct ath10k_hw_mem_layout *mem_layout;1414const struct ath10k_mem_region *current_region;1415struct ath10k_dump_ram_data_hdr *hdr;1416size_t buf_len;1417u8 *buf;14181419if (!crash_data || !crash_data->ramdump_buf)1420return;14211422mem_layout = ath10k_coredump_get_mem_layout(ar);1423if (!mem_layout)1424return;14251426current_region = &mem_layout->region_table.regions[0];14271428buf = crash_data->ramdump_buf;1429buf_len = crash_data->ramdump_buf_len;1430memset(buf, 0, buf_len);14311432/* Reserve space for the header. */1433hdr = (void *)buf;1434buf += sizeof(*hdr);1435buf_len -= sizeof(*hdr);14361437hdr->region_type = cpu_to_le32(current_region->type);1438hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);1439hdr->length = cpu_to_le32(ar->msa.mem_size);14401441if (current_region->len < ar->msa.mem_size) {1442memcpy(buf, ar->msa.vaddr, current_region->len);1443ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",1444current_region->len, ar->msa.mem_size);1445} else {1446memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);1447}1448}14491450void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)1451{1452struct ath10k_fw_crash_data *crash_data;1453char guid[UUID_STRING_LEN + 1];14541455mutex_lock(&ar->dump_mutex);14561457spin_lock_bh(&ar->data_lock);1458ar->stats.fw_crash_counter++;1459spin_unlock_bh(&ar->data_lock);14601461crash_data = ath10k_coredump_new(ar);14621463if (crash_data)1464scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);1465else1466scnprintf(guid, sizeof(guid), "n/a");14671468ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);1469ath10k_print_driver_info(ar);1470ath10k_msa_dump_memory(ar, crash_data);1471mutex_unlock(&ar->dump_mutex);1472}14731474static int ath10k_snoc_modem_notify(struct notifier_block *nb, unsigned long action,1475void *data)1476{1477struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, nb);1478struct ath10k *ar = ar_snoc->ar;1479struct qcom_ssr_notify_data *notify_data = data;14801481switch (action) {1482case QCOM_SSR_BEFORE_POWERUP:1483ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem starting event\n");1484clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1485break;14861487case QCOM_SSR_AFTER_POWERUP:1488ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem running event\n");1489break;14901491case QCOM_SSR_BEFORE_SHUTDOWN:1492ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem %s event\n",1493notify_data->crashed ? "crashed" : "stopping");1494if (!notify_data->crashed)1495set_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1496else1497clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1498break;14991500case QCOM_SSR_AFTER_SHUTDOWN:1501ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem offline event\n");1502break;15031504default:1505ath10k_err(ar, "received unrecognized event %lu\n", action);1506break;1507}15081509return NOTIFY_OK;1510}15111512static int ath10k_modem_init(struct ath10k *ar)1513{1514struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1515void *notifier;1516int ret;15171518ar_snoc->nb.notifier_call = ath10k_snoc_modem_notify;15191520notifier = qcom_register_ssr_notifier("mpss", &ar_snoc->nb);1521if (IS_ERR(notifier)) {1522ret = PTR_ERR(notifier);1523ath10k_err(ar, "failed to initialize modem notifier: %d\n", ret);1524return ret;1525}15261527ar_snoc->notifier = notifier;15281529return 0;1530}15311532static void ath10k_modem_deinit(struct ath10k *ar)1533{1534int ret;1535struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);15361537ret = qcom_unregister_ssr_notifier(ar_snoc->notifier, &ar_snoc->nb);1538if (ret)1539ath10k_err(ar, "error %d unregistering notifier\n", ret);1540}15411542static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)1543{1544struct device *dev = ar->dev;1545struct device_node *node;1546struct resource r;1547int ret;15481549node = of_parse_phandle(dev->of_node, "memory-region", 0);1550if (node) {1551ret = of_address_to_resource(node, 0, &r);1552of_node_put(node);1553if (ret) {1554dev_err(dev, "failed to resolve msa fixed region\n");1555return ret;1556}15571558ar->msa.paddr = r.start;1559ar->msa.mem_size = resource_size(&r);1560ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,1561ar->msa.mem_size,1562MEMREMAP_WT);1563if (IS_ERR(ar->msa.vaddr)) {1564dev_err(dev, "failed to map memory region: %pa\n",1565&r.start);1566return PTR_ERR(ar->msa.vaddr);1567}1568} else {1569ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,1570&ar->msa.paddr,1571GFP_KERNEL);1572if (!ar->msa.vaddr) {1573ath10k_err(ar, "failed to allocate dma memory for msa region\n");1574return -ENOMEM;1575}1576ar->msa.mem_size = msa_size;1577}15781579ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",1580&ar->msa.paddr,1581ar->msa.vaddr);15821583return 0;1584}15851586static int ath10k_fw_init(struct ath10k *ar)1587{1588struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1589struct device *host_dev = &ar_snoc->dev->dev;1590struct platform_device_info info;1591struct iommu_domain *iommu_dom;1592struct platform_device *pdev;1593struct device_node *node;1594int ret;15951596node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");1597if (!node) {1598ar_snoc->use_tz = true;1599return 0;1600}16011602memset(&info, 0, sizeof(info));1603info.fwnode = &node->fwnode;1604info.parent = host_dev;1605info.name = node->name;1606info.dma_mask = DMA_BIT_MASK(32);16071608pdev = platform_device_register_full(&info);1609if (IS_ERR(pdev)) {1610of_node_put(node);1611return PTR_ERR(pdev);1612}16131614pdev->dev.of_node = node;16151616ret = of_dma_configure(&pdev->dev, node, true);1617if (ret) {1618ath10k_err(ar, "dma configure fail: %d\n", ret);1619goto err_unregister;1620}16211622ar_snoc->fw.dev = &pdev->dev;16231624iommu_dom = iommu_domain_alloc(&platform_bus_type);1625if (!iommu_dom) {1626ath10k_err(ar, "failed to allocate iommu domain\n");1627ret = -ENOMEM;1628goto err_unregister;1629}16301631ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);1632if (ret) {1633ath10k_err(ar, "could not attach device: %d\n", ret);1634goto err_iommu_free;1635}16361637ar_snoc->fw.iommu_domain = iommu_dom;1638ar_snoc->fw.fw_start_addr = ar->msa.paddr;16391640ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,1641ar->msa.paddr, ar->msa.mem_size,1642IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);1643if (ret) {1644ath10k_err(ar, "failed to map firmware region: %d\n", ret);1645goto err_iommu_detach;1646}16471648of_node_put(node);16491650return 0;16511652err_iommu_detach:1653iommu_detach_device(iommu_dom, ar_snoc->fw.dev);16541655err_iommu_free:1656iommu_domain_free(iommu_dom);16571658err_unregister:1659platform_device_unregister(pdev);1660of_node_put(node);16611662return ret;1663}16641665static int ath10k_fw_deinit(struct ath10k *ar)1666{1667struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1668const size_t mapped_size = ar_snoc->fw.mapped_mem_size;1669struct iommu_domain *iommu;1670size_t unmapped_size;16711672if (ar_snoc->use_tz)1673return 0;16741675iommu = ar_snoc->fw.iommu_domain;16761677unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,1678mapped_size);1679if (unmapped_size != mapped_size)1680ath10k_err(ar, "failed to unmap firmware: %zu\n",1681unmapped_size);16821683iommu_detach_device(iommu, ar_snoc->fw.dev);1684iommu_domain_free(iommu);16851686platform_device_unregister(to_platform_device(ar_snoc->fw.dev));16871688return 0;1689}16901691static const struct of_device_id ath10k_snoc_dt_match[] = {1692{ .compatible = "qcom,wcn3990-wifi",1693.data = &drv_priv,1694},1695{ }1696};1697MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);16981699static int ath10k_snoc_probe(struct platform_device *pdev)1700{1701const struct ath10k_snoc_drv_priv *drv_data;1702struct ath10k_snoc *ar_snoc;1703struct device *dev;1704struct ath10k *ar;1705u32 msa_size;1706int ret;1707u32 i;17081709dev = &pdev->dev;1710drv_data = device_get_match_data(dev);1711if (!drv_data) {1712dev_err(dev, "failed to find matching device tree id\n");1713return -EINVAL;1714}17151716ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask);1717if (ret) {1718dev_err(dev, "failed to set dma mask: %d\n", ret);1719return ret;1720}17211722ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,1723drv_data->hw_rev, &ath10k_snoc_hif_ops);1724if (!ar) {1725dev_err(dev, "failed to allocate core\n");1726return -ENOMEM;1727}17281729ar_snoc = ath10k_snoc_priv(ar);1730ar_snoc->dev = pdev;1731platform_set_drvdata(pdev, ar);1732ar_snoc->ar = ar;1733ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;1734ar->ce_priv = &ar_snoc->ce;1735msa_size = drv_data->msa_size;17361737ath10k_snoc_quirks_init(ar);17381739ret = ath10k_snoc_resource_init(ar);1740if (ret) {1741ath10k_warn(ar, "failed to initialize resource: %d\n", ret);1742goto err_core_destroy;1743}17441745ret = ath10k_snoc_setup_resource(ar);1746if (ret) {1747ath10k_warn(ar, "failed to setup resource: %d\n", ret);1748goto err_core_destroy;1749}1750ret = ath10k_snoc_request_irq(ar);1751if (ret) {1752ath10k_warn(ar, "failed to request irqs: %d\n", ret);1753goto err_release_resource;1754}17551756ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);1757ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,1758sizeof(*ar_snoc->vregs), GFP_KERNEL);1759if (!ar_snoc->vregs) {1760ret = -ENOMEM;1761goto err_free_irq;1762}1763for (i = 0; i < ar_snoc->num_vregs; i++)1764ar_snoc->vregs[i].supply = ath10k_regulators[i];17651766ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs,1767ar_snoc->vregs);1768if (ret < 0)1769goto err_free_irq;17701771ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks);1772ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks,1773sizeof(*ar_snoc->clks), GFP_KERNEL);1774if (!ar_snoc->clks) {1775ret = -ENOMEM;1776goto err_free_irq;1777}17781779for (i = 0; i < ar_snoc->num_clks; i++)1780ar_snoc->clks[i].id = ath10k_clocks[i];17811782ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks,1783ar_snoc->clks);1784if (ret)1785goto err_free_irq;17861787ret = ath10k_setup_msa_resources(ar, msa_size);1788if (ret) {1789ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);1790goto err_free_irq;1791}17921793ret = ath10k_fw_init(ar);1794if (ret) {1795ath10k_err(ar, "failed to initialize firmware: %d\n", ret);1796goto err_free_irq;1797}17981799ret = ath10k_qmi_init(ar, msa_size);1800if (ret) {1801ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);1802goto err_fw_deinit;1803}18041805ret = ath10k_modem_init(ar);1806if (ret)1807goto err_qmi_deinit;18081809ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");18101811return 0;18121813err_qmi_deinit:1814ath10k_qmi_deinit(ar);18151816err_fw_deinit:1817ath10k_fw_deinit(ar);18181819err_free_irq:1820ath10k_snoc_free_irq(ar);18211822err_release_resource:1823ath10k_snoc_release_resource(ar);18241825err_core_destroy:1826ath10k_core_destroy(ar);18271828return ret;1829}18301831static int ath10k_snoc_free_resources(struct ath10k *ar)1832{1833struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);18341835ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc free resources\n");18361837set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);18381839ath10k_core_unregister(ar);1840ath10k_fw_deinit(ar);1841ath10k_snoc_free_irq(ar);1842ath10k_snoc_release_resource(ar);1843ath10k_modem_deinit(ar);1844ath10k_qmi_deinit(ar);1845ath10k_core_destroy(ar);18461847return 0;1848}18491850static void ath10k_snoc_remove(struct platform_device *pdev)1851{1852struct ath10k *ar = platform_get_drvdata(pdev);1853struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);18541855ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");18561857reinit_completion(&ar->driver_recovery);18581859if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1860wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);18611862ath10k_snoc_free_resources(ar);1863}18641865static void ath10k_snoc_shutdown(struct platform_device *pdev)1866{1867struct ath10k *ar = platform_get_drvdata(pdev);18681869ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");1870ath10k_snoc_free_resources(ar);1871}18721873static struct platform_driver ath10k_snoc_driver = {1874.probe = ath10k_snoc_probe,1875.remove_new = ath10k_snoc_remove,1876.shutdown = ath10k_snoc_shutdown,1877.driver = {1878.name = "ath10k_snoc",1879.of_match_table = ath10k_snoc_dt_match,1880},1881};1882module_platform_driver(ath10k_snoc_driver);18831884MODULE_AUTHOR("Qualcomm");1885MODULE_LICENSE("Dual BSD/GPL");1886MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");188718881889