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