xref: /wlan-driver/qca-wifi-host-cmn/hif/src/sdio/transfer/transfer.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2013-2019 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name 
21*5113495bSYour Name #define ATH_MODULE_NAME hif
22*5113495bSYour Name #include <qdf_types.h>
23*5113495bSYour Name #include <qdf_status.h>
24*5113495bSYour Name #include <qdf_timer.h>
25*5113495bSYour Name #include <qdf_time.h>
26*5113495bSYour Name #include <qdf_lock.h>
27*5113495bSYour Name #include <qdf_mem.h>
28*5113495bSYour Name #include <qdf_util.h>
29*5113495bSYour Name #include <qdf_defer.h>
30*5113495bSYour Name #include <qdf_atomic.h>
31*5113495bSYour Name #include <qdf_nbuf.h>
32*5113495bSYour Name #include <athdefs.h>
33*5113495bSYour Name #include <qdf_net_types.h>
34*5113495bSYour Name #include <a_types.h>
35*5113495bSYour Name #include <athdefs.h>
36*5113495bSYour Name #include <a_osapi.h>
37*5113495bSYour Name #include <hif.h>
38*5113495bSYour Name #include <htc_services.h>
39*5113495bSYour Name #include <a_debug.h>
40*5113495bSYour Name #include <htc_internal.h>
41*5113495bSYour Name #include "hif_sdio_internal.h"
42*5113495bSYour Name #include "transfer.h"
43*5113495bSYour Name 
44*5113495bSYour Name /**
45*5113495bSYour Name  * hif_dev_rw_completion_handler() - Completion routine
46*5113495bSYour Name  * for ALL HIF layer async I/O
47*5113495bSYour Name  * @ctx: hif send context
48*5113495bSYour Name  * @status: completion routine sync/async context
49*5113495bSYour Name  *
50*5113495bSYour Name  * Return: 0 for success and non-zero for failure
51*5113495bSYour Name  */
52*5113495bSYour Name 
hif_dev_rw_completion_handler(void * ctx,QDF_STATUS status)53*5113495bSYour Name QDF_STATUS hif_dev_rw_completion_handler(void *ctx, QDF_STATUS status)
54*5113495bSYour Name {
55*5113495bSYour Name 	QDF_STATUS (*txCompHandler)(void *, qdf_nbuf_t, uint32_t, uint32_t);
56*5113495bSYour Name 	struct hif_sendContext *sctx = (struct hif_sendContext *)ctx;
57*5113495bSYour Name 	struct hif_sdio_device *pdev = sctx->pDev;
58*5113495bSYour Name 	unsigned int xfer_id = sctx->transferID;
59*5113495bSYour Name 	uint32_t toeplitz_hash_result = 0;
60*5113495bSYour Name 	qdf_nbuf_t buf = sctx->netbuf;
61*5113495bSYour Name 
62*5113495bSYour Name 	if (sctx->bNewAlloc)
63*5113495bSYour Name 		qdf_mem_free(ctx);
64*5113495bSYour Name 	else
65*5113495bSYour Name 		qdf_nbuf_pull_head(buf, sctx->head_data_len);
66*5113495bSYour Name 
67*5113495bSYour Name 	txCompHandler = pdev->hif_callbacks.txCompletionHandler;
68*5113495bSYour Name 	if (txCompHandler) {
69*5113495bSYour Name 		txCompHandler(pdev->hif_callbacks.Context, buf,
70*5113495bSYour Name 			      xfer_id, toeplitz_hash_result);
71*5113495bSYour Name 	}
72*5113495bSYour Name 
73*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
74*5113495bSYour Name }
75*5113495bSYour Name 
76*5113495bSYour Name /**
77*5113495bSYour Name  * hif_dev_send_buffer() - send buffer to sdio device
78*5113495bSYour Name  * @pdev: HIf device object
79*5113495bSYour Name  * @xfer_id: transfer id
80*5113495bSYour Name  * @pipe: ul/dl pipe
81*5113495bSYour Name  * @nbytes: no of bytes to transfer
82*5113495bSYour Name  * @buf: pointer to buffer
83*5113495bSYour Name  *
84*5113495bSYour Name  * Return: 0 for success and non-zero for failure
85*5113495bSYour Name  */
hif_dev_send_buffer(struct hif_sdio_device * pdev,uint32_t xfer_id,uint8_t pipe,uint32_t nbytes,qdf_nbuf_t buf)86*5113495bSYour Name QDF_STATUS hif_dev_send_buffer(struct hif_sdio_device *pdev, uint32_t xfer_id,
87*5113495bSYour Name 			       uint8_t pipe, uint32_t nbytes, qdf_nbuf_t buf)
88*5113495bSYour Name {
89*5113495bSYour Name 	QDF_STATUS status;
90*5113495bSYour Name 	unsigned char *pData;
91*5113495bSYour Name 	struct hif_sendContext *sctx;
92*5113495bSYour Name 	uint32_t request = hif_get_send_buffer_flags(pdev);
93*5113495bSYour Name 	uint32_t padded_length;
94*5113495bSYour Name 	unsigned long addr = 0;
95*5113495bSYour Name 	int frag_count = 0, i, count, head_len;
96*5113495bSYour Name 
97*5113495bSYour Name 	if (hif_get_send_address(pdev, pipe, &addr)) {
98*5113495bSYour Name 		hif_err("Invalid address map for pipe 0x%x", pipe);
99*5113495bSYour Name 
100*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
101*5113495bSYour Name 	}
102*5113495bSYour Name 
103*5113495bSYour Name 	padded_length = DEV_CALC_SEND_PADDED_LEN(pdev, nbytes);
104*5113495bSYour Name 	A_ASSERT(padded_length - nbytes < HIF_DUMMY_SPACE_MASK + 1);
105*5113495bSYour Name 
106*5113495bSYour Name 	request |= ((padded_length - nbytes) << 16);
107*5113495bSYour Name 
108*5113495bSYour Name 	frag_count = qdf_nbuf_get_num_frags(buf);
109*5113495bSYour Name 
110*5113495bSYour Name 	if (frag_count > 1) {
111*5113495bSYour Name 		/* Header data length should be total sending length.
112*5113495bSYour Name 		 * Subtract internal data length of netbuf
113*5113495bSYour Name 		 */
114*5113495bSYour Name 		head_len = sizeof(struct hif_sendContext) +
115*5113495bSYour Name 			(nbytes - qdf_nbuf_get_frag_len(buf, frag_count - 1));
116*5113495bSYour Name 	} else {
117*5113495bSYour Name 		/*
118*5113495bSYour Name 		 * | hif_sendContext | netbuf->data
119*5113495bSYour Name 		 */
120*5113495bSYour Name 		head_len = sizeof(struct hif_sendContext);
121*5113495bSYour Name 	}
122*5113495bSYour Name 
123*5113495bSYour Name 	/* Check whether head room is enough to save extra head data */
124*5113495bSYour Name 	if ((head_len <= qdf_nbuf_headroom(buf)) &&
125*5113495bSYour Name 	    (qdf_nbuf_tailroom(buf) >= (padded_length - nbytes))) {
126*5113495bSYour Name 		sctx = (struct hif_sendContext *)qdf_nbuf_push_head(buf,
127*5113495bSYour Name 								    head_len);
128*5113495bSYour Name 		sctx->bNewAlloc = false;
129*5113495bSYour Name 	} else {
130*5113495bSYour Name 		sctx = (struct hif_sendContext *)qdf_mem_malloc(sizeof(*sctx) +
131*5113495bSYour Name 								padded_length);
132*5113495bSYour Name 		if (sctx)
133*5113495bSYour Name 			sctx->bNewAlloc = true;
134*5113495bSYour Name 		else
135*5113495bSYour Name 			return QDF_STATUS_E_NOMEM;
136*5113495bSYour Name 	}
137*5113495bSYour Name 
138*5113495bSYour Name 	sctx->netbuf = buf;
139*5113495bSYour Name 	sctx->pDev = pdev;
140*5113495bSYour Name 	sctx->transferID = xfer_id;
141*5113495bSYour Name 	sctx->head_data_len = head_len;
142*5113495bSYour Name 	/*
143*5113495bSYour Name 	 * Copy data to head part of netbuf or head of allocated buffer.
144*5113495bSYour Name 	 * if buffer is new allocated, the last buffer should be copied also.
145*5113495bSYour Name 	 * It assume last fragment is internal buffer of netbuf
146*5113495bSYour Name 	 * sometime total length of fragments larger than nbytes
147*5113495bSYour Name 	 */
148*5113495bSYour Name 	pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
149*5113495bSYour Name 	for (i = 0, count = sctx->bNewAlloc ? frag_count : frag_count - 1;
150*5113495bSYour Name 	     i < count;
151*5113495bSYour Name 	     i++) {
152*5113495bSYour Name 		int frag_len = qdf_nbuf_get_frag_len(buf, i);
153*5113495bSYour Name 		unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i);
154*5113495bSYour Name 
155*5113495bSYour Name 		if (frag_len > nbytes)
156*5113495bSYour Name 			frag_len = nbytes;
157*5113495bSYour Name 		memcpy(pData, frag_addr, frag_len);
158*5113495bSYour Name 		pData += frag_len;
159*5113495bSYour Name 		nbytes -= frag_len;
160*5113495bSYour Name 		if (nbytes <= 0)
161*5113495bSYour Name 			break;
162*5113495bSYour Name 	}
163*5113495bSYour Name 
164*5113495bSYour Name 	/* Reset pData pointer and sctx out */
165*5113495bSYour Name 	pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
166*5113495bSYour Name 
167*5113495bSYour Name 	status = hif_read_write(pdev->HIFDevice, addr, (char *)pData,
168*5113495bSYour Name 				padded_length, request, (void *)sctx);
169*5113495bSYour Name 
170*5113495bSYour Name 	if (status == QDF_STATUS_E_PENDING) {
171*5113495bSYour Name 		/*
172*5113495bSYour Name 		 * it will return QDF_STATUS_E_PENDING in native HIF
173*5113495bSYour Name 		 * implementation, which should be treated as successful
174*5113495bSYour Name 		 * result here.
175*5113495bSYour Name 		 */
176*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
177*5113495bSYour Name 	}
178*5113495bSYour Name 
179*5113495bSYour Name 	/* release buffer or move back data pointer when failed */
180*5113495bSYour Name 	if (status != QDF_STATUS_SUCCESS) {
181*5113495bSYour Name 		if (sctx->bNewAlloc)
182*5113495bSYour Name 			qdf_mem_free(sctx);
183*5113495bSYour Name 		else
184*5113495bSYour Name 			qdf_nbuf_pull_head(buf, head_len);
185*5113495bSYour Name 	}
186*5113495bSYour Name 
187*5113495bSYour Name 	return status;
188*5113495bSYour Name }
189*5113495bSYour Name 
190*5113495bSYour Name /**
191*5113495bSYour Name  * hif_dev_alloc_and_prepare_rx_packets() - Allocate packets for recv frames.
192*5113495bSYour Name  * @pdev : HIF device object
193*5113495bSYour Name  * @look_aheads : Look ahead information on the frames
194*5113495bSYour Name  * @messages : Number of messages
195*5113495bSYour Name  * @queue : Queue to put the allocated frames
196*5113495bSYour Name  *
197*5113495bSYour Name  * Return : QDF_STATUS_SUCCESS on success else error value
198*5113495bSYour Name  */
hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device * pdev,uint32_t look_aheads[],int messages,HTC_PACKET_QUEUE * queue)199*5113495bSYour Name QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
200*5113495bSYour Name 						uint32_t look_aheads[],
201*5113495bSYour Name 						int messages,
202*5113495bSYour Name 						HTC_PACKET_QUEUE *queue)
203*5113495bSYour Name {
204*5113495bSYour Name 	int i, j;
205*5113495bSYour Name 	bool no_recycle;
206*5113495bSYour Name 	int num_messages;
207*5113495bSYour Name 	HTC_PACKET *packet;
208*5113495bSYour Name 	HTC_FRAME_HDR *hdr;
209*5113495bSYour Name 	uint32_t full_length;
210*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
211*5113495bSYour Name 
212*5113495bSYour Name 	/* lock RX while we assemble the packet buffers */
213*5113495bSYour Name 	LOCK_HIF_DEV_RX(pdev);
214*5113495bSYour Name 
215*5113495bSYour Name 	for (i = 0; i < messages; i++) {
216*5113495bSYour Name 		hdr = (HTC_FRAME_HDR *)&look_aheads[i];
217*5113495bSYour Name 		if (hdr->EndpointID >= ENDPOINT_MAX) {
218*5113495bSYour Name 			hif_err("Invalid Endpoint:%d", hdr->EndpointID);
219*5113495bSYour Name 			status = QDF_STATUS_E_INVAL;
220*5113495bSYour Name 			break;
221*5113495bSYour Name 		}
222*5113495bSYour Name 
223*5113495bSYour Name 		if (hdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
224*5113495bSYour Name 			hif_err("Payload length %d exceeds max HTC : %u",
225*5113495bSYour Name 				hdr->PayloadLen,
226*5113495bSYour Name 				(uint32_t)HTC_MAX_PAYLOAD_LENGTH);
227*5113495bSYour Name 			status = QDF_STATUS_E_INVAL;
228*5113495bSYour Name 			break;
229*5113495bSYour Name 		}
230*5113495bSYour Name 
231*5113495bSYour Name 		if ((hdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
232*5113495bSYour Name 			/* HTC header only indicates 1 message to fetch */
233*5113495bSYour Name 			num_messages = 1;
234*5113495bSYour Name 		} else {
235*5113495bSYour Name 			/* HTC header indicates that every packet to follow
236*5113495bSYour Name 			 * has the same padded length so that it can
237*5113495bSYour Name 			 * be optimally fetched as a full bundle
238*5113495bSYour Name 			 */
239*5113495bSYour Name 			num_messages = GET_RECV_BUNDLE_COUNT(hdr->Flags);
240*5113495bSYour Name 			/* the count doesn't include the starter frame, just
241*5113495bSYour Name 			 * a count of frames to follow
242*5113495bSYour Name 			 */
243*5113495bSYour Name 			num_messages++;
244*5113495bSYour Name 
245*5113495bSYour Name 			hif_info("HTC header : %u messages in bundle",
246*5113495bSYour Name 				 num_messages);
247*5113495bSYour Name 		}
248*5113495bSYour Name 
249*5113495bSYour Name 		full_length = DEV_CALC_RECV_PADDED_LEN(pdev,
250*5113495bSYour Name 						       hdr->PayloadLen +
251*5113495bSYour Name 						       sizeof(HTC_FRAME_HDR));
252*5113495bSYour Name 
253*5113495bSYour Name 		/* get packet buffers for each message, if there was a
254*5113495bSYour Name 		 * bundle detected in the header,
255*5113495bSYour Name 		 * use pHdr as a template to fetch all packets in the bundle
256*5113495bSYour Name 		 */
257*5113495bSYour Name 		for (j = 0; j < num_messages; j++) {
258*5113495bSYour Name 			/* reset flag, any packets allocated using the
259*5113495bSYour Name 			 * RecvAlloc() API cannot be recycled on cleanup,
260*5113495bSYour Name 			 * they must be explicitly returned
261*5113495bSYour Name 			 */
262*5113495bSYour Name 			no_recycle = false;
263*5113495bSYour Name 			packet = hif_dev_alloc_rx_buffer(pdev);
264*5113495bSYour Name 
265*5113495bSYour Name 			if (!packet) {
266*5113495bSYour Name 				/* No error, simply need to mark that
267*5113495bSYour Name 				 * we are waiting for buffers.
268*5113495bSYour Name 				 */
269*5113495bSYour Name 				pdev->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
270*5113495bSYour Name 				/* pDev->EpWaitingForBuffers = pEndpoint->Id; */
271*5113495bSYour Name 				status = QDF_STATUS_E_RESOURCES;
272*5113495bSYour Name 				break;
273*5113495bSYour Name 			}
274*5113495bSYour Name 			/* clear flags */
275*5113495bSYour Name 			packet->PktInfo.AsRx.HTCRxFlags = 0;
276*5113495bSYour Name 			packet->PktInfo.AsRx.IndicationFlags = 0;
277*5113495bSYour Name 			packet->Status = QDF_STATUS_SUCCESS;
278*5113495bSYour Name 
279*5113495bSYour Name 			if (no_recycle) {
280*5113495bSYour Name 				/* flag that these packets cannot be recycled,
281*5113495bSYour Name 				 * they have to be returned to the user
282*5113495bSYour Name 				 */
283*5113495bSYour Name 				packet->PktInfo.AsRx.HTCRxFlags |=
284*5113495bSYour Name 					HTC_RX_PKT_NO_RECYCLE;
285*5113495bSYour Name 			}
286*5113495bSYour Name 			/* add packet to queue (also incase we need to
287*5113495bSYour Name 			 * cleanup down below)
288*5113495bSYour Name 			 */
289*5113495bSYour Name 			HTC_PACKET_ENQUEUE(queue, packet);
290*5113495bSYour Name 
291*5113495bSYour Name 			/* if (HTC_STOPPING(target)) {
292*5113495bSYour Name 			 *      status = QDF_STATUS_E_CANCELED;
293*5113495bSYour Name 			 *      break;
294*5113495bSYour Name 			 *  }
295*5113495bSYour Name 			 */
296*5113495bSYour Name 
297*5113495bSYour Name 			/* make sure  message can fit in the endpoint buffer */
298*5113495bSYour Name 			if (full_length > packet->BufferLength) {
299*5113495bSYour Name 				hif_err("Payload Length Error");
300*5113495bSYour Name 				hif_err("header reports payload: %u(%u)",
301*5113495bSYour Name 					hdr->PayloadLen,
302*5113495bSYour Name 					full_length);
303*5113495bSYour Name 				hif_err("endpoint buffer size: %d",
304*5113495bSYour Name 					packet->BufferLength);
305*5113495bSYour Name 				status = QDF_STATUS_E_INVAL;
306*5113495bSYour Name 				break;
307*5113495bSYour Name 			}
308*5113495bSYour Name 
309*5113495bSYour Name 			if (j > 0) {
310*5113495bSYour Name 				/* for messages fetched in a bundle the expected
311*5113495bSYour Name 				 * lookahead is unknown as we are only using the
312*5113495bSYour Name 				 * lookahead of the first packet as a template
313*5113495bSYour Name 				 * of what to expect for lengths
314*5113495bSYour Name 				 */
315*5113495bSYour Name 				packet->PktInfo.AsRx.HTCRxFlags |=
316*5113495bSYour Name 					HTC_RX_PKT_REFRESH_HDR;
317*5113495bSYour Name 				/* set it to something invalid */
318*5113495bSYour Name 				packet->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
319*5113495bSYour Name 			} else {
320*5113495bSYour Name 				packet->PktInfo.AsRx.ExpectedHdr =
321*5113495bSYour Name 					look_aheads[i];
322*5113495bSYour Name 			}
323*5113495bSYour Name 			/* set the amount of data to fetch */
324*5113495bSYour Name 			packet->ActualLength =
325*5113495bSYour Name 				hdr->PayloadLen + HTC_HDR_LENGTH;
326*5113495bSYour Name 			if ((j == (num_messages - 1)) &&
327*5113495bSYour Name 			    ((hdr->Flags) & HTC_FLAGS_RECV_1MORE_BLOCK))
328*5113495bSYour Name 				packet->PktInfo.AsRx.HTCRxFlags |=
329*5113495bSYour Name 				HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK;
330*5113495bSYour Name 			packet->Endpoint = hdr->EndpointID;
331*5113495bSYour Name 			packet->Completion = NULL;
332*5113495bSYour Name 		}
333*5113495bSYour Name 
334*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status))
335*5113495bSYour Name 			break;
336*5113495bSYour Name 	}
337*5113495bSYour Name 
338*5113495bSYour Name 	UNLOCK_HIF_DEV_RX(pdev);
339*5113495bSYour Name 
340*5113495bSYour Name 	/* for NO RESOURCE error, no need to flush data queue */
341*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)	&&
342*5113495bSYour Name 	    (status != QDF_STATUS_E_RESOURCES)) {
343*5113495bSYour Name 		while (!HTC_QUEUE_EMPTY(queue)) {
344*5113495bSYour Name 			qdf_nbuf_t netbuf;
345*5113495bSYour Name 
346*5113495bSYour Name 			packet = htc_packet_dequeue(queue);
347*5113495bSYour Name 			if (!packet)
348*5113495bSYour Name 				break;
349*5113495bSYour Name 			netbuf = (qdf_nbuf_t)packet->pNetBufContext;
350*5113495bSYour Name 			if (netbuf)
351*5113495bSYour Name 				qdf_nbuf_free(netbuf);
352*5113495bSYour Name 		}
353*5113495bSYour Name 	}
354*5113495bSYour Name 	if (status == QDF_STATUS_E_RESOURCES)
355*5113495bSYour Name 		status = QDF_STATUS_SUCCESS;
356*5113495bSYour Name 	return status;
357*5113495bSYour Name }
358*5113495bSYour Name 
359*5113495bSYour Name /**
360*5113495bSYour Name  * hif_dev_process_trailer() - Process the receive frame trailer
361*5113495bSYour Name  * @pdev : HIF device object
362*5113495bSYour Name  * @buffer : The buffer containing the trailer
363*5113495bSYour Name  * @length : Length of the buffer
364*5113495bSYour Name  * @next_look_aheads : The lookahead that is next
365*5113495bSYour Name  * @num_look_aheads : Number of lookahead information
366*5113495bSYour Name  * @from_endpoint : The endpoint on which the trailer is received
367*5113495bSYour Name  */
hif_dev_process_trailer(struct hif_sdio_device * pdev,uint8_t * buffer,int length,uint32_t * next_look_aheads,int * num_look_aheads,HTC_ENDPOINT_ID from_endpoint)368*5113495bSYour Name QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev,
369*5113495bSYour Name 				   uint8_t *buffer, int length,
370*5113495bSYour Name 				   uint32_t *next_look_aheads,
371*5113495bSYour Name 				   int *num_look_aheads,
372*5113495bSYour Name 				   HTC_ENDPOINT_ID from_endpoint)
373*5113495bSYour Name {
374*5113495bSYour Name 	int orig_length;
375*5113495bSYour Name 	QDF_STATUS status;
376*5113495bSYour Name 	uint8_t *record_buf;
377*5113495bSYour Name 	uint8_t *orig_buffer;
378*5113495bSYour Name 	HTC_RECORD_HDR *record;
379*5113495bSYour Name 	HTC_LOOKAHEAD_REPORT *look_ahead;
380*5113495bSYour Name 
381*5113495bSYour Name 	hif_debug("length:%d", length);
382*5113495bSYour Name 
383*5113495bSYour Name 	orig_buffer = buffer;
384*5113495bSYour Name 	orig_length = length;
385*5113495bSYour Name 	status = QDF_STATUS_SUCCESS;
386*5113495bSYour Name 
387*5113495bSYour Name 	while (length > 0) {
388*5113495bSYour Name 		if (length < sizeof(HTC_RECORD_HDR)) {
389*5113495bSYour Name 			status = QDF_STATUS_E_PROTO;
390*5113495bSYour Name 			break;
391*5113495bSYour Name 		}
392*5113495bSYour Name 		/* these are byte aligned structs */
393*5113495bSYour Name 		record = (HTC_RECORD_HDR *)buffer;
394*5113495bSYour Name 		length -= sizeof(HTC_RECORD_HDR);
395*5113495bSYour Name 		buffer += sizeof(HTC_RECORD_HDR);
396*5113495bSYour Name 
397*5113495bSYour Name 		if (record->Length > length) {
398*5113495bSYour Name 			/* no room left in buffer for record */
399*5113495bSYour Name 			hif_err("Invalid record len: (%u, %u)",
400*5113495bSYour Name 				record->Length,
401*5113495bSYour Name 				record->RecordID);
402*5113495bSYour Name 			hif_err("Buffer has %d bytes left", length);
403*5113495bSYour Name 			status = QDF_STATUS_E_PROTO;
404*5113495bSYour Name 			break;
405*5113495bSYour Name 		}
406*5113495bSYour Name 		/* start of record follows the header */
407*5113495bSYour Name 		record_buf = buffer;
408*5113495bSYour Name 
409*5113495bSYour Name 		switch (record->RecordID) {
410*5113495bSYour Name 		case HTC_RECORD_CREDITS:
411*5113495bSYour Name 			/* Process in HTC, ignore here */
412*5113495bSYour Name 			break;
413*5113495bSYour Name 		case HTC_RECORD_LOOKAHEAD:
414*5113495bSYour Name 			A_ASSERT(record->Length >= sizeof(*look_ahead));
415*5113495bSYour Name 			look_ahead = (HTC_LOOKAHEAD_REPORT *)record_buf;
416*5113495bSYour Name 			if ((look_ahead->PreValid ==
417*5113495bSYour Name 			     ((~look_ahead->PostValid) & 0xFF)) &&
418*5113495bSYour Name 			    next_look_aheads) {
419*5113495bSYour Name 				hif_debug("Look_ahead Report");
420*5113495bSYour Name 				hif_debug("Prevalid:0x%x, postvalid:0x%x",
421*5113495bSYour Name 					  look_ahead->PreValid,
422*5113495bSYour Name 					  look_ahead->PostValid);
423*5113495bSYour Name 				hif_debug("From endpoint %d : %u",
424*5113495bSYour Name 					  from_endpoint,
425*5113495bSYour Name 					  look_ahead->LookAhead0);
426*5113495bSYour Name 				/* look ahead bytes are valid, copy them over */
427*5113495bSYour Name 				((uint8_t *)(&next_look_aheads[0]))[0] =
428*5113495bSYour Name 					look_ahead->LookAhead0;
429*5113495bSYour Name 				((uint8_t *)(&next_look_aheads[0]))[1] =
430*5113495bSYour Name 					look_ahead->LookAhead1;
431*5113495bSYour Name 				((uint8_t *)(&next_look_aheads[0]))[2] =
432*5113495bSYour Name 					look_ahead->LookAhead2;
433*5113495bSYour Name 				((uint8_t *)(&next_look_aheads[0]))[3] =
434*5113495bSYour Name 					look_ahead->LookAhead3;
435*5113495bSYour Name 
436*5113495bSYour Name 				if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
437*5113495bSYour Name 					debug_dump_bytes((uint8_t *)
438*5113495bSYour Name 							 next_look_aheads, 4,
439*5113495bSYour Name 							 "Next Look Ahead");
440*5113495bSYour Name 				}
441*5113495bSYour Name 				/* just one normal lookahead */
442*5113495bSYour Name 				if (num_look_aheads)
443*5113495bSYour Name 					*num_look_aheads = 1;
444*5113495bSYour Name 			}
445*5113495bSYour Name 			break;
446*5113495bSYour Name 		case HTC_RECORD_LOOKAHEAD_BUNDLE:
447*5113495bSYour Name 			A_ASSERT(record->Length >=
448*5113495bSYour Name 					sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
449*5113495bSYour Name 			if ((record->Length >=
450*5113495bSYour Name 			     sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)) &&
451*5113495bSYour Name 			    next_look_aheads) {
452*5113495bSYour Name 				HTC_BUNDLED_LOOKAHEAD_REPORT
453*5113495bSYour Name 				*pBundledLookAheadRpt;
454*5113495bSYour Name 				int i;
455*5113495bSYour Name 
456*5113495bSYour Name 				pBundledLookAheadRpt =
457*5113495bSYour Name 				(HTC_BUNDLED_LOOKAHEAD_REPORT *)record_buf;
458*5113495bSYour Name 
459*5113495bSYour Name 				if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
460*5113495bSYour Name 					debug_dump_bytes(record_buf,
461*5113495bSYour Name 							 record->Length,
462*5113495bSYour Name 							 "Bundle look_ahead");
463*5113495bSYour Name 				}
464*5113495bSYour Name 
465*5113495bSYour Name 				if ((record->Length /
466*5113495bSYour Name 				     (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)))
467*5113495bSYour Name 					> HTC_MAX_MSG_PER_BUNDLE_RX) {
468*5113495bSYour Name 					/* this should never happen, the target
469*5113495bSYour Name 					 * restricts the number of messages per
470*5113495bSYour Name 					 * bundle configured by the host
471*5113495bSYour Name 					 */
472*5113495bSYour Name 					A_ASSERT(false);
473*5113495bSYour Name 					status = QDF_STATUS_E_PROTO;
474*5113495bSYour Name 					break;
475*5113495bSYour Name 				}
476*5113495bSYour Name 				for (i = 0;
477*5113495bSYour Name 				     i <
478*5113495bSYour Name 				     (int)(record->Length /
479*5113495bSYour Name 					   (sizeof
480*5113495bSYour Name 					    (HTC_BUNDLED_LOOKAHEAD_REPORT)));
481*5113495bSYour Name 				     i++) {
482*5113495bSYour Name 					((uint8_t *)(&next_look_aheads[i]))[0] =
483*5113495bSYour Name 					   pBundledLookAheadRpt->LookAhead0;
484*5113495bSYour Name 					((uint8_t *)(&next_look_aheads[i]))[1] =
485*5113495bSYour Name 					   pBundledLookAheadRpt->LookAhead1;
486*5113495bSYour Name 					((uint8_t *)(&next_look_aheads[i]))[2] =
487*5113495bSYour Name 					   pBundledLookAheadRpt->LookAhead2;
488*5113495bSYour Name 					((uint8_t *)(&next_look_aheads[i]))[3] =
489*5113495bSYour Name 					   pBundledLookAheadRpt->LookAhead3;
490*5113495bSYour Name 					pBundledLookAheadRpt++;
491*5113495bSYour Name 				}
492*5113495bSYour Name 				if (num_look_aheads)
493*5113495bSYour Name 					*num_look_aheads = i;
494*5113495bSYour Name 			}
495*5113495bSYour Name 			break;
496*5113495bSYour Name 		default:
497*5113495bSYour Name 			hif_err("HIF unhandled record: id:%u length:%u",
498*5113495bSYour Name 				record->RecordID, record->Length);
499*5113495bSYour Name 			break;
500*5113495bSYour Name 		}
501*5113495bSYour Name 
502*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status))
503*5113495bSYour Name 			break;
504*5113495bSYour Name 
505*5113495bSYour Name 		/* advance buffer past this record for next time around */
506*5113495bSYour Name 		buffer += record->Length;
507*5113495bSYour Name 		length -= record->Length;
508*5113495bSYour Name 	}
509*5113495bSYour Name 
510*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
511*5113495bSYour Name 		debug_dump_bytes(orig_buffer, orig_length,
512*5113495bSYour Name 				 "BAD Recv Trailer");
513*5113495bSYour Name 
514*5113495bSYour Name 	hif_debug("status = %d", status);
515*5113495bSYour Name 
516*5113495bSYour Name 	return status;
517*5113495bSYour Name }
518*5113495bSYour Name 
519*5113495bSYour Name /* process a received message (i.e. strip off header,
520*5113495bSYour Name  * process any trailer data).
521*5113495bSYour Name  * note : locks must be released when this function is called
522*5113495bSYour Name  */
hif_dev_process_recv_header(struct hif_sdio_device * pdev,HTC_PACKET * packet,uint32_t * next_look_aheads,int * num_look_aheads)523*5113495bSYour Name QDF_STATUS hif_dev_process_recv_header(struct hif_sdio_device *pdev,
524*5113495bSYour Name 				       HTC_PACKET *packet,
525*5113495bSYour Name 				       uint32_t *next_look_aheads,
526*5113495bSYour Name 				       int *num_look_aheads)
527*5113495bSYour Name {
528*5113495bSYour Name 	uint8_t temp;
529*5113495bSYour Name 	uint8_t *buf;
530*5113495bSYour Name 	QDF_STATUS status = QDF_STATUS_SUCCESS;
531*5113495bSYour Name 	uint16_t payloadLen;
532*5113495bSYour Name 	uint32_t look_ahead, actual_length;
533*5113495bSYour Name 
534*5113495bSYour Name 	buf = packet->pBuffer;
535*5113495bSYour Name 	actual_length = packet->ActualLength;
536*5113495bSYour Name 
537*5113495bSYour Name 	if (num_look_aheads)
538*5113495bSYour Name 		*num_look_aheads = 0;
539*5113495bSYour Name 
540*5113495bSYour Name 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader\n"));
541*5113495bSYour Name 
542*5113495bSYour Name 	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
543*5113495bSYour Name 		AR_DEBUG_PRINTBUF(buf, packet->ActualLength, "HTC Recv PKT");
544*5113495bSYour Name 
545*5113495bSYour Name 	do {
546*5113495bSYour Name 		/* note, we cannot assume the alignment of pBuffer,
547*5113495bSYour Name 		 * so we use the safe macros to
548*5113495bSYour Name 		 * retrieve 16 bit fields
549*5113495bSYour Name 		 */
550*5113495bSYour Name 		payloadLen = HTC_GET_FIELD(buf, HTC_FRAME_HDR,
551*5113495bSYour Name 					   PAYLOADLEN);
552*5113495bSYour Name 
553*5113495bSYour Name 		((uint8_t *)&look_ahead)[0] = buf[0];
554*5113495bSYour Name 		((uint8_t *)&look_ahead)[1] = buf[1];
555*5113495bSYour Name 		((uint8_t *)&look_ahead)[2] = buf[2];
556*5113495bSYour Name 		((uint8_t *)&look_ahead)[3] = buf[3];
557*5113495bSYour Name 
558*5113495bSYour Name 		if (packet->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
559*5113495bSYour Name 			/* refresh expected hdr, since this was unknown
560*5113495bSYour Name 			 * at the time we grabbed the packets
561*5113495bSYour Name 			 * as part of a bundle
562*5113495bSYour Name 			 */
563*5113495bSYour Name 			packet->PktInfo.AsRx.ExpectedHdr = look_ahead;
564*5113495bSYour Name 			/* refresh actual length since we now have the
565*5113495bSYour Name 			 * real header
566*5113495bSYour Name 			 */
567*5113495bSYour Name 			packet->ActualLength = payloadLen + HTC_HDR_LENGTH;
568*5113495bSYour Name 
569*5113495bSYour Name 			/* validate the actual header that was refreshed  */
570*5113495bSYour Name 			if (packet->ActualLength > packet->BufferLength) {
571*5113495bSYour Name 				hif_err("Bundled RECV Look ahead: 0x%X",
572*5113495bSYour Name 					look_ahead);
573*5113495bSYour Name 				hif_err("Invalid HDR payload length(%d)",
574*5113495bSYour Name 					payloadLen);
575*5113495bSYour Name 				/* limit this to max buffer just to print out
576*5113495bSYour Name 				 * some of the buffer
577*5113495bSYour Name 				 */
578*5113495bSYour Name 				packet->ActualLength =
579*5113495bSYour Name 					min(packet->ActualLength,
580*5113495bSYour Name 					    packet->BufferLength);
581*5113495bSYour Name 				status = QDF_STATUS_E_PROTO;
582*5113495bSYour Name 				break;
583*5113495bSYour Name 			}
584*5113495bSYour Name 
585*5113495bSYour Name 			if (packet->Endpoint
586*5113495bSYour Name 			    != HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID)) {
587*5113495bSYour Name 				hif_err("Refreshed HDR EP (%d)",
588*5113495bSYour Name 					HTC_GET_FIELD(buf, HTC_FRAME_HDR,
589*5113495bSYour Name 						      ENDPOINTID));
590*5113495bSYour Name 				hif_err("Doesn't match expected EP (%d)",
591*5113495bSYour Name 					packet->Endpoint);
592*5113495bSYour Name 				status = QDF_STATUS_E_PROTO;
593*5113495bSYour Name 				break;
594*5113495bSYour Name 			}
595*5113495bSYour Name 		}
596*5113495bSYour Name 
597*5113495bSYour Name 		if (look_ahead != packet->PktInfo.AsRx.ExpectedHdr) {
598*5113495bSYour Name 			/* somehow the lookahead that gave us the full read
599*5113495bSYour Name 			 * length did not reflect the actual header
600*5113495bSYour Name 			 * in the pending message
601*5113495bSYour Name 			 */
602*5113495bSYour Name 			hif_err("Lookahead mismatch!");
603*5113495bSYour Name 			hif_err("pPkt:0x%lX flags:0x%X",
604*5113495bSYour Name 				(unsigned long)packet,
605*5113495bSYour Name 				packet->PktInfo.AsRx.HTCRxFlags);
606*5113495bSYour Name 			hif_err("Look_ahead 0x%08X != 0x%08X",
607*5113495bSYour Name 				look_ahead,
608*5113495bSYour Name 				packet->PktInfo.AsRx.ExpectedHdr);
609*5113495bSYour Name #ifdef ATH_DEBUG_MODULE
610*5113495bSYour Name 			debug_dump_bytes((uint8_t *)&packet->PktInfo.AsRx.
611*5113495bSYour Name 					 ExpectedHdr, 4,
612*5113495bSYour Name 					 "Expected Message look_ahead");
613*5113495bSYour Name 			debug_dump_bytes(buf, sizeof(HTC_FRAME_HDR),
614*5113495bSYour Name 					 "Current Frame Header");
615*5113495bSYour Name #ifdef HTC_CAPTURE_LAST_FRAME
616*5113495bSYour Name 			debug_dump_bytes((uint8_t *)&target->LastFrameHdr,
617*5113495bSYour Name 					 sizeof(HTC_FRAME_HDR),
618*5113495bSYour Name 					 "Last Frame Header");
619*5113495bSYour Name 			if (target->LastTrailerLength != 0)
620*5113495bSYour Name 				debug_dump_bytes(target->LastTrailer,
621*5113495bSYour Name 						 target->LastTrailerLength,
622*5113495bSYour Name 						 "Last trailer");
623*5113495bSYour Name #endif
624*5113495bSYour Name #endif
625*5113495bSYour Name 			status = QDF_STATUS_E_PROTO;
626*5113495bSYour Name 			break;
627*5113495bSYour Name 		}
628*5113495bSYour Name 
629*5113495bSYour Name 		/* get flags */
630*5113495bSYour Name 		temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, FLAGS);
631*5113495bSYour Name 
632*5113495bSYour Name 		if (temp & HTC_FLAGS_RECV_TRAILER) {
633*5113495bSYour Name 			/* this packet has a trailer */
634*5113495bSYour Name 
635*5113495bSYour Name 			/* extract the trailer length in control byte 0 */
636*5113495bSYour Name 			temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, CONTROLBYTES0);
637*5113495bSYour Name 
638*5113495bSYour Name 			if ((temp < sizeof(HTC_RECORD_HDR)) ||
639*5113495bSYour Name 			    (temp > payloadLen)) {
640*5113495bSYour Name 				hif_err("Invalid header");
641*5113495bSYour Name 				hif_err("Payloadlength should be :%d",
642*5113495bSYour Name 					payloadLen);
643*5113495bSYour Name 				hif_err("But control bytes is :%d)", temp);
644*5113495bSYour Name 				status = QDF_STATUS_E_PROTO;
645*5113495bSYour Name 				break;
646*5113495bSYour Name 			}
647*5113495bSYour Name 
648*5113495bSYour Name 			if (packet->PktInfo.AsRx.
649*5113495bSYour Name 			    HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
650*5113495bSYour Name 				/* this packet was fetched as part of an HTC
651*5113495bSYour Name 				 * bundle as the lookahead is not valid.
652*5113495bSYour Name 				 * Next packet may have already been fetched as
653*5113495bSYour Name 				 * part of the bundle
654*5113495bSYour Name 				 */
655*5113495bSYour Name 				next_look_aheads = NULL;
656*5113495bSYour Name 				num_look_aheads = NULL;
657*5113495bSYour Name 			}
658*5113495bSYour Name 
659*5113495bSYour Name 			/* process trailer data that follows HDR and
660*5113495bSYour Name 			 * application payload
661*5113495bSYour Name 			 */
662*5113495bSYour Name 			status =
663*5113495bSYour Name 			hif_dev_process_trailer(pdev,
664*5113495bSYour Name 						(buf + HTC_HDR_LENGTH +
665*5113495bSYour Name 						 payloadLen - temp),
666*5113495bSYour Name 						temp,
667*5113495bSYour Name 						next_look_aheads,
668*5113495bSYour Name 						num_look_aheads,
669*5113495bSYour Name 						packet->Endpoint);
670*5113495bSYour Name 
671*5113495bSYour Name 			if (QDF_IS_STATUS_ERROR(status))
672*5113495bSYour Name 				break;
673*5113495bSYour Name 		}
674*5113495bSYour Name 	} while (false);
675*5113495bSYour Name 
676*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
677*5113495bSYour Name 		/* dump the whole packet */
678*5113495bSYour Name 		debug_dump_bytes(buf, packet->ActualLength,
679*5113495bSYour Name 				 "BAD HTC Recv PKT");
680*5113495bSYour Name 	} else {
681*5113495bSYour Name 		if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
682*5113495bSYour Name 			if (packet->ActualLength > 0) {
683*5113495bSYour Name 				AR_DEBUG_PRINTBUF(packet->pBuffer,
684*5113495bSYour Name 						  packet->ActualLength,
685*5113495bSYour Name 						  "HTC - Application Msg");
686*5113495bSYour Name 			}
687*5113495bSYour Name 		}
688*5113495bSYour Name 	}
689*5113495bSYour Name 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
690*5113495bSYour Name 			("-hif_dev_process_recv_header\n"));
691*5113495bSYour Name 	return status;
692*5113495bSYour Name }
693*5113495bSYour Name 
694*5113495bSYour Name /**
695*5113495bSYour Name  * hif_dev_free_recv_pkt_queue() - Free the allocated recv packets in the queue
696*5113495bSYour Name  * @recv_pkt_queue : The queue that contains the packets to be queued
697*5113495bSYour Name  *
698*5113495bSYour Name  * Return : NONE
699*5113495bSYour Name  */
hif_dev_free_recv_pkt_queue(HTC_PACKET_QUEUE * recv_pkt_queue)700*5113495bSYour Name void hif_dev_free_recv_pkt_queue(HTC_PACKET_QUEUE *recv_pkt_queue)
701*5113495bSYour Name {
702*5113495bSYour Name 	HTC_PACKET *packet;
703*5113495bSYour Name 	qdf_nbuf_t netbuf;
704*5113495bSYour Name 
705*5113495bSYour Name 	while (!HTC_QUEUE_EMPTY(recv_pkt_queue)) {
706*5113495bSYour Name 		packet = htc_packet_dequeue(recv_pkt_queue);
707*5113495bSYour Name 		if (!packet)
708*5113495bSYour Name 			break;
709*5113495bSYour Name 		netbuf = (qdf_nbuf_t)packet->pNetBufContext;
710*5113495bSYour Name 		if (netbuf)
711*5113495bSYour Name 			qdf_nbuf_free(netbuf);
712*5113495bSYour Name 	}
713*5113495bSYour Name }
714