xref: /wlan-driver/qca-wifi-host-cmn/dp/wifi3.0/rh/dp_rh_htt.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
3*5113495bSYour Name  *
4*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
5*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
6*5113495bSYour Name  * above copyright notice and this permission notice appear in all
7*5113495bSYour Name  * copies.
8*5113495bSYour Name  *
9*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
14*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
15*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
17*5113495bSYour Name  */
18*5113495bSYour Name 
19*5113495bSYour Name #include <htt.h>
20*5113495bSYour Name #include "dp_types.h"
21*5113495bSYour Name #include "dp_internal.h"
22*5113495bSYour Name #include "dp_rh_htt.h"
23*5113495bSYour Name #include "dp_rh_rx.h"
24*5113495bSYour Name #include "qdf_mem.h"
25*5113495bSYour Name #include "cdp_txrx_cmn_struct.h"
26*5113495bSYour Name #include "dp_tx_desc.h"
27*5113495bSYour Name #include "dp_rh.h"
28*5113495bSYour Name 
29*5113495bSYour Name #define HTT_MSG_BUF_SIZE(msg_bytes) \
30*5113495bSYour Name 	((msg_bytes) + HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING)
31*5113495bSYour Name 
32*5113495bSYour Name #define HTT_T2H_MSG_BUF_REINIT(_buf, dev)				\
33*5113495bSYour Name 	do {								\
34*5113495bSYour Name 		qdf_nbuf_push_head(_buf, (HTC_HEADER_LEN) +		\
35*5113495bSYour Name 				   HTC_HDR_ALIGNMENT_PADDING);		\
36*5113495bSYour Name 		qdf_nbuf_init_fast((_buf));				\
37*5113495bSYour Name 		qdf_mem_dma_sync_single_for_device(dev,			\
38*5113495bSYour Name 					(QDF_NBUF_CB_PADDR(_buf)),	\
39*5113495bSYour Name 					(skb_end_pointer(_buf) -	\
40*5113495bSYour Name 					(_buf)->data),			\
41*5113495bSYour Name 					PCI_DMA_FROMDEVICE);		\
42*5113495bSYour Name 	} while (0)
43*5113495bSYour Name 
44*5113495bSYour Name /**
45*5113495bSYour Name  * dp_htt_flow_pool_map_handler_rh() - HTT_T2H_MSG_TYPE_FLOW_POOL_MAP handler
46*5113495bSYour Name  * @soc: Handle to DP Soc structure
47*5113495bSYour Name  * @flow_id: flow id
48*5113495bSYour Name  * @flow_type: flow type
49*5113495bSYour Name  * @flow_pool_id: pool id
50*5113495bSYour Name  * @flow_pool_size: pool size
51*5113495bSYour Name  *
52*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS - success, others - failure
53*5113495bSYour Name  */
54*5113495bSYour Name static QDF_STATUS
dp_htt_flow_pool_map_handler_rh(struct dp_soc * soc,uint8_t flow_id,uint8_t flow_type,uint8_t flow_pool_id,uint32_t flow_pool_size)55*5113495bSYour Name dp_htt_flow_pool_map_handler_rh(struct dp_soc *soc, uint8_t flow_id,
56*5113495bSYour Name 				uint8_t flow_type, uint8_t flow_pool_id,
57*5113495bSYour Name 				uint32_t flow_pool_size)
58*5113495bSYour Name {
59*5113495bSYour Name 	struct dp_vdev *vdev;
60*5113495bSYour Name 	struct dp_pdev *pdev;
61*5113495bSYour Name 	QDF_STATUS status;
62*5113495bSYour Name 
63*5113495bSYour Name 	if (flow_pool_id >= MAX_TXDESC_POOLS) {
64*5113495bSYour Name 		dp_err("invalid flow_pool_id %d", flow_pool_id);
65*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
66*5113495bSYour Name 	}
67*5113495bSYour Name 
68*5113495bSYour Name 	vdev = dp_vdev_get_ref_by_id(soc, flow_id, DP_MOD_ID_HTT);
69*5113495bSYour Name 	if (vdev) {
70*5113495bSYour Name 		pdev = vdev->pdev;
71*5113495bSYour Name 		dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_HTT);
72*5113495bSYour Name 	} else {
73*5113495bSYour Name 		pdev = soc->pdev_list[0];
74*5113495bSYour Name 	}
75*5113495bSYour Name 
76*5113495bSYour Name 	status = dp_tx_flow_pool_map_handler(pdev, flow_id, flow_type,
77*5113495bSYour Name 					     flow_pool_id, flow_pool_size);
78*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
79*5113495bSYour Name 		dp_err("failed to create tx flow pool %d", flow_pool_id);
80*5113495bSYour Name 		goto err_out;
81*5113495bSYour Name 	}
82*5113495bSYour Name 
83*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
84*5113495bSYour Name 
85*5113495bSYour Name err_out:
86*5113495bSYour Name 	/* TODO: is assert needed ? */
87*5113495bSYour Name 	qdf_assert_always(0);
88*5113495bSYour Name 	return status;
89*5113495bSYour Name }
90*5113495bSYour Name 
91*5113495bSYour Name /**
92*5113495bSYour Name  * dp_htt_flow_pool_unmap_handler_rh() - HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP handler
93*5113495bSYour Name  * @soc: Handle to DP Soc structure
94*5113495bSYour Name  * @flow_id: flow id
95*5113495bSYour Name  * @flow_type: flow type
96*5113495bSYour Name  * @flow_pool_id: pool id
97*5113495bSYour Name  *
98*5113495bSYour Name  * Return: none
99*5113495bSYour Name  */
100*5113495bSYour Name static void
dp_htt_flow_pool_unmap_handler_rh(struct dp_soc * soc,uint8_t flow_id,uint8_t flow_type,uint8_t flow_pool_id)101*5113495bSYour Name dp_htt_flow_pool_unmap_handler_rh(struct dp_soc *soc, uint8_t flow_id,
102*5113495bSYour Name 				  uint8_t flow_type, uint8_t flow_pool_id)
103*5113495bSYour Name {
104*5113495bSYour Name 	struct dp_vdev *vdev;
105*5113495bSYour Name 	struct dp_pdev *pdev;
106*5113495bSYour Name 
107*5113495bSYour Name 	if (flow_pool_id >= MAX_TXDESC_POOLS) {
108*5113495bSYour Name 		dp_err("invalid flow_pool_id %d", flow_pool_id);
109*5113495bSYour Name 		return;
110*5113495bSYour Name 	}
111*5113495bSYour Name 
112*5113495bSYour Name 	vdev = dp_vdev_get_ref_by_id(soc, flow_id, DP_MOD_ID_HTT);
113*5113495bSYour Name 	if (vdev) {
114*5113495bSYour Name 		pdev = vdev->pdev;
115*5113495bSYour Name 		dp_vdev_unref_delete(soc, vdev, DP_MOD_ID_HTT);
116*5113495bSYour Name 	} else {
117*5113495bSYour Name 		pdev = soc->pdev_list[0];
118*5113495bSYour Name 	}
119*5113495bSYour Name 
120*5113495bSYour Name 	dp_tx_flow_pool_unmap_handler(pdev, flow_id, flow_type,
121*5113495bSYour Name 				      flow_pool_id);
122*5113495bSYour Name }
123*5113495bSYour Name 
124*5113495bSYour Name /*
125*5113495bSYour Name  * dp_htt_h2t_send_complete_free_netbuf() - Free completed buffer
126*5113495bSYour Name  * @soc:	SOC handle
127*5113495bSYour Name  * @status:	Completion status
128*5113495bSYour Name  * @netbuf:	HTT buffer
129*5113495bSYour Name  */
130*5113495bSYour Name static void
dp_htt_h2t_send_complete_free_netbuf(void * soc,A_STATUS status,qdf_nbuf_t netbuf)131*5113495bSYour Name dp_htt_h2t_send_complete_free_netbuf(
132*5113495bSYour Name 	void *soc, A_STATUS status, qdf_nbuf_t netbuf)
133*5113495bSYour Name {
134*5113495bSYour Name 	qdf_nbuf_free(netbuf);
135*5113495bSYour Name }
136*5113495bSYour Name 
dp_htt_h2t_rx_ring_rfs_cfg(struct htt_soc * soc)137*5113495bSYour Name QDF_STATUS dp_htt_h2t_rx_ring_rfs_cfg(struct htt_soc *soc)
138*5113495bSYour Name {
139*5113495bSYour Name 	struct dp_htt_htc_pkt *pkt;
140*5113495bSYour Name 	qdf_nbuf_t msg;
141*5113495bSYour Name 	uint32_t *msg_word;
142*5113495bSYour Name 	QDF_STATUS status;
143*5113495bSYour Name 	uint8_t *htt_logger_bufp;
144*5113495bSYour Name 
145*5113495bSYour Name 	/*
146*5113495bSYour Name 	 * TODO check do we need ini support in Evros
147*5113495bSYour Name 	 * Receive flow steering configuration,
148*5113495bSYour Name 	 * disable gEnableFlowSteering(=0) in ini if
149*5113495bSYour Name 	 * FW doesn't support it
150*5113495bSYour Name 	 */
151*5113495bSYour Name 
152*5113495bSYour Name 	/* reserve room for the HTC header */
153*5113495bSYour Name 	msg = qdf_nbuf_alloc(soc->osdev,
154*5113495bSYour Name 			     HTT_MSG_BUF_SIZE(HTT_RFS_CFG_REQ_BYTES),
155*5113495bSYour Name 			     HTC_HEADER_LEN + HTC_HDR_ALIGNMENT_PADDING, 4,
156*5113495bSYour Name 			     true);
157*5113495bSYour Name 	if (!msg) {
158*5113495bSYour Name 		dp_err("htt_msg alloc failed for RFS config");
159*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
160*5113495bSYour Name 	}
161*5113495bSYour Name 	/*
162*5113495bSYour Name 	 * Set the length of the message.
163*5113495bSYour Name 	 * The contribution from the HTC_HDR_ALIGNMENT_PADDING is added
164*5113495bSYour Name 	 * separately during the below call to qdf_nbuf_push_head.
165*5113495bSYour Name 	 * The contribution from the HTC header is added separately inside HTC.
166*5113495bSYour Name 	 */
167*5113495bSYour Name 	qdf_nbuf_put_tail(msg, HTT_RFS_CFG_REQ_BYTES);
168*5113495bSYour Name 
169*5113495bSYour Name 	/* fill in the message contents */
170*5113495bSYour Name 	msg_word = (uint32_t *)qdf_nbuf_data(msg);
171*5113495bSYour Name 
172*5113495bSYour Name 	/* rewind beyond alignment pad to get to the HTC header reserved area */
173*5113495bSYour Name 	qdf_nbuf_push_head(msg, HTC_HDR_ALIGNMENT_PADDING);
174*5113495bSYour Name 
175*5113495bSYour Name 	/* word 0 */
176*5113495bSYour Name 	*msg_word = 0;
177*5113495bSYour Name 	htt_logger_bufp = (uint8_t *)msg_word;
178*5113495bSYour Name 	HTT_H2T_MSG_TYPE_SET(*msg_word, HTT_H2T_MSG_TYPE_RFS_CONFIG);
179*5113495bSYour Name 	HTT_RX_RFS_CONFIG_SET(*msg_word, 1);
180*5113495bSYour Name 
181*5113495bSYour Name 	/*
182*5113495bSYour Name 	 * TODO value should be obtained from ini maxMSDUsPerRxInd
183*5113495bSYour Name 	 * currently this ini is legacy ol and available only from cds
184*5113495bSYour Name 	 * make this ini common to HL and evros DP
185*5113495bSYour Name 	 */
186*5113495bSYour Name 	*msg_word |= ((32 & 0xff) << 16);
187*5113495bSYour Name 
188*5113495bSYour Name 	dp_htt_info("RFS sent to F.W: 0x%08x", *msg_word);
189*5113495bSYour Name 
190*5113495bSYour Name 	/*start*/
191*5113495bSYour Name 	pkt = htt_htc_pkt_alloc(soc);
192*5113495bSYour Name 	if (!pkt) {
193*5113495bSYour Name 		qdf_nbuf_free(msg);
194*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
195*5113495bSYour Name 	}
196*5113495bSYour Name 
197*5113495bSYour Name 	pkt->soc_ctxt = NULL; /* not used during send-done callback */
198*5113495bSYour Name 	SET_HTC_PACKET_INFO_TX(
199*5113495bSYour Name 		&pkt->htc_pkt,
200*5113495bSYour Name 		dp_htt_h2t_send_complete_free_netbuf,
201*5113495bSYour Name 		qdf_nbuf_data(msg),
202*5113495bSYour Name 		qdf_nbuf_len(msg),
203*5113495bSYour Name 		soc->htc_endpoint,
204*5113495bSYour Name 		HTC_TX_PACKET_TAG_RUNTIME_PUT); /* tag for no FW response msg */
205*5113495bSYour Name 
206*5113495bSYour Name 	SET_HTC_PACKET_NET_BUF_CONTEXT(&pkt->htc_pkt, msg);
207*5113495bSYour Name 	status = DP_HTT_SEND_HTC_PKT(soc, pkt, HTT_H2T_MSG_TYPE_RFS_CONFIG,
208*5113495bSYour Name 				     htt_logger_bufp);
209*5113495bSYour Name 
210*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
211*5113495bSYour Name 		qdf_nbuf_free(msg);
212*5113495bSYour Name 		htt_htc_pkt_free(soc, pkt);
213*5113495bSYour Name 	}
214*5113495bSYour Name 
215*5113495bSYour Name 	return status;
216*5113495bSYour Name }
217*5113495bSYour Name 
218*5113495bSYour Name static void
dp_htt_rx_addba_handler_rh(struct dp_soc * soc,uint16_t peer_id,uint8_t tid,uint16_t win_sz)219*5113495bSYour Name dp_htt_rx_addba_handler_rh(struct dp_soc *soc, uint16_t peer_id,
220*5113495bSYour Name 			   uint8_t tid, uint16_t win_sz)
221*5113495bSYour Name {
222*5113495bSYour Name }
223*5113495bSYour Name 
224*5113495bSYour Name static QDF_STATUS
dp_htt_rx_delba_ind_handler_rh(void * soc_handle,uint16_t peer_id,uint8_t tid,uint16_t win_sz)225*5113495bSYour Name dp_htt_rx_delba_ind_handler_rh(void *soc_handle, uint16_t peer_id,
226*5113495bSYour Name 			       uint8_t tid, uint16_t win_sz)
227*5113495bSYour Name {
228*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
229*5113495bSYour Name }
230*5113495bSYour Name 
231*5113495bSYour Name /**
232*5113495bSYour Name  * dp_htt_t2h_msg_handler_fast() -  Fastpath specific message handler
233*5113495bSYour Name  * @context: HTT context
234*5113495bSYour Name  * @cmpl_msdus: netbuf completions
235*5113495bSYour Name  * @num_cmpls: number of completions to be handled
236*5113495bSYour Name  *
237*5113495bSYour Name  * Return: None
238*5113495bSYour Name  */
239*5113495bSYour Name static void
dp_htt_t2h_msg_handler_fast(void * context,qdf_nbuf_t * cmpl_msdus,uint32_t num_cmpls)240*5113495bSYour Name dp_htt_t2h_msg_handler_fast(void *context, qdf_nbuf_t *cmpl_msdus,
241*5113495bSYour Name 			    uint32_t num_cmpls)
242*5113495bSYour Name {
243*5113495bSYour Name 	struct htt_soc *soc = (struct htt_soc *)context;
244*5113495bSYour Name 	qdf_nbuf_t htt_t2h_msg;
245*5113495bSYour Name 	uint32_t *msg_word;
246*5113495bSYour Name 	uint32_t i;
247*5113495bSYour Name 	enum htt_t2h_msg_type msg_type;
248*5113495bSYour Name 	uint32_t msg_len;
249*5113495bSYour Name 
250*5113495bSYour Name 	for (i = 0; i < num_cmpls; i++) {
251*5113495bSYour Name 		htt_t2h_msg = cmpl_msdus[i];
252*5113495bSYour Name 		msg_len = qdf_nbuf_len(htt_t2h_msg);
253*5113495bSYour Name 
254*5113495bSYour Name 		/*
255*5113495bSYour Name 		 * Move the data pointer to point to HTT header
256*5113495bSYour Name 		 * past the HTC header + HTC header alignment padding
257*5113495bSYour Name 		 */
258*5113495bSYour Name 		qdf_nbuf_pull_head(htt_t2h_msg, HTC_HEADER_LEN +
259*5113495bSYour Name 				   HTC_HDR_ALIGNMENT_PADDING);
260*5113495bSYour Name 
261*5113495bSYour Name 		msg_word = (uint32_t *)qdf_nbuf_data(htt_t2h_msg);
262*5113495bSYour Name 		msg_type = HTT_T2H_MSG_TYPE_GET(*msg_word);
263*5113495bSYour Name 
264*5113495bSYour Name 		switch (msg_type) {
265*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_RX_DATA_IND:
266*5113495bSYour Name 		{
267*5113495bSYour Name 			uint16_t vdev_id, msdu_cnt;
268*5113495bSYour Name 			uint16_t peer_id, frag_ind;
269*5113495bSYour Name 
270*5113495bSYour Name 			peer_id = HTT_RX_DATA_IND_PEER_ID_GET(*msg_word);
271*5113495bSYour Name 			frag_ind = HTT_RX_DATA_IND_FRAG_GET(*(msg_word + 1));
272*5113495bSYour Name 			vdev_id = HTT_RX_DATA_IND_VDEV_ID_GET(*msg_word);
273*5113495bSYour Name 
274*5113495bSYour Name 			if (qdf_unlikely(frag_ind)) {
275*5113495bSYour Name 				dp_rx_frag_indication_handler(soc->dp_soc,
276*5113495bSYour Name 							      htt_t2h_msg,
277*5113495bSYour Name 							      vdev_id, peer_id);
278*5113495bSYour Name 				break;
279*5113495bSYour Name 			}
280*5113495bSYour Name 
281*5113495bSYour Name 			msdu_cnt =
282*5113495bSYour Name 				HTT_RX_DATA_IND_MSDU_CNT_GET(*(msg_word + 1));
283*5113495bSYour Name 			dp_rx_data_indication_handler(soc->dp_soc, htt_t2h_msg,
284*5113495bSYour Name 						      vdev_id, peer_id,
285*5113495bSYour Name 						      msdu_cnt);
286*5113495bSYour Name 			break;
287*5113495bSYour Name 		}
288*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_SOFT_UMAC_TX_COMPL_IND:
289*5113495bSYour Name 		{
290*5113495bSYour Name 			uint32_t num_msdus;
291*5113495bSYour Name 
292*5113495bSYour Name 			num_msdus = HTT_SOFT_UMAC_TX_COMP_IND_MSDU_COUNT_GET(*msg_word);
293*5113495bSYour Name 
294*5113495bSYour Name 			if ((num_msdus * HTT_TX_MSDU_INFO_SIZE +
295*5113495bSYour Name 			     HTT_SOFT_UMAC_TX_COMPL_IND_SIZE) > msg_len) {
296*5113495bSYour Name 				dp_htt_err("Invalid msdu count in tx compl indication %d", num_msdus);
297*5113495bSYour Name 				break;
298*5113495bSYour Name 			}
299*5113495bSYour Name 
300*5113495bSYour Name 			dp_tx_compl_handler_rh(soc->dp_soc, htt_t2h_msg);
301*5113495bSYour Name 			break;
302*5113495bSYour Name 		}
303*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_RX_PN_IND:
304*5113495bSYour Name 		{
305*5113495bSYour Name 			/* TODO check and add PN IND handling */
306*5113495bSYour Name 			break;
307*5113495bSYour Name 		}
308*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_RX_ADDBA:
309*5113495bSYour Name 		{
310*5113495bSYour Name 			uint16_t peer_id;
311*5113495bSYour Name 			uint8_t tid;
312*5113495bSYour Name 			uint16_t win_sz;
313*5113495bSYour Name 
314*5113495bSYour Name 			/*
315*5113495bSYour Name 			 * Update REO Queue Desc with new values
316*5113495bSYour Name 			 */
317*5113495bSYour Name 			peer_id = HTT_RX_ADDBA_PEER_ID_GET(*msg_word);
318*5113495bSYour Name 			tid = HTT_RX_ADDBA_TID_GET(*msg_word);
319*5113495bSYour Name 			win_sz = HTT_RX_ADDBA_WIN_SIZE_GET(*msg_word);
320*5113495bSYour Name 
321*5113495bSYour Name 			/*
322*5113495bSYour Name 			 * Window size needs to be incremented by 1
323*5113495bSYour Name 			 * since fw needs to represent a value of 256
324*5113495bSYour Name 			 * using just 8 bits
325*5113495bSYour Name 			 */
326*5113495bSYour Name 			dp_htt_rx_addba_handler_rh(soc->dp_soc, peer_id,
327*5113495bSYour Name 						   tid, win_sz + 1);
328*5113495bSYour Name 			break;
329*5113495bSYour Name 		}
330*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_RX_DELBA:
331*5113495bSYour Name 		{
332*5113495bSYour Name 			uint16_t peer_id;
333*5113495bSYour Name 			uint8_t tid;
334*5113495bSYour Name 			uint8_t win_sz;
335*5113495bSYour Name 			QDF_STATUS status;
336*5113495bSYour Name 
337*5113495bSYour Name 			peer_id = HTT_RX_DELBA_PEER_ID_GET(*msg_word);
338*5113495bSYour Name 			tid = HTT_RX_DELBA_TID_GET(*msg_word);
339*5113495bSYour Name 			win_sz = HTT_RX_DELBA_WIN_SIZE_GET(*msg_word);
340*5113495bSYour Name 
341*5113495bSYour Name 			status = dp_htt_rx_delba_ind_handler_rh(soc->dp_soc,
342*5113495bSYour Name 								peer_id, tid,
343*5113495bSYour Name 								win_sz);
344*5113495bSYour Name 
345*5113495bSYour Name 			dp_htt_info("DELBA PeerID %d BAW %d TID %d stat %d",
346*5113495bSYour Name 				    peer_id, win_sz, tid, status);
347*5113495bSYour Name 			break;
348*5113495bSYour Name 		}
349*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_PPDU_STATS_IND:
350*5113495bSYour Name 		{
351*5113495bSYour Name 			qdf_nbuf_t nbuf_copy;
352*5113495bSYour Name 			HTC_PACKET htc_pkt = {0};
353*5113495bSYour Name 
354*5113495bSYour Name 			nbuf_copy = qdf_nbuf_copy(htt_t2h_msg);
355*5113495bSYour Name 			if (qdf_unlikely(!nbuf_copy)) {
356*5113495bSYour Name 				dp_htt_err("NBUF copy failed for PPDU stats msg");
357*5113495bSYour Name 				break;
358*5113495bSYour Name 			}
359*5113495bSYour Name 			htc_pkt.Status = QDF_STATUS_SUCCESS;
360*5113495bSYour Name 			htc_pkt.pPktContext = (void *)nbuf_copy;
361*5113495bSYour Name 			dp_htt_t2h_msg_handler(context, &htc_pkt);
362*5113495bSYour Name 			break;
363*5113495bSYour Name 		}
364*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_FLOW_POOL_MAP:
365*5113495bSYour Name 		{
366*5113495bSYour Name 			uint8_t num_flows;
367*5113495bSYour Name 			struct htt_flow_pool_map_payload_t *pool_map;
368*5113495bSYour Name 
369*5113495bSYour Name 			num_flows = HTT_FLOW_POOL_MAP_NUM_FLOWS_GET(*msg_word);
370*5113495bSYour Name 
371*5113495bSYour Name 			if (((HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
372*5113495bSYour Name 			      HTT_FLOW_POOL_MAP_HEADER_SZ) * num_flows + 1) * sizeof(*msg_word) > msg_len) {
373*5113495bSYour Name 				dp_htt_err("Invalid flow count in flow pool map message");
374*5113495bSYour Name 				WARN_ON(1);
375*5113495bSYour Name 				break;
376*5113495bSYour Name 			}
377*5113495bSYour Name 
378*5113495bSYour Name 			msg_word++;
379*5113495bSYour Name 
380*5113495bSYour Name 			while (num_flows) {
381*5113495bSYour Name 				pool_map = (struct htt_flow_pool_map_payload_t *)msg_word;
382*5113495bSYour Name 				dp_htt_flow_pool_map_handler_rh(
383*5113495bSYour Name 					soc->dp_soc, pool_map->flow_id,
384*5113495bSYour Name 					pool_map->flow_type,
385*5113495bSYour Name 					pool_map->flow_pool_id,
386*5113495bSYour Name 					pool_map->flow_pool_size);
387*5113495bSYour Name 
388*5113495bSYour Name 				msg_word += (HTT_FLOW_POOL_MAP_PAYLOAD_SZ /
389*5113495bSYour Name 							 HTT_FLOW_POOL_MAP_HEADER_SZ);
390*5113495bSYour Name 				num_flows--;
391*5113495bSYour Name 			}
392*5113495bSYour Name 
393*5113495bSYour Name 			break;
394*5113495bSYour Name 		}
395*5113495bSYour Name 		case HTT_T2H_MSG_TYPE_FLOW_POOL_UNMAP:
396*5113495bSYour Name 		{
397*5113495bSYour Name 			struct htt_flow_pool_unmap_t *pool_unmap;
398*5113495bSYour Name 
399*5113495bSYour Name 			if (msg_len < sizeof(struct htt_flow_pool_unmap_t)) {
400*5113495bSYour Name 				dp_htt_err("Invalid length in flow pool unmap message %d", msg_len);
401*5113495bSYour Name 				WARN_ON(1);
402*5113495bSYour Name 				break;
403*5113495bSYour Name 			}
404*5113495bSYour Name 
405*5113495bSYour Name 			pool_unmap = (struct htt_flow_pool_unmap_t *)msg_word;
406*5113495bSYour Name 			dp_htt_flow_pool_unmap_handler_rh(
407*5113495bSYour Name 				soc->dp_soc, pool_unmap->flow_id,
408*5113495bSYour Name 				pool_unmap->flow_type,
409*5113495bSYour Name 				pool_unmap->flow_pool_id);
410*5113495bSYour Name 			break;
411*5113495bSYour Name 		}
412*5113495bSYour Name 		default:
413*5113495bSYour Name 		{
414*5113495bSYour Name 			HTC_PACKET htc_pkt = {0};
415*5113495bSYour Name 
416*5113495bSYour Name 			htc_pkt.Status = QDF_STATUS_SUCCESS;
417*5113495bSYour Name 			htc_pkt.pPktContext = (void *)htt_t2h_msg;
418*5113495bSYour Name 			/*
419*5113495bSYour Name 			 * Increment user count to protect buffer
420*5113495bSYour Name 			 * from generic handler free count will be
421*5113495bSYour Name 			 * reset to 1 during MSG_BUF_REINIT
422*5113495bSYour Name 			 */
423*5113495bSYour Name 			qdf_nbuf_inc_users(htt_t2h_msg);
424*5113495bSYour Name 			dp_htt_t2h_msg_handler(context, &htc_pkt);
425*5113495bSYour Name 			break;
426*5113495bSYour Name 		}
427*5113495bSYour Name 		}
428*5113495bSYour Name 
429*5113495bSYour Name 		/* Re-initialize the indication buffer */
430*5113495bSYour Name 		HTT_T2H_MSG_BUF_REINIT(htt_t2h_msg, soc->osdev);
431*5113495bSYour Name 		qdf_nbuf_set_pktlen(htt_t2h_msg, 0);
432*5113495bSYour Name 	}
433*5113495bSYour Name }
434*5113495bSYour Name 
435*5113495bSYour Name static QDF_STATUS
dp_htt_htc_attach(struct htt_soc * soc,uint16_t service_id)436*5113495bSYour Name dp_htt_htc_attach(struct htt_soc *soc, uint16_t service_id)
437*5113495bSYour Name {
438*5113495bSYour Name 	struct dp_soc_rh *rh_soc = dp_get_rh_soc_from_dp_soc(soc->dp_soc);
439*5113495bSYour Name 	struct htc_service_connect_req connect;
440*5113495bSYour Name 	struct htc_service_connect_resp response;
441*5113495bSYour Name 	QDF_STATUS status;
442*5113495bSYour Name 
443*5113495bSYour Name 	qdf_mem_zero(&connect, sizeof(connect));
444*5113495bSYour Name 	qdf_mem_zero(&response, sizeof(response));
445*5113495bSYour Name 
446*5113495bSYour Name 	connect.pMetaData = NULL;
447*5113495bSYour Name 	connect.MetaDataLength = 0;
448*5113495bSYour Name 	connect.EpCallbacks.pContext = soc;
449*5113495bSYour Name 	connect.EpCallbacks.EpTxComplete = dp_htt_h2t_send_complete;
450*5113495bSYour Name 	connect.EpCallbacks.EpTxCompleteMultiple = NULL;
451*5113495bSYour Name 	/* fastpath handler will be used instead */
452*5113495bSYour Name 	connect.EpCallbacks.EpRecv = NULL;
453*5113495bSYour Name 
454*5113495bSYour Name 	/* rx buffers currently are provided by HIF, not by EpRecvRefill */
455*5113495bSYour Name 	connect.EpCallbacks.EpRecvRefill = NULL;
456*5113495bSYour Name 	/* N/A, fill is done by HIF */
457*5113495bSYour Name 	connect.EpCallbacks.RecvRefillWaterMark = 1;
458*5113495bSYour Name 
459*5113495bSYour Name 	connect.EpCallbacks.EpSendFull = dp_htt_h2t_full;
460*5113495bSYour Name 	/*
461*5113495bSYour Name 	 * Specify how deep to let a queue get before htc_send_pkt will
462*5113495bSYour Name 	 * call the EpSendFull function due to excessive send queue depth.
463*5113495bSYour Name 	 */
464*5113495bSYour Name 	connect.MaxSendQueueDepth = DP_HTT_MAX_SEND_QUEUE_DEPTH;
465*5113495bSYour Name 
466*5113495bSYour Name 	/* disable flow control for HTT data message service */
467*5113495bSYour Name 	connect.ConnectionFlags |= HTC_CONNECT_FLAGS_DISABLE_CREDIT_FLOW_CTRL;
468*5113495bSYour Name 
469*5113495bSYour Name 	/* connect to control service */
470*5113495bSYour Name 	connect.service_id = service_id;
471*5113495bSYour Name 
472*5113495bSYour Name 	status = htc_connect_service(soc->htc_soc, &connect, &response);
473*5113495bSYour Name 
474*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
475*5113495bSYour Name 		dp_htt_err("HTC connect svc failed for id:%u", service_id);
476*5113495bSYour Name 		return status;
477*5113495bSYour Name 	}
478*5113495bSYour Name 
479*5113495bSYour Name 	if (service_id == HTT_DATA_MSG_SVC)
480*5113495bSYour Name 		soc->htc_endpoint = response.Endpoint;
481*5113495bSYour Name 
482*5113495bSYour Name 	/* Save the EP_ID of the TX pipe that to be used during TX enqueue */
483*5113495bSYour Name 	if (service_id == HTT_DATA2_MSG_SVC)
484*5113495bSYour Name 		rh_soc->tx_endpoint = response.Endpoint;
485*5113495bSYour Name 
486*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
487*5113495bSYour Name }
488*5113495bSYour Name 
489*5113495bSYour Name static QDF_STATUS
dp_htt_htc_soc_attach_all(struct htt_soc * soc)490*5113495bSYour Name dp_htt_htc_soc_attach_all(struct htt_soc *soc)
491*5113495bSYour Name {
492*5113495bSYour Name 	struct dp_soc *dp_soc = soc->dp_soc;
493*5113495bSYour Name 	int svc_list[3] = {HTT_DATA_MSG_SVC, HTT_DATA2_MSG_SVC,
494*5113495bSYour Name 		HTT_DATA3_MSG_SVC};
495*5113495bSYour Name 	QDF_STATUS status;
496*5113495bSYour Name 	int i;
497*5113495bSYour Name 
498*5113495bSYour Name 	for (i = 0; i < QDF_ARRAY_SIZE(svc_list); i++) {
499*5113495bSYour Name 		status = dp_htt_htc_attach(soc, svc_list[i]);
500*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status))
501*5113495bSYour Name 			return status;
502*5113495bSYour Name 	}
503*5113495bSYour Name 
504*5113495bSYour Name 	dp_hif_update_pipe_callback(dp_soc, (void *)soc,
505*5113495bSYour Name 				    dp_htt_hif_t2h_hp_callback,
506*5113495bSYour Name 				    DP_HTT_T2H_HP_PIPE);
507*5113495bSYour Name 
508*5113495bSYour Name 	/* Register fastpath cb handlers for RX CE's */
509*5113495bSYour Name 	if (hif_ce_fastpath_cb_register(dp_soc->hif_handle,
510*5113495bSYour Name 					dp_htt_t2h_msg_handler_fast, soc)) {
511*5113495bSYour Name 		dp_htt_err("failed to register fastpath callback");
512*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
513*5113495bSYour Name 	}
514*5113495bSYour Name 
515*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
516*5113495bSYour Name }
517*5113495bSYour Name 
518*5113495bSYour Name /*
519*5113495bSYour Name  * dp_htt_soc_initialize_rh() - SOC level HTT initialization
520*5113495bSYour Name  * @htt_soc: Opaque htt SOC handle
521*5113495bSYour Name  * @ctrl_psoc: Opaque ctrl SOC handle
522*5113495bSYour Name  * @htc_soc: SOC level HTC handle
523*5113495bSYour Name  * @hal_soc: Opaque HAL SOC handle
524*5113495bSYour Name  * @osdev: QDF device
525*5113495bSYour Name  *
526*5113495bSYour Name  * Return: HTT handle on success; NULL on failure
527*5113495bSYour Name  */
528*5113495bSYour Name void *
dp_htt_soc_initialize_rh(struct htt_soc * htt_soc,struct cdp_ctrl_objmgr_psoc * ctrl_psoc,HTC_HANDLE htc_soc,hal_soc_handle_t hal_soc_hdl,qdf_device_t osdev)529*5113495bSYour Name dp_htt_soc_initialize_rh(struct htt_soc *htt_soc,
530*5113495bSYour Name 			 struct cdp_ctrl_objmgr_psoc *ctrl_psoc,
531*5113495bSYour Name 			 HTC_HANDLE htc_soc,
532*5113495bSYour Name 			 hal_soc_handle_t hal_soc_hdl, qdf_device_t osdev)
533*5113495bSYour Name {
534*5113495bSYour Name 	struct htt_soc *soc = (struct htt_soc *)htt_soc;
535*5113495bSYour Name 
536*5113495bSYour Name 	soc->osdev = osdev;
537*5113495bSYour Name 	soc->ctrl_psoc = ctrl_psoc;
538*5113495bSYour Name 	soc->htc_soc = htc_soc;
539*5113495bSYour Name 	soc->hal_soc = hal_soc_hdl;
540*5113495bSYour Name 
541*5113495bSYour Name 	if (dp_htt_htc_soc_attach_all(soc))
542*5113495bSYour Name 		goto fail2;
543*5113495bSYour Name 
544*5113495bSYour Name 	return soc;
545*5113495bSYour Name 
546*5113495bSYour Name fail2:
547*5113495bSYour Name 	return NULL;
548*5113495bSYour Name }
549