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