brintos

brintos / linux-shallow public Read only

0
0
Text · 45.4 KiB · 0fe47d5 Raw
1901 lines · c
1// SPDX-License-Identifier: ISC2/*3 * Copyright (c) 2018 The Linux Foundation. All rights reserved.4 */5 6#include <linux/bits.h>7#include <linux/clk.h>8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/of.h>11#include <linux/of_device.h>12#include <linux/platform_device.h>13#include <linux/property.h>14#include <linux/regulator/consumer.h>15#include <linux/remoteproc/qcom_rproc.h>16#include <linux/of_address.h>17#include <linux/iommu.h>18 19#include "ce.h"20#include "coredump.h"21#include "debug.h"22#include "hif.h"23#include "htc.h"24#include "snoc.h"25 26#define ATH10K_SNOC_RX_POST_RETRY_MS 5027#define CE_POLL_PIPE 428#define ATH10K_SNOC_WAKE_IRQ 229 30static char *const ce_name[] = {31	"WLAN_CE_0",32	"WLAN_CE_1",33	"WLAN_CE_2",34	"WLAN_CE_3",35	"WLAN_CE_4",36	"WLAN_CE_5",37	"WLAN_CE_6",38	"WLAN_CE_7",39	"WLAN_CE_8",40	"WLAN_CE_9",41	"WLAN_CE_10",42	"WLAN_CE_11",43};44 45static const char * const ath10k_regulators[] = {46	"vdd-0.8-cx-mx",47	"vdd-1.8-xo",48	"vdd-1.3-rfa",49	"vdd-3.3-ch0",50	"vdd-3.3-ch1",51};52 53static const char * const ath10k_clocks[] = {54	"cxo_ref_clk_pin", "qdss",55};56 57static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state);58static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state);59static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state);60static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state);61static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state);62static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state);63 64static const struct ath10k_snoc_drv_priv drv_priv = {65	.hw_rev = ATH10K_HW_WCN3990,66	.dma_mask = DMA_BIT_MASK(35),67	.msa_size = 0x100000,68};69 70#define WCN3990_SRC_WR_IDX_OFFSET 0x3C71#define WCN3990_DST_WR_IDX_OFFSET 0x4072 73static struct ath10k_shadow_reg_cfg target_shadow_reg_cfg_map[] = {74		{75			.ce_id = __cpu_to_le16(0),76			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),77		},78 79		{80			.ce_id = __cpu_to_le16(3),81			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),82		},83 84		{85			.ce_id = __cpu_to_le16(4),86			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),87		},88 89		{90			.ce_id = __cpu_to_le16(5),91			.reg_offset =  __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),92		},93 94		{95			.ce_id = __cpu_to_le16(7),96			.reg_offset = __cpu_to_le16(WCN3990_SRC_WR_IDX_OFFSET),97		},98 99		{100			.ce_id = __cpu_to_le16(1),101			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),102		},103 104		{105			.ce_id = __cpu_to_le16(2),106			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),107		},108 109		{110			.ce_id = __cpu_to_le16(7),111			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),112		},113 114		{115			.ce_id = __cpu_to_le16(8),116			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),117		},118 119		{120			.ce_id = __cpu_to_le16(9),121			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),122		},123 124		{125			.ce_id = __cpu_to_le16(10),126			.reg_offset =  __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),127		},128 129		{130			.ce_id = __cpu_to_le16(11),131			.reg_offset = __cpu_to_le16(WCN3990_DST_WR_IDX_OFFSET),132		},133};134 135static struct ce_attr host_ce_config_wlan[] = {136	/* CE0: host->target HTC control streams */137	{138		.flags = CE_ATTR_FLAGS,139		.src_nentries = 16,140		.src_sz_max = 2048,141		.dest_nentries = 0,142		.send_cb = ath10k_snoc_htc_tx_cb,143	},144 145	/* CE1: target->host HTT + HTC control */146	{147		.flags = CE_ATTR_FLAGS,148		.src_nentries = 0,149		.src_sz_max = 2048,150		.dest_nentries = 512,151		.recv_cb = ath10k_snoc_htt_htc_rx_cb,152	},153 154	/* CE2: target->host WMI */155	{156		.flags = CE_ATTR_FLAGS,157		.src_nentries = 0,158		.src_sz_max = 2048,159		.dest_nentries = 64,160		.recv_cb = ath10k_snoc_htc_rx_cb,161	},162 163	/* CE3: host->target WMI */164	{165		.flags = CE_ATTR_FLAGS,166		.src_nentries = 32,167		.src_sz_max = 2048,168		.dest_nentries = 0,169		.send_cb = ath10k_snoc_htc_tx_cb,170	},171 172	/* CE4: host->target HTT */173	{174		.flags = CE_ATTR_FLAGS | CE_ATTR_DIS_INTR,175		.src_nentries = 2048,176		.src_sz_max = 256,177		.dest_nentries = 0,178		.send_cb = ath10k_snoc_htt_tx_cb,179	},180 181	/* CE5: target->host HTT (ipa_uc->target ) */182	{183		.flags = CE_ATTR_FLAGS,184		.src_nentries = 0,185		.src_sz_max = 512,186		.dest_nentries = 512,187		.recv_cb = ath10k_snoc_htt_rx_cb,188	},189 190	/* CE6: target autonomous hif_memcpy */191	{192		.flags = CE_ATTR_FLAGS,193		.src_nentries = 0,194		.src_sz_max = 0,195		.dest_nentries = 0,196	},197 198	/* CE7: ce_diag, the Diagnostic Window */199	{200		.flags = CE_ATTR_FLAGS,201		.src_nentries = 2,202		.src_sz_max = 2048,203		.dest_nentries = 2,204	},205 206	/* CE8: Target to uMC */207	{208		.flags = CE_ATTR_FLAGS,209		.src_nentries = 0,210		.src_sz_max = 2048,211		.dest_nentries = 128,212	},213 214	/* CE9 target->host HTT */215	{216		.flags = CE_ATTR_FLAGS,217		.src_nentries = 0,218		.src_sz_max = 2048,219		.dest_nentries = 512,220		.recv_cb = ath10k_snoc_htt_htc_rx_cb,221	},222 223	/* CE10: target->host HTT */224	{225		.flags = CE_ATTR_FLAGS,226		.src_nentries = 0,227		.src_sz_max = 2048,228		.dest_nentries = 512,229		.recv_cb = ath10k_snoc_htt_htc_rx_cb,230	},231 232	/* CE11: target -> host PKTLOG */233	{234		.flags = CE_ATTR_FLAGS,235		.src_nentries = 0,236		.src_sz_max = 2048,237		.dest_nentries = 512,238		.recv_cb = ath10k_snoc_pktlog_rx_cb,239	},240};241 242static struct ce_pipe_config target_ce_config_wlan[] = {243	/* CE0: host->target HTC control and raw streams */244	{245		.pipenum = __cpu_to_le32(0),246		.pipedir = __cpu_to_le32(PIPEDIR_OUT),247		.nentries = __cpu_to_le32(32),248		.nbytes_max = __cpu_to_le32(2048),249		.flags = __cpu_to_le32(CE_ATTR_FLAGS),250		.reserved = __cpu_to_le32(0),251	},252 253	/* CE1: target->host HTT + HTC control */254	{255		.pipenum = __cpu_to_le32(1),256		.pipedir = __cpu_to_le32(PIPEDIR_IN),257		.nentries = __cpu_to_le32(32),258		.nbytes_max = __cpu_to_le32(2048),259		.flags = __cpu_to_le32(CE_ATTR_FLAGS),260		.reserved = __cpu_to_le32(0),261	},262 263	/* CE2: target->host WMI */264	{265		.pipenum = __cpu_to_le32(2),266		.pipedir = __cpu_to_le32(PIPEDIR_IN),267		.nentries = __cpu_to_le32(64),268		.nbytes_max = __cpu_to_le32(2048),269		.flags = __cpu_to_le32(CE_ATTR_FLAGS),270		.reserved = __cpu_to_le32(0),271	},272 273	/* CE3: host->target WMI */274	{275		.pipenum = __cpu_to_le32(3),276		.pipedir = __cpu_to_le32(PIPEDIR_OUT),277		.nentries = __cpu_to_le32(32),278		.nbytes_max = __cpu_to_le32(2048),279		.flags = __cpu_to_le32(CE_ATTR_FLAGS),280		.reserved = __cpu_to_le32(0),281	},282 283	/* CE4: host->target HTT */284	{285		.pipenum = __cpu_to_le32(4),286		.pipedir = __cpu_to_le32(PIPEDIR_OUT),287		.nentries = __cpu_to_le32(256),288		.nbytes_max = __cpu_to_le32(256),289		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),290		.reserved = __cpu_to_le32(0),291	},292 293	/* CE5: target->host HTT (HIF->HTT) */294	{295		.pipenum = __cpu_to_le32(5),296		.pipedir = __cpu_to_le32(PIPEDIR_OUT),297		.nentries = __cpu_to_le32(1024),298		.nbytes_max = __cpu_to_le32(64),299		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),300		.reserved = __cpu_to_le32(0),301	},302 303	/* CE6: Reserved for target autonomous hif_memcpy */304	{305		.pipenum = __cpu_to_le32(6),306		.pipedir = __cpu_to_le32(PIPEDIR_INOUT),307		.nentries = __cpu_to_le32(32),308		.nbytes_max = __cpu_to_le32(16384),309		.flags = __cpu_to_le32(CE_ATTR_FLAGS),310		.reserved = __cpu_to_le32(0),311	},312 313	/* CE7 used only by Host */314	{315		.pipenum = __cpu_to_le32(7),316		.pipedir = __cpu_to_le32(4),317		.nentries = __cpu_to_le32(0),318		.nbytes_max = __cpu_to_le32(0),319		.flags = __cpu_to_le32(CE_ATTR_FLAGS | CE_ATTR_DIS_INTR),320		.reserved = __cpu_to_le32(0),321	},322 323	/* CE8 Target to uMC */324	{325		.pipenum = __cpu_to_le32(8),326		.pipedir = __cpu_to_le32(PIPEDIR_IN),327		.nentries = __cpu_to_le32(32),328		.nbytes_max = __cpu_to_le32(2048),329		.flags = __cpu_to_le32(0),330		.reserved = __cpu_to_le32(0),331	},332 333	/* CE9 target->host HTT */334	{335		.pipenum = __cpu_to_le32(9),336		.pipedir = __cpu_to_le32(PIPEDIR_IN),337		.nentries = __cpu_to_le32(32),338		.nbytes_max = __cpu_to_le32(2048),339		.flags = __cpu_to_le32(CE_ATTR_FLAGS),340		.reserved = __cpu_to_le32(0),341	},342 343	/* CE10 target->host HTT */344	{345		.pipenum = __cpu_to_le32(10),346		.pipedir = __cpu_to_le32(PIPEDIR_IN),347		.nentries = __cpu_to_le32(32),348		.nbytes_max = __cpu_to_le32(2048),349		.flags = __cpu_to_le32(CE_ATTR_FLAGS),350		.reserved = __cpu_to_le32(0),351	},352 353	/* CE11 target autonomous qcache memcpy */354	{355		.pipenum = __cpu_to_le32(11),356		.pipedir = __cpu_to_le32(PIPEDIR_IN),357		.nentries = __cpu_to_le32(32),358		.nbytes_max = __cpu_to_le32(2048),359		.flags = __cpu_to_le32(CE_ATTR_FLAGS),360		.reserved = __cpu_to_le32(0),361	},362};363 364static struct ce_service_to_pipe target_service_to_ce_map_wlan[] = {365	{366		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),367		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */368		__cpu_to_le32(3),369	},370	{371		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VO),372		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */373		__cpu_to_le32(2),374	},375	{376		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),377		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */378		__cpu_to_le32(3),379	},380	{381		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BK),382		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */383		__cpu_to_le32(2),384	},385	{386		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),387		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */388		__cpu_to_le32(3),389	},390	{391		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_BE),392		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */393		__cpu_to_le32(2),394	},395	{396		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),397		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */398		__cpu_to_le32(3),399	},400	{401		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_DATA_VI),402		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */403		__cpu_to_le32(2),404	},405	{406		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),407		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */408		__cpu_to_le32(3),409	},410	{411		__cpu_to_le32(ATH10K_HTC_SVC_ID_WMI_CONTROL),412		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */413		__cpu_to_le32(2),414	},415	{416		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),417		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */418		__cpu_to_le32(0),419	},420	{421		__cpu_to_le32(ATH10K_HTC_SVC_ID_RSVD_CTRL),422		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */423		__cpu_to_le32(2),424	},425	{ /* not used */426		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),427		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */428		__cpu_to_le32(0),429	},430	{ /* not used */431		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),432		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */433		__cpu_to_le32(2),434	},435	{436		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),437		__cpu_to_le32(PIPEDIR_OUT),	/* out = UL = host -> target */438		__cpu_to_le32(4),439	},440	{441		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA_MSG),442		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */443		__cpu_to_le32(1),444	},445	{ /* not used */446		__cpu_to_le32(ATH10K_HTC_SVC_ID_TEST_RAW_STREAMS),447		__cpu_to_le32(PIPEDIR_OUT),448		__cpu_to_le32(5),449	},450	{ /* in = DL = target -> host */451		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA2_MSG),452		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */453		__cpu_to_le32(9),454	},455	{ /* in = DL = target -> host */456		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_DATA3_MSG),457		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */458		__cpu_to_le32(10),459	},460	{ /* in = DL = target -> host pktlog */461		__cpu_to_le32(ATH10K_HTC_SVC_ID_HTT_LOG_MSG),462		__cpu_to_le32(PIPEDIR_IN),	/* in = DL = target -> host */463		__cpu_to_le32(11),464	},465	/* (Additions here) */466 467	{ /* must be last */468		__cpu_to_le32(0),469		__cpu_to_le32(0),470		__cpu_to_le32(0),471	},472};473 474static void ath10k_snoc_write32(struct ath10k *ar, u32 offset, u32 value)475{476	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);477 478	iowrite32(value, ar_snoc->mem + offset);479}480 481static u32 ath10k_snoc_read32(struct ath10k *ar, u32 offset)482{483	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);484	u32 val;485 486	val = ioread32(ar_snoc->mem + offset);487 488	return val;489}490 491static int __ath10k_snoc_rx_post_buf(struct ath10k_snoc_pipe *pipe)492{493	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;494	struct ath10k *ar = pipe->hif_ce_state;495	struct ath10k_ce *ce = ath10k_ce_priv(ar);496	struct sk_buff *skb;497	dma_addr_t paddr;498	int ret;499 500	skb = dev_alloc_skb(pipe->buf_sz);501	if (!skb)502		return -ENOMEM;503 504	WARN_ONCE((unsigned long)skb->data & 3, "unaligned skb");505 506	paddr = dma_map_single(ar->dev, skb->data,507			       skb->len + skb_tailroom(skb),508			       DMA_FROM_DEVICE);509	if (unlikely(dma_mapping_error(ar->dev, paddr))) {510		ath10k_warn(ar, "failed to dma map snoc rx buf\n");511		dev_kfree_skb_any(skb);512		return -EIO;513	}514 515	ATH10K_SKB_RXCB(skb)->paddr = paddr;516 517	spin_lock_bh(&ce->ce_lock);518	ret = ce_pipe->ops->ce_rx_post_buf(ce_pipe, skb, paddr);519	spin_unlock_bh(&ce->ce_lock);520	if (ret) {521		dma_unmap_single(ar->dev, paddr, skb->len + skb_tailroom(skb),522				 DMA_FROM_DEVICE);523		dev_kfree_skb_any(skb);524		return ret;525	}526 527	return 0;528}529 530static void ath10k_snoc_rx_post_pipe(struct ath10k_snoc_pipe *pipe)531{532	struct ath10k *ar = pipe->hif_ce_state;533	struct ath10k_ce *ce = ath10k_ce_priv(ar);534	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);535	struct ath10k_ce_pipe *ce_pipe = pipe->ce_hdl;536	int ret, num;537 538	if (pipe->buf_sz == 0)539		return;540 541	if (!ce_pipe->dest_ring)542		return;543 544	spin_lock_bh(&ce->ce_lock);545	num = __ath10k_ce_rx_num_free_bufs(ce_pipe);546	spin_unlock_bh(&ce->ce_lock);547	while (num--) {548		ret = __ath10k_snoc_rx_post_buf(pipe);549		if (ret) {550			if (ret == -ENOSPC)551				break;552			ath10k_warn(ar, "failed to post rx buf: %d\n", ret);553			mod_timer(&ar_snoc->rx_post_retry, jiffies +554				  ATH10K_SNOC_RX_POST_RETRY_MS);555			break;556		}557	}558}559 560static void ath10k_snoc_rx_post(struct ath10k *ar)561{562	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);563	int i;564 565	for (i = 0; i < CE_COUNT; i++)566		ath10k_snoc_rx_post_pipe(&ar_snoc->pipe_info[i]);567}568 569static void ath10k_snoc_process_rx_cb(struct ath10k_ce_pipe *ce_state,570				      void (*callback)(struct ath10k *ar,571						       struct sk_buff *skb))572{573	struct ath10k *ar = ce_state->ar;574	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);575	struct ath10k_snoc_pipe *pipe_info =  &ar_snoc->pipe_info[ce_state->id];576	struct sk_buff *skb;577	struct sk_buff_head list;578	void *transfer_context;579	unsigned int nbytes, max_nbytes;580 581	__skb_queue_head_init(&list);582	while (ath10k_ce_completed_recv_next(ce_state, &transfer_context,583					     &nbytes) == 0) {584		skb = transfer_context;585		max_nbytes = skb->len + skb_tailroom(skb);586		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,587				 max_nbytes, DMA_FROM_DEVICE);588 589		if (unlikely(max_nbytes < nbytes)) {590			ath10k_warn(ar, "rxed more than expected (nbytes %d, max %d)\n",591				    nbytes, max_nbytes);592			dev_kfree_skb_any(skb);593			continue;594		}595 596		skb_put(skb, nbytes);597		__skb_queue_tail(&list, skb);598	}599 600	while ((skb = __skb_dequeue(&list))) {601		ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc rx ce pipe %d len %d\n",602			   ce_state->id, skb->len);603 604		callback(ar, skb);605	}606 607	ath10k_snoc_rx_post_pipe(pipe_info);608}609 610static void ath10k_snoc_htc_rx_cb(struct ath10k_ce_pipe *ce_state)611{612	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);613}614 615static void ath10k_snoc_htt_htc_rx_cb(struct ath10k_ce_pipe *ce_state)616{617	/* CE4 polling needs to be done whenever CE pipe which transports618	 * HTT Rx (target->host) is processed.619	 */620	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);621 622	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);623}624 625/* Called by lower (CE) layer when data is received from the Target.626 * WCN3990 firmware uses separate CE(CE11) to transfer pktlog data.627 */628static void ath10k_snoc_pktlog_rx_cb(struct ath10k_ce_pipe *ce_state)629{630	ath10k_snoc_process_rx_cb(ce_state, ath10k_htc_rx_completion_handler);631}632 633static void ath10k_snoc_htt_rx_deliver(struct ath10k *ar, struct sk_buff *skb)634{635	skb_pull(skb, sizeof(struct ath10k_htc_hdr));636	ath10k_htt_t2h_msg_handler(ar, skb);637}638 639static void ath10k_snoc_htt_rx_cb(struct ath10k_ce_pipe *ce_state)640{641	ath10k_ce_per_engine_service(ce_state->ar, CE_POLL_PIPE);642	ath10k_snoc_process_rx_cb(ce_state, ath10k_snoc_htt_rx_deliver);643}644 645static void ath10k_snoc_rx_replenish_retry(struct timer_list *t)646{647	struct ath10k_snoc *ar_snoc = from_timer(ar_snoc, t, rx_post_retry);648	struct ath10k *ar = ar_snoc->ar;649 650	ath10k_snoc_rx_post(ar);651}652 653static void ath10k_snoc_htc_tx_cb(struct ath10k_ce_pipe *ce_state)654{655	struct ath10k *ar = ce_state->ar;656	struct sk_buff_head list;657	struct sk_buff *skb;658 659	__skb_queue_head_init(&list);660	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {661		if (!skb)662			continue;663 664		__skb_queue_tail(&list, skb);665	}666 667	while ((skb = __skb_dequeue(&list)))668		ath10k_htc_tx_completion_handler(ar, skb);669}670 671static void ath10k_snoc_htt_tx_cb(struct ath10k_ce_pipe *ce_state)672{673	struct ath10k *ar = ce_state->ar;674	struct sk_buff *skb;675 676	while (ath10k_ce_completed_send_next(ce_state, (void **)&skb) == 0) {677		if (!skb)678			continue;679 680		dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,681				 skb->len, DMA_TO_DEVICE);682		ath10k_htt_hif_tx_complete(ar, skb);683	}684}685 686static int ath10k_snoc_hif_tx_sg(struct ath10k *ar, u8 pipe_id,687				 struct ath10k_hif_sg_item *items, int n_items)688{689	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);690	struct ath10k_ce *ce = ath10k_ce_priv(ar);691	struct ath10k_snoc_pipe *snoc_pipe;692	struct ath10k_ce_pipe *ce_pipe;693	int err, i = 0;694 695	snoc_pipe = &ar_snoc->pipe_info[pipe_id];696	ce_pipe = snoc_pipe->ce_hdl;697	spin_lock_bh(&ce->ce_lock);698 699	for (i = 0; i < n_items - 1; i++) {700		ath10k_dbg(ar, ATH10K_DBG_SNOC,701			   "snoc tx item %d paddr %pad len %d n_items %d\n",702			   i, &items[i].paddr, items[i].len, n_items);703 704		err = ath10k_ce_send_nolock(ce_pipe,705					    items[i].transfer_context,706					    items[i].paddr,707					    items[i].len,708					    items[i].transfer_id,709					    CE_SEND_FLAG_GATHER);710		if (err)711			goto err;712	}713 714	ath10k_dbg(ar, ATH10K_DBG_SNOC,715		   "snoc tx item %d paddr %pad len %d n_items %d\n",716		   i, &items[i].paddr, items[i].len, n_items);717 718	err = ath10k_ce_send_nolock(ce_pipe,719				    items[i].transfer_context,720				    items[i].paddr,721				    items[i].len,722				    items[i].transfer_id,723				    0);724	if (err)725		goto err;726 727	spin_unlock_bh(&ce->ce_lock);728 729	return 0;730 731err:732	for (; i > 0; i--)733		__ath10k_ce_send_revert(ce_pipe);734 735	spin_unlock_bh(&ce->ce_lock);736	return err;737}738 739static int ath10k_snoc_hif_get_target_info(struct ath10k *ar,740					   struct bmi_target_info *target_info)741{742	target_info->version = ATH10K_HW_WCN3990;743	target_info->type = ATH10K_HW_WCN3990;744 745	return 0;746}747 748static u16 ath10k_snoc_hif_get_free_queue_number(struct ath10k *ar, u8 pipe)749{750	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);751 752	ath10k_dbg(ar, ATH10K_DBG_SNOC, "hif get free queue number\n");753 754	return ath10k_ce_num_free_src_entries(ar_snoc->pipe_info[pipe].ce_hdl);755}756 757static void ath10k_snoc_hif_send_complete_check(struct ath10k *ar, u8 pipe,758						int force)759{760	int resources;761 762	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif send complete check\n");763 764	if (!force) {765		resources = ath10k_snoc_hif_get_free_queue_number(ar, pipe);766 767		if (resources > (host_ce_config_wlan[pipe].src_nentries >> 1))768			return;769	}770	ath10k_ce_per_engine_service(ar, pipe);771}772 773static int ath10k_snoc_hif_map_service_to_pipe(struct ath10k *ar,774					       u16 service_id,775					       u8 *ul_pipe, u8 *dl_pipe)776{777	const struct ce_service_to_pipe *entry;778	bool ul_set = false, dl_set = false;779	int i;780 781	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif map service\n");782 783	for (i = 0; i < ARRAY_SIZE(target_service_to_ce_map_wlan); i++) {784		entry = &target_service_to_ce_map_wlan[i];785 786		if (__le32_to_cpu(entry->service_id) != service_id)787			continue;788 789		switch (__le32_to_cpu(entry->pipedir)) {790		case PIPEDIR_NONE:791			break;792		case PIPEDIR_IN:793			WARN_ON(dl_set);794			*dl_pipe = __le32_to_cpu(entry->pipenum);795			dl_set = true;796			break;797		case PIPEDIR_OUT:798			WARN_ON(ul_set);799			*ul_pipe = __le32_to_cpu(entry->pipenum);800			ul_set = true;801			break;802		case PIPEDIR_INOUT:803			WARN_ON(dl_set);804			WARN_ON(ul_set);805			*dl_pipe = __le32_to_cpu(entry->pipenum);806			*ul_pipe = __le32_to_cpu(entry->pipenum);807			dl_set = true;808			ul_set = true;809			break;810		}811	}812 813	if (!ul_set || !dl_set)814		return -ENOENT;815 816	return 0;817}818 819static void ath10k_snoc_hif_get_default_pipe(struct ath10k *ar,820					     u8 *ul_pipe, u8 *dl_pipe)821{822	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc hif get default pipe\n");823 824	(void)ath10k_snoc_hif_map_service_to_pipe(ar,825						 ATH10K_HTC_SVC_ID_RSVD_CTRL,826						 ul_pipe, dl_pipe);827}828 829static inline void ath10k_snoc_irq_disable(struct ath10k *ar)830{831	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);832	int id;833 834	for (id = 0; id < CE_COUNT_MAX; id++)835		disable_irq(ar_snoc->ce_irqs[id].irq_line);836}837 838static inline void ath10k_snoc_irq_enable(struct ath10k *ar)839{840	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);841	int id;842 843	for (id = 0; id < CE_COUNT_MAX; id++)844		enable_irq(ar_snoc->ce_irqs[id].irq_line);845}846 847static void ath10k_snoc_rx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)848{849	struct ath10k_ce_pipe *ce_pipe;850	struct ath10k_ce_ring *ce_ring;851	struct sk_buff *skb;852	struct ath10k *ar;853	int i;854 855	ar = snoc_pipe->hif_ce_state;856	ce_pipe = snoc_pipe->ce_hdl;857	ce_ring = ce_pipe->dest_ring;858 859	if (!ce_ring)860		return;861 862	if (!snoc_pipe->buf_sz)863		return;864 865	for (i = 0; i < ce_ring->nentries; i++) {866		skb = ce_ring->per_transfer_context[i];867		if (!skb)868			continue;869 870		ce_ring->per_transfer_context[i] = NULL;871 872		dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,873				 skb->len + skb_tailroom(skb),874				 DMA_FROM_DEVICE);875		dev_kfree_skb_any(skb);876	}877}878 879static void ath10k_snoc_tx_pipe_cleanup(struct ath10k_snoc_pipe *snoc_pipe)880{881	struct ath10k_ce_pipe *ce_pipe;882	struct ath10k_ce_ring *ce_ring;883	struct sk_buff *skb;884	struct ath10k *ar;885	int i;886 887	ar = snoc_pipe->hif_ce_state;888	ce_pipe = snoc_pipe->ce_hdl;889	ce_ring = ce_pipe->src_ring;890 891	if (!ce_ring)892		return;893 894	if (!snoc_pipe->buf_sz)895		return;896 897	for (i = 0; i < ce_ring->nentries; i++) {898		skb = ce_ring->per_transfer_context[i];899		if (!skb)900			continue;901 902		ce_ring->per_transfer_context[i] = NULL;903 904		ath10k_htc_tx_completion_handler(ar, skb);905	}906}907 908static void ath10k_snoc_buffer_cleanup(struct ath10k *ar)909{910	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);911	struct ath10k_snoc_pipe *pipe_info;912	int pipe_num;913 914	del_timer_sync(&ar_snoc->rx_post_retry);915	for (pipe_num = 0; pipe_num < CE_COUNT; pipe_num++) {916		pipe_info = &ar_snoc->pipe_info[pipe_num];917		ath10k_snoc_rx_pipe_cleanup(pipe_info);918		ath10k_snoc_tx_pipe_cleanup(pipe_info);919	}920}921 922static void ath10k_snoc_hif_stop(struct ath10k *ar)923{924	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags))925		ath10k_snoc_irq_disable(ar);926 927	ath10k_core_napi_sync_disable(ar);928	ath10k_snoc_buffer_cleanup(ar);929	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif stop\n");930}931 932static int ath10k_snoc_hif_start(struct ath10k *ar)933{934	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);935 936	bitmap_clear(ar_snoc->pending_ce_irqs, 0, CE_COUNT_MAX);937 938	dev_set_threaded(ar->napi_dev, true);939	ath10k_core_napi_enable(ar);940	ath10k_snoc_irq_enable(ar);941	ath10k_snoc_rx_post(ar);942 943	clear_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);944 945	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif start\n");946 947	return 0;948}949 950static int ath10k_snoc_init_pipes(struct ath10k *ar)951{952	int i, ret;953 954	for (i = 0; i < CE_COUNT; i++) {955		ret = ath10k_ce_init_pipe(ar, i, &host_ce_config_wlan[i]);956		if (ret) {957			ath10k_err(ar, "failed to initialize copy engine pipe %d: %d\n",958				   i, ret);959			return ret;960		}961	}962 963	return 0;964}965 966static int ath10k_snoc_wlan_enable(struct ath10k *ar,967				   enum ath10k_firmware_mode fw_mode)968{969	struct ath10k_tgt_pipe_cfg tgt_cfg[CE_COUNT_MAX];970	struct ath10k_qmi_wlan_enable_cfg cfg;971	enum wlfw_driver_mode_enum_v01 mode;972	int pipe_num;973 974	for (pipe_num = 0; pipe_num < CE_COUNT_MAX; pipe_num++) {975		tgt_cfg[pipe_num].pipe_num =976				target_ce_config_wlan[pipe_num].pipenum;977		tgt_cfg[pipe_num].pipe_dir =978				target_ce_config_wlan[pipe_num].pipedir;979		tgt_cfg[pipe_num].nentries =980				target_ce_config_wlan[pipe_num].nentries;981		tgt_cfg[pipe_num].nbytes_max =982				target_ce_config_wlan[pipe_num].nbytes_max;983		tgt_cfg[pipe_num].flags =984				target_ce_config_wlan[pipe_num].flags;985		tgt_cfg[pipe_num].reserved = 0;986	}987 988	cfg.num_ce_tgt_cfg = sizeof(target_ce_config_wlan) /989				sizeof(struct ath10k_tgt_pipe_cfg);990	cfg.ce_tgt_cfg = (struct ath10k_tgt_pipe_cfg *)991		&tgt_cfg;992	cfg.num_ce_svc_pipe_cfg = sizeof(target_service_to_ce_map_wlan) /993				  sizeof(struct ath10k_svc_pipe_cfg);994	cfg.ce_svc_cfg = (struct ath10k_svc_pipe_cfg *)995		&target_service_to_ce_map_wlan;996	cfg.num_shadow_reg_cfg = ARRAY_SIZE(target_shadow_reg_cfg_map);997	cfg.shadow_reg_cfg = (struct ath10k_shadow_reg_cfg *)998		&target_shadow_reg_cfg_map;999 1000	switch (fw_mode) {1001	case ATH10K_FIRMWARE_MODE_NORMAL:1002		mode = QMI_WLFW_MISSION_V01;1003		break;1004	case ATH10K_FIRMWARE_MODE_UTF:1005		mode = QMI_WLFW_FTM_V01;1006		break;1007	default:1008		ath10k_err(ar, "invalid firmware mode %d\n", fw_mode);1009		return -EINVAL;1010	}1011 1012	return ath10k_qmi_wlan_enable(ar, &cfg, mode,1013				       NULL);1014}1015 1016static int ath10k_hw_power_on(struct ath10k *ar)1017{1018	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1019	int ret;1020 1021	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power on\n");1022 1023	ret = regulator_bulk_enable(ar_snoc->num_vregs, ar_snoc->vregs);1024	if (ret)1025		return ret;1026 1027	ret = clk_bulk_prepare_enable(ar_snoc->num_clks, ar_snoc->clks);1028	if (ret)1029		goto vreg_off;1030 1031	return ret;1032 1033vreg_off:1034	regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1035	return ret;1036}1037 1038static int ath10k_hw_power_off(struct ath10k *ar)1039{1040	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1041 1042	ath10k_dbg(ar, ATH10K_DBG_SNOC, "soc power off\n");1043 1044	clk_bulk_disable_unprepare(ar_snoc->num_clks, ar_snoc->clks);1045 1046	return regulator_bulk_disable(ar_snoc->num_vregs, ar_snoc->vregs);1047}1048 1049static void ath10k_snoc_wlan_disable(struct ath10k *ar)1050{1051	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1052 1053	/* If both ATH10K_FLAG_CRASH_FLUSH and ATH10K_SNOC_FLAG_RECOVERY1054	 * flags are not set, it means that the driver has restarted1055	 * due to a crash inject via debugfs. In this case, the driver1056	 * needs to restart the firmware and hence send qmi wlan disable,1057	 * during the driver restart sequence.1058	 */1059	if (!test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags) ||1060	    !test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1061		ath10k_qmi_wlan_disable(ar);1062}1063 1064static void ath10k_snoc_hif_power_down(struct ath10k *ar)1065{1066	ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot hif power down\n");1067 1068	ath10k_snoc_wlan_disable(ar);1069	ath10k_ce_free_rri(ar);1070	ath10k_hw_power_off(ar);1071}1072 1073static int ath10k_snoc_hif_power_up(struct ath10k *ar,1074				    enum ath10k_firmware_mode fw_mode)1075{1076	int ret;1077 1078	ath10k_dbg(ar, ATH10K_DBG_SNOC, "%s:WCN3990 driver state = %d\n",1079		   __func__, ar->state);1080 1081	ret = ath10k_hw_power_on(ar);1082	if (ret) {1083		ath10k_err(ar, "failed to power on device: %d\n", ret);1084		return ret;1085	}1086 1087	ret = ath10k_snoc_wlan_enable(ar, fw_mode);1088	if (ret) {1089		ath10k_err(ar, "failed to enable wcn3990: %d\n", ret);1090		goto err_hw_power_off;1091	}1092 1093	ath10k_ce_alloc_rri(ar);1094 1095	ret = ath10k_snoc_init_pipes(ar);1096	if (ret) {1097		ath10k_err(ar, "failed to initialize CE: %d\n", ret);1098		goto err_free_rri;1099	}1100 1101	ath10k_ce_enable_interrupts(ar);1102 1103	return 0;1104 1105err_free_rri:1106	ath10k_ce_free_rri(ar);1107	ath10k_snoc_wlan_disable(ar);1108 1109err_hw_power_off:1110	ath10k_hw_power_off(ar);1111 1112	return ret;1113}1114 1115static int ath10k_snoc_hif_set_target_log_mode(struct ath10k *ar,1116					       u8 fw_log_mode)1117{1118	u8 fw_dbg_mode;1119 1120	if (fw_log_mode)1121		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_CE;1122	else1123		fw_dbg_mode = ATH10K_ENABLE_FW_LOG_DIAG;1124 1125	return ath10k_qmi_set_fw_log_mode(ar, fw_dbg_mode);1126}1127 1128#ifdef CONFIG_PM1129static int ath10k_snoc_hif_suspend(struct ath10k *ar)1130{1131	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1132	int ret;1133 1134	if (!device_may_wakeup(ar->dev))1135		return -EPERM;1136 1137	ret = enable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1138	if (ret) {1139		ath10k_err(ar, "failed to enable wakeup irq :%d\n", ret);1140		return ret;1141	}1142 1143	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device suspended\n");1144 1145	return ret;1146}1147 1148static int ath10k_snoc_hif_resume(struct ath10k *ar)1149{1150	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1151	int ret;1152 1153	if (!device_may_wakeup(ar->dev))1154		return -EPERM;1155 1156	ret = disable_irq_wake(ar_snoc->ce_irqs[ATH10K_SNOC_WAKE_IRQ].irq_line);1157	if (ret) {1158		ath10k_err(ar, "failed to disable wakeup irq: %d\n", ret);1159		return ret;1160	}1161 1162	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc device resumed\n");1163 1164	return ret;1165}1166#endif1167 1168static const struct ath10k_hif_ops ath10k_snoc_hif_ops = {1169	.read32		= ath10k_snoc_read32,1170	.write32	= ath10k_snoc_write32,1171	.start		= ath10k_snoc_hif_start,1172	.stop		= ath10k_snoc_hif_stop,1173	.map_service_to_pipe	= ath10k_snoc_hif_map_service_to_pipe,1174	.get_default_pipe	= ath10k_snoc_hif_get_default_pipe,1175	.power_up		= ath10k_snoc_hif_power_up,1176	.power_down		= ath10k_snoc_hif_power_down,1177	.tx_sg			= ath10k_snoc_hif_tx_sg,1178	.send_complete_check	= ath10k_snoc_hif_send_complete_check,1179	.get_free_queue_number	= ath10k_snoc_hif_get_free_queue_number,1180	.get_target_info	= ath10k_snoc_hif_get_target_info,1181	.set_target_log_mode    = ath10k_snoc_hif_set_target_log_mode,1182 1183#ifdef CONFIG_PM1184	.suspend                = ath10k_snoc_hif_suspend,1185	.resume                 = ath10k_snoc_hif_resume,1186#endif1187};1188 1189static const struct ath10k_bus_ops ath10k_snoc_bus_ops = {1190	.read32		= ath10k_snoc_read32,1191	.write32	= ath10k_snoc_write32,1192};1193 1194static int ath10k_snoc_get_ce_id_from_irq(struct ath10k *ar, int irq)1195{1196	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1197	int i;1198 1199	for (i = 0; i < CE_COUNT_MAX; i++) {1200		if (ar_snoc->ce_irqs[i].irq_line == irq)1201			return i;1202	}1203	ath10k_err(ar, "No matching CE id for irq %d\n", irq);1204 1205	return -EINVAL;1206}1207 1208static irqreturn_t ath10k_snoc_per_engine_handler(int irq, void *arg)1209{1210	struct ath10k *ar = arg;1211	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1212	int ce_id = ath10k_snoc_get_ce_id_from_irq(ar, irq);1213 1214	if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_snoc->pipe_info)) {1215		ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,1216			    ce_id);1217		return IRQ_HANDLED;1218	}1219 1220	ath10k_ce_disable_interrupt(ar, ce_id);1221	set_bit(ce_id, ar_snoc->pending_ce_irqs);1222 1223	napi_schedule(&ar->napi);1224 1225	return IRQ_HANDLED;1226}1227 1228static int ath10k_snoc_napi_poll(struct napi_struct *ctx, int budget)1229{1230	struct ath10k *ar = container_of(ctx, struct ath10k, napi);1231	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1232	int done = 0;1233	int ce_id;1234 1235	if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {1236		napi_complete(ctx);1237		return done;1238	}1239 1240	for (ce_id = 0; ce_id < CE_COUNT; ce_id++)1241		if (test_and_clear_bit(ce_id, ar_snoc->pending_ce_irqs)) {1242			ath10k_ce_per_engine_service(ar, ce_id);1243			ath10k_ce_enable_interrupt(ar, ce_id);1244		}1245 1246	done = ath10k_htt_txrx_compl_task(ar, budget);1247 1248	if (done < budget)1249		napi_complete(ctx);1250 1251	return done;1252}1253 1254static void ath10k_snoc_init_napi(struct ath10k *ar)1255{1256	netif_napi_add(ar->napi_dev, &ar->napi, ath10k_snoc_napi_poll);1257}1258 1259static int ath10k_snoc_request_irq(struct ath10k *ar)1260{1261	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1262	int ret, id;1263 1264	for (id = 0; id < CE_COUNT_MAX; id++) {1265		ret = request_irq(ar_snoc->ce_irqs[id].irq_line,1266				  ath10k_snoc_per_engine_handler,1267				  IRQF_NO_AUTOEN, ce_name[id], ar);1268		if (ret) {1269			ath10k_err(ar,1270				   "failed to register IRQ handler for CE %d: %d\n",1271				   id, ret);1272			goto err_irq;1273		}1274	}1275 1276	return 0;1277 1278err_irq:1279	for (id -= 1; id >= 0; id--)1280		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);1281 1282	return ret;1283}1284 1285static void ath10k_snoc_free_irq(struct ath10k *ar)1286{1287	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1288	int id;1289 1290	for (id = 0; id < CE_COUNT_MAX; id++)1291		free_irq(ar_snoc->ce_irqs[id].irq_line, ar);1292}1293 1294static int ath10k_snoc_resource_init(struct ath10k *ar)1295{1296	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1297	struct platform_device *pdev;1298	struct resource *res;1299	int i, ret = 0;1300 1301	pdev = ar_snoc->dev;1302	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "membase");1303	if (!res) {1304		ath10k_err(ar, "Memory base not found in DT\n");1305		return -EINVAL;1306	}1307 1308	ar_snoc->mem_pa = res->start;1309	ar_snoc->mem = devm_ioremap(&pdev->dev, ar_snoc->mem_pa,1310				    resource_size(res));1311	if (!ar_snoc->mem) {1312		ath10k_err(ar, "Memory base ioremap failed with physical address %pa\n",1313			   &ar_snoc->mem_pa);1314		return -EINVAL;1315	}1316 1317	for (i = 0; i < CE_COUNT; i++) {1318		ret = platform_get_irq(ar_snoc->dev, i);1319		if (ret < 0)1320			return ret;1321		ar_snoc->ce_irqs[i].irq_line = ret;1322	}1323 1324	ret = device_property_read_u32(&pdev->dev, "qcom,xo-cal-data",1325				       &ar_snoc->xo_cal_data);1326	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc xo-cal-data return %d\n", ret);1327	if (ret == 0) {1328		ar_snoc->xo_cal_supported = true;1329		ath10k_dbg(ar, ATH10K_DBG_SNOC, "xo cal data %x\n",1330			   ar_snoc->xo_cal_data);1331	}1332 1333	return 0;1334}1335 1336static void ath10k_snoc_quirks_init(struct ath10k *ar)1337{1338	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1339	struct device *dev = &ar_snoc->dev->dev;1340 1341	/* ignore errors, keep NULL if there is no property */1342	of_property_read_string(dev->of_node, "firmware-name", &ar->board_name);1343 1344	if (of_property_read_bool(dev->of_node, "qcom,snoc-host-cap-8bit-quirk"))1345		set_bit(ATH10K_SNOC_FLAG_8BIT_HOST_CAP_QUIRK, &ar_snoc->flags);1346}1347 1348int ath10k_snoc_fw_indication(struct ath10k *ar, u64 type)1349{1350	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1351	struct ath10k_bus_params bus_params = {};1352	int ret;1353 1354	if (test_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags))1355		return 0;1356 1357	switch (type) {1358	case ATH10K_QMI_EVENT_FW_READY_IND:1359		if (test_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags)) {1360			ath10k_core_start_recovery(ar);1361			break;1362		}1363 1364		bus_params.dev_type = ATH10K_DEV_TYPE_LL;1365		bus_params.chip_id = ar_snoc->target_info.soc_version;1366		ret = ath10k_core_register(ar, &bus_params);1367		if (ret) {1368			ath10k_err(ar, "Failed to register driver core: %d\n",1369				   ret);1370			return ret;1371		}1372		set_bit(ATH10K_SNOC_FLAG_REGISTERED, &ar_snoc->flags);1373		break;1374	case ATH10K_QMI_EVENT_FW_DOWN_IND:1375		set_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags);1376		set_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);1377		break;1378	default:1379		ath10k_err(ar, "invalid fw indication: %llx\n", type);1380		return -EINVAL;1381	}1382 1383	return 0;1384}1385 1386static int ath10k_snoc_setup_resource(struct ath10k *ar)1387{1388	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1389	struct ath10k_ce *ce = ath10k_ce_priv(ar);1390	struct ath10k_snoc_pipe *pipe;1391	int i, ret;1392 1393	timer_setup(&ar_snoc->rx_post_retry, ath10k_snoc_rx_replenish_retry, 0);1394	spin_lock_init(&ce->ce_lock);1395	for (i = 0; i < CE_COUNT; i++) {1396		pipe = &ar_snoc->pipe_info[i];1397		pipe->ce_hdl = &ce->ce_states[i];1398		pipe->pipe_num = i;1399		pipe->hif_ce_state = ar;1400 1401		ret = ath10k_ce_alloc_pipe(ar, i, &host_ce_config_wlan[i]);1402		if (ret) {1403			ath10k_err(ar, "failed to allocate copy engine pipe %d: %d\n",1404				   i, ret);1405			return ret;1406		}1407 1408		pipe->buf_sz = host_ce_config_wlan[i].src_sz_max;1409	}1410	ath10k_snoc_init_napi(ar);1411 1412	return 0;1413}1414 1415static void ath10k_snoc_release_resource(struct ath10k *ar)1416{1417	int i;1418 1419	netif_napi_del(&ar->napi);1420	for (i = 0; i < CE_COUNT; i++)1421		ath10k_ce_free_pipe(ar, i);1422}1423 1424static void ath10k_msa_dump_memory(struct ath10k *ar,1425				   struct ath10k_fw_crash_data *crash_data)1426{1427	const struct ath10k_hw_mem_layout *mem_layout;1428	const struct ath10k_mem_region *current_region;1429	struct ath10k_dump_ram_data_hdr *hdr;1430	size_t buf_len;1431	u8 *buf;1432 1433	if (!crash_data || !crash_data->ramdump_buf)1434		return;1435 1436	mem_layout = ath10k_coredump_get_mem_layout(ar);1437	if (!mem_layout)1438		return;1439 1440	current_region = &mem_layout->region_table.regions[0];1441 1442	buf = crash_data->ramdump_buf;1443	buf_len = crash_data->ramdump_buf_len;1444	memset(buf, 0, buf_len);1445 1446	/* Reserve space for the header. */1447	hdr = (void *)buf;1448	buf += sizeof(*hdr);1449	buf_len -= sizeof(*hdr);1450 1451	hdr->region_type = cpu_to_le32(current_region->type);1452	hdr->start = cpu_to_le32((unsigned long)ar->msa.vaddr);1453	hdr->length = cpu_to_le32(ar->msa.mem_size);1454 1455	if (current_region->len < ar->msa.mem_size) {1456		memcpy(buf, ar->msa.vaddr, current_region->len);1457		ath10k_warn(ar, "msa dump length is less than msa size %x, %x\n",1458			    current_region->len, ar->msa.mem_size);1459	} else {1460		memcpy(buf, ar->msa.vaddr, ar->msa.mem_size);1461	}1462}1463 1464void ath10k_snoc_fw_crashed_dump(struct ath10k *ar)1465{1466	struct ath10k_fw_crash_data *crash_data;1467	char guid[UUID_STRING_LEN + 1];1468 1469	mutex_lock(&ar->dump_mutex);1470 1471	spin_lock_bh(&ar->data_lock);1472	ar->stats.fw_crash_counter++;1473	spin_unlock_bh(&ar->data_lock);1474 1475	crash_data = ath10k_coredump_new(ar);1476 1477	if (crash_data)1478		scnprintf(guid, sizeof(guid), "%pUl", &crash_data->guid);1479	else1480		scnprintf(guid, sizeof(guid), "n/a");1481 1482	ath10k_err(ar, "firmware crashed! (guid %s)\n", guid);1483	ath10k_print_driver_info(ar);1484	ath10k_msa_dump_memory(ar, crash_data);1485	mutex_unlock(&ar->dump_mutex);1486}1487 1488static int ath10k_snoc_modem_notify(struct notifier_block *nb, unsigned long action,1489				    void *data)1490{1491	struct ath10k_snoc *ar_snoc = container_of(nb, struct ath10k_snoc, nb);1492	struct ath10k *ar = ar_snoc->ar;1493	struct qcom_ssr_notify_data *notify_data = data;1494 1495	switch (action) {1496	case QCOM_SSR_BEFORE_POWERUP:1497		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem starting event\n");1498		clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1499		break;1500 1501	case QCOM_SSR_AFTER_POWERUP:1502		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem running event\n");1503		break;1504 1505	case QCOM_SSR_BEFORE_SHUTDOWN:1506		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem %s event\n",1507			   notify_data->crashed ? "crashed" : "stopping");1508		if (!notify_data->crashed)1509			set_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1510		else1511			clear_bit(ATH10K_SNOC_FLAG_MODEM_STOPPED, &ar_snoc->flags);1512		break;1513 1514	case QCOM_SSR_AFTER_SHUTDOWN:1515		ath10k_dbg(ar, ATH10K_DBG_SNOC, "received modem offline event\n");1516		break;1517 1518	default:1519		ath10k_err(ar, "received unrecognized event %lu\n", action);1520		break;1521	}1522 1523	return NOTIFY_OK;1524}1525 1526static int ath10k_modem_init(struct ath10k *ar)1527{1528	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1529	void *notifier;1530	int ret;1531 1532	ar_snoc->nb.notifier_call = ath10k_snoc_modem_notify;1533 1534	notifier = qcom_register_ssr_notifier("mpss", &ar_snoc->nb);1535	if (IS_ERR(notifier)) {1536		ret = PTR_ERR(notifier);1537		ath10k_err(ar, "failed to initialize modem notifier: %d\n", ret);1538		return ret;1539	}1540 1541	ar_snoc->notifier = notifier;1542 1543	return 0;1544}1545 1546static void ath10k_modem_deinit(struct ath10k *ar)1547{1548	int ret;1549	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1550 1551	ret = qcom_unregister_ssr_notifier(ar_snoc->notifier, &ar_snoc->nb);1552	if (ret)1553		ath10k_err(ar, "error %d unregistering notifier\n", ret);1554}1555 1556static int ath10k_setup_msa_resources(struct ath10k *ar, u32 msa_size)1557{1558	struct device *dev = ar->dev;1559	struct device_node *node;1560	struct resource r;1561	int ret;1562 1563	node = of_parse_phandle(dev->of_node, "memory-region", 0);1564	if (node) {1565		ret = of_address_to_resource(node, 0, &r);1566		of_node_put(node);1567		if (ret) {1568			dev_err(dev, "failed to resolve msa fixed region\n");1569			return ret;1570		}1571 1572		ar->msa.paddr = r.start;1573		ar->msa.mem_size = resource_size(&r);1574		ar->msa.vaddr = devm_memremap(dev, ar->msa.paddr,1575					      ar->msa.mem_size,1576					      MEMREMAP_WT);1577		if (IS_ERR(ar->msa.vaddr)) {1578			dev_err(dev, "failed to map memory region: %pa\n",1579				&r.start);1580			return PTR_ERR(ar->msa.vaddr);1581		}1582	} else {1583		ar->msa.vaddr = dmam_alloc_coherent(dev, msa_size,1584						    &ar->msa.paddr,1585						    GFP_KERNEL);1586		if (!ar->msa.vaddr) {1587			ath10k_err(ar, "failed to allocate dma memory for msa region\n");1588			return -ENOMEM;1589		}1590		ar->msa.mem_size = msa_size;1591	}1592 1593	ath10k_dbg(ar, ATH10K_DBG_QMI, "qmi msa.paddr: %pad , msa.vaddr: 0x%p\n",1594		   &ar->msa.paddr,1595		   ar->msa.vaddr);1596 1597	return 0;1598}1599 1600static int ath10k_fw_init(struct ath10k *ar)1601{1602	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1603	struct device *host_dev = &ar_snoc->dev->dev;1604	struct platform_device_info info;1605	struct iommu_domain *iommu_dom;1606	struct platform_device *pdev;1607	struct device_node *node;1608	int ret;1609 1610	node = of_get_child_by_name(host_dev->of_node, "wifi-firmware");1611	if (!node) {1612		ar_snoc->use_tz = true;1613		return 0;1614	}1615 1616	memset(&info, 0, sizeof(info));1617	info.fwnode = &node->fwnode;1618	info.parent = host_dev;1619	info.name = node->name;1620	info.dma_mask = DMA_BIT_MASK(32);1621 1622	pdev = platform_device_register_full(&info);1623	if (IS_ERR(pdev)) {1624		of_node_put(node);1625		return PTR_ERR(pdev);1626	}1627 1628	pdev->dev.of_node = node;1629 1630	ret = of_dma_configure(&pdev->dev, node, true);1631	if (ret) {1632		ath10k_err(ar, "dma configure fail: %d\n", ret);1633		goto err_unregister;1634	}1635 1636	ar_snoc->fw.dev = &pdev->dev;1637 1638	iommu_dom = iommu_paging_domain_alloc(ar_snoc->fw.dev);1639	if (IS_ERR(iommu_dom)) {1640		ath10k_err(ar, "failed to allocate iommu domain\n");1641		ret = PTR_ERR(iommu_dom);1642		goto err_unregister;1643	}1644 1645	ret = iommu_attach_device(iommu_dom, ar_snoc->fw.dev);1646	if (ret) {1647		ath10k_err(ar, "could not attach device: %d\n", ret);1648		goto err_iommu_free;1649	}1650 1651	ar_snoc->fw.iommu_domain = iommu_dom;1652	ar_snoc->fw.fw_start_addr = ar->msa.paddr;1653 1654	ret = iommu_map(iommu_dom, ar_snoc->fw.fw_start_addr,1655			ar->msa.paddr, ar->msa.mem_size,1656			IOMMU_READ | IOMMU_WRITE, GFP_KERNEL);1657	if (ret) {1658		ath10k_err(ar, "failed to map firmware region: %d\n", ret);1659		goto err_iommu_detach;1660	}1661 1662	of_node_put(node);1663 1664	return 0;1665 1666err_iommu_detach:1667	iommu_detach_device(iommu_dom, ar_snoc->fw.dev);1668 1669err_iommu_free:1670	iommu_domain_free(iommu_dom);1671 1672err_unregister:1673	platform_device_unregister(pdev);1674	of_node_put(node);1675 1676	return ret;1677}1678 1679static int ath10k_fw_deinit(struct ath10k *ar)1680{1681	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1682	const size_t mapped_size = ar_snoc->fw.mapped_mem_size;1683	struct iommu_domain *iommu;1684	size_t unmapped_size;1685 1686	if (ar_snoc->use_tz)1687		return 0;1688 1689	iommu = ar_snoc->fw.iommu_domain;1690 1691	unmapped_size = iommu_unmap(iommu, ar_snoc->fw.fw_start_addr,1692				    mapped_size);1693	if (unmapped_size != mapped_size)1694		ath10k_err(ar, "failed to unmap firmware: %zu\n",1695			   unmapped_size);1696 1697	iommu_detach_device(iommu, ar_snoc->fw.dev);1698	iommu_domain_free(iommu);1699 1700	platform_device_unregister(to_platform_device(ar_snoc->fw.dev));1701 1702	return 0;1703}1704 1705static const struct of_device_id ath10k_snoc_dt_match[] = {1706	{ .compatible = "qcom,wcn3990-wifi",1707	 .data = &drv_priv,1708	},1709	{ }1710};1711MODULE_DEVICE_TABLE(of, ath10k_snoc_dt_match);1712 1713static int ath10k_snoc_probe(struct platform_device *pdev)1714{1715	const struct ath10k_snoc_drv_priv *drv_data;1716	struct ath10k_snoc *ar_snoc;1717	struct device *dev;1718	struct ath10k *ar;1719	u32 msa_size;1720	int ret;1721	u32 i;1722 1723	dev = &pdev->dev;1724	drv_data = device_get_match_data(dev);1725	if (!drv_data) {1726		dev_err(dev, "failed to find matching device tree id\n");1727		return -EINVAL;1728	}1729 1730	ret = dma_set_mask_and_coherent(dev, drv_data->dma_mask);1731	if (ret) {1732		dev_err(dev, "failed to set dma mask: %d\n", ret);1733		return ret;1734	}1735 1736	ar = ath10k_core_create(sizeof(*ar_snoc), dev, ATH10K_BUS_SNOC,1737				drv_data->hw_rev, &ath10k_snoc_hif_ops);1738	if (!ar) {1739		dev_err(dev, "failed to allocate core\n");1740		return -ENOMEM;1741	}1742 1743	ar_snoc = ath10k_snoc_priv(ar);1744	ar_snoc->dev = pdev;1745	platform_set_drvdata(pdev, ar);1746	ar_snoc->ar = ar;1747	ar_snoc->ce.bus_ops = &ath10k_snoc_bus_ops;1748	ar->ce_priv = &ar_snoc->ce;1749	msa_size = drv_data->msa_size;1750 1751	ath10k_snoc_quirks_init(ar);1752 1753	ret = ath10k_snoc_resource_init(ar);1754	if (ret) {1755		ath10k_warn(ar, "failed to initialize resource: %d\n", ret);1756		goto err_core_destroy;1757	}1758 1759	ret = ath10k_snoc_setup_resource(ar);1760	if (ret) {1761		ath10k_warn(ar, "failed to setup resource: %d\n", ret);1762		goto err_core_destroy;1763	}1764	ret = ath10k_snoc_request_irq(ar);1765	if (ret) {1766		ath10k_warn(ar, "failed to request irqs: %d\n", ret);1767		goto err_release_resource;1768	}1769 1770	ar_snoc->num_vregs = ARRAY_SIZE(ath10k_regulators);1771	ar_snoc->vregs = devm_kcalloc(&pdev->dev, ar_snoc->num_vregs,1772				      sizeof(*ar_snoc->vregs), GFP_KERNEL);1773	if (!ar_snoc->vregs) {1774		ret = -ENOMEM;1775		goto err_free_irq;1776	}1777	for (i = 0; i < ar_snoc->num_vregs; i++)1778		ar_snoc->vregs[i].supply = ath10k_regulators[i];1779 1780	ret = devm_regulator_bulk_get(&pdev->dev, ar_snoc->num_vregs,1781				      ar_snoc->vregs);1782	if (ret < 0)1783		goto err_free_irq;1784 1785	ar_snoc->num_clks = ARRAY_SIZE(ath10k_clocks);1786	ar_snoc->clks = devm_kcalloc(&pdev->dev, ar_snoc->num_clks,1787				     sizeof(*ar_snoc->clks), GFP_KERNEL);1788	if (!ar_snoc->clks) {1789		ret = -ENOMEM;1790		goto err_free_irq;1791	}1792 1793	for (i = 0; i < ar_snoc->num_clks; i++)1794		ar_snoc->clks[i].id = ath10k_clocks[i];1795 1796	ret = devm_clk_bulk_get_optional(&pdev->dev, ar_snoc->num_clks,1797					 ar_snoc->clks);1798	if (ret)1799		goto err_free_irq;1800 1801	ret = ath10k_setup_msa_resources(ar, msa_size);1802	if (ret) {1803		ath10k_warn(ar, "failed to setup msa resources: %d\n", ret);1804		goto err_free_irq;1805	}1806 1807	ret = ath10k_fw_init(ar);1808	if (ret) {1809		ath10k_err(ar, "failed to initialize firmware: %d\n", ret);1810		goto err_free_irq;1811	}1812 1813	ret = ath10k_qmi_init(ar, msa_size);1814	if (ret) {1815		ath10k_warn(ar, "failed to register wlfw qmi client: %d\n", ret);1816		goto err_fw_deinit;1817	}1818 1819	ret = ath10k_modem_init(ar);1820	if (ret)1821		goto err_qmi_deinit;1822 1823	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc probe\n");1824 1825	return 0;1826 1827err_qmi_deinit:1828	ath10k_qmi_deinit(ar);1829 1830err_fw_deinit:1831	ath10k_fw_deinit(ar);1832 1833err_free_irq:1834	ath10k_snoc_free_irq(ar);1835 1836err_release_resource:1837	ath10k_snoc_release_resource(ar);1838 1839err_core_destroy:1840	ath10k_core_destroy(ar);1841 1842	return ret;1843}1844 1845static int ath10k_snoc_free_resources(struct ath10k *ar)1846{1847	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1848 1849	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc free resources\n");1850 1851	set_bit(ATH10K_SNOC_FLAG_UNREGISTERING, &ar_snoc->flags);1852 1853	ath10k_core_unregister(ar);1854	ath10k_fw_deinit(ar);1855	ath10k_snoc_free_irq(ar);1856	ath10k_snoc_release_resource(ar);1857	ath10k_modem_deinit(ar);1858	ath10k_qmi_deinit(ar);1859	ath10k_core_destroy(ar);1860 1861	return 0;1862}1863 1864static void ath10k_snoc_remove(struct platform_device *pdev)1865{1866	struct ath10k *ar = platform_get_drvdata(pdev);1867	struct ath10k_snoc *ar_snoc = ath10k_snoc_priv(ar);1868 1869	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc remove\n");1870 1871	reinit_completion(&ar->driver_recovery);1872 1873	if (test_bit(ATH10K_SNOC_FLAG_RECOVERY, &ar_snoc->flags))1874		wait_for_completion_timeout(&ar->driver_recovery, 3 * HZ);1875 1876	ath10k_snoc_free_resources(ar);1877}1878 1879static void ath10k_snoc_shutdown(struct platform_device *pdev)1880{1881	struct ath10k *ar = platform_get_drvdata(pdev);1882 1883	ath10k_dbg(ar, ATH10K_DBG_SNOC, "snoc shutdown\n");1884	ath10k_snoc_free_resources(ar);1885}1886 1887static struct platform_driver ath10k_snoc_driver = {1888	.probe  = ath10k_snoc_probe,1889	.remove_new = ath10k_snoc_remove,1890	.shutdown = ath10k_snoc_shutdown,1891	.driver = {1892		.name   = "ath10k_snoc",1893		.of_match_table = ath10k_snoc_dt_match,1894	},1895};1896module_platform_driver(ath10k_snoc_driver);1897 1898MODULE_AUTHOR("Qualcomm");1899MODULE_LICENSE("Dual BSD/GPL");1900MODULE_DESCRIPTION("Driver support for Atheros WCN3990 SNOC devices");1901