xref: /wlan-dirver/qca-wifi-host-cmn/hif/src/sdio/transfer/transfer.c (revision 8cfe6b10058a04cafb17eed051f2ddf11bee8931)
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 
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  */
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("%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 			return QDF_STATUS_E_NOMEM;
137 	}
138 
139 	sctx->netbuf = buf;
140 	sctx->pDev = pdev;
141 	sctx->transferID = xfer_id;
142 	sctx->head_data_len = head_len;
143 	/*
144 	 * Copy data to head part of netbuf or head of allocated buffer.
145 	 * if buffer is new allocated, the last buffer should be copied also.
146 	 * It assume last fragment is internal buffer of netbuf
147 	 * sometime total length of fragments larger than nbytes
148 	 */
149 	pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
150 	for (i = 0, count = sctx->bNewAlloc ? frag_count : frag_count - 1;
151 	     i < count;
152 	     i++) {
153 		int frag_len = qdf_nbuf_get_frag_len(buf, i);
154 		unsigned char *frag_addr = qdf_nbuf_get_frag_vaddr(buf, i);
155 
156 		if (frag_len > nbytes)
157 			frag_len = nbytes;
158 		memcpy(pData, frag_addr, frag_len);
159 		pData += frag_len;
160 		nbytes -= frag_len;
161 		if (nbytes <= 0)
162 			break;
163 	}
164 
165 	/* Reset pData pointer and sctx out */
166 	pData = (unsigned char *)sctx + sizeof(struct hif_sendContext);
167 
168 	status = hif_read_write(pdev->HIFDevice, addr, (char *)pData,
169 				padded_length, request, (void *)sctx);
170 
171 	if (status == QDF_STATUS_E_PENDING) {
172 		/*
173 		 * it will return QDF_STATUS_E_PENDING in native HIF
174 		 * implementation, which should be treated as successful
175 		 * result here.
176 		 */
177 		status = QDF_STATUS_SUCCESS;
178 	}
179 
180 	/* release buffer or move back data pointer when failed */
181 	if (status != QDF_STATUS_SUCCESS) {
182 		if (sctx->bNewAlloc)
183 			qdf_mem_free(sctx);
184 		else
185 			qdf_nbuf_pull_head(buf, head_len);
186 	}
187 
188 	return status;
189 }
190 
191 /**
192  * hif_dev_alloc_and_prepare_rx_packets() - Allocate packets for recv frames.
193  * @pdev : HIF device object
194  * @look_aheads : Look ahead information on the frames
195  * @messages : Number of messages
196  * @queue : Queue to put the allocated frames
197  *
198  * Return : QDF_STATUS_SUCCESS on success else error value
199  */
200 QDF_STATUS hif_dev_alloc_and_prepare_rx_packets(struct hif_sdio_device *pdev,
201 						uint32_t look_aheads[],
202 						int messages,
203 						HTC_PACKET_QUEUE *queue)
204 {
205 	int i, j;
206 	bool no_recycle;
207 	int num_messages;
208 	HTC_PACKET *packet;
209 	HTC_FRAME_HDR *hdr;
210 	uint32_t full_length;
211 	QDF_STATUS status = QDF_STATUS_SUCCESS;
212 
213 	/* lock RX while we assemble the packet buffers */
214 	LOCK_HIF_DEV_RX(pdev);
215 
216 	for (i = 0; i < messages; i++) {
217 		hdr = (HTC_FRAME_HDR *)&look_aheads[i];
218 		if (hdr->EndpointID >= ENDPOINT_MAX) {
219 			hif_err("%s: Invalid Endpoint:%d\n",
220 				__func__, hdr->EndpointID);
221 			status = QDF_STATUS_E_INVAL;
222 			break;
223 		}
224 
225 		if (hdr->PayloadLen > HTC_MAX_PAYLOAD_LENGTH) {
226 			hif_err("%s: Payload length %d exceeds max HTC : %u",
227 				__func__,
228 				hdr->PayloadLen,
229 				(uint32_t)HTC_MAX_PAYLOAD_LENGTH);
230 			status = QDF_STATUS_E_INVAL;
231 			break;
232 		}
233 
234 		if ((hdr->Flags & HTC_FLAGS_RECV_BUNDLE_CNT_MASK) == 0) {
235 			/* HTC header only indicates 1 message to fetch */
236 			num_messages = 1;
237 		} else {
238 			/* HTC header indicates that every packet to follow
239 			 * has the same padded length so that it can
240 			 * be optimally fetched as a full bundle
241 			 */
242 			num_messages = GET_RECV_BUNDLE_COUNT(hdr->Flags);
243 			/* the count doesn't include the starter frame, just
244 			 * a count of frames to follow
245 			 */
246 			num_messages++;
247 
248 			hif_info("%s: HTC header : %u messages in bundle",
249 				 __func__, num_messages);
250 		}
251 
252 		full_length = DEV_CALC_RECV_PADDED_LEN(pdev,
253 						       hdr->PayloadLen +
254 						       sizeof(HTC_FRAME_HDR));
255 
256 		/* get packet buffers for each message, if there was a
257 		 * bundle detected in the header,
258 		 * use pHdr as a template to fetch all packets in the bundle
259 		 */
260 		for (j = 0; j < num_messages; j++) {
261 			/* reset flag, any packets allocated using the
262 			 * RecvAlloc() API cannot be recycled on cleanup,
263 			 * they must be explicitly returned
264 			 */
265 			no_recycle = false;
266 			packet = hif_dev_alloc_rx_buffer(pdev);
267 
268 			if (!packet) {
269 				/* No error, simply need to mark that
270 				 * we are waiting for buffers.
271 				 */
272 				pdev->RecvStateFlags |= HTC_RECV_WAIT_BUFFERS;
273 				/* pDev->EpWaitingForBuffers = pEndpoint->Id; */
274 				status = QDF_STATUS_E_RESOURCES;
275 				break;
276 			}
277 			/* clear flags */
278 			packet->PktInfo.AsRx.HTCRxFlags = 0;
279 			packet->PktInfo.AsRx.IndicationFlags = 0;
280 			packet->Status = QDF_STATUS_SUCCESS;
281 
282 			if (no_recycle) {
283 				/* flag that these packets cannot be recycled,
284 				 * they have to be returned to the user
285 				 */
286 				packet->PktInfo.AsRx.HTCRxFlags |=
287 					HTC_RX_PKT_NO_RECYCLE;
288 			}
289 			/* add packet to queue (also incase we need to
290 			 * cleanup down below)
291 			 */
292 			HTC_PACKET_ENQUEUE(queue, packet);
293 
294 			/* if (HTC_STOPPING(target)) {
295 			 *      status = QDF_STATUS_E_CANCELED;
296 			 *      break;
297 			 *  }
298 			 */
299 
300 			/* make sure  message can fit in the endpoint buffer */
301 			if (full_length > packet->BufferLength) {
302 				hif_err("%s: Payload Length Error", __func__);
303 				hif_err("%s: header reports payload: %u(%u)",
304 					__func__, hdr->PayloadLen,
305 					full_length);
306 				hif_err("%s: endpoint buffer size: %d\n",
307 					__func__, packet->BufferLength);
308 				status = QDF_STATUS_E_INVAL;
309 				break;
310 			}
311 
312 			if (j > 0) {
313 				/* for messages fetched in a bundle the expected
314 				 * lookahead is unknown as we are only using the
315 				 * lookahead of the first packet as a template
316 				 * of what to expect for lengths
317 				 */
318 				packet->PktInfo.AsRx.HTCRxFlags |=
319 					HTC_RX_PKT_REFRESH_HDR;
320 				/* set it to something invalid */
321 				packet->PktInfo.AsRx.ExpectedHdr = 0xFFFFFFFF;
322 			} else {
323 				packet->PktInfo.AsRx.ExpectedHdr =
324 					look_aheads[i];
325 			}
326 			/* set the amount of data to fetch */
327 			packet->ActualLength =
328 				hdr->PayloadLen + HTC_HDR_LENGTH;
329 			if ((j == (num_messages - 1)) &&
330 			    ((hdr->Flags) & HTC_FLAGS_RECV_1MORE_BLOCK))
331 				packet->PktInfo.AsRx.HTCRxFlags |=
332 				HTC_RX_PKT_LAST_BUNDLED_PKT_HAS_ADDTIONAL_BLOCK;
333 			packet->Endpoint = hdr->EndpointID;
334 			packet->Completion = NULL;
335 		}
336 
337 		if (QDF_IS_STATUS_ERROR(status))
338 			break;
339 	}
340 
341 	UNLOCK_HIF_DEV_RX(pdev);
342 
343 	/* for NO RESOURCE error, no need to flush data queue */
344 	if (QDF_IS_STATUS_ERROR(status)	&&
345 	    (status != QDF_STATUS_E_RESOURCES)) {
346 		while (!HTC_QUEUE_EMPTY(queue)) {
347 			qdf_nbuf_t netbuf;
348 
349 			packet = htc_packet_dequeue(queue);
350 			if (!packet)
351 				break;
352 			netbuf = (qdf_nbuf_t)packet->pNetBufContext;
353 			if (netbuf)
354 				qdf_nbuf_free(netbuf);
355 		}
356 	}
357 	if (status == QDF_STATUS_E_RESOURCES)
358 		status = QDF_STATUS_SUCCESS;
359 	return status;
360 }
361 
362 /**
363  * hif_dev_process_trailer() - Process the receive frame trailer
364  * @pdev : HIF device object
365  * @buffer : The buffer containing the trailer
366  * @length : Length of the buffer
367  * @next_look_aheads : The lookahead that is next
368  * @num_look_aheads : Number of lookahead information
369  * @from_endpoint : The endpoint on which the trailer is received
370  */
371 QDF_STATUS hif_dev_process_trailer(struct hif_sdio_device *pdev,
372 				   uint8_t *buffer, int length,
373 				   uint32_t *next_look_aheads,
374 				   int *num_look_aheads,
375 				   HTC_ENDPOINT_ID from_endpoint)
376 {
377 	int orig_length;
378 	QDF_STATUS status;
379 	uint8_t *record_buf;
380 	uint8_t *orig_buffer;
381 	HTC_RECORD_HDR *record;
382 	HTC_LOOKAHEAD_REPORT *look_ahead;
383 
384 	hif_debug("%s: length:%d", __func__, length);
385 
386 	orig_buffer = buffer;
387 	orig_length = length;
388 	status = QDF_STATUS_SUCCESS;
389 
390 	while (length > 0) {
391 		if (length < sizeof(HTC_RECORD_HDR)) {
392 			status = QDF_STATUS_E_PROTO;
393 			break;
394 		}
395 		/* these are byte aligned structs */
396 		record = (HTC_RECORD_HDR *)buffer;
397 		length -= sizeof(HTC_RECORD_HDR);
398 		buffer += sizeof(HTC_RECORD_HDR);
399 
400 		if (record->Length > length) {
401 			/* no room left in buffer for record */
402 			hif_err("%s: invalid record len: (%u, %u)",
403 				__func__, record->Length,
404 				record->RecordID);
405 			hif_err("%s: buffer has %d bytes left",
406 				__func__, length);
407 			status = QDF_STATUS_E_PROTO;
408 			break;
409 		}
410 		/* start of record follows the header */
411 		record_buf = buffer;
412 
413 		switch (record->RecordID) {
414 		case HTC_RECORD_CREDITS:
415 			/* Process in HTC, ignore here */
416 			break;
417 		case HTC_RECORD_LOOKAHEAD:
418 			A_ASSERT(record->Length >= sizeof(*look_ahead));
419 			look_ahead = (HTC_LOOKAHEAD_REPORT *)record_buf;
420 			if ((look_ahead->PreValid ==
421 			     ((~look_ahead->PostValid) & 0xFF)) &&
422 			    next_look_aheads) {
423 				hif_debug("%s: look_ahead Report", __func__);
424 				hif_debug("%s:prevalid:0x%x, postvalid:0x%x",
425 					  __func__, look_ahead->PreValid,
426 					  look_ahead->PostValid);
427 				hif_debug("%s:from endpoint %d : %u",
428 					  __func__, from_endpoint,
429 					  look_ahead->LookAhead0);
430 				/* look ahead bytes are valid, copy them over */
431 				((uint8_t *)(&next_look_aheads[0]))[0] =
432 					look_ahead->LookAhead0;
433 				((uint8_t *)(&next_look_aheads[0]))[1] =
434 					look_ahead->LookAhead1;
435 				((uint8_t *)(&next_look_aheads[0]))[2] =
436 					look_ahead->LookAhead2;
437 				((uint8_t *)(&next_look_aheads[0]))[3] =
438 					look_ahead->LookAhead3;
439 
440 				if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
441 					debug_dump_bytes((uint8_t *)
442 							 next_look_aheads, 4,
443 							 "Next Look Ahead");
444 				}
445 				/* just one normal lookahead */
446 				if (num_look_aheads)
447 					*num_look_aheads = 1;
448 			}
449 			break;
450 		case HTC_RECORD_LOOKAHEAD_BUNDLE:
451 			A_ASSERT(record->Length >=
452 					sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT));
453 			if ((record->Length >=
454 			     sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)) &&
455 			    next_look_aheads) {
456 				HTC_BUNDLED_LOOKAHEAD_REPORT
457 				*pBundledLookAheadRpt;
458 				int i;
459 
460 				pBundledLookAheadRpt =
461 				(HTC_BUNDLED_LOOKAHEAD_REPORT *)record_buf;
462 
463 				if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
464 					debug_dump_bytes(record_buf,
465 							 record->Length,
466 							 "Bundle look_ahead");
467 				}
468 
469 				if ((record->Length /
470 				     (sizeof(HTC_BUNDLED_LOOKAHEAD_REPORT)))
471 					> HTC_MAX_MSG_PER_BUNDLE_RX) {
472 					/* this should never happen, the target
473 					 * restricts the number of messages per
474 					 * bundle configured by the host
475 					 */
476 					A_ASSERT(false);
477 					status = QDF_STATUS_E_PROTO;
478 					break;
479 				}
480 				for (i = 0;
481 				     i <
482 				     (int)(record->Length /
483 					   (sizeof
484 					    (HTC_BUNDLED_LOOKAHEAD_REPORT)));
485 				     i++) {
486 					((uint8_t *)(&next_look_aheads[i]))[0] =
487 					   pBundledLookAheadRpt->LookAhead0;
488 					((uint8_t *)(&next_look_aheads[i]))[1] =
489 					   pBundledLookAheadRpt->LookAhead1;
490 					((uint8_t *)(&next_look_aheads[i]))[2] =
491 					   pBundledLookAheadRpt->LookAhead2;
492 					((uint8_t *)(&next_look_aheads[i]))[3] =
493 					   pBundledLookAheadRpt->LookAhead3;
494 					pBundledLookAheadRpt++;
495 				}
496 				if (num_look_aheads)
497 					*num_look_aheads = i;
498 			}
499 			break;
500 		default:
501 			hif_err("%s: HIF unhandled record: id:%u length:%u",
502 				__func__, record->RecordID, record->Length);
503 			break;
504 		}
505 
506 		if (QDF_IS_STATUS_ERROR(status))
507 			break;
508 
509 		/* advance buffer past this record for next time around */
510 		buffer += record->Length;
511 		length -= record->Length;
512 	}
513 
514 	if (QDF_IS_STATUS_ERROR(status))
515 		debug_dump_bytes(orig_buffer, orig_length,
516 				 "BAD Recv Trailer");
517 
518 	hif_debug("%s: status = %d", __func__, status);
519 
520 	return status;
521 }
522 
523 /* process a received message (i.e. strip off header,
524  * process any trailer data).
525  * note : locks must be released when this function is called
526  */
527 QDF_STATUS hif_dev_process_recv_header(struct hif_sdio_device *pdev,
528 				       HTC_PACKET *packet,
529 				       uint32_t *next_look_aheads,
530 				       int *num_look_aheads)
531 {
532 	uint8_t temp;
533 	uint8_t *buf;
534 	QDF_STATUS status = QDF_STATUS_SUCCESS;
535 	uint16_t payloadLen;
536 	uint32_t look_ahead, actual_length;
537 
538 	buf = packet->pBuffer;
539 	actual_length = packet->ActualLength;
540 
541 	if (num_look_aheads)
542 		*num_look_aheads = 0;
543 
544 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("+HTCProcessRecvHeader\n"));
545 
546 	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
547 		AR_DEBUG_PRINTBUF(buf, packet->ActualLength, "HTC Recv PKT");
548 
549 	do {
550 		/* note, we cannot assume the alignment of pBuffer,
551 		 * so we use the safe macros to
552 		 * retrieve 16 bit fields
553 		 */
554 		payloadLen = HTC_GET_FIELD(buf, HTC_FRAME_HDR,
555 					   PAYLOADLEN);
556 
557 		((uint8_t *)&look_ahead)[0] = buf[0];
558 		((uint8_t *)&look_ahead)[1] = buf[1];
559 		((uint8_t *)&look_ahead)[2] = buf[2];
560 		((uint8_t *)&look_ahead)[3] = buf[3];
561 
562 		if (packet->PktInfo.AsRx.HTCRxFlags & HTC_RX_PKT_REFRESH_HDR) {
563 			/* refresh expected hdr, since this was unknown
564 			 * at the time we grabbed the packets
565 			 * as part of a bundle
566 			 */
567 			packet->PktInfo.AsRx.ExpectedHdr = look_ahead;
568 			/* refresh actual length since we now have the
569 			 * real header
570 			 */
571 			packet->ActualLength = payloadLen + HTC_HDR_LENGTH;
572 
573 			/* validate the actual header that was refreshed  */
574 			if (packet->ActualLength > packet->BufferLength) {
575 				hif_err("%s: Bundled RECV Look ahead: 0x%X",
576 					__func__, look_ahead);
577 				hif_err("%s: Invalid HDR payload length(%d)",
578 					__func__,  payloadLen);
579 				/* limit this to max buffer just to print out
580 				 * some of the buffer
581 				 */
582 				packet->ActualLength =
583 					min(packet->ActualLength,
584 					    packet->BufferLength);
585 				status = QDF_STATUS_E_PROTO;
586 				break;
587 			}
588 
589 			if (packet->Endpoint
590 			    != HTC_GET_FIELD(buf, HTC_FRAME_HDR, ENDPOINTID)) {
591 				hif_err("%s: Refreshed HDR EP (%d)",
592 					__func__,
593 					HTC_GET_FIELD(buf, HTC_FRAME_HDR,
594 						      ENDPOINTID));
595 				hif_err("%s: doesn't match expected EP (%d)",
596 					__func__, packet->Endpoint);
597 				status = QDF_STATUS_E_PROTO;
598 				break;
599 			}
600 		}
601 
602 		if (look_ahead != packet->PktInfo.AsRx.ExpectedHdr) {
603 			/* somehow the lookahead that gave us the full read
604 			 * length did not reflect the actual header
605 			 * in the pending message
606 			 */
607 			hif_err("%s: lookahead mismatch!", __func__);
608 			hif_err("%s: pPkt:0x%lX flags:0x%X",
609 				__func__, (unsigned long)packet,
610 				packet->PktInfo.AsRx.HTCRxFlags);
611 			hif_err("%s: look_ahead 0x%08X != 0x%08X",
612 				__func__, look_ahead,
613 				packet->PktInfo.AsRx.ExpectedHdr);
614 #ifdef ATH_DEBUG_MODULE
615 			debug_dump_bytes((uint8_t *)&packet->PktInfo.AsRx.
616 					 ExpectedHdr, 4,
617 					 "Expected Message look_ahead");
618 			debug_dump_bytes(buf, sizeof(HTC_FRAME_HDR),
619 					 "Current Frame Header");
620 #ifdef HTC_CAPTURE_LAST_FRAME
621 			debug_dump_bytes((uint8_t *)&target->LastFrameHdr,
622 					 sizeof(HTC_FRAME_HDR),
623 					 "Last Frame Header");
624 			if (target->LastTrailerLength != 0)
625 				debug_dump_bytes(target->LastTrailer,
626 						 target->LastTrailerLength,
627 						 "Last trailer");
628 #endif
629 #endif
630 			status = QDF_STATUS_E_PROTO;
631 			break;
632 		}
633 
634 		/* get flags */
635 		temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, FLAGS);
636 
637 		if (temp & HTC_FLAGS_RECV_TRAILER) {
638 			/* this packet has a trailer */
639 
640 			/* extract the trailer length in control byte 0 */
641 			temp = HTC_GET_FIELD(buf, HTC_FRAME_HDR, CONTROLBYTES0);
642 
643 			if ((temp < sizeof(HTC_RECORD_HDR)) ||
644 			    (temp > payloadLen)) {
645 				hif_err("%s: invalid header",
646 					__func__);
647 				hif_err("%s: payloadlength should be :%d",
648 					__func__, payloadLen);
649 				hif_err("%s: But control bytes is :%d)",
650 					__func__, temp);
651 				status = QDF_STATUS_E_PROTO;
652 				break;
653 			}
654 
655 			if (packet->PktInfo.AsRx.
656 			    HTCRxFlags & HTC_RX_PKT_IGNORE_LOOKAHEAD) {
657 				/* this packet was fetched as part of an HTC
658 				 * bundle as the lookahead is not valid.
659 				 * Next packet may have already been fetched as
660 				 * part of the bundle
661 				 */
662 				next_look_aheads = NULL;
663 				num_look_aheads = NULL;
664 			}
665 
666 			/* process trailer data that follows HDR and
667 			 * application payload
668 			 */
669 			status =
670 			hif_dev_process_trailer(pdev,
671 						(buf + HTC_HDR_LENGTH +
672 						 payloadLen - temp),
673 						temp,
674 						next_look_aheads,
675 						num_look_aheads,
676 						packet->Endpoint);
677 
678 			if (QDF_IS_STATUS_ERROR(status))
679 				break;
680 		}
681 	} while (false);
682 
683 	if (QDF_IS_STATUS_ERROR(status)) {
684 		/* dump the whole packet */
685 		debug_dump_bytes(buf, packet->ActualLength,
686 				 "BAD HTC Recv PKT");
687 	} else {
688 		if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV)) {
689 			if (packet->ActualLength > 0) {
690 				AR_DEBUG_PRINTBUF(packet->pBuffer,
691 						  packet->ActualLength,
692 						  "HTC - Application Msg");
693 			}
694 		}
695 	}
696 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
697 			("-hif_dev_process_recv_header\n"));
698 	return status;
699 }
700 
701 /**
702  * hif_dev_free_recv_pkt_queue() - Free the allocated recv packets in the queue
703  * @recv_pkt_queue : The queue that contains the packets to be queued
704  *
705  * Return : NONE
706  */
707 void hif_dev_free_recv_pkt_queue(HTC_PACKET_QUEUE *recv_pkt_queue)
708 {
709 	HTC_PACKET *packet;
710 	qdf_nbuf_t netbuf;
711 
712 	while (!HTC_QUEUE_EMPTY(recv_pkt_queue)) {
713 		packet = htc_packet_dequeue(recv_pkt_queue);
714 		if (!packet)
715 			break;
716 		netbuf = (qdf_nbuf_t)packet->pNetBufContext;
717 		if (netbuf)
718 			qdf_nbuf_free(netbuf);
719 	}
720 }
721