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