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