xref: /wlan-dirver/qca-wifi-host-cmn/htc/htc_recv.c (revision a4b8d357569709a7889c418ba927c180e2cd45dc)
1 /*
2  * Copyright (c) 2013-2017 The Linux Foundation. All rights reserved.
3  *
4  * Previously licensed under the ISC license by Qualcomm Atheros, Inc.
5  *
6  *
7  * Permission to use, copy, modify, and/or distribute this software for
8  * any purpose with or without fee is hereby granted, provided that the
9  * above copyright notice and this permission notice appear in all
10  * copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
16  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
17  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
18  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
19  * PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 /*
23  * This file was originally distributed by Qualcomm Atheros, Inc.
24  * under proprietary terms before Copyright ownership was assigned
25  * to the Linux Foundation.
26  */
27 
28 #include "htc_debug.h"
29 #include "htc_internal.h"
30 #include <qdf_nbuf.h>           /* qdf_nbuf_t */
31 
32 /* HTC Control message receive timeout msec */
33 #define HTC_CONTROL_RX_TIMEOUT     3000
34 
35 #if defined(WLAN_DEBUG) || defined(DEBUG)
36 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
37 {
38 	int8_t stream[60];
39 	int8_t byteOffsetStr[10];
40 	uint32_t i;
41 	uint16_t offset, count, byteOffset;
42 
43 	A_PRINTF("<---------Dumping %d Bytes : %s ------>\n", length,
44 		 pDescription);
45 
46 	count = 0;
47 	offset = 0;
48 	byteOffset = 0;
49 	for (i = 0; i < length; i++) {
50 		A_SNPRINTF(stream + offset, (sizeof(stream) - offset),
51 			   "%02X ", buffer[i]);
52 		count++;
53 		offset += 3;
54 
55 		if (count == 16) {
56 			count = 0;
57 			offset = 0;
58 			A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X",
59 				   byteOffset);
60 			A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
61 			qdf_mem_zero(stream, 60);
62 			byteOffset += 16;
63 		}
64 	}
65 
66 	if (offset != 0) {
67 		A_SNPRINTF(byteOffsetStr, sizeof(byteOffset), "%4.4X",
68 			   byteOffset);
69 		A_PRINTF("[%s]: %s\n", byteOffsetStr, stream);
70 	}
71 
72 	A_PRINTF("<------------------------------------------------->\n");
73 }
74 #else
75 void debug_dump_bytes(uint8_t *buffer, uint16_t length, char *pDescription)
76 {
77 }
78 #endif
79 
80 static A_STATUS htc_process_trailer(HTC_TARGET *target,
81 				    uint8_t *pBuffer,
82 				    int Length, HTC_ENDPOINT_ID FromEndpoint);
83 
84 static void do_recv_completion(HTC_ENDPOINT *pEndpoint,
85 			       HTC_PACKET_QUEUE *pQueueToIndicate)
86 {
87 
88 	do {
89 
90 		if (HTC_QUEUE_EMPTY(pQueueToIndicate)) {
91 			/* nothing to indicate */
92 			break;
93 		}
94 
95 		if (pEndpoint->EpCallBacks.EpRecvPktMultiple != NULL) {
96 			AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
97 					("HTC calling ep %d, recv multiple callback (%d pkts)\n",
98 					 pEndpoint->Id,
99 					 HTC_PACKET_QUEUE_DEPTH
100 						 (pQueueToIndicate)));
101 			/* a recv multiple handler is being used, pass the queue
102 			 * to the handler
103 			 */
104 			pEndpoint->EpCallBacks.EpRecvPktMultiple(
105 						pEndpoint->EpCallBacks.pContext,
106 						pQueueToIndicate);
107 			INIT_HTC_PACKET_QUEUE(pQueueToIndicate);
108 		} else {
109 			HTC_PACKET *pPacket;
110 			/* using legacy EpRecv */
111 			while (!HTC_QUEUE_EMPTY(pQueueToIndicate)) {
112 				pPacket = htc_packet_dequeue(pQueueToIndicate);
113 				if (pEndpoint->EpCallBacks.EpRecv == NULL) {
114 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
115 							("HTC ep %d has NULL recv callback on packet %p\n",
116 							 pEndpoint->Id,
117 							 pPacket));
118 					if (pPacket)
119 						qdf_nbuf_free(
120 							pPacket->pPktContext);
121 					continue;
122 				}
123 				AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
124 						("HTC calling ep %d recv callback on packet %p\n",
125 						 pEndpoint->Id, pPacket));
126 				pEndpoint->EpCallBacks.EpRecv(pEndpoint->
127 							      EpCallBacks.
128 							      pContext,
129 							      pPacket);
130 			}
131 		}
132 
133 	} while (false);
134 
135 }
136 
137 static void recv_packet_completion(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint,
138 				   HTC_PACKET *pPacket)
139 {
140 	HTC_PACKET_QUEUE container;
141 
142 	INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
143 	/* do completion */
144 	do_recv_completion(pEndpoint, &container);
145 }
146 
147 void htc_control_rx_complete(void *Context, HTC_PACKET *pPacket)
148 {
149 	/* TODO, can't really receive HTC control messages yet.... */
150 	AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
151 			("Invalid call to  htc_control_rx_complete\n"));
152 }
153 
154 void htc_unblock_recv(HTC_HANDLE HTCHandle)
155 {
156 	/* TODO  find the Need in new model */
157 }
158 
159 void htc_enable_recv(HTC_HANDLE HTCHandle)
160 {
161 
162 	/* TODO  find the Need in new model */
163 }
164 
165 void htc_disable_recv(HTC_HANDLE HTCHandle)
166 {
167 
168 	/* TODO  find the Need in new model */
169 }
170 
171 int htc_get_num_recv_buffers(HTC_HANDLE HTCHandle, HTC_ENDPOINT_ID Endpoint)
172 {
173 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
174 
175 	HTC_ENDPOINT *pEndpoint = &target->endpoint[Endpoint];
176 	return HTC_PACKET_QUEUE_DEPTH(&pEndpoint->RxBufferHoldQueue);
177 }
178 
179 HTC_PACKET *allocate_htc_packet_container(HTC_TARGET *target)
180 {
181 	HTC_PACKET *pPacket;
182 
183 	LOCK_HTC_RX(target);
184 
185 	if (NULL == target->pHTCPacketStructPool) {
186 		UNLOCK_HTC_RX(target);
187 		return NULL;
188 	}
189 
190 	pPacket = target->pHTCPacketStructPool;
191 	target->pHTCPacketStructPool = (HTC_PACKET *) pPacket->ListLink.pNext;
192 
193 	UNLOCK_HTC_RX(target);
194 
195 	pPacket->ListLink.pNext = NULL;
196 	return pPacket;
197 }
198 
199 void free_htc_packet_container(HTC_TARGET *target, HTC_PACKET *pPacket)
200 {
201 	LOCK_HTC_RX(target);
202 
203 	if (NULL == target->pHTCPacketStructPool) {
204 		target->pHTCPacketStructPool = pPacket;
205 		pPacket->ListLink.pNext = NULL;
206 	} else {
207 		pPacket->ListLink.pNext =
208 			(DL_LIST *) target->pHTCPacketStructPool;
209 		target->pHTCPacketStructPool = pPacket;
210 	}
211 
212 	UNLOCK_HTC_RX(target);
213 }
214 
215 #ifdef RX_SG_SUPPORT
216 qdf_nbuf_t rx_sg_to_single_netbuf(HTC_TARGET *target)
217 {
218 	qdf_nbuf_t skb;
219 	uint8_t *anbdata;
220 	uint8_t *anbdata_new;
221 	uint32_t anblen;
222 	qdf_nbuf_t new_skb = NULL;
223 	uint32_t sg_queue_len;
224 	qdf_nbuf_queue_t *rx_sg_queue = &target->RxSgQueue;
225 
226 	sg_queue_len = qdf_nbuf_queue_len(rx_sg_queue);
227 
228 	if (sg_queue_len <= 1) {
229 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
230 				("rx_sg_to_single_netbuf: invalid sg queue len %u\n"));
231 		goto _failed;
232 	}
233 
234 	new_skb = qdf_nbuf_alloc(target->ExpRxSgTotalLen, 0, 4, false);
235 	if (new_skb == NULL) {
236 		AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
237 				("rx_sg_to_single_netbuf: can't allocate %u size netbuf\n",
238 				 target->ExpRxSgTotalLen));
239 		goto _failed;
240 	}
241 
242 	qdf_nbuf_peek_header(new_skb, &anbdata_new, &anblen);
243 
244 	skb = qdf_nbuf_queue_remove(rx_sg_queue);
245 	do {
246 		qdf_nbuf_peek_header(skb, &anbdata, &anblen);
247 		qdf_mem_copy(anbdata_new, anbdata, qdf_nbuf_len(skb));
248 		qdf_nbuf_put_tail(new_skb, qdf_nbuf_len(skb));
249 		anbdata_new += qdf_nbuf_len(skb);
250 		qdf_nbuf_free(skb);
251 		skb = qdf_nbuf_queue_remove(rx_sg_queue);
252 	} while (skb != NULL);
253 
254 	RESET_RX_SG_CONFIG(target);
255 	return new_skb;
256 
257 _failed:
258 
259 	while ((skb = qdf_nbuf_queue_remove(rx_sg_queue)) != NULL)
260 		qdf_nbuf_free(skb);
261 
262 	RESET_RX_SG_CONFIG(target);
263 	return NULL;
264 }
265 #endif
266 
267 #ifdef CONFIG_WIN
268 #define HTC_MSG_NACK_SUSPEND 7
269 #endif
270 
271 QDF_STATUS htc_rx_completion_handler(void *Context, qdf_nbuf_t netbuf,
272 				   uint8_t pipeID)
273 {
274 	QDF_STATUS status = QDF_STATUS_SUCCESS;
275 	HTC_FRAME_HDR *HtcHdr;
276 	HTC_TARGET *target = (HTC_TARGET *) Context;
277 	uint8_t *netdata;
278 	uint32_t netlen;
279 	HTC_ENDPOINT *pEndpoint;
280 	HTC_PACKET *pPacket;
281 	uint16_t payloadLen;
282 	uint32_t trailerlen = 0;
283 	uint8_t htc_ep_id;
284 	struct htc_init_info *info;
285 
286 #ifdef RX_SG_SUPPORT
287 	LOCK_HTC_RX(target);
288 	if (target->IsRxSgInprogress) {
289 		target->CurRxSgTotalLen += qdf_nbuf_len(netbuf);
290 		qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
291 		if (target->CurRxSgTotalLen == target->ExpRxSgTotalLen) {
292 			netbuf = rx_sg_to_single_netbuf(target);
293 			if (netbuf == NULL) {
294 				UNLOCK_HTC_RX(target);
295 				goto _out;
296 			}
297 		} else {
298 			netbuf = NULL;
299 			UNLOCK_HTC_RX(target);
300 			goto _out;
301 		}
302 	}
303 	UNLOCK_HTC_RX(target);
304 #endif
305 
306 	netdata = qdf_nbuf_data(netbuf);
307 	netlen = qdf_nbuf_len(netbuf);
308 
309 	HtcHdr = (HTC_FRAME_HDR *) netdata;
310 
311 	do {
312 
313 		htc_ep_id = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, ENDPOINTID);
314 
315 		if (htc_ep_id >= ENDPOINT_MAX) {
316 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
317 					("HTC Rx: invalid EndpointID=%d\n",
318 					 htc_ep_id));
319 			debug_dump_bytes((uint8_t *) HtcHdr,
320 					sizeof(HTC_FRAME_HDR),
321 					"BAD HTC Header");
322 			status = QDF_STATUS_E_FAILURE;
323 			QDF_BUG(0);
324 			break;
325 		}
326 
327 		pEndpoint = &target->endpoint[htc_ep_id];
328 
329 		/*
330 		 * If this endpoint that received a message from the target has
331 		 * a to-target HIF pipe whose send completions are polled rather
332 		 * than interrupt driven, this is a good point to ask HIF to
333 		 * check whether it has any completed sends to handle.
334 		 */
335 		if (pEndpoint->ul_is_polled)
336 			htc_send_complete_check(pEndpoint, 1);
337 
338 		payloadLen = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, PAYLOADLEN);
339 
340 		if (netlen < (payloadLen + HTC_HDR_LENGTH)) {
341 #ifdef RX_SG_SUPPORT
342 			LOCK_HTC_RX(target);
343 			target->IsRxSgInprogress = true;
344 			qdf_nbuf_queue_init(&target->RxSgQueue);
345 			qdf_nbuf_queue_add(&target->RxSgQueue, netbuf);
346 			target->ExpRxSgTotalLen = (payloadLen + HTC_HDR_LENGTH);
347 			target->CurRxSgTotalLen += netlen;
348 			UNLOCK_HTC_RX(target);
349 			netbuf = NULL;
350 			break;
351 #else
352 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
353 					("HTC Rx: insufficient length, got:%d expected =%zu\n",
354 					 netlen, payloadLen + HTC_HDR_LENGTH));
355 			debug_dump_bytes((uint8_t *) HtcHdr,
356 					 sizeof(HTC_FRAME_HDR),
357 					 "BAD RX packet length");
358 			status = QDF_STATUS_E_FAILURE;
359 			QDF_BUG(0);
360 			break;
361 #endif
362 		}
363 #ifdef HTC_EP_STAT_PROFILING
364 		LOCK_HTC_RX(target);
365 		INC_HTC_EP_STAT(pEndpoint, RxReceived, 1);
366 		UNLOCK_HTC_RX(target);
367 #endif
368 
369 		/* if (IS_TX_CREDIT_FLOW_ENABLED(pEndpoint)) { */
370 		{
371 			uint8_t temp;
372 			A_STATUS temp_status;
373 			/* get flags to check for trailer */
374 			temp = HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR, FLAGS);
375 			if (temp & HTC_FLAGS_RECV_TRAILER) {
376 				/* extract the trailer length */
377 				temp =
378 					HTC_GET_FIELD(HtcHdr, HTC_FRAME_HDR,
379 						      CONTROLBYTES0);
380 				if ((temp < sizeof(HTC_RECORD_HDR))
381 				    || (temp > payloadLen)) {
382 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
383 						("htc_rx_completion_handler, invalid header (payloadlength should be :%d, CB[0] is:%d)\n",
384 						payloadLen, temp));
385 					status = QDF_STATUS_E_INVAL;
386 					break;
387 				}
388 
389 				trailerlen = temp;
390 				/* process trailer data that follows HDR +
391 				 * application payload
392 				 */
393 				temp_status = htc_process_trailer(target,
394 						((uint8_t *) HtcHdr +
395 							HTC_HDR_LENGTH +
396 							payloadLen - temp),
397 						temp, htc_ep_id);
398 				if (A_FAILED(temp_status)) {
399 					status = QDF_STATUS_E_FAILURE;
400 					break;
401 				}
402 
403 			}
404 		}
405 
406 		if (((int)payloadLen - (int)trailerlen) <= 0) {
407 			/* 0 length packet with trailer data, just drop these */
408 			break;
409 		}
410 
411 		if (htc_ep_id == ENDPOINT_0) {
412 			uint16_t message_id;
413 			HTC_UNKNOWN_MSG *htc_msg;
414 			bool wow_nack;
415 
416 			/* remove HTC header */
417 			qdf_nbuf_pull_head(netbuf, HTC_HDR_LENGTH);
418 			netdata = qdf_nbuf_data(netbuf);
419 			netlen = qdf_nbuf_len(netbuf);
420 
421 			htc_msg = (HTC_UNKNOWN_MSG *) netdata;
422 			message_id = HTC_GET_FIELD(htc_msg, HTC_UNKNOWN_MSG,
423 						   MESSAGEID);
424 
425 			switch (message_id) {
426 			default:
427 				/* handle HTC control message */
428 				if (target->CtrlResponseProcessing) {
429 					/* this is a fatal error, target should
430 					 * not be sending unsolicited messages
431 					 * on the endpoint 0
432 					 */
433 					AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
434 							("HTC Rx Ctrl still processing\n"));
435 					status = QDF_STATUS_E_FAILURE;
436 					QDF_BUG(false);
437 					break;
438 				}
439 
440 				LOCK_HTC_RX(target);
441 				target->CtrlResponseLength =
442 					min((int)netlen,
443 					    HTC_MAX_CONTROL_MESSAGE_LENGTH);
444 				qdf_mem_copy(target->CtrlResponseBuffer,
445 					     netdata,
446 					     target->CtrlResponseLength);
447 
448 				/* Requester will clear this flag */
449 				target->CtrlResponseProcessing = true;
450 				UNLOCK_HTC_RX(target);
451 
452 				qdf_event_set(&target->ctrl_response_valid);
453 				break;
454 #ifdef HTC_MSG_WAKEUP_FROM_SUSPEND_ID
455 			case HTC_MSG_WAKEUP_FROM_SUSPEND_ID:
456 				AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
457 					("Received initial wake up"));
458 				LOCK_HTC_CREDIT(target);
459 				htc_credit_record(HTC_INITIAL_WAKE_UP,
460 					pEndpoint->TxCredits,
461 					HTC_PACKET_QUEUE_DEPTH(
462 						&pEndpoint->TxQueue));
463 				UNLOCK_HTC_CREDIT(target);
464 				info = &target->HTCInitInfo;
465 				if (info && info->target_initial_wakeup_cb)
466 					info->target_initial_wakeup_cb(
467 						info->target_psoc);
468 				else
469 					AR_DEBUG_PRINTF(ATH_DEBUG_ANY,
470 						("No initial wake up cb"));
471 				break;
472 #endif
473 			case HTC_MSG_SEND_SUSPEND_COMPLETE:
474 				wow_nack = false;
475 				LOCK_HTC_CREDIT(target);
476 				htc_credit_record(HTC_SUSPEND_ACK,
477 					pEndpoint->TxCredits,
478 					HTC_PACKET_QUEUE_DEPTH(
479 						&pEndpoint->TxQueue));
480 				UNLOCK_HTC_CREDIT(target);
481 				target->HTCInitInfo.TargetSendSuspendComplete(
482 					target->HTCInitInfo.target_psoc,
483 					wow_nack);
484 
485 				break;
486 			case HTC_MSG_NACK_SUSPEND:
487 				wow_nack = true;
488 				LOCK_HTC_CREDIT(target);
489 				htc_credit_record(HTC_SUSPEND_ACK,
490 					pEndpoint->TxCredits,
491 					HTC_PACKET_QUEUE_DEPTH(
492 						&pEndpoint->TxQueue));
493 				UNLOCK_HTC_CREDIT(target);
494 
495 				target->HTCInitInfo.TargetSendSuspendComplete(
496 					target->HTCInitInfo.target_psoc,
497 					wow_nack);
498 				break;
499 			}
500 
501 			qdf_nbuf_free(netbuf);
502 			netbuf = NULL;
503 			break;
504 		}
505 
506 		/* the current message based HIF architecture allocates net bufs
507 		 * for recv packets since this layer bridges that HIF to upper
508 		 * layers , which expects HTC packets, we form the packets here
509 		 * TODO_FIXME
510 		 */
511 		pPacket = allocate_htc_packet_container(target);
512 		if (NULL == pPacket) {
513 			status = QDF_STATUS_E_RESOURCES;
514 			break;
515 		}
516 		pPacket->Status = QDF_STATUS_SUCCESS;
517 		pPacket->Endpoint = htc_ep_id;
518 		pPacket->pPktContext = netbuf;
519 		pPacket->pBuffer = qdf_nbuf_data(netbuf) + HTC_HDR_LENGTH;
520 		pPacket->ActualLength = netlen - HTC_HEADER_LEN - trailerlen;
521 
522 		qdf_nbuf_pull_head(netbuf, HTC_HEADER_LEN);
523 		qdf_nbuf_set_pktlen(netbuf, pPacket->ActualLength);
524 
525 		recv_packet_completion(target, pEndpoint, pPacket);
526 		/* recover the packet container */
527 		free_htc_packet_container(target, pPacket);
528 		netbuf = NULL;
529 
530 	} while (false);
531 
532 #ifdef RX_SG_SUPPORT
533 _out:
534 #endif
535 
536 	if (netbuf != NULL)
537 		qdf_nbuf_free(netbuf);
538 
539 	return status;
540 
541 }
542 
543 A_STATUS htc_add_receive_pkt_multiple(HTC_HANDLE HTCHandle,
544 				      HTC_PACKET_QUEUE *pPktQueue)
545 {
546 	HTC_TARGET *target = GET_HTC_TARGET_FROM_HANDLE(HTCHandle);
547 	HTC_ENDPOINT *pEndpoint;
548 	HTC_PACKET *pFirstPacket;
549 	A_STATUS status = A_OK;
550 	HTC_PACKET *pPacket;
551 
552 	pFirstPacket = htc_get_pkt_at_head(pPktQueue);
553 
554 	if (NULL == pFirstPacket) {
555 		A_ASSERT(false);
556 		return A_EINVAL;
557 	}
558 
559 	AR_DEBUG_ASSERT(pFirstPacket->Endpoint < ENDPOINT_MAX);
560 
561 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
562 			("+- htc_add_receive_pkt_multiple : endPointId: %d, cnt:%d, length: %d\n",
563 			 pFirstPacket->Endpoint,
564 			 HTC_PACKET_QUEUE_DEPTH(pPktQueue),
565 			 pFirstPacket->BufferLength));
566 
567 	pEndpoint = &target->endpoint[pFirstPacket->Endpoint];
568 
569 	LOCK_HTC_RX(target);
570 
571 	do {
572 
573 		if (HTC_STOPPING(target)) {
574 			status = A_ERROR;
575 			break;
576 		}
577 
578 		/* store receive packets */
579 		HTC_PACKET_QUEUE_TRANSFER_TO_TAIL(&pEndpoint->RxBufferHoldQueue,
580 						  pPktQueue);
581 
582 	} while (false);
583 
584 	UNLOCK_HTC_RX(target);
585 
586 	if (A_FAILED(status)) {
587 		/* walk through queue and mark each one canceled */
588 		HTC_PACKET_QUEUE_ITERATE_ALLOW_REMOVE(pPktQueue, pPacket) {
589 			pPacket->Status = QDF_STATUS_E_CANCELED;
590 		}
591 		HTC_PACKET_QUEUE_ITERATE_END;
592 
593 		do_recv_completion(pEndpoint, pPktQueue);
594 	}
595 
596 	return status;
597 }
598 
599 A_STATUS htc_add_receive_pkt(HTC_HANDLE HTCHandle, HTC_PACKET *pPacket)
600 {
601 	HTC_PACKET_QUEUE queue;
602 
603 	INIT_HTC_PACKET_QUEUE_AND_ADD(&queue, pPacket);
604 	return htc_add_receive_pkt_multiple(HTCHandle, &queue);
605 }
606 
607 void htc_flush_rx_hold_queue(HTC_TARGET *target, HTC_ENDPOINT *pEndpoint)
608 {
609 	HTC_PACKET *pPacket;
610 	HTC_PACKET_QUEUE container;
611 
612 	LOCK_HTC_RX(target);
613 
614 	while (1) {
615 		pPacket = htc_packet_dequeue(&pEndpoint->RxBufferHoldQueue);
616 		if (pPacket == NULL)
617 			break;
618 		UNLOCK_HTC_RX(target);
619 		pPacket->Status = QDF_STATUS_E_CANCELED;
620 		pPacket->ActualLength = 0;
621 		AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
622 				("Flushing RX packet:%p, length:%d, ep:%d\n",
623 				 pPacket, pPacket->BufferLength,
624 				 pPacket->Endpoint));
625 		INIT_HTC_PACKET_QUEUE_AND_ADD(&container, pPacket);
626 		/* give the packet back */
627 		do_recv_completion(pEndpoint, &container);
628 		LOCK_HTC_RX(target);
629 	}
630 
631 	UNLOCK_HTC_RX(target);
632 }
633 
634 void htc_recv_init(HTC_TARGET *target)
635 {
636 	/* Initialize ctrl_response_valid to block */
637 	qdf_event_create(&target->ctrl_response_valid);
638 }
639 
640 /* polling routine to wait for a control packet to be received */
641 QDF_STATUS htc_wait_recv_ctrl_message(HTC_TARGET *target)
642 {
643 /*    int count = HTC_TARGET_MAX_RESPONSE_POLL; */
644 
645 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("+HTCWaitCtrlMessageRecv\n"));
646 
647 	/* Wait for BMI request/response transaction to complete */
648 	if (qdf_wait_single_event(&target->ctrl_response_valid,
649 				  HTC_CONTROL_RX_TIMEOUT)) {
650 		QDF_BUG(0);
651 		return QDF_STATUS_E_FAILURE;
652 	}
653 
654 	LOCK_HTC_RX(target);
655 	/* caller will clear this flag */
656 	target->CtrlResponseProcessing = true;
657 
658 	UNLOCK_HTC_RX(target);
659 
660 	AR_DEBUG_PRINTF(ATH_DEBUG_TRC, ("-HTCWaitCtrlMessageRecv success\n"));
661 	return QDF_STATUS_SUCCESS;
662 }
663 
664 static A_STATUS htc_process_trailer(HTC_TARGET *target,
665 				    uint8_t *pBuffer,
666 				    int Length, HTC_ENDPOINT_ID FromEndpoint)
667 {
668 	HTC_RECORD_HDR *pRecord;
669 	uint8_t htc_rec_id;
670 	uint8_t htc_rec_len;
671 	uint8_t *pRecordBuf;
672 	uint8_t *pOrigBuffer;
673 	int origLength;
674 	A_STATUS status;
675 
676 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV,
677 			("+htc_process_trailer (length:%d)\n", Length));
678 
679 	if (AR_DEBUG_LVL_CHECK(ATH_DEBUG_RECV))
680 		AR_DEBUG_PRINTBUF(pBuffer, Length, "Recv Trailer");
681 
682 	pOrigBuffer = pBuffer;
683 	origLength = Length;
684 	status = A_OK;
685 
686 	while (Length > 0) {
687 
688 		if (Length < sizeof(HTC_RECORD_HDR)) {
689 			status = A_EPROTO;
690 			break;
691 		}
692 		/* these are byte aligned structs */
693 		pRecord = (HTC_RECORD_HDR *) pBuffer;
694 		Length -= sizeof(HTC_RECORD_HDR);
695 		pBuffer += sizeof(HTC_RECORD_HDR);
696 
697 		htc_rec_len = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, LENGTH);
698 		htc_rec_id = HTC_GET_FIELD(pRecord, HTC_RECORD_HDR, RECORDID);
699 
700 		if (htc_rec_len > Length) {
701 			/* no room left in buffer for record */
702 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
703 					("invalid record length: %d (id:%d) buffer has: %d bytes left\n",
704 					 htc_rec_len, htc_rec_id, Length));
705 			status = A_EPROTO;
706 			break;
707 		}
708 		/* start of record follows the header */
709 		pRecordBuf = pBuffer;
710 
711 		switch (htc_rec_id) {
712 		case HTC_RECORD_CREDITS:
713 			AR_DEBUG_ASSERT(htc_rec_len >=
714 					sizeof(HTC_CREDIT_REPORT));
715 			htc_process_credit_rpt(target,
716 					       (HTC_CREDIT_REPORT *) pRecordBuf,
717 					       htc_rec_len /
718 					       (sizeof(HTC_CREDIT_REPORT)),
719 					       FromEndpoint);
720 			break;
721 
722 #ifdef HIF_SDIO
723 		case HTC_RECORD_LOOKAHEAD:
724 			/* Process in HIF layer */
725 			break;
726 
727 		case HTC_RECORD_LOOKAHEAD_BUNDLE:
728 			/* Process in HIF layer */
729 			break;
730 #endif /* HIF_SDIO */
731 
732 		default:
733 			AR_DEBUG_PRINTF(ATH_DEBUG_ERR,
734 					("HTC unhandled record: id:%d length:%d\n",
735 					 htc_rec_id, htc_rec_len));
736 			break;
737 		}
738 
739 		if (A_FAILED(status)) {
740 			break;
741 		}
742 
743 		/* advance buffer past this record for next time around */
744 		pBuffer += htc_rec_len;
745 		Length -= htc_rec_len;
746 	}
747 
748 	if (A_FAILED(status))
749 		debug_dump_bytes(pOrigBuffer, origLength, "BAD Recv Trailer");
750 
751 	AR_DEBUG_PRINTF(ATH_DEBUG_RECV, ("-htc_process_trailer\n"));
752 	return status;
753 
754 }
755