Path: blob/main/sys/contrib/dev/athk/ath10k/snoc.c
106597 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_reserved_mem.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 = timer_container_of(ar_snoc, t,647rx_post_retry);648struct ath10k *ar = ar_snoc->ar;649650ath10k_snoc_rx_post(ar);651}652653static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)654{655struct ath10k *ar = ce_state->ar;656struct sk_buff_head list;657struct sk_buff *skb;658659__skb_queue_head_init(&list);660while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {661if (!skb)662continue;663664__skb_queue_tail(&list, skb);665}666667while ((skb = __skb_dequeue(&list)))668ath10k_htc_tx_completion_handler(ar, skb);669}670671static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)672{673struct ath10k *ar = ce_state->ar;674struct sk_buff *skb;675676while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {677if (!skb)678continue;679680dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,681skb->len, DMA_TO_DEVICE);682ath10k_htt_hif_tx_complete(ar, skb);683}684}685686static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,687struct ath10k_hif_sg_item *items, int n_items)688{689struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);690struct ath10k_ce *ce = ath10k_ce_priv(ar);691struct ath10k_snoc_pipe *snoc_pipe;692struct ath10k_ce_pipe *ce_pipe;693int err, i = 0;694695snoc_pipe = &ar_snoc->pipe_info[pipe_id];696ce_pipe = snoc_pipe->ce_hdl;697spin_lock_bh(&ce->ce_lock);698699for (i = 0; i < n_items - 1; i++) {700ath10k_dbg(ar, ATH10K_DBG_SNOC,701"snoc tx item %d paddr %pad len %d n_items %d\n",702i, &items[i].paddr, items[i].len, n_items);703704err = ath10k_ce_send_nolock(ce_pipe,705items[i].transfer_context,706items[i].paddr,707items[i].len,708items[i].transfer_id,709CE_SEND_FLAG_GATHER);710if (err)711goto err;712}713714ath10k_dbg(ar, ATH10K_DBG_SNOC,715"snoc tx item %d paddr %pad len %d n_items %d\n",716i, &items[i].paddr, items[i].len, n_items);717718err = ath10k_ce_send_nolock(ce_pipe,719items[i].transfer_context,720items[i].paddr,721items[i].len,722items[i].transfer_id,7230);724if (err)725goto err;726727spin_unlock_bh(&ce->ce_lock);728729return 0;730731err:732for (; i > 0; i--)733__ath10k_ce_send_revert(ce_pipe);734735spin_unlock_bh(&ce->ce_lock);736return err;737}738739static int ath10k_snoc_hif_get_target_info(struct ath10k *ar,740struct bmi_target_info *target_info)741{742target_info->version = ATH10K_HW_WCN3990;743target_info->type = ATH10K_HW_WCN3990;744745return 0;746}747748static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)749{750struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);751752ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");753754return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);755}756757static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,758int force)759{760int resources;761762ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");763764if (!force) {765resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);766767if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))768return;769}770ath10k_ce_per_engine_service(ar, pipe);771}772773static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,774u16 service_id,775u8 *ul_pipe, u8 *dl_pipe)776{777const struct ce_service_to_pipe *entry;778bool ul_set = false, dl_set = false;779int i;780781ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n");782783for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {784entry = &target_service_to_ce_map_wlan[i];785786if (__le32_to_cpu(entry->service_id) != service_id)787continue;788789switch (__le32_to_cpu(entry->pipedir)) {790case PIPEDIR_NONE:791break;792case PIPEDIR_IN:793WARN_ON(dl_set);794*dl_pipe = __le32_to_cpu(entry->pipenum);795dl_set = true;796break;797case PIPEDIR_OUT:798WARN_ON(ul_set);799*ul_pipe = __le32_to_cpu(entry->pipenum);800ul_set = true;801break;802case PIPEDIR_INOUT:803WARN_ON(dl_set);804WARN_ON(ul_set);805*dl_pipe = __le32_to_cpu(entry->pipenum);806*ul_pipe = __le32_to_cpu(entry->pipenum);807dl_set = true;808ul_set = true;809break;810}811}812813if (!ul_set || !dl_set)814return -ENOENT;815816return 0;817}818819static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,820u8 *ul_pipe, u8 *dl_pipe)821{822ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n");823824(void)ath10k_snoc_hif_map_service_to_pipe(ar,825ATH10K_HTC_SVC_ID_RSVD_CTRL,826ul_pipe, dl_pipe);827}828829static inline void ath10k_snoc_irq_disable(struct ath10k *ar)830{831struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);832int id;833834for (id = 0; id < CE_COUNT_MAX; id++)835disable_irq(ar_snoc->ce_irqs[id].irq_line);836}837838static inline void ath10k_snoc_irq_enable(struct ath10k *ar)839{840struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);841int id;842843for (id = 0; id < CE_COUNT_MAX; id++)844enable_irq(ar_snoc->ce_irqs[id].irq_line);845}846847static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)848{849struct ath10k_ce_pipe *ce_pipe;850struct ath10k_ce_ring *ce_ring;851struct sk_buff *skb;852struct ath10k *ar;853int i;854855ar = snoc_pipe->hif_ce_state;856ce_pipe = snoc_pipe->ce_hdl;857ce_ring = ce_pipe->dest_ring;858859if (!ce_ring)860return;861862if (!snoc_pipe->buf_sz)863return;864865for (i = 0; i < ce_ring->nentries; i++) {866skb = ce_ring->per_transfer_context[i];867if (!skb)868continue;869870ce_ring->per_transfer_context[i] = NULL;871872dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,873skb->len + skb_tailroom(skb),874DMA_FROM_DEVICE);875dev_kfree_skb_any(skb);876}877}878879static void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)880{881struct ath10k_ce_pipe *ce_pipe;882struct ath10k_ce_ring *ce_ring;883struct sk_buff *skb;884struct ath10k *ar;885int i;886887ar = snoc_pipe->hif_ce_state;888ce_pipe = snoc_pipe->ce_hdl;889ce_ring = ce_pipe->src_ring;890891if (!ce_ring)892return;893894if (!snoc_pipe->buf_sz)895return;896897for (i = 0; i < ce_ring->nentries; i++) {898skb = ce_ring->per_transfer_context[i];899if (!skb)900continue;901902ce_ring->per_transfer_context[i] = NULL;903904ath10k_htc_tx_completion_handler(ar, skb);905}906}907908static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)909{910struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);911struct ath10k_snoc_pipe *pipe_info;912int pipe_num;913914timer_delete_sync(&ar_snoc->rx_post_retry);915for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {916pipe_info = &ar_snoc->pipe_info[pipe_num];917ath10k_snoc_rx_pipe_cleanup(pipe_info);918ath10k_snoc_tx_pipe_cleanup(pipe_info);919}920}921922static void ath10k_snoc_hif_stop(struct ath10k *ar)923{924if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))925ath10k_snoc_irq_disable(ar);926927ath10k_core_napi_sync_disable(ar);928ath10k_snoc_buffer_cleanup(ar);929ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");930}931932static int ath10k_snoc_hif_start(struct ath10k *ar)933{934struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);935936bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);937938netif_threaded_enable(ar->napi_dev);939ath10k_core_napi_enable(ar);940/* IRQs are left enabled when we restart due to a firmware crash */941if (!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))942ath10k_snoc_irq_enable(ar);943ath10k_snoc_rx_post(ar);944945clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);946947ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");948949return 0;950}951952static int ath10k_snoc_init_pipes(struct ath10k *ar)953{954int i, ret;955956for (i = 0; i < CE_COUNT; i++) {957ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);958if (ret) {959ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",960i, ret);961return ret;962}963}964965return 0;966}967968static int ath10k_snoc_wlan_enable(struct ath10k *ar,969enum ath10k_firmware_mode fw_mode)970{971struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];972struct ath10k_qmi_wlan_enable_cfg cfg;973enum wlfw_driver_mode_enum_v01 mode;974int pipe_num;975976for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {977tgt_cfg[pipe_num].pipe_num =978target_ce_config_wlan[pipe_num].pipenum;979tgt_cfg[pipe_num].pipe_dir =980target_ce_config_wlan[pipe_num].pipedir;981tgt_cfg[pipe_num].nentries =982target_ce_config_wlan[pipe_num].nentries;983tgt_cfg[pipe_num].nbytes_max =984target_ce_config_wlan[pipe_num].nbytes_max;985tgt_cfg[pipe_num].flags =986target_ce_config_wlan[pipe_num].flags;987tgt_cfg[pipe_num].reserved = 0;988}989990cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /991sizeof(struct ath10k_tgt_pipe_cfg);992cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)993&tgt_cfg;994cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /995sizeof(struct ath10k_svc_pipe_cfg);996cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)997&target_service_to_ce_map_wlan;998cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map);999cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)1000&target_shadow_reg_cfg_map;10011002switch (fw_mode) {1003case ATH10K_FIRMWARE_MODE_NORMAL:1004mode = QMI_WLFW_MISSION_V01;1005break;1006case ATH10K_FIRMWARE_MODE_UTF:1007mode = QMI_WLFW_FTM_V01;1008break;1009default:1010ath10k_err(ar, "invalid firmware mode %d\n", fw_mode);1011return -EINVAL;1012}10131014return ath10k_qmi_wlan_enable(ar, &cfg, mode,1015NULL);1016}10171018static int ath10k_hw_power_on(struct ath10k *ar)1019{1020struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1021int ret;10221023ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");10241025ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);1026if (ret)1027return ret;10281029ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);1030if (ret)1031goto vreg_off;10321033return ret;10341035vreg_off:1036regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1037return ret;1038}10391040static int ath10k_hw_power_off(struct ath10k *ar)1041{1042struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);10431044ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");10451046clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);10471048return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1049}10501051static void ath10k_snoc_wlan_disable(struct ath10k *ar)1052{1053struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);10541055/* If both ATH10K_FLAG_CRASH_FLUSH and ATH10K_SNOC_FLAG_RECOVERY1056* flags are not set, it means that the driver has restarted1057* due to a crash inject via debugfs. In this case, the driver1058* needs to restart the firmware and hence send qmi wlan disable,1059* during the driver restart sequence.1060*/1061if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags) ||1062!test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1063ath10k_qmi_wlan_disable(ar);1064}10651066static void ath10k_snoc_hif_power_down(struct ath10k *ar)1067{1068ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");10691070ath10k_snoc_wlan_disable(ar);1071ath10k_ce_free_rri(ar);1072ath10k_hw_power_off(ar);1073}10741075static int ath10k_snoc_hif_power_up(struct ath10k *ar,1076enum ath10k_firmware_mode fw_mode)1077{1078int ret;10791080ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",1081__func__, ar->state);10821083ret = ath10k_hw_power_on(ar);1084if (ret) {1085ath10k_err(ar, "failed to power on device: %d\n", ret);1086return ret;1087}10881089ret = ath10k_snoc_wlan_enable(ar, fw_mode);1090if (ret) {1091ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);1092goto err_hw_power_off;1093}10941095ath10k_ce_alloc_rri(ar);10961097ret = ath10k_snoc_init_pipes(ar);1098if (ret) {1099ath10k_err(ar, "failed to initialize CE: %d\n", ret);1100goto err_free_rri;1101}11021103ath10k_ce_enable_interrupts(ar);11041105return 0;11061107err_free_rri:1108ath10k_ce_free_rri(ar);1109ath10k_snoc_wlan_disable(ar);11101111err_hw_power_off:1112ath10k_hw_power_off(ar);11131114return ret;1115}11161117static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,1118u8 fw_log_mode)1119{1120u8 fw_dbg_mode;11211122if (fw_log_mode)1123fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;1124else1125fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;11261127return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);1128}11291130#ifdef CONFIG_PM1131static int ath10k_snoc_hif_suspend(struct ath10k *ar)1132{1133struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1134int ret;11351136if (!device_may_wakeup(ar->dev))1137return -EPERM;11381139ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1140if (ret) {1141ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret);1142return ret;1143}11441145ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n");11461147return ret;1148}11491150static int ath10k_snoc_hif_resume(struct ath10k *ar)1151{1152struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1153int ret;11541155if (!device_may_wakeup(ar->dev))1156return -EPERM;11571158ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1159if (ret) {1160ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret);1161return ret;1162}11631164ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n");11651166return ret;1167}1168#endif11691170static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {1171.read32 = ath10k_snoc_read32,1172.write32 = ath10k_snoc_write32,1173.start = ath10k_snoc_hif_start,1174.stop = ath10k_snoc_hif_stop,1175.map_service_to_pipe = ath10k_snoc_hif_map_service_to_pipe,1176.get_default_pipe = ath10k_snoc_hif_get_default_pipe,1177.power_up = ath10k_snoc_hif_power_up,1178.power_down = ath10k_snoc_hif_power_down,1179.tx_sg = ath10k_snoc_hif_tx_sg,1180.send_complete_check = ath10k_snoc_hif_send_complete_check,1181.get_free_queue_number = ath10k_snoc_hif_get_free_queue_number,1182.get_target_info = ath10k_snoc_hif_get_target_info,1183.set_target_log_mode = ath10k_snoc_hif_set_target_log_mode,11841185#ifdef CONFIG_PM1186.suspend = ath10k_snoc_hif_suspend,1187.resume = ath10k_snoc_hif_resume,1188#endif1189};11901191static const struct ath10k_bus_ops ath10k_snoc_bus_ops = {1192.read32 = ath10k_snoc_read32,1193.write32 = ath10k_snoc_write32,1194};11951196static int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq)1197{1198struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1199int i;12001201for (i = 0; i < CE_COUNT_MAX; i++) {1202if (ar_snoc->ce_irqs[i].irq_line == irq)1203return i;1204}1205ath10k_err(ar, "No matching CE id for irq %d\n", irq);12061207return -EINVAL;1208}12091210static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg)1211{1212struct ath10k *ar = arg;1213struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1214int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq);12151216if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) {1217ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,1218ce_id);1219return IRQ_HANDLED;1220}12211222ath10k_ce_disable_interrupt(ar, ce_id);1223set_bit(ce_id, ar_snoc->pending_ce_irqs);12241225napi_schedule(&ar->napi);12261227return IRQ_HANDLED;1228}12291230static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)1231{1232struct ath10k *ar = container_of(ctx, struct ath10k, napi);1233struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1234int done = 0;1235int ce_id;12361237if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {1238napi_complete(ctx);1239return done;1240}12411242for (ce_id = 0; ce_id < CE_COUNT; ce_id++)1243if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {1244ath10k_ce_per_engine_service(ar, ce_id);1245ath10k_ce_enable_interrupt(ar, ce_id);1246}12471248done = ath10k_htt_txrx_compl_task(ar, budget);12491250if (done < budget)1251napi_complete(ctx);12521253return done;1254}12551256static void ath10k_snoc_init_napi(struct ath10k *ar)1257{1258netif_napi_add(ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll);1259}12601261static int ath10k_snoc_request_irq(struct ath10k *ar)1262{1263struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1264int ret, id;12651266for (id = 0; id < CE_COUNT_MAX; id++) {1267ret = request_irq(ar_snoc->ce_irqs[id].irq_line,1268ath10k_snoc_per_engine_handler,1269IRQF_NO_AUTOEN, ce_name[id], ar);1270if (ret) {1271ath10k_err(ar,1272"failed to register IRQ handler for CE %d: %d\n",1273id, ret);1274goto err_irq;1275}1276}12771278return 0;12791280err_irq:1281for (id -= 1; id >= 0; id--)1282free_irq(ar_snoc->ce_irqs[id].irq_line, ar);12831284return ret;1285}12861287static void ath10k_snoc_free_irq(struct ath10k *ar)1288{1289struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1290int id;12911292for (id = 0; id < CE_COUNT_MAX; id++)1293free_irq(ar_snoc->ce_irqs[id].irq_line, ar);1294}12951296static int ath10k_snoc_resource_init(struct ath10k *ar)1297{1298struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1299struct platform_device *pdev;1300struct resource *res;1301int i, ret = 0;13021303pdev = ar_snoc->dev;1304res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");1305if (!res) {1306ath10k_err(ar, "Memory base not found in DT\n");1307return -EINVAL;1308}13091310ar_snoc->mem_pa = res->start;1311ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa,1312resource_size(res));1313if (!ar_snoc->mem) {1314ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n",1315&ar_snoc->mem_pa);1316return -EINVAL;1317}13181319for (i = 0; i < CE_COUNT; i++) {1320ret = platform_get_irq(ar_snoc->dev, i);1321if (ret < 0)1322return ret;1323ar_snoc->ce_irqs[i].irq_line = ret;1324}13251326ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data",1327&ar_snoc->xo_cal_data);1328ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret);1329if (ret == 0) {1330ar_snoc->xo_cal_supported = true;1331ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n",1332ar_snoc->xo_cal_data);1333}13341335return 0;1336}13371338static void ath10k_snoc_quirks_init(struct ath10k *ar)1339{1340struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1341struct device *dev = &ar_snoc->dev->dev;13421343/* ignore errors, keep NULL if there is no property */1344of_property_read_string(dev->of_node, "firmware-name", &ar->board_name);13451346if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))1347set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);1348}13491350int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)1351{1352struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1353struct ath10k_bus_params bus_params = {};1354int ret;13551356if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))1357return 0;13581359switch (type) {1360case ATH10K_QMI_EVENT_FW_READY_IND:1361if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {1362ath10k_core_start_recovery(ar);1363break;1364}13651366bus_params.dev_type = ATH10K_DEV_TYPE_LL;1367bus_params.chip_id = ar_snoc->target_info.soc_version;1368ret = ath10k_core_register(ar, &bus_params);1369if (ret) {1370ath10k_err(ar, "Failed to register driver core: %d\n",1371ret);1372return ret;1373}1374set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);1375break;1376case ATH10K_QMI_EVENT_FW_DOWN_IND:1377set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);1378set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);1379break;1380default:1381ath10k_err(ar, "invalid fw indication: %llx\n", type);1382return -EINVAL;1383}13841385return 0;1386}13871388static int ath10k_snoc_setup_resource(struct ath10k *ar)1389{1390struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1391struct ath10k_ce *ce = ath10k_ce_priv(ar);1392struct ath10k_snoc_pipe *pipe;1393int i, ret;13941395timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0);1396spin_lock_init(&ce->ce_lock);1397for (i = 0; i < CE_COUNT; i++) {1398pipe = &ar_snoc->pipe_info[i];1399pipe->ce_hdl = &ce->ce_states[i];1400pipe->pipe_num = i;1401pipe->hif_ce_state = ar;14021403ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);1404if (ret) {1405ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",1406i, ret);1407return ret;1408}14091410pipe->buf_sz = host_ce_config_wlan[i].src_sz_max;1411}1412ath10k_snoc_init_napi(ar);14131414return 0;1415}14161417static void ath10k_snoc_release_resource(struct ath10k *ar)1418{1419int i;14201421netif_napi_del(&ar->napi);1422for (i = 0; i < CE_COUNT; i++)1423ath10k_ce_free_pipe(ar, i);1424}14251426static void ath10k_msa_dump_memory(struct ath10k *ar,1427struct ath10k_fw_crash_data *crash_data)1428{1429const struct ath10k_hw_mem_layout *mem_layout;1430const struct ath10k_mem_region *current_region;1431struct ath10k_dump_ram_data_hdr *hdr;1432size_t buf_len;1433u8 *buf;14341435if (!crash_data || !crash_data->ramdump_buf)1436return;14371438mem_layout = ath10k_coredump_get_mem_layout(ar);1439if (!mem_layout)1440return;14411442current_region = &mem_layout->region_table.regions[0];14431444buf = crash_data->ramdump_buf;1445buf_len = crash_data->ramdump_buf_len;1446memset(buf, 0, buf_len);14471448/* Reserve space for the header. */1449hdr = (void *)buf;1450buf += sizeof(*hdr);1451buf_len -= sizeof(*hdr);14521453hdr->region_type = cpu_to_le32(current_region->type);1454hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);1455hdr->length = cpu_to_le32(ar->msa.mem_size);14561457if (current_region->len < ar->msa.mem_size) {1458memcpy(buf, ar->msa.vaddr, current_region->len);1459ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",1460current_region->len, ar->msa.mem_size);1461} else {1462memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);1463}1464}14651466void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)1467{1468struct ath10k_fw_crash_data *crash_data;1469char guid[UUID_STRING_LEN + 1];14701471mutex_lock(&ar->dump_mutex);14721473spin_lock_bh(&ar->data_lock);1474ar->stats.fw_crash_counter++;1475spin_unlock_bh(&ar->data_lock);14761477crash_data = ath10k_coredump_new(ar);14781479if (crash_data)1480scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);1481else1482scnprintf(guid, sizeof(guid), "n/a");14831484ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);1485ath10k_print_driver_info(ar);1486ath10k_msa_dump_memory(ar, crash_data);1487mutex_unlock(&ar->dump_mutex);1488}14891490static int ath10k_snoc_modem_notify(struct notifier_block *nb, unsigned long action,1491void *data)1492{1493struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, nb);1494struct ath10k *ar = ar_snoc->ar;1495struct qcom_ssr_notify_data *notify_data = data;14961497switch (action) {1498case QCOM_SSR_BEFORE_POWERUP:1499ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem starting event\n");1500clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1501break;15021503case QCOM_SSR_AFTER_POWERUP:1504ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem running event\n");1505break;15061507case QCOM_SSR_BEFORE_SHUTDOWN:1508ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem %s event\n",1509notify_data->crashed ? "crashed" : "stopping");1510if (!notify_data->crashed)1511set_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1512else1513clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1514break;15151516case QCOM_SSR_AFTER_SHUTDOWN:1517ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem offline event\n");1518break;15191520default:1521ath10k_err(ar, "received unrecognized event %lu\n", action);1522break;1523}15241525return NOTIFY_OK;1526}15271528static int ath10k_modem_init(struct ath10k *ar)1529{1530struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1531void *notifier;1532int ret;15331534ar_snoc->nb.notifier_call = ath10k_snoc_modem_notify;15351536notifier = qcom_register_ssr_notifier("mpss", &ar_snoc->nb);1537if (IS_ERR(notifier)) {1538ret = PTR_ERR(notifier);1539ath10k_err(ar, "failed to initialize modem notifier: %d\n", ret);1540return ret;1541}15421543ar_snoc->notifier = notifier;15441545return 0;1546}15471548static void ath10k_modem_deinit(struct ath10k *ar)1549{1550int ret;1551struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);15521553ret = qcom_unregister_ssr_notifier(ar_snoc->notifier, &ar_snoc->nb);1554if (ret)1555ath10k_err(ar, "error %d unregistering notifier\n", ret);1556}15571558static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)1559{1560struct device *dev = ar->dev;1561struct resource r;1562int ret;15631564ret = of_reserved_mem_region_to_resource(dev->of_node, 0, &r);1565if (!ret) {1566ar->msa.paddr = r.start;1567ar->msa.mem_size = resource_size(&r);1568ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,1569ar->msa.mem_size,1570MEMREMAP_WT);1571if (IS_ERR(ar->msa.vaddr)) {1572dev_err(dev, "failed to map memory region: %pa\n",1573&r.start);1574return PTR_ERR(ar->msa.vaddr);1575}1576} else {1577ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,1578&ar->msa.paddr,1579GFP_KERNEL);1580if (!ar->msa.vaddr) {1581ath10k_err(ar, "failed to allocate dma memory for msa region\n");1582return -ENOMEM;1583}1584ar->msa.mem_size = msa_size;1585}15861587ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",1588&ar->msa.paddr,1589ar->msa.vaddr);15901591return 0;1592}15931594static int ath10k_fw_init(struct ath10k *ar)1595{1596struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1597struct device *host_dev = &ar_snoc->dev->dev;1598struct platform_device_info info;1599struct iommu_domain *iommu_dom;1600struct platform_device *pdev;1601struct device_node *node;1602int ret;16031604node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");1605if (!node) {1606ar_snoc->use_tz = true;1607return 0;1608}16091610memset(&info, 0, sizeof(info));1611info.fwnode = &node->fwnode;1612info.parent = host_dev;1613info.name = node->name;1614info.dma_mask = DMA_BIT_MASK(32);16151616pdev = platform_device_register_full(&info);1617if (IS_ERR(pdev)) {1618of_node_put(node);1619return PTR_ERR(pdev);1620}16211622pdev->dev.of_node = node;16231624ret = of_dma_configure(&pdev->dev, node, true);1625if (ret) {1626ath10k_err(ar, "dma configure fail: %d\n", ret);1627goto err_unregister;1628}16291630ar_snoc->fw.dev = &pdev->dev;16311632iommu_dom = iommu_paging_domain_alloc(ar_snoc->fw.dev);1633if (IS_ERR(iommu_dom)) {1634ath10k_err(ar, "failed to allocate iommu domain\n");1635ret = PTR_ERR(iommu_dom);1636goto err_unregister;1637}16381639ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);1640if (ret) {1641ath10k_err(ar, "could not attach device: %d\n", ret);1642goto err_iommu_free;1643}16441645ar_snoc->fw.iommu_domain = iommu_dom;1646ar_snoc->fw.fw_start_addr = ar->msa.paddr;16471648ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,1649ar->msa.paddr, ar->msa.mem_size,1650IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);1651if (ret) {1652ath10k_err(ar, "failed to map firmware region: %d\n", ret);1653goto err_iommu_detach;1654}16551656of_node_put(node);16571658return 0;16591660err_iommu_detach:1661iommu_detach_device(iommu_dom, ar_snoc->fw.dev);16621663err_iommu_free:1664iommu_domain_free(iommu_dom);16651666err_unregister:1667platform_device_unregister(pdev);1668of_node_put(node);16691670return ret;1671}16721673static int ath10k_fw_deinit(struct ath10k *ar)1674{1675struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1676const size_t mapped_size = ar_snoc->fw.mapped_mem_size;1677struct iommu_domain *iommu;1678size_t unmapped_size;16791680if (ar_snoc->use_tz)1681return 0;16821683iommu = ar_snoc->fw.iommu_domain;16841685unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,1686mapped_size);1687if (unmapped_size != mapped_size)1688ath10k_err(ar, "failed to unmap firmware: %zu\n",1689unmapped_size);16901691iommu_detach_device(iommu, ar_snoc->fw.dev);1692iommu_domain_free(iommu);16931694platform_device_unregister(to_platform_device(ar_snoc->fw.dev));16951696return 0;1697}16981699static const struct of_device_id ath10k_snoc_dt_match[] = {1700{ .compatible = "qcom,wcn3990-wifi",1701.data = &drv_priv,1702},1703{ }1704};1705MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);17061707static int ath10k_snoc_probe(struct platform_device *pdev)1708{1709const struct ath10k_snoc_drv_priv *drv_data;1710struct ath10k_snoc *ar_snoc;1711struct device *dev;1712struct ath10k *ar;1713u32 msa_size;1714int ret;1715u32 i;17161717dev = &pdev->dev;1718drv_data = device_get_match_data(dev);1719if (!drv_data) {1720dev_err(dev, "failed to find matching device tree id\n");1721return -EINVAL;1722}17231724ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask);1725if (ret) {1726dev_err(dev, "failed to set dma mask: %d\n", ret);1727return ret;1728}17291730ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,1731drv_data->hw_rev, &ath10k_snoc_hif_ops);1732if (!ar) {1733dev_err(dev, "failed to allocate core\n");1734return -ENOMEM;1735}17361737ar_snoc = ath10k_snoc_priv(ar);1738ar_snoc->dev = pdev;1739platform_set_drvdata(pdev, ar);1740ar_snoc->ar = ar;1741ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;1742ar->ce_priv = &ar_snoc->ce;1743msa_size = drv_data->msa_size;17441745ath10k_snoc_quirks_init(ar);17461747ret = ath10k_snoc_resource_init(ar);1748if (ret) {1749ath10k_warn(ar, "failed to initialize resource: %d\n", ret);1750goto err_core_destroy;1751}17521753ret = ath10k_snoc_setup_resource(ar);1754if (ret) {1755ath10k_warn(ar, "failed to setup resource: %d\n", ret);1756goto err_core_destroy;1757}1758ret = ath10k_snoc_request_irq(ar);1759if (ret) {1760ath10k_warn(ar, "failed to request irqs: %d\n", ret);1761goto err_release_resource;1762}17631764ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);1765ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,1766sizeof(*ar_snoc->vregs), GFP_KERNEL);1767if (!ar_snoc->vregs) {1768ret = -ENOMEM;1769goto err_free_irq;1770}1771for (i = 0; i < ar_snoc->num_vregs; i++)1772ar_snoc->vregs[i].supply = ath10k_regulators[i];17731774ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs,1775ar_snoc->vregs);1776if (ret < 0)1777goto err_free_irq;17781779ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks);1780ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks,1781sizeof(*ar_snoc->clks), GFP_KERNEL);1782if (!ar_snoc->clks) {1783ret = -ENOMEM;1784goto err_free_irq;1785}17861787for (i = 0; i < ar_snoc->num_clks; i++)1788ar_snoc->clks[i].id = ath10k_clocks[i];17891790ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks,1791ar_snoc->clks);1792if (ret)1793goto err_free_irq;17941795ret = ath10k_setup_msa_resources(ar, msa_size);1796if (ret) {1797ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);1798goto err_free_irq;1799}18001801ret = ath10k_fw_init(ar);1802if (ret) {1803ath10k_err(ar, "failed to initialize firmware: %d\n", ret);1804goto err_free_irq;1805}18061807ret = ath10k_qmi_init(ar, msa_size);1808if (ret) {1809ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);1810goto err_fw_deinit;1811}18121813ret = ath10k_modem_init(ar);1814if (ret)1815goto err_qmi_deinit;18161817ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");18181819return 0;18201821err_qmi_deinit:1822ath10k_qmi_deinit(ar);18231824err_fw_deinit:1825ath10k_fw_deinit(ar);18261827err_free_irq:1828ath10k_snoc_free_irq(ar);18291830err_release_resource:1831ath10k_snoc_release_resource(ar);18321833err_core_destroy:1834ath10k_core_destroy(ar);18351836return ret;1837}18381839static int ath10k_snoc_free_resources(struct ath10k *ar)1840{1841struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);18421843ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc free resources\n");18441845set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);18461847ath10k_core_unregister(ar);1848ath10k_fw_deinit(ar);1849ath10k_snoc_free_irq(ar);1850ath10k_snoc_release_resource(ar);1851ath10k_modem_deinit(ar);1852ath10k_qmi_deinit(ar);1853ath10k_core_destroy(ar);18541855return 0;1856}18571858static void ath10k_snoc_remove(struct platform_device *pdev)1859{1860struct ath10k *ar = platform_get_drvdata(pdev);1861struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);18621863ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");18641865reinit_completion(&ar->driver_recovery);18661867if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1868wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);18691870ath10k_snoc_free_resources(ar);1871}18721873static void ath10k_snoc_shutdown(struct platform_device *pdev)1874{1875struct ath10k *ar = platform_get_drvdata(pdev);18761877ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");1878ath10k_snoc_free_resources(ar);1879}18801881static struct platform_driver ath10k_snoc_driver = {1882.probe = ath10k_snoc_probe,1883.remove = ath10k_snoc_remove,1884.shutdown = ath10k_snoc_shutdown,1885.driver = {1886.name = "ath10k_snoc",1887.of_match_table = ath10k_snoc_dt_match,1888},1889};1890module_platform_driver(ath10k_snoc_driver);18911892MODULE_AUTHOR("Qualcomm");1893MODULE_LICENSE("Dual BSD/GPL");1894MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");189518961897